From 7913a09fe14e619b82f6d0b667d25eccec37d589 Mon Sep 17 00:00:00 2001 From: Robert Beach Date: Sun, 26 Apr 2020 10:47:59 +0200 Subject: [PATCH 01/26] Added Circle tool as alternative function of Rectangle tool --- client-data/js/board.js | 1 + client-data/tools/rect/rect.js | 53 +++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/client-data/js/board.js b/client-data/js/board.js index 13b16e10..a8d31909 100644 --- a/client-data/js/board.js +++ b/client-data/js/board.js @@ -41,6 +41,7 @@ Tools.svg = document.getElementById("canvas"); //Initialization Tools.curTool = null; +Tools.drawingEvent = true; Tools.socket = null; Tools.connect = function() { diff --git a/client-data/tools/rect/rect.js b/client-data/tools/rect/rect.js index c4419c02..d77a5447 100644 --- a/client-data/tools/rect/rect.js +++ b/client-data/tools/rect/rect.js @@ -26,10 +26,14 @@ (function () { //Code isolation //Indicates the id of the shape the user is currently drawing or an empty string while the user is not drawing - var curId = "", + var curshape="Rectangle", + shapeIcons = ["▢","◯"], + end=false, + curId = "", curUpdate = { //The data of the message that will be sent for every new point 'type': 'update', 'id': "", + 'shape':curshape, 'x': 0, 'y': 0, 'x2': 0, @@ -47,6 +51,7 @@ Tools.drawAndSend({ 'type': 'rect', 'id': curId, + 'shape': curshape, 'color': Tools.getColor(), 'size': Tools.getSize(), 'opacity': Tools.getOpacity(), @@ -57,6 +62,7 @@ }); curUpdate.id = curId; + curUpdate.shape = curshape; curUpdate.x = x; curUpdate.y = y; } @@ -66,7 +72,7 @@ This allows the animation to be smother*/ if (curId !== "") { curUpdate['x2'] = x; curUpdate['y2'] = y; - if (performance.now() - lastTime > 70) { + if (performance.now() - lastTime > 70 || end) { Tools.drawAndSend(curUpdate); lastTime = performance.now(); } else { @@ -78,11 +84,14 @@ function stop(x, y) { //Add a last point to the shape + end=true; move(x, y); + end=false; curId = ""; } function draw(data) { + Tools.drawingEvent=true; switch (data.type) { case "rect": createShape(data); @@ -90,14 +99,18 @@ case "update": var shape = svg.getElementById(data['id']); if (!shape) { - console.error("Straight shape: Hmmm... I received a point of a rect that has not been created (%s).", data['id']); + console.error("Straight shape: Hmmm... I received a point of a shape that has not been created (%s).", data['id']); createShape({ //create a new shape in order not to loose the points "id": data['id'], "x": data['x2'], "y": data['y2'] }); } - updateShape(shape, data); + if(data.shape === "Circle"){ + updateCircle(shape, data); + }else { + updateRect(shape, data); + } break; default: console.error("Straight shape: Draw instruction with unknown type. ", data); @@ -108,9 +121,15 @@ var svg = Tools.svg; function createShape(data) { //Creates a new shape on the canvas, or update a shape that already exists with new information - var shape = svg.getElementById(data.id) || Tools.createSVGElement("rect"); + var shape = svg.getElementById(data.id) + if (data.shape === "Circle"){ + if(!shape) shape = Tools.createSVGElement("circle"); + updateCircle(shape, data); + } else { + if(!shape) shape = Tools.createSVGElement("rect"); + updateRect(shape, data); + } shape.id = data.id; - updateShape(shape, data); //If some data is not provided, choose default value. The shape may be updated later shape.setAttribute("stroke", data.color || "black"); shape.setAttribute("stroke-width", data.size || 10); @@ -119,13 +138,32 @@ return shape; } - function updateShape(shape, data) { + function updateRect(shape, data) { shape.x.baseVal.value = Math.min(data['x2'], data['x']); shape.y.baseVal.value = Math.min(data['y2'], data['y']); shape.width.baseVal.value = Math.abs(data['x2'] - data['x']); shape.height.baseVal.value = Math.abs(data['y2'] - data['y']); } + function updateCircle(shape, data) { + shape.cx.baseVal.value = Math.round((data['x2'] + data['x'])/2); + shape.cy.baseVal.value = Math.round((data['y2'] + data['y'])/2); + shape.r.baseVal.value = Math.round(Math.sqrt(Math.pow(data['x2'] - data['x'],2)+Math.pow(data['y2'] - data['y'],2))/2); + shape.setAttribute("fill", "none"); + } + + function toggle(elem){ + var index = 0; + if(curshape === "Rectangle"){ + curshape = "Circle"; + index = 1; + }else{ + curshape = "Rectangle"; + } + elem.getElementsByClassName("tool-icon")[0].textContent = shapeIcons[index]; + } + + Tools.add({ //The new tool "name": "Rectangle", "shortcut": "r", @@ -135,6 +173,7 @@ "release": stop, }, "draw": draw, + "toggle": toggle, "mouseCursor": "crosshair", "icon": "tools/rect/icon.svg", "stylesheet": "tools/rect/rect.css" From b6f09a79577b049ba2cc2295662900c0081f085d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Finn=20B=C3=B6ger?= Date: Sun, 26 Apr 2020 14:06:27 +0200 Subject: [PATCH 02/26] change toggle function to work with new icon structure and toggle name --- client-data/tools/rect/icon-circle.svg | 3 +++ client-data/tools/rect/{icon.svg => icon-rect.svg} | 0 client-data/tools/rect/rect.js | 13 +++++++------ 3 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 client-data/tools/rect/icon-circle.svg rename client-data/tools/rect/{icon.svg => icon-rect.svg} (100%) diff --git a/client-data/tools/rect/icon-circle.svg b/client-data/tools/rect/icon-circle.svg new file mode 100644 index 00000000..c0f08af4 --- /dev/null +++ b/client-data/tools/rect/icon-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/client-data/tools/rect/icon.svg b/client-data/tools/rect/icon-rect.svg similarity index 100% rename from client-data/tools/rect/icon.svg rename to client-data/tools/rect/icon-rect.svg diff --git a/client-data/tools/rect/rect.js b/client-data/tools/rect/rect.js index d77a5447..6b3e048b 100644 --- a/client-data/tools/rect/rect.js +++ b/client-data/tools/rect/rect.js @@ -26,9 +26,9 @@ (function () { //Code isolation //Indicates the id of the shape the user is currently drawing or an empty string while the user is not drawing - var curshape="Rectangle", - shapeIcons = ["▢","◯"], - end=false, + let curshape = "Rectangle"; + const icons = ["tools/rect/icon-rect.svg", "tools/rect/icon-circle.svg"]; + let end=false, curId = "", curUpdate = { //The data of the message that will be sent for every new point 'type': 'update', @@ -153,14 +153,15 @@ } function toggle(elem){ - var index = 0; + let index = 0; if(curshape === "Rectangle"){ curshape = "Circle"; index = 1; }else{ curshape = "Rectangle"; } - elem.getElementsByClassName("tool-icon")[0].textContent = shapeIcons[index]; + elem.getElementsByClassName("tool-icon")[0].src = icons[index]; + elem.getElementsByClassName("tool-name")[0].textContent = curshape; } @@ -175,7 +176,7 @@ "draw": draw, "toggle": toggle, "mouseCursor": "crosshair", - "icon": "tools/rect/icon.svg", + "icon": icons[0], "stylesheet": "tools/rect/rect.css" }); From 177ddbc7f0eeba9e65ae4b54caf2fa495dbcbf98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Finn=20B=C3=B6ger?= Date: Tue, 28 Apr 2020 12:02:11 +0200 Subject: [PATCH 03/26] split circle into separate tool and added ellipse as secondary function. Also added server side rendering for svg export --- client-data/board.html | 1 + client-data/tools/circle/circle.css | 3 + client-data/tools/circle/circle.js | 174 ++++++++++++++++++ .../tools/{rect => circle}/icon-circle.svg | 0 client-data/tools/circle/icon-ellipse.svg | 3 + .../tools/rect/{icon-rect.svg => icon.svg} | 0 client-data/tools/rect/rect.js | 49 +---- server/createSVG.js | 17 ++ 8 files changed, 205 insertions(+), 42 deletions(-) create mode 100644 client-data/tools/circle/circle.css create mode 100644 client-data/tools/circle/circle.js rename client-data/tools/{rect => circle}/icon-circle.svg (100%) create mode 100644 client-data/tools/circle/icon-ellipse.svg rename client-data/tools/rect/{icon-rect.svg => icon.svg} (100%) diff --git a/client-data/board.html b/client-data/board.html index 191c87bc..bff35db1 100644 --- a/client-data/board.html +++ b/client-data/board.html @@ -84,6 +84,7 @@ + diff --git a/client-data/tools/circle/circle.css b/client-data/tools/circle/circle.css new file mode 100644 index 00000000..599ff07d --- /dev/null +++ b/client-data/tools/circle/circle.css @@ -0,0 +1,3 @@ +#canvas ellipse { + fill: none; +} diff --git a/client-data/tools/circle/circle.js b/client-data/tools/circle/circle.js new file mode 100644 index 00000000..18356c44 --- /dev/null +++ b/client-data/tools/circle/circle.js @@ -0,0 +1,174 @@ +/** + * WHITEBOPHIR + ********************************************************* + * @licstart The following is the entire license notice for the + * JavaScript code in this page. + * + * Copyright (C) 2013 Ophir LOJKINE + * + * + * The JavaScript code in this page is free software: you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License (GNU GPL) as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) + * any later version. The code is distributed WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. + * + * As additional permission under GNU GPL version 3 section 7, you + * may distribute non-source (e.g., minimized or compacted) forms of + * that code without the copy of the GNU GPL normally required by + * section 4, provided you include this license notice and a URL + * through which recipients can access the Corresponding Source. + * + * @licend + */ + +(function () { //Code isolation + //Indicates the id of the shape the user is currently drawing or an empty string while the user is not drawing + let curshape = "Circle"; + const icons = ["tools/circle/icon-circle.svg", "tools/circle/icon-ellipse.svg"]; + let end=false, + curId = "", + curUpdate = { //The data of the message that will be sent for every new point + 'type': 'update', + 'id': "", + 'shape': curshape, + 'x': 0, + 'y': 0, + 'x2': 0, + 'y2': 0 + }, + lastTime = performance.now(); //The time at which the last point was drawn + + function start(x, y, evt) { + + //Prevent the press from being interpreted by the browser + evt.preventDefault(); + + curId = Tools.generateUID("c"); //"c" for circle + + Tools.drawAndSend({ + 'type': 'circle', + 'id': curId, + 'shape': curshape, + 'color': Tools.getColor(), + 'size': Tools.getSize(), + 'opacity': Tools.getOpacity(), + 'x': x, + 'y': y, + 'x2': x, + 'y2': y + }); + + curUpdate.id = curId; + curUpdate.shape = curshape; + curUpdate.x = x; + curUpdate.y = y; + } + + function move(x, y, evt) { + /*Wait 70ms before adding any point to the currently drawing shape. + This allows the animation to be smother*/ + if (curId !== "") { + curUpdate['x2'] = x; curUpdate['y2'] = y; + if (performance.now() - lastTime > 70 || end) { + Tools.drawAndSend(curUpdate); + lastTime = performance.now(); + } else { + draw(curUpdate); + } + } + if (evt) evt.preventDefault(); + } + + function stop(x, y) { + //Add a last point to the shape + end=true; + move(x, y); + end=false; + curId = ""; + } + + function draw(data) { + Tools.drawingEvent=true; + switch (data.type) { + case "circle": + createShape(data); + break; + case "update": + var shape = svg.getElementById(data['id']); + if (!shape) { + console.error("Straight shape: Hmmm... I received a point of a shape that has not been created (%s).", data['id']); + createShape({ //create a new shape in order not to loose the points + "id": data['id'], + "x": data['x2'], + "y": data['y2'] + }); + } + updateShape(shape, data, data.shape === "Circle"); + break; + default: + console.error("Straight shape: Draw instruction with unknown type. ", data); + break; + } + } + + var svg = Tools.svg; + function createShape(data) { + //Creates a new shape on the canvas, or update a shape that already exists with new information + var shape = svg.getElementById(data.id) || Tools.createSVGElement("ellipse"); + updateShape(shape, data, data.shape === "Circle"); + shape.id = data.id; + //If some data is not provided, choose default value. The shape may be updated later + shape.setAttribute("stroke", data.color || "black"); + shape.setAttribute("stroke-width", data.size || 10); + shape.setAttribute("opacity", Math.max(0.1, Math.min(1, data.opacity)) || 1); + svg.appendChild(shape); + return shape; + } + + function updateShape(shape, data, circle) { + console.log(data); + shape.cx.baseVal.value = Math.round((data['x2'] + data['x'])/2); + shape.cy.baseVal.value = Math.round((data['y2'] + data['y'])/2); + if (circle) { + var r = Math.round(Math.sqrt(Math.pow(data['x2'] - data['x'],2)+Math.pow(data['y2'] - data['y'],2))/2); + shape.rx.baseVal.value = r; + shape.ry.baseVal.value = r; + } else { + shape.rx.baseVal.value = Math.abs(data['x2'] - data['x'])/2; + shape.ry.baseVal.value = Math.abs(data['y2'] - data['y'])/2; + } + } + + + function toggle(elem){ + let index = 0; + if (curshape === "Circle") { + curshape = "Ellipse"; + index = 1; + } else { + curshape = "Circle"; + } + elem.getElementsByClassName("tool-icon")[0].src = icons[index]; + elem.getElementsByClassName("tool-name")[0].textContent = curshape; + } + + + Tools.add({ //The new tool + "name": "Circle", + "shortcut": "c", + "listeners": { + "press": start, + "move": move, + "release": stop, + }, + "draw": draw, + "toggle": toggle, + "mouseCursor": "crosshair", + "icon": icons[0], + "stylesheet": "tools/circle/circle.css" + }); + +})(); //End of code isolation diff --git a/client-data/tools/rect/icon-circle.svg b/client-data/tools/circle/icon-circle.svg similarity index 100% rename from client-data/tools/rect/icon-circle.svg rename to client-data/tools/circle/icon-circle.svg diff --git a/client-data/tools/circle/icon-ellipse.svg b/client-data/tools/circle/icon-ellipse.svg new file mode 100644 index 00000000..42b50fb7 --- /dev/null +++ b/client-data/tools/circle/icon-ellipse.svg @@ -0,0 +1,3 @@ + + + diff --git a/client-data/tools/rect/icon-rect.svg b/client-data/tools/rect/icon.svg similarity index 100% rename from client-data/tools/rect/icon-rect.svg rename to client-data/tools/rect/icon.svg diff --git a/client-data/tools/rect/rect.js b/client-data/tools/rect/rect.js index 6b3e048b..39f7ee22 100644 --- a/client-data/tools/rect/rect.js +++ b/client-data/tools/rect/rect.js @@ -26,14 +26,11 @@ (function () { //Code isolation //Indicates the id of the shape the user is currently drawing or an empty string while the user is not drawing - let curshape = "Rectangle"; - const icons = ["tools/rect/icon-rect.svg", "tools/rect/icon-circle.svg"]; let end=false, curId = "", curUpdate = { //The data of the message that will be sent for every new point 'type': 'update', 'id': "", - 'shape':curshape, 'x': 0, 'y': 0, 'x2': 0, @@ -51,7 +48,6 @@ Tools.drawAndSend({ 'type': 'rect', 'id': curId, - 'shape': curshape, 'color': Tools.getColor(), 'size': Tools.getSize(), 'opacity': Tools.getOpacity(), @@ -62,7 +58,6 @@ }); curUpdate.id = curId; - curUpdate.shape = curshape; curUpdate.x = x; curUpdate.y = y; } @@ -99,18 +94,14 @@ case "update": var shape = svg.getElementById(data['id']); if (!shape) { - console.error("Straight shape: Hmmm... I received a point of a shape that has not been created (%s).", data['id']); + console.error("Straight shape: Hmmm... I received a point of a rect that has not been created (%s).", data['id']); createShape({ //create a new shape in order not to loose the points "id": data['id'], "x": data['x2'], "y": data['y2'] }); } - if(data.shape === "Circle"){ - updateCircle(shape, data); - }else { - updateRect(shape, data); - } + updateShape(shape, data); break; default: console.error("Straight shape: Draw instruction with unknown type. ", data); @@ -121,15 +112,9 @@ var svg = Tools.svg; function createShape(data) { //Creates a new shape on the canvas, or update a shape that already exists with new information - var shape = svg.getElementById(data.id) - if (data.shape === "Circle"){ - if(!shape) shape = Tools.createSVGElement("circle"); - updateCircle(shape, data); - } else { - if(!shape) shape = Tools.createSVGElement("rect"); - updateRect(shape, data); - } + var shape = svg.getElementById(data.id) || Tools.createSVGElement("rect"); shape.id = data.id; + updateShape(shape, data); //If some data is not provided, choose default value. The shape may be updated later shape.setAttribute("stroke", data.color || "black"); shape.setAttribute("stroke-width", data.size || 10); @@ -138,33 +123,14 @@ return shape; } - function updateRect(shape, data) { + function updateShape(shape, data) { + console.log(data); shape.x.baseVal.value = Math.min(data['x2'], data['x']); shape.y.baseVal.value = Math.min(data['y2'], data['y']); shape.width.baseVal.value = Math.abs(data['x2'] - data['x']); shape.height.baseVal.value = Math.abs(data['y2'] - data['y']); } - function updateCircle(shape, data) { - shape.cx.baseVal.value = Math.round((data['x2'] + data['x'])/2); - shape.cy.baseVal.value = Math.round((data['y2'] + data['y'])/2); - shape.r.baseVal.value = Math.round(Math.sqrt(Math.pow(data['x2'] - data['x'],2)+Math.pow(data['y2'] - data['y'],2))/2); - shape.setAttribute("fill", "none"); - } - - function toggle(elem){ - let index = 0; - if(curshape === "Rectangle"){ - curshape = "Circle"; - index = 1; - }else{ - curshape = "Rectangle"; - } - elem.getElementsByClassName("tool-icon")[0].src = icons[index]; - elem.getElementsByClassName("tool-name")[0].textContent = curshape; - } - - Tools.add({ //The new tool "name": "Rectangle", "shortcut": "r", @@ -174,9 +140,8 @@ "release": stop, }, "draw": draw, - "toggle": toggle, "mouseCursor": "crosshair", - "icon": icons[0], + "icon": "tools/rect/icon.svg", "stylesheet": "tools/rect/rect.css" }); diff --git a/server/createSVG.js b/server/createSVG.js index c8247c11..bea6c288 100644 --- a/server/createSVG.js +++ b/server/createSVG.js @@ -57,6 +57,23 @@ var Tools = { "L" + el.x + " " + el.y; return renderPath(el, pathstring); }, + "Circle": function (el) { + const cx = Math.round((el.x2 + el.x)/2); + const cy = Math.round((el.y2 + el.y)/2); + let rx, ry; + if (el.shape === "Circle") { + rx = ry = Math.round(Math.sqrt(Math.pow(el.x2 - el.x,2)+Math.pow(el.y2 - el.y,2))/2); + } else { + rx = Math.abs(el.x2 - el.x)/2; + ry = Math.abs(el.y2 - el.y)/2; + } + const pathstring = + "M" + cx + " " + cy + + "m" + -rx + ", 0" + + "a" + rx + "," + ry + " 0 1,0 " + (rx * 2) + ",0" + + "a" + rx + "," + ry + " 0 1,0 " + (rx * -2) + ",0"; + return renderPath(el, pathstring); + }, "Straight line": function (el) { var pathstring = "M" + el.x + " " + el.y + "L" + el.x2 + " " + el.y2; return renderPath(el, pathstring); From c051d6b903fd8b540598d9823612aa7dab5b5d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Finn=20B=C3=B6ger?= Date: Tue, 28 Apr 2020 12:13:17 +0200 Subject: [PATCH 04/26] change ellipse to be default --- client-data/board.html | 2 +- .../circle.css => ellipse/ellipse.css} | 0 .../{circle/circle.js => ellipse/ellipse.js} | 21 +++++++++---------- .../tools/{circle => ellipse}/icon-circle.svg | 0 .../{circle => ellipse}/icon-ellipse.svg | 0 server/createSVG.js | 2 +- 6 files changed, 12 insertions(+), 13 deletions(-) rename client-data/tools/{circle/circle.css => ellipse/ellipse.css} (100%) rename client-data/tools/{circle/circle.js => ellipse/ellipse.js} (93%) rename client-data/tools/{circle => ellipse}/icon-circle.svg (100%) rename client-data/tools/{circle => ellipse}/icon-ellipse.svg (100%) diff --git a/client-data/board.html b/client-data/board.html index bff35db1..104316be 100644 --- a/client-data/board.html +++ b/client-data/board.html @@ -84,7 +84,7 @@ - + diff --git a/client-data/tools/circle/circle.css b/client-data/tools/ellipse/ellipse.css similarity index 100% rename from client-data/tools/circle/circle.css rename to client-data/tools/ellipse/ellipse.css diff --git a/client-data/tools/circle/circle.js b/client-data/tools/ellipse/ellipse.js similarity index 93% rename from client-data/tools/circle/circle.js rename to client-data/tools/ellipse/ellipse.js index 18356c44..914b9512 100644 --- a/client-data/tools/circle/circle.js +++ b/client-data/tools/ellipse/ellipse.js @@ -26,8 +26,8 @@ (function () { //Code isolation //Indicates the id of the shape the user is currently drawing or an empty string while the user is not drawing - let curshape = "Circle"; - const icons = ["tools/circle/icon-circle.svg", "tools/circle/icon-ellipse.svg"]; + let curshape = "Ellipse"; + const icons = ["tools/ellipse/icon-ellipse.svg", "tools/ellipse/icon-circle.svg"]; let end=false, curId = "", curUpdate = { //The data of the message that will be sent for every new point @@ -46,10 +46,10 @@ //Prevent the press from being interpreted by the browser evt.preventDefault(); - curId = Tools.generateUID("c"); //"c" for circle + curId = Tools.generateUID("e"); //"e" for ellipse Tools.drawAndSend({ - 'type': 'circle', + 'type': 'ellipse', 'id': curId, 'shape': curshape, 'color': Tools.getColor(), @@ -93,7 +93,7 @@ function draw(data) { Tools.drawingEvent=true; switch (data.type) { - case "circle": + case "ellipse": createShape(data); break; case "update": @@ -129,7 +129,6 @@ } function updateShape(shape, data, circle) { - console.log(data); shape.cx.baseVal.value = Math.round((data['x2'] + data['x'])/2); shape.cy.baseVal.value = Math.round((data['y2'] + data['y'])/2); if (circle) { @@ -145,11 +144,11 @@ function toggle(elem){ let index = 0; - if (curshape === "Circle") { - curshape = "Ellipse"; + if (curshape === "Ellipse") { + curshape = "Circle"; index = 1; } else { - curshape = "Circle"; + curshape = "Ellipse"; } elem.getElementsByClassName("tool-icon")[0].src = icons[index]; elem.getElementsByClassName("tool-name")[0].textContent = curshape; @@ -157,7 +156,7 @@ Tools.add({ //The new tool - "name": "Circle", + "name": "Ellipse", "shortcut": "c", "listeners": { "press": start, @@ -168,7 +167,7 @@ "toggle": toggle, "mouseCursor": "crosshair", "icon": icons[0], - "stylesheet": "tools/circle/circle.css" + "stylesheet": "tools/ellipse/ellipse.css" }); })(); //End of code isolation diff --git a/client-data/tools/circle/icon-circle.svg b/client-data/tools/ellipse/icon-circle.svg similarity index 100% rename from client-data/tools/circle/icon-circle.svg rename to client-data/tools/ellipse/icon-circle.svg diff --git a/client-data/tools/circle/icon-ellipse.svg b/client-data/tools/ellipse/icon-ellipse.svg similarity index 100% rename from client-data/tools/circle/icon-ellipse.svg rename to client-data/tools/ellipse/icon-ellipse.svg diff --git a/server/createSVG.js b/server/createSVG.js index bea6c288..f3dd6b58 100644 --- a/server/createSVG.js +++ b/server/createSVG.js @@ -57,7 +57,7 @@ var Tools = { "L" + el.x + " " + el.y; return renderPath(el, pathstring); }, - "Circle": function (el) { + "Ellipse": function (el) { const cx = Math.round((el.x2 + el.x)/2); const cy = Math.round((el.y2 + el.y)/2); let rx, ry; From 00debd76ab158203a686d1482a71a056993c6988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Finn=20B=C3=B6ger?= Date: Tue, 28 Apr 2020 12:47:12 +0200 Subject: [PATCH 05/26] change circle behaviour to same as inkscape --- client-data/tools/ellipse/ellipse.js | 11 ++++++++--- server/createSVG.js | 13 ++++++++++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/client-data/tools/ellipse/ellipse.js b/client-data/tools/ellipse/ellipse.js index 914b9512..48117aa1 100644 --- a/client-data/tools/ellipse/ellipse.js +++ b/client-data/tools/ellipse/ellipse.js @@ -129,13 +129,18 @@ } function updateShape(shape, data, circle) { - shape.cx.baseVal.value = Math.round((data['x2'] + data['x'])/2); - shape.cy.baseVal.value = Math.round((data['y2'] + data['y'])/2); if (circle) { - var r = Math.round(Math.sqrt(Math.pow(data['x2'] - data['x'],2)+Math.pow(data['y2'] - data['y'],2))/2); + var deltaX = data['x2'] - data['x']; + var deltaY = data['y2'] - data['y']; + var r = Math.max(Math.abs(deltaX), Math.abs(deltaY))/2; + shape.cx.baseVal.value = data['x'] + ((deltaX > 0) - (deltaX < 0)) * r; + shape.cy.baseVal.value = data['y'] + ((deltaY > 0) - (deltaY < 0)) * r; + //var r = Math.round(Math.sqrt(Math.pow(data['x2'] - data['x'],2)+Math.pow(data['y2'] - data['y'],2))/2); shape.rx.baseVal.value = r; shape.ry.baseVal.value = r; } else { + shape.cx.baseVal.value = Math.round((data['x2'] + data['x'])/2); + shape.cy.baseVal.value = Math.round((data['y2'] + data['y'])/2); shape.rx.baseVal.value = Math.abs(data['x2'] - data['x'])/2; shape.ry.baseVal.value = Math.abs(data['y2'] - data['y'])/2; } diff --git a/server/createSVG.js b/server/createSVG.js index f3dd6b58..0dd112ca 100644 --- a/server/createSVG.js +++ b/server/createSVG.js @@ -58,12 +58,19 @@ var Tools = { return renderPath(el, pathstring); }, "Ellipse": function (el) { - const cx = Math.round((el.x2 + el.x)/2); - const cy = Math.round((el.y2 + el.y)/2); + let cx; + let cy; let rx, ry; if (el.shape === "Circle") { - rx = ry = Math.round(Math.sqrt(Math.pow(el.x2 - el.x,2)+Math.pow(el.y2 - el.y,2))/2); + const deltaX = el.x2 - el.x; + const deltaY = el.y2 - el.y; + const r = Math.max(Math.abs(deltaX), Math.abs(deltaY))/2; + cx = el.x + ((deltaX > 0) - (deltaX < 0)) * r; + cy = el.y + ((deltaY > 0) - (deltaY < 0)) * r; + rx = ry = r; } else { + cx = Math.round((el.x2 + el.x)/2); + cy = Math.round((el.y2 + el.y)/2); rx = Math.abs(el.x2 - el.x)/2; ry = Math.abs(el.y2 - el.y)/2; } From 85e20c91d47229d1934ff10fab2f0d73f438f214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Finn=20B=C3=B6ger?= Date: Tue, 28 Apr 2020 13:07:03 +0200 Subject: [PATCH 06/26] toggle to alternative while holding shift --- client-data/tools/ellipse/ellipse.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/client-data/tools/ellipse/ellipse.js b/client-data/tools/ellipse/ellipse.js index 48117aa1..8ded681f 100644 --- a/client-data/tools/ellipse/ellipse.js +++ b/client-data/tools/ellipse/ellipse.js @@ -159,6 +159,16 @@ elem.getElementsByClassName("tool-name")[0].textContent = curshape; } + function keyToggle(e) { + if (e.key === "Shift" && Tools.curTool.name === "Ellipse") { + var elem = document.getElementById("toolID-" + Tools.curTool.name); + Tools.curTool.toggle(elem); + curUpdate.shape = curshape; + draw(curUpdate); + } + } + window.addEventListener("keydown", keyToggle); + window.addEventListener("keyup", keyToggle); Tools.add({ //The new tool "name": "Ellipse", From fcdc6a0d50beac928ada53eededb30538446599c Mon Sep 17 00:00:00 2001 From: ophir Date: Tue, 28 Apr 2020 21:54:12 +0200 Subject: [PATCH 07/26] v1.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 00e35c92..7c537773 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "collaborative", "whiteboard" ], - "version": "1.3.0", + "version": "1.3.1", "license": "AGPL-3.0-or-later", "dependencies": { "accept-language-parser": "^1.5.0", From a84491a1c2c42a418856cd2365fd2ef43267a669 Mon Sep 17 00:00:00 2001 From: ophir Date: Fri, 1 May 2020 19:28:54 +0200 Subject: [PATCH 08/26] README: fix syntax error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c78dd742..d42f95de 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ A demonstration server is available at [wbo.ophir.dev](https://wbo.ophir.dev) teaching math on WBO - wbo + wbo teaching drawing art angel drawn on WBO From fce694df2810fedde59baeda544e9658faa5f065 Mon Sep 17 00:00:00 2001 From: finnboeger Date: Sat, 2 May 2020 06:13:48 +0200 Subject: [PATCH 09/26] Add a cursor (#46) * Added cursors * Prepare cursor code for future settings to toggle cursors on or off. Let cursor be the color the person has currently selected * fix cursor on mobile (still won't display it in most cases as there is no hover on mobile but at least it won't throw errors) * use correct size for cursor * throttle cursor update rate to dramatically improve performance by eliminating congestion * fix remote cursor size on desktop * show own cursor by default and renove offset * use svg as mouse cursor for pencil to be able to apply a reduced opacity to it and view our cursor * don't throttle local cursor * throttle local cursor at an independent higher rate. This could be made user adjustable for low power devices * remove let and const from client-side code * get emit count and emit count period from configuration * reduce network cursor updates a lot to prevent instantly getting banned with the current defaults * prevent eraser from deleting cursors * use group inside of svg as drawing area and only delete elements inside it with the eraser * use transform: translate to move cursors around instead of manipulating x and y directly * fix: add socket ids to cursor messages * fix incorrect remote cursor scaling and make local cursor visible again after it has been moved after being hidden due to inactivity * create cursors in a proper fashion and keep them in a separate group * scaling has been fixed in a1a5580 * move duplicated cursor creation code to function * show cursors above content * pass some of ther server configuration through to the client * fix bug introduced in a833ce9 * allocate at most half of the allowed traffic to cursor updates * remove debugging leftover * use feature detection instead of ua sniffing Co-Authored-By: Ophir LOJKINE * fix regression where local cursor color was not updated on color change * Define the cursor as a tool * Remove the cursor tool from the UI * Throttle remote cursor updates, not local ones * Do not increment notification count on cursor move * Use only one pencil icon Use the same image for the pencil icon in the menu and the pencil cursor that appears while drawing * Add a test for the new cursor feature * only stop drawing remote cursor when using some tools and always draw local cursor * increase idle period before hiding cursor * change idle duration back and set whether a cursor should be sent when using a tool in the respective tool Co-authored-by: Robert Beach Co-authored-by: Ophir LOJKINE Co-authored-by: ophir --- client-data/board.css | 9 +++ client-data/board.html | 8 ++- client-data/js/board.js | 75 ++++++++++++++-------- client-data/tools/cursor/cursor.js | 99 +++++++++++++++++++++++++++++ client-data/tools/eraser/eraser.js | 21 +++++- client-data/tools/hand/hand.js | 3 +- client-data/tools/line/line.js | 4 +- client-data/tools/pencil/cursor.svg | 8 +++ client-data/tools/pencil/icon.svg | 2 +- client-data/tools/pencil/pencil.js | 6 +- client-data/tools/rect/rect.js | 4 +- client-data/tools/text/text.js | 4 +- client-data/tools/zoom/zoom.js | 1 + server/client_configuration.js | 8 +++ server/configuration.js | 6 ++ server/sockets.js | 39 +++++++----- server/templating.js | 4 +- tests/integration.js | 29 +++++++-- 18 files changed, 269 insertions(+), 61 deletions(-) create mode 100644 client-data/tools/cursor/cursor.js create mode 100644 client-data/tools/pencil/cursor.svg create mode 100644 server/client_configuration.js diff --git a/client-data/board.css b/client-data/board.css index c630c951..e69c6592 100644 --- a/client-data/board.css +++ b/client-data/board.css @@ -237,3 +237,12 @@ text { user-select:none; -moz-user-select:none; } + +circle.opcursor { + pointer-events: none; + transition: .1s; +} + +#cursor-me { + transition: 0s; +} \ No newline at end of file diff --git a/client-data/board.html b/client-data/board.html index 19edc71e..7ced080c 100644 --- a/client-data/board.html +++ b/client-data/board.html @@ -27,6 +27,8 @@
+ +
@@ -64,7 +66,7 @@ - +