From ed5e9e11d9b3cf7910f42b9def231743a7b81d30 Mon Sep 17 00:00:00 2001 From: Ugo Date: Sun, 8 Sep 2019 22:45:14 +0200 Subject: [PATCH] small bug fixes and dynamic springs --- frontend/assets/js/canvas.js | 41 +++++++++++++++++++++++------------- main.py | 4 ++-- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/frontend/assets/js/canvas.js b/frontend/assets/js/canvas.js index a115adc..09d85d8 100644 --- a/frontend/assets/js/canvas.js +++ b/frontend/assets/js/canvas.js @@ -35,7 +35,7 @@ const node_text_layout = { fontSize: 22, width: 2 * node_size - 1, height: 2 * node_size - 1, - fontFamily: 'Roboto', + fontFamily: 'Roboto, Arial, Verdana, sans-serif', fill: 'black', verticalAlign: 'middle', align: 'center' @@ -50,7 +50,7 @@ const edge_text_layout = { fontSize: 22, width: 2 * node_size, height: 2 * node_size, - fontFamily: 'Roboto', + fontFamily: 'Roboto, Arial, Verdana, sans-serif', fill: 'black', verticalAlign: 'middle', align: 'center' @@ -103,10 +103,10 @@ function initialization() { for (var i = 0; i < 1000; i++) { force_directed_graph(); } - edge_layer.show(); + node_layer.draw(); } -initialization(); + //----------------------------------------------------------------------------- @@ -135,6 +135,7 @@ function draw_new_node(name, x, y) { let group = new Konva.Group({ x: x, y: y, + dragDistance: 5, draggable: true, dragBoundFunc: function(pos) { return { @@ -186,7 +187,7 @@ function draw_new_edge(edge) { let line = new Konva.Line(edge_layout); let simpleText = new Konva.Text({ ...edge_text_layout, - text: weight + text: ""+weight }); graph_copy[edge["start"]].push(edge["end"]); @@ -237,7 +238,7 @@ 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].strokeWidth(node_layout.strokeWidth+1); selected[id].children[0].stroke("rgb(240, 141, 25)"); } node_layer.draw(); @@ -298,8 +299,8 @@ function create_node() { state = "create_node"; // let mousePos = stage.getPointerPosition(); let pos = { - x: width / 2, - y: height / 2 + x: (Math.random()-0.5)*node_size*4+width / 2, + y: (Math.random()-0.5)*node_size*4+height / 2 }; create_input(pos.x, pos.y).then(function(text) { post("nodes", { @@ -387,7 +388,6 @@ function find_path(data) { show_error("Select at least 2 nodes."); return; } - console.log(url + "paths/" + data[0].attrs.id + "/" + data[1].attrs.id); fetch(url + "paths/" + data[0].attrs.id + "/" + data[1].attrs.id).then(res => res.json()) .then(function(res) { if (res["error"]) { @@ -434,6 +434,9 @@ function toggle_auto_layout() { function normalize(vec) { let l = Math.sqrt(vec[0] ** 2 + vec[1] ** 2); + if (l == 0){ + return [vec[0], vec[1]]; + } return [vec[0] / l, vec[1] / l]; } @@ -463,15 +466,20 @@ function force_directed_graph(spring_length = 300, step = 0.004) { 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); + let dist = Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2); + if (dist == 0){ + continue; + } if (in_edges(konva_nodes[idx], konva_nodes[jdx])) { - let f = (dist / spring_length); + let f = (dist**2 / 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]; + if (dist < width*0.4){ + let f = (spring_length ** 2 / 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]); @@ -493,11 +501,14 @@ function force_directed_graph(spring_length = 300, step = 0.004) { var anim = new Konva.Animation(function(frame) { if (auto_layout && focus) { const step = 0.00025 * frame.timeDiff; - force_directed_graph(300, step) + let spring_factor = Math.min((konva_edges.length+konva_nodes.length-3)/20, 1); + force_directed_graph(150+(1-spring_factor)*180, step); } }, node_layer); anim.start(); +initialization(); + // bug: this avoids glitches window.onfocus = function() {focus = true;}; window.onblur = function() {focus = false;}; diff --git a/main.py b/main.py index 664f2f0..d5efb6a 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,4 @@ -from flask import Flask, jsonify, request, render_template +from flask import Flask, jsonify, request, render_template, escape import numpy as np app = Flask(__name__) @@ -84,7 +84,7 @@ def create_node(): if name == "": return error("Name cannot be empty."), 400 if name in graph: - return error(f'Node with name "{name}" already exist.'), 400 + return error(f'Node with name "{escape(name)}" already exist.'), 400 graph[name] = {} return jsonify(name), 201