Compare commits

...

1 Commits

Author SHA1 Message Date
Ugo Paavo Finnendahl 1228131dcc Frontend Part 2 5 years ago
  1. 14
      static/css/src/style.scss
  2. 1
      static/css/style.min.css
  3. 329
      static/js/canvas.js
  4. 34
      templates/index.html

@ -0,0 +1,14 @@
*{
margin:0;
padding: 0;
}
.canvas{
height: 90vh;
background-color: lightgrey;
position: relative;
input{
position: absolute;
}
}

@ -0,0 +1 @@
*{margin:0;padding:0}.canvas{height:90vh;background-color:lightgrey;position:relative}.canvas input{position:absolute}

@ -0,0 +1,329 @@
const canvas = document.getElementById("canvas");
const width = canvas.offsetWidth;
const height = canvas.offsetHeight;
const node_size = 60;
// Layouts
var stage = new Konva.Stage({
container: canvas,
width: width,
height: height
});
const node_layout = {
radius: node_size,
// fill: '#00D2FF',
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: 28,
width: 2 * node_size,
height: 2 * node_size,
fontFamily: 'Calibri',
fill: 'black',
verticalAlign: 'middle',
align: 'center'
};
const edge_layout = {
stroke: 'black',
strokeWidth: 3,
}
const edge_text_layout = {
fontSize: 28,
width: 2 * node_size,
height: 2 * node_size,
fontFamily: 'Calibri',
fill: 'black',
verticalAlign: 'middle',
align: 'center'
};
var edge_layer = new Konva.Layer();
var node_layer = new Konva.Layer();
var konva_edges = [];
var konva_nodes = [];
var graph_copy = {};
stage.add(edge_layer);
stage.add(node_layer);
for (id in nodes) {
draw_node(nodes[id], node_size + Math.random() * (width - 2 * node_size), node_size + Math.random() * (height - 2 * node_size));
}
for (id in edges) {
draw_edge(edges[id]);
}
function update_edges(edges) {
for (id in edges) {
update_edge(edges[id]);
}
}
function sort(array) {
return array.sort(function(a, b) {
return a - b;
})
}
function draw_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);
graph_copy[name] = [];
konva_nodes.push(group);
node_layer.add(group);
node_layer.draw();
}
function draw_edge(edge) {
let start_node = stage.find('#' + edge["start"])[0];
let end_node = stage.find('#' + edge["end"])[0];
let weight = edge["weight"];
let group = new Konva.Group({
start_node: start_node,
end_node: end_node,
weight: weight,
});
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 line_length = Math.sqrt((start_node.getX() - end_node.getX()) ** 2 + (start_node.getY() - end_node.getY()) ** 2) - node_size;
line.points([start_node.getX(), start_node.getY(), end_node.getX(), end_node.getY()]);
line.dash([line_length / 2, node_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();
}
node_layer.on('beforeDraw', function() {
update_edges(konva_edges);
});
var selected = [];
function on_node_click(e) {
e.cancelBubble = true;
let mousePos = stage.getPointerPosition();
// if (state == "CREATE_EDGE"){
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 draw_selected_nodes() {
for (let id in konva_nodes) {
konva_nodes[id].children[0].strokeWidth(node_layout.strokeWidth);
}
for (id in selected) {
selected[id].children[0].strokeWidth(node_layout.strokeWidth + 4);
}
node_layer.draw();
}
var state = "CREATE_NODE";
var old_state;
stage.on('click', function(e) {
if (state == "CREATE_NODE") {
state = "CREATING_NODE";
let mousePos = stage.getPointerPosition();
create_input(mousePos.x, mousePos.y).then(function(text) {
draw_node(text, mousePos.x, mousePos.y);
state = "CREATE_NODE";
},function(){state = "CREATE_NODE"});
}
});
function create_edge() {
state = "CREATE_EDGE";
if (selected.length < 2) {
alert("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_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 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 normalize(vec) {
let l = Math.sqrt(vec[0]**2+vec[1]**2);
return [vec[0]/l,vec[1]/l];
}
var auto_layout = "ENABLED";
function force_directed_graph(silent = false){
if (auto_layout == "ENABLED") {
const spring_length = 350;
const step = 0.025;
for (var idx in konva_nodes){
var x1 = konva_nodes[idx].getX();
var y1 = konva_nodes[idx].getY();
// console.log(idx);
// console.log(konva_nodes[idx]);
var rep = [0,0];
var attr = [0,0];
for (let jdx in konva_nodes){
if (idx == jdx){
continue;
}
// console.log(idx,jdx);
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])){
// console.log(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 += (1-new_x/2*node_size);
}
konva_nodes[idx].x(sort([2*node_size, x1+step*(rep[0]+attr[0]), width-2*node_size])[1]);
konva_nodes[idx].y(sort([2*node_size, y1+step*(rep[1]+attr[1]), height-2*node_size])[1]);
if (!silent) {
node_layer.draw();
}
}
}
}
// force_directed_graph();
window.setInterval(force_directed_graph, 1000/50);
for (var i = 0; i < 100; i++) {
force_directed_graph(true);
node_layer.draw();
}
function change_state(new_state){
state = new_state;
}
// // add cursor styling
// box.on('mouseover', function() {
// document.body.style.cursor = 'pointer';
// });
// box.on('mouseout', function() {
// document.body.style.cursor = 'default';
// });

@ -3,11 +3,39 @@
<head>
<meta charset="utf-8">
<title>Assignment</title>
<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>
<p><b>nodes:</b> {{ nodes }}</p>
<p><b>edges:</b> {{ edges }}</p>
<div ></div>
<div id="canvas" class="canvas">
</div>
<nav><button type="button" onclick="state='CREATE_NODE'">Create Node</button><button type="button" onclick="create_edge()">Create Edge</button><button type="button" onclick="find_path()">Find Path</button></nav>
<div></div>
<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>

Loading…
Cancel
Save