Frontend requiremets finished

delete_edge
Ugo Finnendahl 5 years ago
parent 8494cc6992
commit e2bb890704
  1. 8
      frontend/assets/css/src/style.scss
  2. 2
      frontend/assets/css/style.min.css
  3. 150
      frontend/assets/js/canvas.js
  4. 28
      frontend/index.html

@ -37,6 +37,14 @@ main{
position: relative; position: relative;
height: 100%; height: 100%;
.background{
position: absolute;
top:0;
left:0;
background-color: rgba(0,0,0,0.5);
width: 100%;
height: 100%;
}
input{ input{
position: absolute; position: absolute;
border: none; border: none;

@ -1 +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} *{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 .background{position:absolute;top:0;left:0;background-color:rgba(0,0,0,0.5);width:100%;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}

@ -1,6 +1,8 @@
const canvas = document.getElementById("canvas"); const canvas = document.getElementById("canvas");
// Layouts //-----------------------------------------------------------------------------
//-----------------------------Layouts-----------------------------------------
//-----------------------------------------------------------------------------
var width = canvas.offsetWidth; var width = canvas.offsetWidth;
var height = canvas.offsetHeight; var height = canvas.offsetHeight;
@ -54,6 +56,7 @@ const edge_text_layout = {
align: 'center' align: 'center'
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
//-------------------------------Init------------------------------------------ //-------------------------------Init------------------------------------------
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -62,6 +65,7 @@ var node_layer = new Konva.Layer();
var konva_edges = []; var konva_edges = [];
var konva_nodes = []; var konva_nodes = [];
var graph_copy = {}; var graph_copy = {};
var state = "idle"; var state = "idle";
@ -73,10 +77,9 @@ var path_elements = [];
// (additions) auto layout // (additions) auto layout
var auto_layout = false; var auto_layout = false;
function initialisation(){ function initialization() {
stage.add(edge_layer); stage.add(edge_layer);
stage.add(node_layer); stage.add(node_layer);
// avoid flickering // avoid flickering
edge_layer.hide(); edge_layer.hide();
@ -89,7 +92,6 @@ function initialisation(){
} }
// (additions) auto layout // (additions) auto layout
if (sessionStorage.getItem("auto_layout") !== null) { if (sessionStorage.getItem("auto_layout") !== null) {
// Restore the contents of the text field // Restore the contents of the text field
auto_layout = (sessionStorage.getItem("auto_layout") == 'true'); auto_layout = (sessionStorage.getItem("auto_layout") == 'true');
@ -101,13 +103,12 @@ function initialisation(){
for (var i = 0; i < 1000; i++) { for (var i = 0; i < 1000; i++) {
force_directed_graph(); force_directed_graph();
} }
node_layer.draw();
edge_layer.show(); edge_layer.show();
} }
initialisation(); initialization();
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
//------------------------------utils------------------------------------------ //------------------------------utils------------------------------------------
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -116,16 +117,24 @@ function sort(array) {
return a - b; return a - b;
}) })
} }
function show_error(msg) {
let infobar = document.querySelector("#infobar");
infobar.innerHTML = msg;
infobar.classList.add("active");
window.setTimeout(function() {
infobar.classList.remove("active");
}, 4000);
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
//---------------------------draw methods-------------------------------------- //---------------------------draw methods--------------------------------------
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
function draw_new_node(name, x, y) { function draw_new_node(name, x, y) {
const pos = {
x: x,
y: y
};
let group = new Konva.Group({ let group = new Konva.Group({
...pos, x: x,
y: y,
draggable: true, draggable: true,
dragBoundFunc: function(pos) { dragBoundFunc: function(pos) {
return { return {
@ -136,7 +145,10 @@ function draw_new_node(name, x, y) {
id: name id: name
}); });
let box = new Konva.Circle(node_layout); let box = new Konva.Circle(node_layout);
let simpleText = new Konva.Text({...node_text_layout, text: name}); let simpleText = new Konva.Text({
...node_text_layout,
text: name
});
group.add(box); group.add(box);
group.add(simpleText); group.add(simpleText);
group.on("click", on_node_click); group.on("click", on_node_click);
@ -171,7 +183,10 @@ function draw_new_edge(edge) {
id: edge["start"] + edge["end"] id: edge["start"] + edge["end"]
}); });
let line = new Konva.Line(edge_layout); let line = new Konva.Line(edge_layout);
let simpleText = new Konva.Text({...edge_text_layout, text: weight}); let simpleText = new Konva.Text({
...edge_text_layout,
text: weight
});
graph_copy[edge["start"]].push(edge["end"]); graph_copy[edge["start"]].push(edge["end"]);
graph_copy[edge["end"]].push(edge["start"]); graph_copy[edge["end"]].push(edge["start"]);
@ -194,6 +209,7 @@ function update_edge(konva_edge) {
let end_node = konva_edge.attrs.end_node; let end_node = konva_edge.attrs.end_node;
let size = 15 + text.text().length * 15; 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; 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.points([start_node.getX(), start_node.getY(), end_node.getX(), end_node.getY()]);
line.dash([line_length / 2, size, line_length / 2]); line.dash([line_length / 2, size, line_length / 2]);
text.x((start_node.getX() + end_node.getX()) / 2 - node_size); text.x((start_node.getX() + end_node.getX()) / 2 - node_size);
@ -263,21 +279,44 @@ function on_node_click(e) {
draw_selected_nodes(); draw_selected_nodes();
}; };
//-----------------------------------------------------------------------------
//---------------------------REST methods--------------------------------------
//-----------------------------------------------------------------------------
function post(endpoint, data) {
return fetch(url + endpoint, {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.json())
}
function create_node() { function create_node() {
if (state != "create_node") { if (state != "create_node") {
state = "create_node"; state = "create_node";
// let mousePos = stage.getPointerPosition(); // let mousePos = stage.getPointerPosition();
let pos = {x: width/2, y: height/2}; let pos = {
x: width / 2,
y: height / 2
};
create_input(pos.x, pos.y).then(function(text) { create_input(pos.x, pos.y).then(function(text) {
post("nodes", {
name: text
})
.then(function(res) {
if (res["error"]) {
show_error(res["error"])
} else {
draw_new_node(text, pos.x, pos.y); draw_new_node(text, pos.x, pos.y);
}
state = "idle"; state = "idle";
})
.catch(error => console.error('Error:', error));
}, function() {state = "idle"}); }, function() {state = "idle"});
} }
} }
function create_edge() { function create_edge() {
if (selected.length < 2) { if (selected.length < 2) {
show_error("Select at least 2 nodes."); show_error("Select at least 2 nodes.");
@ -286,6 +325,15 @@ function create_edge() {
let x = (selected[0].getX() + selected[1].getX()) / 2; let x = (selected[0].getX() + selected[1].getX()) / 2;
let y = (selected[0].getY() + selected[1].getY()) / 2; let y = (selected[0].getY() + selected[1].getY()) / 2;
create_input(x, y).then(function(text) { create_input(x, y).then(function(text) {
post("edges", {
start: selected[0].id(),
end: selected[1].id(),
weight: text
})
.then(function(res) {
if (res["error"]) {
show_error(res["error"])
} else {
draw_new_edge({ draw_new_edge({
"start": selected[0].children[1].text(), "start": selected[0].children[1].text(),
"end": selected[1].children[1].text(), "end": selected[1].children[1].text(),
@ -293,45 +341,74 @@ function create_edge() {
}); });
selected = []; selected = [];
draw_selected_nodes(); draw_selected_nodes();
},function(){});
} }
})
.catch(error => console.error('Error:', error));
}, function() {});
}
function create_input(x, y) { function create_input(x, y) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var container = document.createElement("div");
container.classList.add("background");
var input = document.createElement("input"); var input = document.createElement("input");
var clear = function() {
container.remove();
stage.listening(true);
focus = true;
}
input.setAttribute("type", "text"); input.setAttribute("type", "text");
input.style.left = x + "px"; input.style.left = x + "px";
input.style.top = y + "px"; input.style.top = y + "px";
canvas.appendChild(input); canvas.appendChild(container);
container.appendChild(input);
input.focus(); input.focus();
stage.listening(false); stage.listening(false);
focus = false;
window.addEventListener("keyup", function(event) { window.addEventListener("keyup", function(event) {
if (event.key === "Escape") { if (event.key === "Escape") {
input.remove();
stage.listening(true);
reject(); reject();
clear();
} }
}); });
input.addEventListener("keyup", function(event) { input.addEventListener("keyup", function(event) {
if (event.key === "Enter") { if (event.key === "Enter") {
resolve(input.value); resolve(input.value);
input.remove(); clear();
stage.listening(true);
} }
}); });
}); });
} }
function find_path(){ function find_path(data) {
draw_path(elem); if (data.length < 2) {
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"]) {
show_error(res["error"]);
} else {
selected = [];
draw_path(res["path"]);
}
})
.catch(error => console.error('Error:', error));
} }
//-----------------------------------------------------------------------------
//------------------------background methods-----------------------------------
//-----------------------------------------------------------------------------
function update_edges(edges) { function update_edges(edges) {
for (id in edges) { for (id in edges) {
update_edge(edges[id]); update_edge(edges[id]);
} }
} }
node_layer.on('beforeDraw', function() { node_layer.on('beforeDraw', function() {
update_edges(konva_edges); update_edges(konva_edges);
}); });
@ -346,10 +423,8 @@ function fitStageIntoParentContainer() {
} }
window.addEventListener('resize', fitStageIntoParentContainer); window.addEventListener('resize', fitStageIntoParentContainer);
//-----------------------------------------------------------------------------
//---------------------(additions) auto layout---------------------------------
//-----------------------------------------------------------------------------
//---------------------(additions) auto layout---------------------------------
function toggle_auto_layout() { function toggle_auto_layout() {
auto_layout = !auto_layout; auto_layout = !auto_layout;
document.querySelector("[data-activeon=auto_layout]").classList.toggle("active"); document.querySelector("[data-activeon=auto_layout]").classList.toggle("active");
@ -415,22 +490,13 @@ function force_directed_graph(spring_length = 300, step = 0.004){
} }
var anim = new Konva.Animation(function(frame) { var anim = new Konva.Animation(function(frame) {
if (auto_layout) { if (auto_layout && focus) {
const spring_length = 300;
const step = 0.00025 * frame.timeDiff; const step = 0.00025 * frame.timeDiff;
force_directed_graph(spring_length, step) force_directed_graph(300, step)
} }
}, node_layer); }, node_layer);
anim.start(); 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 // bug: this avoids glitches
window.onfocus = function () {auto_layout = true;}; window.onfocus = function() {focus = true;};
window.onblur = function () {auto_layout = false;}; window.onblur = function() {focus = false;};

@ -20,7 +20,7 @@
<img src="{{ url_for('static', filename='imgs/drawing.svg') }}"> <img src="{{ url_for('static', filename='imgs/drawing.svg') }}">
<h1>Connect</h1> <h1>Connect</h1>
</button> </button>
<button type="button" onclick="find_path()"> <button type="button" onclick="find_path(selected)">
<img src="{{ url_for('static', filename='imgs/share.svg') }}"> <img src="{{ url_for('static', filename='imgs/share.svg') }}">
<h1>Find Path</h1> <h1>Find Path</h1>
</button> </button>
@ -32,29 +32,9 @@
</footer> </footer>
</main> </main>
<script> <script>
var nodes = ["Aachen", "Berlin", "Chemnitz", "Dresden", "Essen"] var nodes = {{ nodes|safe }};
var edges = [{ var edges = {{ edges|safe }};
"start": "Aachen", const url = "http://{{ request.host|safe }}/api/";
"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>
<script src="{{ url_for('static', filename='js/canvas.js')}}"></script> <script src="{{ url_for('static', filename='js/canvas.js')}}"></script>
</body> </body>

Loading…
Cancel
Save