parent
4a7b82b2f8
commit
0d773e28b7
@ -0,0 +1,102 @@ |
|||||||
|
$button-color: rgb(147, 146, 146); |
||||||
|
$main-color: rgb(240, 141, 25); |
||||||
|
|
||||||
|
*{ |
||||||
|
margin:0; |
||||||
|
padding: 0; |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
body{ |
||||||
|
font-family: Roboto; |
||||||
|
|
||||||
|
} |
||||||
|
main{ |
||||||
|
position: relative; |
||||||
|
height: 100vh; |
||||||
|
|
||||||
|
#infobar{ |
||||||
|
position: absolute; |
||||||
|
top:0; |
||||||
|
width: 100%; |
||||||
|
padding: 0.4em; |
||||||
|
background-color: rgba(232, 9, 9, 0.4); |
||||||
|
border: 4px solid rgba(232, 9, 9, 0.8); |
||||||
|
text-align: center; |
||||||
|
font-weight: bold; |
||||||
|
font-size: 1.8em; |
||||||
|
z-index: 1; |
||||||
|
transform: translateY(-100%); |
||||||
|
transition: transform 1s; |
||||||
|
&.active{ |
||||||
|
transform: translateY(0%); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.canvas{ |
||||||
|
background-color: lightgrey; |
||||||
|
position: relative; |
||||||
|
height: 100%; |
||||||
|
|
||||||
|
input{ |
||||||
|
position: absolute; |
||||||
|
border: none; |
||||||
|
padding: 0.6em 1em; |
||||||
|
width: 50px; |
||||||
|
transform: translateX(-50%) translateY(-50%); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
nav, footer{ |
||||||
|
display: flex; |
||||||
|
position: absolute; |
||||||
|
top: 1em; |
||||||
|
left: 1em; |
||||||
|
opacity: 0.9; |
||||||
|
|
||||||
|
button{ |
||||||
|
display: block; |
||||||
|
background-color: $button-color; |
||||||
|
border: none; |
||||||
|
border-radius: 1em; |
||||||
|
padding: 1em 1em; |
||||||
|
min-width: 8em; |
||||||
|
margin: 0.4em; |
||||||
|
color: black; |
||||||
|
border: solid 2px darken($button-color, 50); |
||||||
|
box-shadow: 2px 2px 8px rgba(0,0,0,0.5); |
||||||
|
|
||||||
|
&:focus { |
||||||
|
outline: none; |
||||||
|
} |
||||||
|
&::-moz-focus-inner { |
||||||
|
border: 0; |
||||||
|
} |
||||||
|
&:hover{ |
||||||
|
background-color: lighten($button-color, 10); |
||||||
|
border-color: darken($button-color, 100); |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
&.active{ |
||||||
|
background-color: $main-color; |
||||||
|
} |
||||||
|
h1{ |
||||||
|
text-align: center; |
||||||
|
font-size: 1.4em; |
||||||
|
font-weight: normal; |
||||||
|
|
||||||
|
white-space: nowrap |
||||||
|
} |
||||||
|
img{ |
||||||
|
display: block; |
||||||
|
margin: 0 auto 0.5em auto; |
||||||
|
width: 2em; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
footer{ |
||||||
|
top: auto; |
||||||
|
left: auto; |
||||||
|
bottom: 1em; |
||||||
|
right: 1em; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
*{margin:0;padding:0;box-sizing:border-box}body{font-family:Roboto}main{position:relative;height:100vh}main #infobar{position:absolute;top:0;width:100%;padding:0.4em;background-color:rgba(232,9,9,0.4);border:4px solid rgba(232,9,9,0.8);text-align:center;font-weight:bold;font-size:1.8em;z-index:1;transform:translateY(-100%);transition:transform 1s}main #infobar.active{transform:translateY(0%)}main .canvas{background-color:lightgrey;position:relative;height:100%}main .canvas input{position:absolute;border:none;padding:0.6em 1em;width:50px;transform:translateX(-50%) translateY(-50%)}main nav,main footer{display:flex;position:absolute;top:1em;left:1em;opacity:0.9}main nav button,main footer button{display:block;background-color:#939292;border:none;border-radius:1em;padding:1em 1em;min-width:8em;margin:0.4em;color:black;border:solid 2px #131313;box-shadow:2px 2px 8px rgba(0,0,0,0.5)}main nav button:focus,main footer button:focus{outline:none}main nav button::-moz-focus-inner,main footer button::-moz-focus-inner{border:0}main nav button:hover,main footer button:hover{background-color:#acacac;border-color:#000;cursor:pointer}main nav button.active,main footer button.active{background-color:#f08d19}main nav button h1,main footer button h1{text-align:center;font-size:1.4em;font-weight:normal;white-space:nowrap}main nav button img,main footer button img{display:block;margin:0 auto 0.5em auto;width:2em}main footer{top:auto;left:auto;bottom:1em;right:1em} |
Binary file not shown.
After Width: | Height: | Size: 774 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,12 @@ |
|||||||
|
@font-face { |
||||||
|
font-family: 'Roboto-Regular'; |
||||||
|
src: url('Roboto-Regular.eot'); |
||||||
|
src: url('Roboto-Regular.eot?#iefix') format('embedded-opentype'), |
||||||
|
url('Roboto-Regular.svg#Roboto-Regular') format('svg'), |
||||||
|
url('Roboto-Regular.ttf') format('truetype'), |
||||||
|
url('Roboto-Regular.woff') format('woff'), |
||||||
|
url('Roboto-Regular.woff2') format('woff2'); |
||||||
|
font-weight: normal; |
||||||
|
font-style: normal; |
||||||
|
} |
||||||
|
|
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,436 @@ |
|||||||
|
const canvas = document.getElementById("canvas"); |
||||||
|
|
||||||
|
// Layouts
|
||||||
|
var width = canvas.offsetWidth; |
||||||
|
var height = canvas.offsetHeight; |
||||||
|
|
||||||
|
const node_size = 55; |
||||||
|
|
||||||
|
var stage = new Konva.Stage({ |
||||||
|
container: canvas, |
||||||
|
width: width, |
||||||
|
height: height |
||||||
|
}); |
||||||
|
|
||||||
|
const node_layout = { |
||||||
|
radius: node_size, |
||||||
|
fill: 'white', |
||||||
|
stroke: 'black', |
||||||
|
strokeWidth: 2, |
||||||
|
shadowColor: 'black', |
||||||
|
shadowBlur: 10, |
||||||
|
shadowOffset: { |
||||||
|
x: 2, |
||||||
|
y: 2 |
||||||
|
}, |
||||||
|
shadowOpacity: 0.3, |
||||||
|
}; |
||||||
|
|
||||||
|
const node_text_layout = { |
||||||
|
x: 1 - node_size, |
||||||
|
y: 2 - node_size, |
||||||
|
text: name, |
||||||
|
fontSize: 22, |
||||||
|
width: 2 * node_size-1, |
||||||
|
height: 2 * node_size-1, |
||||||
|
fontFamily: 'Roboto', |
||||||
|
fill: 'black', |
||||||
|
verticalAlign: 'middle', |
||||||
|
align: 'center' |
||||||
|
}; |
||||||
|
|
||||||
|
const edge_layout = { |
||||||
|
stroke: 'black', |
||||||
|
strokeWidth: 3, |
||||||
|
} |
||||||
|
|
||||||
|
const edge_text_layout = { |
||||||
|
fontSize: 22, |
||||||
|
width: 2 * node_size, |
||||||
|
height: 2 * node_size, |
||||||
|
fontFamily: 'Roboto', |
||||||
|
fill: 'black', |
||||||
|
verticalAlign: 'middle', |
||||||
|
align: 'center' |
||||||
|
}; |
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//-------------------------------Init------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
var edge_layer = new Konva.Layer(); |
||||||
|
var node_layer = new Konva.Layer(); |
||||||
|
|
||||||
|
var konva_edges = []; |
||||||
|
var konva_nodes = []; |
||||||
|
var graph_copy = {}; |
||||||
|
|
||||||
|
var state = "idle"; |
||||||
|
|
||||||
|
// selected nodes
|
||||||
|
var selected = []; |
||||||
|
var path_elements = []; |
||||||
|
|
||||||
|
// (additions) auto layout
|
||||||
|
var auto_layout = false; |
||||||
|
|
||||||
|
function initialisation(){ |
||||||
|
stage.add(edge_layer); |
||||||
|
stage.add(node_layer); |
||||||
|
|
||||||
|
// avoid flickering
|
||||||
|
edge_layer.hide(); |
||||||
|
|
||||||
|
// draw initial graph
|
||||||
|
for (id in nodes) { |
||||||
|
draw_new_node(nodes[id], node_size + Math.random() * (width - 2 * node_size), node_size + Math.random() * (height - 2 * node_size)); |
||||||
|
} |
||||||
|
for (id in edges) { |
||||||
|
draw_new_edge(edges[id]); |
||||||
|
} |
||||||
|
|
||||||
|
// (additions) auto layout
|
||||||
|
|
||||||
|
if ( sessionStorage.getItem("auto_layout") !== null) { |
||||||
|
// Restore the contents of the text field
|
||||||
|
auto_layout = (sessionStorage.getItem("auto_layout") == 'true'); |
||||||
|
if (auto_layout){ |
||||||
|
document.querySelector("[data-activeon=auto_layout]").classList.add("active"); |
||||||
|
} |
||||||
|
} |
||||||
|
// Precalculate a good graph presentation
|
||||||
|
for (var i = 0; i < 1000; i++) { |
||||||
|
force_directed_graph(); |
||||||
|
} |
||||||
|
node_layer.draw(); |
||||||
|
|
||||||
|
|
||||||
|
edge_layer.show(); |
||||||
|
|
||||||
|
} |
||||||
|
initialisation(); |
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//------------------------------utils------------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
function sort(array) { |
||||||
|
return array.sort(function(a, b) { |
||||||
|
return a - b; |
||||||
|
}) |
||||||
|
} |
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//---------------------------draw methods--------------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
function draw_new_node(name, x, y) { |
||||||
|
const pos = { |
||||||
|
x: x, |
||||||
|
y: y |
||||||
|
}; |
||||||
|
let group = new Konva.Group({ |
||||||
|
...pos, |
||||||
|
draggable: true, |
||||||
|
dragBoundFunc: function(pos) { |
||||||
|
return { |
||||||
|
x: sort([node_size, pos.x, width - node_size])[1], |
||||||
|
y: sort([node_size, pos.y, height - node_size])[1], |
||||||
|
}; |
||||||
|
}, |
||||||
|
id: name |
||||||
|
}); |
||||||
|
let box = new Konva.Circle(node_layout); |
||||||
|
let simpleText = new Konva.Text({...node_text_layout, text: name}); |
||||||
|
group.add(box); |
||||||
|
group.add(simpleText); |
||||||
|
group.on("click", on_node_click); |
||||||
|
group.on('dragstart', function() { |
||||||
|
group.attrs.dragging = true; |
||||||
|
}); |
||||||
|
group.on('dragend', function() { |
||||||
|
group.attrs.dragging = false; |
||||||
|
}); |
||||||
|
group.on('mouseover', function() { |
||||||
|
document.body.style.cursor = 'pointer'; |
||||||
|
}); |
||||||
|
group.on('mouseout', function() { |
||||||
|
document.body.style.cursor = 'default'; |
||||||
|
}); |
||||||
|
graph_copy[name] = []; |
||||||
|
konva_nodes.push(group); |
||||||
|
|
||||||
|
node_layer.add(group); |
||||||
|
node_layer.draw(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function draw_new_edge(edge) { |
||||||
|
let start_node = stage.findOne('#' + edge["start"]); |
||||||
|
let end_node = stage.findOne('#' + edge["end"]); |
||||||
|
let weight = edge["weight"]; |
||||||
|
let group = new Konva.Group({ |
||||||
|
start_node: start_node, |
||||||
|
end_node: end_node, |
||||||
|
weight: weight, |
||||||
|
id: edge["start"]+edge["end"] |
||||||
|
}); |
||||||
|
let line = new Konva.Line(edge_layout); |
||||||
|
let simpleText = new Konva.Text({...edge_text_layout, text: weight}); |
||||||
|
|
||||||
|
graph_copy[edge["start"]].push(edge["end"]); |
||||||
|
graph_copy[edge["end"]].push(edge["start"]); |
||||||
|
|
||||||
|
group.add(line); |
||||||
|
group.add(simpleText); |
||||||
|
konva_edges.push(group); |
||||||
|
update_edge(group); |
||||||
|
|
||||||
|
edge_layer.add(group); |
||||||
|
edge_layer.draw(); |
||||||
|
|
||||||
|
return group; |
||||||
|
} |
||||||
|
|
||||||
|
function update_edge(konva_edge) { |
||||||
|
let line = konva_edge.children[0]; |
||||||
|
let text = konva_edge.children[1]; |
||||||
|
let start_node = konva_edge.attrs.start_node; |
||||||
|
let end_node = konva_edge.attrs.end_node; |
||||||
|
let size = 15+text.text().length*15; |
||||||
|
let line_length = Math.sqrt((start_node.getX() - end_node.getX()) ** 2 + (start_node.getY() - end_node.getY()) ** 2) - size; |
||||||
|
line.points([start_node.getX(), start_node.getY(), end_node.getX(), end_node.getY()]); |
||||||
|
line.dash([line_length / 2, size, line_length / 2]); |
||||||
|
text.x((start_node.getX() + end_node.getX()) / 2 - node_size); |
||||||
|
text.y((start_node.getY() + end_node.getY()) / 2 - node_size), |
||||||
|
|
||||||
|
edge_layer.draw(); |
||||||
|
} |
||||||
|
|
||||||
|
function reset_node_style(){ |
||||||
|
for (let id in konva_nodes) { |
||||||
|
konva_nodes[id].children[0].strokeWidth(node_layout.strokeWidth); |
||||||
|
konva_nodes[id].children[0].stroke("black"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function reset_edge_style(){ |
||||||
|
for (let id in konva_edges) { |
||||||
|
konva_edges[id].children[0].strokeWidth(edge_layout.strokeWidth); |
||||||
|
konva_edges[id].children[0].stroke("black"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function draw_selected_nodes() { |
||||||
|
reset_node_style(); |
||||||
|
reset_edge_style(); |
||||||
|
for (let id in selected) { |
||||||
|
selected[id].children[0].strokeWidth(node_layout.strokeWidth + 1); |
||||||
|
selected[id].children[0].stroke("rgb(240, 141, 25)"); |
||||||
|
} |
||||||
|
node_layer.draw(); |
||||||
|
} |
||||||
|
|
||||||
|
function draw_path(path){ |
||||||
|
let path_elements = []; |
||||||
|
for (let id in path){ |
||||||
|
path_elements.push(stage.findOne("#"+path[id])); |
||||||
|
if (id == 0) { |
||||||
|
continue |
||||||
|
} |
||||||
|
let current_edge = stage.findOne("#"+path[id-1]+path[id]); |
||||||
|
if (current_edge){ |
||||||
|
path_elements.push(current_edge); |
||||||
|
}else{ |
||||||
|
path_elements.push(stage.findOne("#"+path[id]+path[id-1])); |
||||||
|
} |
||||||
|
} |
||||||
|
reset_node_style(); |
||||||
|
reset_edge_style(); |
||||||
|
for (let id in path_elements) { |
||||||
|
path_elements[id].children[0].strokeWidth(node_layout.strokeWidth + 1); |
||||||
|
path_elements[id].children[0].stroke("rgb(240, 141, 25)"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function on_node_click(e) { |
||||||
|
e.cancelBubble = true; |
||||||
|
// let mousePos = stage.getPointerPosition();
|
||||||
|
let idx = selected.indexOf(this); |
||||||
|
if (idx >= 0) { |
||||||
|
selected.splice(idx, 1); |
||||||
|
} else if (selected.length < 2) { |
||||||
|
selected.push(this); |
||||||
|
} else { |
||||||
|
selected.shift(); |
||||||
|
selected.push(this); |
||||||
|
} |
||||||
|
draw_selected_nodes(); |
||||||
|
}; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function create_node(){ |
||||||
|
if (state != "create_node"){ |
||||||
|
state = "create_node"; |
||||||
|
// let mousePos = stage.getPointerPosition();
|
||||||
|
let pos = {x: width/2, y: height/2}; |
||||||
|
create_input(pos.x, pos.y).then(function(text) { |
||||||
|
draw_new_node(text, pos.x, pos.y); |
||||||
|
state = "idle"; |
||||||
|
}, function(){state = "idle"}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function create_edge() { |
||||||
|
if (selected.length < 2) { |
||||||
|
show_error("Select at least 2 nodes."); |
||||||
|
return; |
||||||
|
} |
||||||
|
let x = (selected[0].getX() + selected[1].getX()) / 2; |
||||||
|
let y = (selected[0].getY() + selected[1].getY()) / 2; |
||||||
|
create_input(x, y).then(function(text) { |
||||||
|
draw_new_edge({ |
||||||
|
"start": selected[0].children[1].text(), |
||||||
|
"end": selected[1].children[1].text(), |
||||||
|
"weight": text |
||||||
|
}); |
||||||
|
selected = []; |
||||||
|
draw_selected_nodes(); |
||||||
|
},function(){}); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function create_input(x, y) { |
||||||
|
return new Promise(function(resolve, reject) { |
||||||
|
var input = document.createElement("input"); |
||||||
|
input.setAttribute("type", "text"); |
||||||
|
input.style.left = x + "px"; |
||||||
|
input.style.top = y + "px"; |
||||||
|
canvas.appendChild(input); |
||||||
|
input.focus(); |
||||||
|
stage.listening(false); |
||||||
|
window.addEventListener("keyup", function(event) { |
||||||
|
if (event.key === "Escape") { |
||||||
|
input.remove(); |
||||||
|
stage.listening(true); |
||||||
|
reject(); |
||||||
|
} |
||||||
|
}); |
||||||
|
input.addEventListener("keyup", function(event) { |
||||||
|
if (event.key === "Enter") { |
||||||
|
resolve(input.value); |
||||||
|
input.remove(); |
||||||
|
stage.listening(true); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
function find_path(){ |
||||||
|
draw_path(elem); |
||||||
|
} |
||||||
|
|
||||||
|
function update_edges(edges) { |
||||||
|
for (id in edges) { |
||||||
|
update_edge(edges[id]); |
||||||
|
} |
||||||
|
} |
||||||
|
node_layer.on('beforeDraw', function() { |
||||||
|
update_edges(konva_edges); |
||||||
|
}); |
||||||
|
|
||||||
|
// adapt the stage on any window resize
|
||||||
|
function fitStageIntoParentContainer() { |
||||||
|
width = canvas.offsetWidth; |
||||||
|
height = canvas.offsetHeight; |
||||||
|
stage.width(canvas.offsetWidth); |
||||||
|
stage.height(canvas.offsetHeight); |
||||||
|
stage.draw(); |
||||||
|
} |
||||||
|
window.addEventListener('resize', fitStageIntoParentContainer); |
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
//---------------------(additions) auto layout---------------------------------
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function toggle_auto_layout() { |
||||||
|
auto_layout = !auto_layout; |
||||||
|
document.querySelector("[data-activeon=auto_layout]").classList.toggle("active"); |
||||||
|
sessionStorage.setItem("auto_layout", auto_layout); |
||||||
|
} |
||||||
|
|
||||||
|
function normalize(vec) { |
||||||
|
let l = Math.sqrt(vec[0]**2+vec[1]**2); |
||||||
|
return [vec[0]/l,vec[1]/l]; |
||||||
|
} |
||||||
|
|
||||||
|
function in_edges(start_node, end_node){ |
||||||
|
let idx = graph_copy[start_node.attrs.id].indexOf(end_node.attrs.id); |
||||||
|
if (idx < 0){ |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
function force_directed_graph(spring_length = 300, step = 0.004){ |
||||||
|
for (var idx in konva_nodes){ |
||||||
|
if (konva_nodes[idx].attrs.dragging){ |
||||||
|
continue |
||||||
|
} |
||||||
|
var x1 = konva_nodes[idx].getX(); |
||||||
|
var y1 = konva_nodes[idx].getY(); |
||||||
|
|
||||||
|
var rep = [0,0]; |
||||||
|
var attr = [0,0]; |
||||||
|
for (let jdx in konva_nodes){ |
||||||
|
if (idx == jdx){ |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
let x2 = konva_nodes[jdx].getX(); |
||||||
|
let y2 = konva_nodes[jdx].getY(); |
||||||
|
let dir = normalize([x2-x1,y2-y1]); |
||||||
|
let dist = ((x1-x2)**2+(y1-y2)**2); |
||||||
|
if (in_edges(konva_nodes[idx], konva_nodes[jdx])){ |
||||||
|
let f = (dist/spring_length); |
||||||
|
attr[0] += f*dir[0]; |
||||||
|
attr[1] += f*dir[1]; |
||||||
|
} |
||||||
|
let f = (spring_length**2/Math.sqrt(dist)); |
||||||
|
rep[0] -= f*dir[0]; |
||||||
|
rep[1] -= f*dir[1]; |
||||||
|
} |
||||||
|
let new_x = x1+step*(rep[0]+attr[0]); |
||||||
|
let new_y = y1+step*(rep[1]+attr[1]); |
||||||
|
if (new_x < 2*node_size) { |
||||||
|
new_x += 10*step*((2*node_size-new_x)); |
||||||
|
} else if (new_x > width-2*node_size) { |
||||||
|
new_x += 10*step*((width-2*node_size-new_x)); |
||||||
|
} |
||||||
|
if (new_y < 2*node_size) { |
||||||
|
new_y += 10*step*((2*node_size-new_y)); |
||||||
|
} else if (new_y > height-2*node_size) { |
||||||
|
new_y += 10*step*((height-2*node_size-new_y)); |
||||||
|
} |
||||||
|
konva_nodes[idx].x(new_x); |
||||||
|
konva_nodes[idx].y(new_y); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
var anim = new Konva.Animation(function(frame) { |
||||||
|
if (auto_layout) { |
||||||
|
const spring_length = 300; |
||||||
|
const step = 0.00025*frame.timeDiff; |
||||||
|
force_directed_graph(spring_length, step) |
||||||
|
} |
||||||
|
}, node_layer); |
||||||
|
anim.start(); |
||||||
|
|
||||||
|
|
||||||
|
function show_error(msg){ |
||||||
|
let infobar = document.querySelector("#infobar"); |
||||||
|
infobar.innerHTML = msg; |
||||||
|
infobar.classList.add("active"); |
||||||
|
window.setTimeout(function(){ infobar.classList.remove("active"); }, 4000); |
||||||
|
} |
||||||
|
|
||||||
|
// bug: this avoids glitches
|
||||||
|
window.onfocus = function () {auto_layout = true;}; |
||||||
|
window.onblur = function () {auto_layout = false;}; |
@ -0,0 +1,61 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="de" dir="ltr"> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<title>Assignment</title> |
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='fonts/roboto.css') }}"> |
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.min.css') }}"> |
||||||
|
<script src="https://unpkg.com/konva@4.0.7/konva.min.js"></script> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<main> |
||||||
|
<div id="infobar">You have to select at least 2 nodes</div> |
||||||
|
<div id="canvas" class="canvas"></div> |
||||||
|
<nav> |
||||||
|
<button type="button" onclick="create_node()"> |
||||||
|
<img src="{{ url_for('static', filename='imgs/plus.svg') }}"> |
||||||
|
<h1>Create</h1> |
||||||
|
</button> |
||||||
|
<button type="button" onclick="create_edge()"> |
||||||
|
<img src="{{ url_for('static', filename='imgs/drawing.svg') }}"> |
||||||
|
<h1>Connect</h1> |
||||||
|
</button> |
||||||
|
<button type="button" onclick="find_path()"> |
||||||
|
<img src="{{ url_for('static', filename='imgs/share.svg') }}"> |
||||||
|
<h1>Find Path</h1> |
||||||
|
</button> |
||||||
|
</nav> |
||||||
|
<footer> |
||||||
|
<button type="button" data-activeon="auto_layout" onclick="toggle_auto_layout()"> |
||||||
|
<h1>Automatic Layout</h1> |
||||||
|
</button> |
||||||
|
</footer> |
||||||
|
</main> |
||||||
|
<script> |
||||||
|
var nodes = ["Aachen", "Berlin", "Chemnitz", "Dresden", "Essen"] |
||||||
|
var edges = [{ |
||||||
|
"start": "Aachen", |
||||||
|
"end": "Berlin", |
||||||
|
"weight": 800 |
||||||
|
},{ |
||||||
|
"start": "Dresden", |
||||||
|
"end": "Berlin", |
||||||
|
"weight": 800 |
||||||
|
},{ |
||||||
|
"start": "Essen", |
||||||
|
"end": "Berlin", |
||||||
|
"weight": 800 |
||||||
|
}, { |
||||||
|
"start": "Chemnitz", |
||||||
|
"end": "Dresden", |
||||||
|
"weight": 5 |
||||||
|
}, |
||||||
|
{ |
||||||
|
"start": "Chemnitz", |
||||||
|
"end": "Berlin", |
||||||
|
"weight": 5 |
||||||
|
}] |
||||||
|
</script> |
||||||
|
<script src="{{ url_for('static', filename='js/canvas.js')}}"></script> |
||||||
|
</body> |
||||||
|
</html> |
@ -1,13 +0,0 @@ |
|||||||
<!DOCTYPE html> |
|
||||||
<html lang="de" dir="ltr"> |
|
||||||
<head> |
|
||||||
<meta charset="utf-8"> |
|
||||||
<title>Assignment</title> |
|
||||||
</head> |
|
||||||
<body> |
|
||||||
<p><b>nodes:</b> {{ nodes }}</p> |
|
||||||
<p><b>edges:</b> {{ edges }}</p> |
|
||||||
<div ></div> |
|
||||||
<script src="{{ url_for('static', filename='js/canvas.js')}}"></script> |
|
||||||
</body> |
|
||||||
</html> |
|
Loading…
Reference in new issue