소스 검색

Move (#97)

* Add mover skeleton

Atm it is just the eraser with new icons and renamed variables

* The mover not detect the object to move

* We can move ellipses and rectangles

* The mover now moves all types of objects

* Add the move everything functionality

* Aesthetic changes

* Replace the use of const and let with classic var

* Undo few commits

* Start the transform-translate implementation

* Mover now moves with transform translate

* Put the function to get the translation matrix in the Tools

* Shapes (ellipse, line, pencil, rect, and text) now properly load translate coords

* Add the transform-translate to the createSVG functions

* Done movement using transform-translate

* Fix parenthesization bug in the SVG create

* Fix comment about mover states

* Undo translation loading from Ellipse, Mover, Pencil, and Text tools

* Makes the board send update message to the mover as needed

* Remove the old code from the line tool too

* Simplify the mover tool

See #86

* update the mover icon

* Merge the mover and the hand tools

* Improve preview for pre-rendered elements

* v1.6.0

Co-authored-by: Paolo Bolzoni <paolo.bolzoni1@studenti.unipr.it>
dev_h
Ophir LOJKINE 5 년 전
부모
커밋
50da719bda
No account linked to committer's email address
10개의 변경된 파일146개의 추가작업 그리고 31개의 파일을 삭제
  1. 1
    1
      client-data/board.html
  2. 7
    0
      client-data/js/board.js
  3. 102
    21
      client-data/tools/hand/hand.js
  4. 1
    1
      client-data/tools/hand/hand.svg
  5. 10
    0
      client-data/tools/hand/mover.svg
  6. 1
    1
      package.json
  7. 4
    1
      server/boardData.js
  8. 10
    3
      server/createSVG.js
  9. 0
    1
      server/sockets.js
  10. 10
    2
      server/translations.json

+ 1
- 1
client-data/board.html 파일 보기

@@ -101,4 +101,4 @@
101 101
 	<script src="../js/canvascolor.js"></script>
102 102
 </body>
103 103
 
104
-</html>
104
+</html>

+ 7
- 0
client-data/js/board.js 파일 보기

@@ -314,6 +314,7 @@ Tools.pendingMessages = {};
314 314
 function messageForTool(message) {
315 315
 	var name = message.tool,
316 316
 		tool = Tools.list[name];
317
+
317 318
 	if (tool) {
318 319
 		Tools.applyHooks(Tools.messageHooks, message);
319 320
 		tool.draw(message, false);
@@ -323,6 +324,11 @@ function messageForTool(message) {
323 324
 		if (!Tools.pendingMessages[name]) Tools.pendingMessages[name] = [message];
324 325
 		else Tools.pendingMessages[name].push(message);
325 326
 	}
327
+
328
+	if (message.tool !== 'Hand' && message.deltax != null && message.deltay != null) {
329
+		//this message has special info for the mover
330
+		messageForTool({ tool: 'Hand', type: 'update', deltax: message.deltax || 0, deltay: message.deltay || 0, id: message.id });
331
+	}
326 332
 }
327 333
 
328 334
 // Apply the function to all arguments by batches
@@ -612,6 +618,7 @@ Tools.getOpacity = (function opacity() {
612 618
 	};
613 619
 })();
614 620
 
621
+
615 622
 //Scale the canvas on load
616 623
 Tools.svg.width.baseVal.value = document.body.clientWidth;
617 624
 Tools.svg.height.baseVal.value = document.body.clientHeight;

+ 102
- 21
client-data/tools/hand/hand.js 파일 보기

@@ -1,8 +1,8 @@
1 1
 /**
2
- *                        WHITEBOPHIR
2
+ *						  WHITEBOPHIR
3 3
  *********************************************************
4 4
  * @licstart  The following is the entire license notice for the 
5
- *  JavaScript code in this page.
5
+ *	JavaScript code in this page.
6 6
  *
7 7
  * Copyright (C) 2013  Ophir LOJKINE
8 8
  *
@@ -24,39 +24,120 @@
24 24
  * @licend
25 25
  */
26 26
 
27
-(function () { //Code isolation
27
+(function hand() { //Code isolation
28
+	var selected = null;
29
+	var last_sent = 0;
28 30
 
29
-	var orig = { x: 0, y: 0 };
30
-	var pressed = false;
31
-	function press(x, y, evt, isTouchEvent) {
31
+
32
+	function startMovingElement(x, y, evt) {
33
+		//Prevent the press from being interpreted by the browser
34
+		evt.preventDefault();
35
+		if (!evt.target || !Tools.drawingArea.contains(evt.target)) return;
36
+		var tmatrix = get_translate_matrix(evt.target);
37
+		selected = { x: x - tmatrix.e, y: y - tmatrix.f, elem: evt.target };
38
+	}
39
+
40
+	function moveElement(x, y) {
41
+		if (!selected) return;
42
+		var deltax = x - selected.x;
43
+		var deltay = y - selected.y;
44
+		var msg = { type: "update", id: selected.elem.id, deltax: deltax, deltay: deltay };
45
+		var now = performance.now();
46
+		if (now - last_sent > 70) {
47
+			last_sent = now;
48
+			Tools.drawAndSend(msg);
49
+		} else {
50
+			draw(msg);
51
+		}
52
+	}
53
+
54
+	function get_translate_matrix(elem) {
55
+		// Returns the first translate or transform matrix or makes one
56
+		var translate = null;
57
+		for (var i = 0; i < elem.transform.baseVal.numberOfItems; ++i) {
58
+			var baseVal = elem.transform.baseVal[i];
59
+			// quick tests showed that even if one changes only the fields e and f or uses createSVGTransformFromMatrix
60
+			// the brower may add a SVG_TRANSFORM_MATRIX instead of a SVG_TRANSFORM_TRANSLATE
61
+			if (baseVal.type === SVGTransform.SVG_TRANSFORM_TRANSLATE || baseVal.type === SVGTransform.SVG_TRANSFORM_MATRIX) {
62
+				translate = baseVal;
63
+				break;
64
+			}
65
+		}
66
+		if (translate == null) {
67
+			translate = elem.transform.baseVal.createSVGTransformFromMatrix(Tools.svg.createSVGMatrix());
68
+			elem.transform.baseVal.appendItem(translate);
69
+		}
70
+		return translate.matrix;
71
+	}
72
+
73
+	function draw(data) {
74
+		switch (data.type) {
75
+			case "update":
76
+				var elem = Tools.svg.getElementById(data.id);
77
+				if (!elem) throw new Error("Mover: Tried to move an element that does not exist.");
78
+				var tmatrix = get_translate_matrix(elem);
79
+				tmatrix.e = data.deltax || 0;
80
+				tmatrix.f = data.deltay || 0;
81
+				break;
82
+
83
+			default:
84
+				throw new Error("Mover: 'move' instruction with unknown type. ", data);
85
+		}
86
+	}
87
+
88
+	function startHand(x, y, evt, isTouchEvent) {
32 89
 		if (!isTouchEvent) {
33
-			pressed = true;
34
-			orig.x = document.documentElement.scrollLeft + evt.clientX;
35
-			orig.y = document.documentElement.scrollTop + evt.clientY;
90
+			selected = {
91
+				x: document.documentElement.scrollLeft + evt.clientX,
92
+				y: document.documentElement.scrollTop + evt.clientY,
93
+			}
36 94
 		}
37 95
 	}
38
-	function move(x, y, evt, isTouchEvent) {
39
-		if (pressed && !isTouchEvent) { //Let the browser handle touch to scroll
40
-			window.scrollTo(orig.x - evt.clientX, orig.y - evt.clientY);
96
+	function moveHand(x, y, evt, isTouchEvent) {
97
+		if (selected && !isTouchEvent) { //Let the browser handle touch to scroll
98
+			window.scrollTo(selected.x - evt.clientX, selected.y - evt.clientY);
41 99
 		}
42 100
 	}
43
-	function release() {
44
-		pressed = false;
101
+
102
+	function press(x, y, evt, isTouchEvent) {
103
+		if (!handTool.secondary.active) startHand(x, y, evt, isTouchEvent);
104
+		else startMovingElement(x, y, evt, isTouchEvent);
105
+	}
106
+
107
+
108
+	function move(x, y, evt, isTouchEvent) {
109
+		if (!handTool.secondary.active) moveHand(x, y, evt, isTouchEvent);
110
+		else moveElement(x, y, evt, isTouchEvent);
111
+	}
112
+
113
+	function release(x, y, evt, isTouchEvent) {
114
+		move(x, y, evt, isTouchEvent);
115
+		selected = null;
45 116
 	}
46 117
 
47
-	Tools.add({ //The new tool
118
+	function switchTool() {
119
+		selected = null;
120
+	}
121
+
122
+	var handTool = { //The new tool
48 123
 		"name": "Hand",
49 124
 		"shortcut": "h",
50 125
 		"listeners": {
51 126
 			"press": press,
52 127
 			"move": move,
53
-			"release": release
128
+			"release": release,
129
+		},
130
+		"secondary": {
131
+			"name": "Mover",
132
+			"icon": "tools/hand/mover.svg",
133
+			"active": false,
134
+			"switch": switchTool,
54 135
 		},
55
-		"icon": "tools/hand/icon.svg",
136
+		"draw": draw,
137
+		"icon": "tools/hand/hand.svg",
56 138
 		"mouseCursor": "move",
57 139
 		"showMarker": true,
58
-	});
59
-
60
-	//The hand tool is selected by default
61
-	Tools.change("Hand");
140
+	};
141
+	Tools.add(handTool);
142
+	Tools.change("Hand"); // Use the hand tool by default
62 143
 })(); //End of code isolation

client-data/tools/hand/icon.svg → client-data/tools/hand/hand.svg 파일 보기

@@ -1,4 +1,4 @@
1
-<svg viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg">
1
+<svg viewBox="0 0 70 70" xmlns="http://www.w3.org/2000/svg">
2 2
     <g fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
3 3
         <path d="M18.66 19.24a3.53 3.53 0 10-5.57 4.25l11.54 15.1 2.69 3.39-7.9-10.33a3.53 3.53 0 10-5.56 4.24l7.9 10.34 6.26 7.9c5.47 6.27 14.52 5.93 20.79.46a19.62 19.62 0 006.51-12.31c.39-4.23.81-15.3.81-15.3-.18-2.6-3.13-4.52-3.51-3.18l-4.9 9.76-3.36-4.23 3.36 4.23-3.36-4.23-13.47-17.2a3.53 3.53 0 10-5.56 4.24l4.25 5.57L36 30.42 22.58 12.74a3.53 3.53 0 10-5.56 4.25L31.69 36"/>
4 4
         <path stroke-miterlimit="10" d="M11.67 42.87c0 2.57 1.75 4.64 3.9 4.64M7.06 42.44c0 5.6 3.81 10.12 8.52 10.12M45.26 21.24c0-2.57-1.75-4.65-3.9-4.65M49.87 21.67c0-5.6-3.8-10.12-8.51-10.12"/>

+ 10
- 0
client-data/tools/hand/mover.svg 파일 보기

@@ -0,0 +1,10 @@
1
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 70 70" >
2
+    <path id="arrow" stroke="black" fill="none" stroke-width="2" stroke-linecap="round"
3
+        d="M 8 28 h 54
4
+           M 8 42 h 54
5
+           M 57 22 L 70 35 L 57 48
6
+        " />
7
+    <use href="#arrow" transform="rotate(90 35 35)"/>
8
+    <use href="#arrow" transform="rotate(180 35 35)"/>
9
+    <use href="#arrow" transform="rotate(-90 35 35)"/>
10
+</svg>

+ 1
- 1
package.json 파일 보기

@@ -1,7 +1,7 @@
1 1
 {
2 2
    "name": "whitebophir",
3 3
    "description": "Online collaborative whiteboard",
4
-   "version": "1.5.0",
4
+   "version": "1.6.0",
5 5
    "keywords": [
6 6
       "collaborative",
7 7
       "whiteboard"

+ 4
- 1
server/boardData.js 파일 보기

@@ -70,10 +70,13 @@ BoardData.prototype.addChild = function (parentId, child) {
70 70
 
71 71
 /** Update the data in the board
72 72
  * @param {string} id - Identifier of the data to update.
73
- * @param {object} data - Object containing the the values to update.
73
+ * @param {object} data - Object containing the values to update.
74 74
  * @param {boolean} create - True if the object should be created if it's not currently in the DB.
75 75
 */
76 76
 BoardData.prototype.update = function (id, data, create) {
77
+	delete data.type;
78
+	delete data.tool;
79
+
77 80
 	var obj = this.board[id];
78 81
 	if (typeof obj === "object") {
79 82
 		for (var i in data) {

+ 10
- 3
server/createSVG.js 파일 보기

@@ -11,7 +11,9 @@ function htmlspecialchars(str) {
11 11
 			case '>': return '&gt;';
12 12
 			case '&': return '&amp;';
13 13
 			case '"': return '&quot;';
14
-			case "'": return '&#39;'; }});
14
+			case "'": return '&#39;';
15
+		}
16
+	});
15 17
 }
16 18
 
17 19
 function renderPath(el, pathstring) {
@@ -23,6 +25,8 @@ function renderPath(el, pathstring) {
23 25
 			('opacity="' + parseFloat(el.opacity) + '" ') : '') +
24 26
 		'stroke="' + htmlspecialchars(el.color) + '" ' +
25 27
 		'd="' + pathstring + '" ' +
28
+		(el.deltax || el.deltay ?
29
+			('transform="translate(' + (+el.deltax) + ',' + (+el.deltay) + ')"') : '') +
26 30
 		'/>';
27 31
 }
28 32
 
@@ -37,6 +41,7 @@ const Tools = {
37 41
 			'y="' + (el.y | 0) + '" ' +
38 42
 			'font-size="' + (el.size | 0) + '" ' +
39 43
 			'fill="' + htmlspecialchars(el.color || "#000") + '" ' +
44
+			(el.deltax || el.deltay ? ('transform="translate(' + (el.deltax || 0) + ',' + (el.deltay || 0) + ')"') : '') +
40 45
 			'>' + htmlspecialchars(el.txt || "") + '</text>';
41 46
 	},
42 47
 	/**
@@ -65,6 +70,7 @@ const Tools = {
65 70
 			'height="' + (el.y2 - el.y) + '" ' +
66 71
 			'stroke="' + htmlspecialchars(el.color) + '" ' +
67 72
 			'stroke-width="' + (el.size | 0) + '" ' +
73
+			(el.deltax || el.deltay ? ('transform="translate(' + (el.deltax || 0) + ',' + (el.deltay || 0) + ')"') : '') +
68 74
 			'/>';
69 75
 	},
70 76
 	/**
@@ -100,9 +106,10 @@ async function toSVG(obj, writeable) {
100 106
 	const margin = 400;
101 107
 	const elems = Object.values(obj);
102 108
 	const dim = elems.reduce(function (dim, elem) {
109
+		if (elem._children) elem = elem._children[0];
103 110
 		return [
104
-			Math.max(elem.x + margin | 0, dim[0]),
105
-			Math.max(elem.y + margin | 0, dim[1]),
111
+			Math.max(elem.x + margin + elem.deltax | 0, dim[0]),
112
+			Math.max(elem.y + margin + elem.deltay | 0, dim[1]),
106 113
 		]
107 114
 	}, [margin, margin]);
108 115
 	writeable.write(

+ 0
- 1
server/sockets.js 파일 보기

@@ -140,7 +140,6 @@ async function saveHistory(boardName, message) {
140 140
 			if (id) board.delete(id);
141 141
 			break;
142 142
 		case "update":
143
-			delete message.type;
144 143
 			if (id) board.update(id, message);
145 144
 			break;
146 145
 		case "child":

+ 10
- 2
server/translations.json 파일 보기

@@ -15,6 +15,7 @@
15 15
         "click_to_toggle": "click to toggle",
16 16
         "menu": "Menu",
17 17
         "text": "Text",
18
+        "mover": "Mover",
18 19
         "straight_line": "Straight line",
19 20
         "pencil": "Pencil",
20 21
         "grid": "Grid",
@@ -54,6 +55,7 @@
54 55
         "eraser": "Gomme",
55 56
         "white-out": "Blanco",
56 57
         "hand": "Main",
58
+        "mover": "Déplacer un élément",
57 59
         "straight_line": "Ligne droite",
58 60
         "grid": "Grille",
59 61
         "keyboard_shortcut": "raccourci clavier",
@@ -73,6 +75,7 @@
73 75
     },
74 76
     "de": {
75 77
         "hand": "Hand",
78
+        "mover": "Verschiebung",
76 79
         "loading": "Lädt",
77 80
         "tagline": "Ein freies quelloffenes kollaboratives Zeichentool. Zeichnet eure Ideen zusammen auf WBO!",
78 81
         "configuration": "Konfiguration",
@@ -110,6 +113,7 @@
110 113
     },
111 114
     "ja": {
112 115
         "hand": "手のひらツール",
116
+        "mover": "変位",
113 117
         "loading": "読み込み中",
114 118
         "tagline": "無料でオープンソースの協同作業できるオンラインホワイトボード。WBOでアイディアを共有しましょう!",
115 119
         "configuration": "設定",
@@ -157,7 +161,7 @@
157 161
         "text": "Текст",
158 162
         "eraser": "Ластик",
159 163
         "white-out": "Корректор",
160
-        "hand": "Движение",
164
+        "hand": "Рука",
161 165
         "straight_line": "Прямая линия",
162 166
         "rectangle": "Прямоугольник",
163 167
         "square": "Квадрат",
@@ -165,8 +169,9 @@
165 169
         "ellipse": "Эллипс",
166 170
         "click_to_toggle": "нажмите, чтобы переключиться",
167 171
         "zoom": "Лупа",
172
+        "mover": "Сдвинуть объект",
168 173
         "grid": "Сетка",
169
-        "configuration": "Настроики",
174
+        "configuration": "Настройки",
170 175
         "keyboard_shortcut": "горячая клавиша",
171 176
         "mousewheel": "колёсико мыши ",
172 177
         "tagline": "Бесплатная и открытая доска для совместной работы в интернете. Рисуете свои идеи вместе в WBO !",
@@ -200,6 +205,7 @@
200 205
         "eraser": "橡皮",
201 206
         "white-out": "修正液",
202 207
         "hand": "移动",
208
+        "mover": "平移",
203 209
         "straight_line": "直线",
204 210
         "configuration": "刷设置",
205 211
         "keyboard_shortcut": "键盘快捷键",
@@ -220,6 +226,7 @@
220 226
     },
221 227
     "es": {
222 228
         "hand": "Mano",
229
+        "mover": "Desplazamiento",
223 230
         "loading": "Cargando",
224 231
         "tagline": "Una herramienta de dibujo colaborativa en línea gratuita y de código abierto. Esboce nuevas ideas en la pizarra colaborativa WBO !",
225 232
         "configuration": "Configuration",
@@ -257,6 +264,7 @@
257 264
     },
258 265
     "it": {
259 266
         "hand": "Mano",
267
+        "mover": "Spostamento",
260 268
         "loading": "Caricamento in corso",
261 269
         "tagline": "Uno strumento collaborativo per disegnare online, gratuito e open source. Disegniamo insieme nuove idee su WBO!",
262 270
         "configuration": "Configurazione",

Loading…
취소
저장