diff --git a/frontend/assets/css/src/style.scss b/frontend/assets/css/src/style.scss index 1a175ed..76dfcf0 100644 --- a/frontend/assets/css/src/style.scss +++ b/frontend/assets/css/src/style.scss @@ -109,6 +109,7 @@ main{ left: 1em; display: flex; justify-content: flex-end; + overflow: hidden; #infobar{ position: absolute; bottom:0; @@ -120,9 +121,11 @@ main{ font-size: 1.8em; z-index: 1; opacity: 0; - transition: opacity 1s; + transform: translateY(100%); + transition: all 1s; &.active{ opacity: 1; + transform: translateY(0); } } } diff --git a/frontend/assets/css/style.min.css b/frontend/assets/css/style.min.css index a168ddd..824919f 100644 --- a/frontend/assets/css/style.min.css +++ b/frontend/assets/css/style.min.css @@ -1 +1 @@ -*{margin:0;padding:0;box-sizing:border-box;font-family:"Roboto-Regular"}main{position:relative;height:100vh}main #errorbar{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 #errorbar.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:200px;font-size:1.2em;text-align:center;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;left:1em;display:flex;justify-content:flex-end}main footer #infobar{position:absolute;bottom:0;left:0;width:50%;padding:0.4em;color:rgba(0,0,0,0.8);font-weight:bold;font-size:1.8em;z-index:1;opacity:0;transition:opacity 1s}main footer #infobar.active{opacity:1} +*{margin:0;padding:0;box-sizing:border-box;font-family:"Roboto-Regular"}main{position:relative;height:100vh}main #errorbar{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 #errorbar.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:200px;font-size:1.2em;text-align:center;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;left:1em;display:flex;justify-content:flex-end;overflow:hidden}main footer #infobar{position:absolute;bottom:0;left:0;width:50%;padding:0.4em;color:rgba(0,0,0,0.8);font-weight:bold;font-size:1.8em;z-index:1;opacity:0;transform:translateY(100%);transition:all 1s}main footer #infobar.active{opacity:1;transform:translateY(0)} diff --git a/frontend/assets/js/canvas.js b/frontend/assets/js/canvas.js index edc7ccb..5e0139a 100644 --- a/frontend/assets/js/canvas.js +++ b/frontend/assets/js/canvas.js @@ -70,6 +70,8 @@ var graph_copy = {}; var state = "idle"; +var info_timer = {}; + // selected nodes var selected = []; var path_elements = []; @@ -122,7 +124,10 @@ function show_info(msg, elem="#errorbar") { let infobar = document.querySelector(elem); infobar.innerHTML = msg; infobar.classList.add("active"); - window.setTimeout(function() { + if (info_timer[elem]){ + clearTimeout(info_timer[elem]); + } + info_timer[elem] = window.setTimeout(function() { infobar.classList.remove("active"); }, 4000); } @@ -260,12 +265,14 @@ function draw_path(path) { 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)"); + path_elements[id].children[0].stroke("rgb(240, 44, 25)"); } node_layer.draw(); edge_layer.draw(); } +//----------------------------------------------------------------------------- + function on_node_click(e) { e.cancelBubble = true; // let mousePos = stage.getPointerPosition(); @@ -412,7 +419,6 @@ function save_graph() { if (res["error"]) { show_info(res["error"]); } else { - console.log(res); show_info(res["info"], "#infobar"); } }) @@ -425,7 +431,7 @@ function clear_graph() { if (res["error"]) { show_info(res["error"]); } else { - location.reload(); + window.location.reload(false); } }) .catch(error => console.error('Error:', error)); diff --git a/main.py b/main.py index 318cde6..3e541a1 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,6 @@ -import json, os +import json +import os +import math from flask import Flask, jsonify, request, render_template, escape app = Flask(__name__) @@ -102,6 +104,8 @@ def create_edge(): weight = request.json['weight'] try: weight = float(weight) + if math.isnan(weight) or math.isinf(weight): + raise ValueError() except ValueError: return error("Weight must be a number."), 400 if weight < 0: @@ -127,7 +131,7 @@ def save(): try: with open(PATH, 'w') as f: json.dump(graph, f) - return jsonify({"info":"Saved graph",**graph}), 200 + return jsonify({"info":"Saved serverside graph",**graph}), 200 except Exception: return error("Internal Server Error"), 500 @@ -136,7 +140,7 @@ def save(): def clear(): global graph graph = {} - return "", 204 + return jsonify({"info":"Graph cleared"}), 200 @app.route("/")