|
|
@ -28,32 +28,32 @@ const node_layout = { |
|
|
|
shadowOpacity: 0.3, |
|
|
|
shadowOpacity: 0.3, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const text_layout = { |
|
|
|
|
|
|
|
fontSize: 22, |
|
|
|
|
|
|
|
fontFamily: 'Roboto, Arial, sans-serif', |
|
|
|
|
|
|
|
fill: 'black', |
|
|
|
|
|
|
|
verticalAlign: 'middle', |
|
|
|
|
|
|
|
align: 'center' |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const node_text_layout = { |
|
|
|
const node_text_layout = { |
|
|
|
|
|
|
|
...text_layout, |
|
|
|
x: 1 - node_size, |
|
|
|
x: 1 - node_size, |
|
|
|
y: 2 - node_size, |
|
|
|
y: 2 - node_size, |
|
|
|
text: name, |
|
|
|
|
|
|
|
fontSize: 22, |
|
|
|
|
|
|
|
width: 2 * node_size - 1, |
|
|
|
width: 2 * node_size - 1, |
|
|
|
height: 2 * node_size - 1, |
|
|
|
height: 2 * node_size - 1, |
|
|
|
fontFamily: 'Roboto, Arial, Verdana, sans-serif', |
|
|
|
|
|
|
|
fill: 'black', |
|
|
|
|
|
|
|
verticalAlign: 'middle', |
|
|
|
|
|
|
|
align: 'center' |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const edge_layout = { |
|
|
|
const edge_layout = { |
|
|
|
stroke: 'black', |
|
|
|
stroke: 'black', |
|
|
|
strokeWidth: 3, |
|
|
|
strokeWidth: 3, |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const edge_text_layout = { |
|
|
|
const edge_text_layout = { |
|
|
|
fontSize: 22, |
|
|
|
...text_layout, |
|
|
|
width: 2 * node_size, |
|
|
|
width: 2 * node_size, |
|
|
|
height: 2 * node_size, |
|
|
|
height: 2 * node_size, |
|
|
|
fontFamily: 'Roboto, Arial, Verdana, sans-serif', |
|
|
|
|
|
|
|
fill: 'black', |
|
|
|
|
|
|
|
verticalAlign: 'middle', |
|
|
|
|
|
|
|
align: 'center' |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -118,8 +118,8 @@ function sort(array) { |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function show_error(msg) { |
|
|
|
function show_info(msg, elem="#errorbar") { |
|
|
|
let infobar = document.querySelector("#infobar"); |
|
|
|
let infobar = document.querySelector(elem); |
|
|
|
infobar.innerHTML = msg; |
|
|
|
infobar.innerHTML = msg; |
|
|
|
infobar.classList.add("active"); |
|
|
|
infobar.classList.add("active"); |
|
|
|
window.setTimeout(function() { |
|
|
|
window.setTimeout(function() { |
|
|
@ -127,7 +127,6 @@ function show_error(msg) { |
|
|
|
}, 4000); |
|
|
|
}, 4000); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//---------------------------draw methods--------------------------------------
|
|
|
|
//---------------------------draw methods--------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
@ -173,7 +172,6 @@ function draw_new_node(name, x, y) { |
|
|
|
node_layer.draw(); |
|
|
|
node_layer.draw(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function draw_new_edge(edge) { |
|
|
|
function draw_new_edge(edge) { |
|
|
|
let start_node = stage.findOne('#' + edge["start"]); |
|
|
|
let start_node = stage.findOne('#' + edge["start"]); |
|
|
|
let end_node = stage.findOne('#' + edge["end"]); |
|
|
|
let end_node = stage.findOne('#' + edge["end"]); |
|
|
@ -264,6 +262,8 @@ function draw_path(path) { |
|
|
|
path_elements[id].children[0].strokeWidth(node_layout.strokeWidth + 1); |
|
|
|
path_elements[id].children[0].strokeWidth(node_layout.strokeWidth + 1); |
|
|
|
path_elements[id].children[0].stroke("rgb(240, 141, 25)"); |
|
|
|
path_elements[id].children[0].stroke("rgb(240, 141, 25)"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
node_layer.draw(); |
|
|
|
|
|
|
|
edge_layer.draw(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function on_node_click(e) { |
|
|
|
function on_node_click(e) { |
|
|
@ -281,19 +281,58 @@ function on_node_click(e) { |
|
|
|
draw_selected_nodes(); |
|
|
|
draw_selected_nodes(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function create_input(x, y) { |
|
|
|
|
|
|
|
return new Promise(function(resolve, reject) { |
|
|
|
|
|
|
|
var container = document.createElement("div"); |
|
|
|
|
|
|
|
container.classList.add("background"); |
|
|
|
|
|
|
|
var input = document.createElement("input"); |
|
|
|
|
|
|
|
var clear = function() { |
|
|
|
|
|
|
|
container.remove(); |
|
|
|
|
|
|
|
stage.listening(true); |
|
|
|
|
|
|
|
focus = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
input.setAttribute("type", "text"); |
|
|
|
|
|
|
|
input.style.left = x + "px"; |
|
|
|
|
|
|
|
input.style.top = y + "px"; |
|
|
|
|
|
|
|
canvas.appendChild(container); |
|
|
|
|
|
|
|
container.appendChild(input); |
|
|
|
|
|
|
|
input.focus(); |
|
|
|
|
|
|
|
stage.listening(false); |
|
|
|
|
|
|
|
focus = false; |
|
|
|
|
|
|
|
window.addEventListener("keyup", function(event) { |
|
|
|
|
|
|
|
if (event.key === "Escape") { |
|
|
|
|
|
|
|
reject(); |
|
|
|
|
|
|
|
clear(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
input.addEventListener("keyup", function(event) { |
|
|
|
|
|
|
|
if (event.key === "Enter") { |
|
|
|
|
|
|
|
resolve(input.value); |
|
|
|
|
|
|
|
clear(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//---------------------------REST methods--------------------------------------
|
|
|
|
//---------------------------REST methods--------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
function post(endpoint, data) { |
|
|
|
function rest_req(method, endpoint, data) { |
|
|
|
return fetch(url + endpoint, { |
|
|
|
let body_data = {} |
|
|
|
method: 'POST', |
|
|
|
if(!!data){ |
|
|
|
body: JSON.stringify(data), |
|
|
|
body_data = {body: JSON.stringify(data)}; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return fetch(url + "api/" + endpoint, { |
|
|
|
|
|
|
|
method: method, |
|
|
|
|
|
|
|
...body_data, |
|
|
|
headers: { |
|
|
|
headers: { |
|
|
|
'Content-Type': 'application/json' |
|
|
|
'Content-Type': 'application/json' |
|
|
|
} |
|
|
|
} |
|
|
|
}).then(res => res.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"; |
|
|
@ -303,12 +342,12 @@ function create_node() { |
|
|
|
y: (Math.random()-0.5)*node_size*4+height / 2 |
|
|
|
y: (Math.random()-0.5)*node_size*4+height / 2 |
|
|
|
}; |
|
|
|
}; |
|
|
|
create_input(pos.x, pos.y).then(function(text) { |
|
|
|
create_input(pos.x, pos.y).then(function(text) { |
|
|
|
post("nodes", { |
|
|
|
rest_req('POST', "nodes", { |
|
|
|
name: text |
|
|
|
name: text |
|
|
|
}) |
|
|
|
}) |
|
|
|
.then(function(res) { |
|
|
|
.then(function(res) { |
|
|
|
if (res["error"]) { |
|
|
|
if (res["error"]) { |
|
|
|
show_error(res["error"]) |
|
|
|
show_info(res["error"]) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
draw_new_node(text, pos.x, pos.y); |
|
|
|
draw_new_node(text, pos.x, pos.y); |
|
|
|
} |
|
|
|
} |
|
|
@ -321,26 +360,22 @@ function create_node() { |
|
|
|
|
|
|
|
|
|
|
|
function create_edge() { |
|
|
|
function create_edge() { |
|
|
|
if (selected.length < 2) { |
|
|
|
if (selected.length < 2) { |
|
|
|
show_error("Select at least 2 nodes."); |
|
|
|
show_info("Select 2 nodes."); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
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", { |
|
|
|
rest_req('POST',"edges", { |
|
|
|
start: selected[0].id(), |
|
|
|
start: selected[0].id(), |
|
|
|
end: selected[1].id(), |
|
|
|
end: selected[1].id(), |
|
|
|
weight: text |
|
|
|
weight: text |
|
|
|
}) |
|
|
|
}) |
|
|
|
.then(function(res) { |
|
|
|
.then(function(res) { |
|
|
|
if (res["error"]) { |
|
|
|
if (res["error"]) { |
|
|
|
show_error(res["error"]) |
|
|
|
show_info(res["error"]) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
draw_new_edge({ |
|
|
|
draw_new_edge(res); |
|
|
|
"start": selected[0].children[1].text(), |
|
|
|
|
|
|
|
"end": selected[1].children[1].text(), |
|
|
|
|
|
|
|
"weight": text |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
selected = []; |
|
|
|
selected = []; |
|
|
|
draw_selected_nodes(); |
|
|
|
draw_selected_nodes(); |
|
|
|
} |
|
|
|
} |
|
|
@ -350,56 +385,51 @@ function create_edge() { |
|
|
|
}, function() {}); |
|
|
|
}, function() {}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function create_input(x, y) { |
|
|
|
|
|
|
|
return new Promise(function(resolve, reject) { |
|
|
|
|
|
|
|
var container = document.createElement("div"); |
|
|
|
|
|
|
|
container.classList.add("background"); |
|
|
|
|
|
|
|
var input = document.createElement("input"); |
|
|
|
|
|
|
|
var clear = function() { |
|
|
|
|
|
|
|
container.remove(); |
|
|
|
|
|
|
|
stage.listening(true); |
|
|
|
|
|
|
|
focus = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
input.setAttribute("type", "text"); |
|
|
|
|
|
|
|
input.style.left = x + "px"; |
|
|
|
|
|
|
|
input.style.top = y + "px"; |
|
|
|
|
|
|
|
canvas.appendChild(container); |
|
|
|
|
|
|
|
container.appendChild(input); |
|
|
|
|
|
|
|
input.focus(); |
|
|
|
|
|
|
|
stage.listening(false); |
|
|
|
|
|
|
|
focus = false; |
|
|
|
|
|
|
|
window.addEventListener("keyup", function(event) { |
|
|
|
|
|
|
|
if (event.key === "Escape") { |
|
|
|
|
|
|
|
reject(); |
|
|
|
|
|
|
|
clear(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
input.addEventListener("keyup", function(event) { |
|
|
|
|
|
|
|
if (event.key === "Enter") { |
|
|
|
|
|
|
|
resolve(input.value); |
|
|
|
|
|
|
|
clear(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function find_path(data) { |
|
|
|
function find_path(data) { |
|
|
|
if (data.length < 2) { |
|
|
|
if (data.length < 2) { |
|
|
|
show_error("Select at least 2 nodes."); |
|
|
|
show_info("Select 2 nodes."); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
fetch(url + "paths/" + data[0].attrs.id + "/" + data[1].attrs.id).then(res => res.json()) |
|
|
|
rest_req("GET", "paths/" + data[0].attrs.id + "/" + data[1].attrs.id, null) |
|
|
|
.then(function(res) { |
|
|
|
.then(function(res) { |
|
|
|
if (res["error"]) { |
|
|
|
if (res["error"]) { |
|
|
|
show_error(res["error"]); |
|
|
|
show_info(res["error"]); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
selected = []; |
|
|
|
selected = []; |
|
|
|
draw_path(res["path"]); |
|
|
|
draw_path(res["path"]); |
|
|
|
|
|
|
|
show_info(res["path"], "#infobar"); |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
.catch(error => console.error('Error:', error)); |
|
|
|
.catch(error => console.error('Error:', error)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function save_graph() { |
|
|
|
|
|
|
|
fetch(url+"save").then(res => res.json()) |
|
|
|
|
|
|
|
.then(function(res) { |
|
|
|
|
|
|
|
if (res["error"]) { |
|
|
|
|
|
|
|
show_info(res["error"]); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
console.log(res); |
|
|
|
|
|
|
|
show_info(res["info"], "#infobar"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.catch(error => console.error('Error:', error)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function clear_graph() { |
|
|
|
|
|
|
|
fetch(url+"clear").then(res => res.json()) |
|
|
|
|
|
|
|
.then(function(res) { |
|
|
|
|
|
|
|
if (res["error"]) { |
|
|
|
|
|
|
|
show_info(res["error"]); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
location.reload(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.catch(error => console.error('Error:', error)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//------------------------background methods-----------------------------------
|
|
|
|
//------------------------background methods-----------------------------------
|
|
|
@ -507,8 +537,9 @@ var anim = new Konva.Animation(function(frame) { |
|
|
|
}, node_layer); |
|
|
|
}, node_layer); |
|
|
|
anim.start(); |
|
|
|
anim.start(); |
|
|
|
|
|
|
|
|
|
|
|
initialization(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// bug: this avoids glitches
|
|
|
|
// bug: this avoids glitches
|
|
|
|
window.onfocus = function() {focus = true;}; |
|
|
|
window.onfocus = function() {focus = true;}; |
|
|
|
window.onblur = function() {focus = false;}; |
|
|
|
window.onblur = function() {focus = false;}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
initialization(); |
|
|
|