Browse Source

Add handle to scale selection

dev_h
Finn Krein 4 years ago
parent
commit
5086d9a81d

+ 2
- 2
client-data/js/board.js View File

363
 		else Tools.pendingMessages[name].push(message);
363
 		else Tools.pendingMessages[name].push(message);
364
 	}
364
 	}
365
 
365
 
366
-	if (message.tool !== 'Hand' && message.deltax != null && message.deltay != null) {
366
+	if (message.tool !== 'Hand' && message.transform != null) {
367
 		//this message has special info for the mover
367
 		//this message has special info for the mover
368
-		messageForTool({ tool: 'Hand', type: 'update', deltax: message.deltax || 0, deltay: message.deltay || 0, id: message.id });
368
+	    messageForTool({ tool: 'Hand', type: 'update', transform: message.transform, id: message.id});
369
 	}
369
 	}
370
 }
370
 }
371
 
371
 

+ 18
- 7
client-data/js/intersect.js View File

28
     [pointInTransformedBBox,
28
     [pointInTransformedBBox,
29
      transformedBBoxIntersects] = (function () {
29
      transformedBBoxIntersects] = (function () {
30
 
30
 
31
-	var applyTransform = function (m,t) {
31
+	var transformRelative = function (m,t) {
32
 	    return [
32
 	    return [
33
 		m.a*t[0]+m.c*t[1],
33
 		m.a*t[0]+m.c*t[1],
34
 		m.b*t[0]+m.d*t[1]
34
 		m.b*t[0]+m.d*t[1]
35
 	    ]
35
 	    ]
36
 	}
36
 	}
37
 
37
 
38
+	var transformAbsolute = function (m,t) {
39
+	    return [
40
+		m.a*t[0]+m.c*t[1]+m.e,
41
+		m.b*t[0]+m.d*t[1]+m.f
42
+	    ]
43
+	}
44
+
38
 	SVGGraphicsElement.prototype.transformedBBox = function (scale=1) {
45
 	SVGGraphicsElement.prototype.transformedBBox = function (scale=1) {
39
 	    bbox = this.getBBox();
46
 	    bbox = this.getBBox();
40
 	    tmatrix = this.getCTM();
47
 	    tmatrix = this.getCTM();
48
+	    tmatrix.e /= scale;
49
+	    tmatrix.f /= scale;
41
 	    return {
50
 	    return {
42
-		r: [bbox.x + tmatrix.e/scale, bbox.y + tmatrix.f/scale],
43
-		a: applyTransform(tmatrix,[bbox.width/scale,0]),
44
-		b: applyTransform(tmatrix,[0,bbox.height/scale])
51
+		r: transformAbsolute(tmatrix,[bbox.x/scale,bbox.y/scale]),
52
+		a: transformRelative(tmatrix,[bbox.width/scale,0]),
53
+		b: transformRelative(tmatrix,[0,bbox.height/scale])
45
 	    }
54
 	    }
46
 	}
55
 	}
47
 
56
 
53
 		height: this.height.baseVal.value
62
 		height: this.height.baseVal.value
54
 	    };
63
 	    };
55
 	    tmatrix = this.getCTM();
64
 	    tmatrix = this.getCTM();
65
+	    tmatrix.e /= scale;
66
+	    tmatrix.f /= scale;
56
 	    return {
67
 	    return {
57
-		r: [bbox.x + tmatrix.e/scale, bbox.y + tmatrix.f/scale],
58
-		a: applyTransform(tmatrix,[bbox.width/scale,0]),
59
-		b: applyTransform(tmatrix,[0,bbox.height/scale])
68
+		r: transformAbsolute(tmatrix,[bbox.x/scale,bbox.y/scale]),
69
+		a: transformRelative(tmatrix,[bbox.width/scale,0]),
70
+		b: transformRelative(tmatrix,[0,bbox.height/scale])
60
 	    }
71
 	    }
61
 	}
72
 	}
62
 
73
 

+ 147
- 40
client-data/tools/hand/hand.js View File

28
 	var selectorStates = {
28
 	var selectorStates = {
29
 		pointing: 0,
29
 		pointing: 0,
30
 		selecting: 1,
30
 		selecting: 1,
31
-		moving: 2
31
+		transform: 2
32
 	}
32
 	}
33
 	var selected = null;
33
 	var selected = null;
34
 	var selected_els = [];
34
 	var selected_els = [];
35
 	var selectionRect = createSelectorRect();
35
 	var selectionRect = createSelectorRect();
36
-	var selectionRectTranslation;
37
-	var translation_elements = [];
36
+	var selectionRectTransform;
37
+	var currentTransform = null;
38
+	var transform_elements = [];
38
 	var selectorState = selectorStates.pointing;
39
 	var selectorState = selectorStates.pointing;
39
 	var last_sent = 0;
40
 	var last_sent = 0;
40
 
41
 
57
 			me.style.display = "";
58
 			me.style.display = "";
58
 		},
59
 		},
59
 									   duplicateSelection);
60
 									   duplicateSelection);
60
-	var selectionButtons = [deleteButton, duplicateButton];
61
+	var scaleHandle = createButton("scaleHandle", "handle", 14, 14,
62
+		function(me, bbox, s) {
63
+			me.width.baseVal.value = me.origWidth / s;
64
+			me.height.baseVal.value = me.origHeight / s;
65
+			me.x.baseVal.value = bbox.r[0] + bbox.a[0] - me.origWidth/(2*s);
66
+			me.y.baseVal.value = bbox.r[1] + bbox.b[1] - me.origHeight/(2*s);
67
+			me.style.display = "";
68
+		},
69
+								   startScalingTransform);
70
+	var selectionButtons = [deleteButton, duplicateButton, scaleHandle];
61
 
71
 
62
-	function getScale() {
63
-		return Tools.drawingArea.getCTM().a;
64
-	}
72
+	var getScale = Tools.getScale;
65
 
73
 
66
 	function getParentMathematics(el) {
74
 	function getParentMathematics(el) {
67
 		var target;
75
 		var target;
171
 
179
 
172
 	function startMovingElements(x, y, evt) {
180
 	function startMovingElements(x, y, evt) {
173
 		evt.preventDefault();
181
 		evt.preventDefault();
174
-		selectorState = selectorStates.moving;
182
+		selectorState = selectorStates.transform;
183
+		currentTransform = moveSelection;
175
 		selected = { x: x, y: y };
184
 		selected = { x: x, y: y };
176
 		// Some of the selected elements could have been deleted
185
 		// Some of the selected elements could have been deleted
177
 		selected_els = selected_els.filter(function(el) {
186
 		selected_els = selected_els.filter(function(el) {
178
 				return Tools.svg.getElementById(el.id) !== null;
187
 				return Tools.svg.getElementById(el.id) !== null;
179
 			});
188
 			});
180
-		translation_elements = selected_els.map(function(el) {
181
-			var tmatrix = get_translate_matrix(el);
182
-			return { x: tmatrix.e, y: tmatrix.f };
189
+		transform_elements = selected_els.map(function(el) {
190
+			var tmatrix = get_transform_matrix(el);
191
+			return {
192
+				a: tmatrix.a, b: tmatrix.b, c: tmatrix.c,
193
+				d: tmatrix.d, e: tmatrix.e, f: tmatrix.f
194
+			};
195
+		});
196
+		var tmatrix = get_transform_matrix(selectionRect);
197
+		selectionRectTransform = { x: tmatrix.e, y: tmatrix.f };
198
+	}
199
+
200
+	function startScalingTransform(x, y, evt) {
201
+		evt.preventDefault();
202
+		hideSelectionButtons();
203
+		selectorState = selectorStates.transform;
204
+		var scale = getScale();
205
+		var bbox = selectionRect.transformedBBox(scale);
206
+		selected = {
207
+			x: bbox.r[0],
208
+			y: bbox.r[1],
209
+			w: bbox.a[0],
210
+			h: bbox.b[1],
211
+			s: scale
212
+		};
213
+		transform_elements = selected_els.map(function(el) {
214
+			var tmatrix = get_transform_matrix(el);
215
+			return {
216
+				a: tmatrix.a, b: tmatrix.b, c: tmatrix.c,
217
+				d: tmatrix.d, e: tmatrix.e, f: tmatrix.f
218
+			};
183
 		});
219
 		});
184
-		var tmatrix = get_translate_matrix(selectionRect);
185
-		selectionRectTranslation = { x: tmatrix.e, y: tmatrix.f };
220
+		var tmatrix = get_transform_matrix(selectionRect);
221
+		selectionRectTransform = {
222
+			a: tmatrix.a, d: tmatrix.d,
223
+			e: tmatrix.e, f: tmatrix.f
224
+		};
225
+		currentTransform = scaleSelection;
186
 	}
226
 	}
187
 
227
 
188
 	function startSelector(x, y, evt) {
228
 	function startSelector(x, y, evt) {
195
 		selectionRect.width.baseVal.value = 0;
235
 		selectionRect.width.baseVal.value = 0;
196
 		selectionRect.height.baseVal.value = 0;
236
 		selectionRect.height.baseVal.value = 0;
197
 		selectionRect.style.display = "";
237
 		selectionRect.style.display = "";
198
-		tmatrix = get_translate_matrix(selectionRect);
238
+		tmatrix = get_transform_matrix(selectionRect);
199
 		tmatrix.e = 0;
239
 		tmatrix.e = 0;
200
 		tmatrix.f = 0;
240
 		tmatrix.f = 0;
201
 	}
241
 	}
217
 		var dx = x - selected.x;
257
 		var dx = x - selected.x;
218
 		var dy = y - selected.y;
258
 		var dy = y - selected.y;
219
 		var msgs = selected_els.map(function(el, i) {
259
 		var msgs = selected_els.map(function(el, i) {
220
-				return {
221
-					type: "update",
222
-					id: el.id,
223
-					deltax: dx + translation_elements[i].x,
224
-					deltay: dy + translation_elements[i].y
225
-				};
226
-			})
260
+			var oldTransform = transform_elements[i];
261
+			return {
262
+				type: "update",
263
+				id: el.id,
264
+				transform: {
265
+					a: oldTransform.a,
266
+					b: oldTransform.b,
267
+					c: oldTransform.c,
268
+					d: oldTransform.d,
269
+					e: dx + oldTransform.e,
270
+					f: dy + oldTransform.f
271
+				}
272
+			};
273
+		})
274
+		var msg = {
275
+			_children: msgs
276
+		};
277
+		var tmatrix = get_transform_matrix(selectionRect);
278
+		tmatrix.e = dx + selectionRectTransform.x;
279
+		tmatrix.f = dy + selectionRectTransform.y;
280
+		var now = performance.now();
281
+		if (now - last_sent > 70) {
282
+			last_sent = now;
283
+			Tools.drawAndSend(msg);
284
+		} else {
285
+			draw(msg);
286
+		}
287
+	}
288
+
289
+	function scaleSelection(x, y) {
290
+		var rx = (x - selected.x)/(selected.w);
291
+		var ry = (y - selected.y)/(selected.h);
292
+		var scale = getScale();
293
+		var msgs = selected_els.map(function(el, i) {
294
+			var oldTransform = transform_elements[i];
295
+			var x = el.transformedBBox(scale).r[0];
296
+			var y = el.transformedBBox(scale).r[1];
297
+			var a = oldTransform.a * rx;
298
+			var d = oldTransform.d * ry;
299
+			var e = selected.x * (1 - rx) - x * a +
300
+				(x * oldTransform.a + oldTransform.e) * rx
301
+			var f = selected.y * (1 - ry) - y * d +
302
+				(y * oldTransform.d + oldTransform.f) * ry
303
+			return {
304
+				type: "update",
305
+				id: el.id,
306
+				transform: {
307
+					a: a,
308
+					b: oldTransform.b,
309
+					c: oldTransform.c,
310
+					d: d,
311
+					e: e,
312
+					f: f
313
+				}
314
+			};
315
+		})
227
 		var msg = {
316
 		var msg = {
228
 			_children: msgs
317
 			_children: msgs
229
 		};
318
 		};
230
-		var tmatrix = get_translate_matrix(selectionRect);
231
-		tmatrix.e = dx + selectionRectTranslation.x;
232
-		tmatrix.f = dy + selectionRectTranslation.y;
319
+
320
+		var tmatrix = get_transform_matrix(selectionRect);
321
+		tmatrix.a = rx;
322
+		tmatrix.d = ry;
323
+		tmatrix.e = selectionRectTransform.e +
324
+			selectionRect.x.baseVal.value * (selectionRectTransform.a - rx)
325
+		tmatrix.f = selectionRectTransform.f +
326
+			selectionRect.y.baseVal.value * (selectionRectTransform.d - ry)
233
 		var now = performance.now();
327
 		var now = performance.now();
234
 		if (now - last_sent > 70) {
328
 		if (now - last_sent > 70) {
235
 			last_sent = now;
329
 			last_sent = now;
246
 		rect.height.baseVal.value = Math.abs(y - selected.y);
340
 		rect.height.baseVal.value = Math.abs(y - selected.y);
247
 	}
341
 	}
248
 
342
 
249
-	function get_translate_matrix(elem) {
343
+	function resetSelectionRect() {
344
+		var bbox = selectionRect.transformedBBox(getScale());
345
+		var tmatrix = get_transform_matrix(selectionRect);
346
+		selectionRect.x.baseVal.value = bbox.r[0];
347
+		selectionRect.y.baseVal.value = bbox.r[1];
348
+		selectionRect.width.baseVal.value = bbox.a[0];
349
+		selectionRect.height.baseVal.value = bbox.b[1];
350
+		tmatrix.a = 1; tmatrix.b = 0; tmatrix.c = 0;
351
+		tmatrix.d = 1; tmatrix.e = 0; tmatrix.f = 0;
352
+	}
353
+
354
+	function get_transform_matrix(elem) {
250
 		// Returns the first translate or transform matrix or makes one
355
 		// Returns the first translate or transform matrix or makes one
251
-		var translate = null;
356
+		var transform = null;
252
 		for (var i = 0; i < elem.transform.baseVal.numberOfItems; ++i) {
357
 		for (var i = 0; i < elem.transform.baseVal.numberOfItems; ++i) {
253
 			var baseVal = elem.transform.baseVal[i];
358
 			var baseVal = elem.transform.baseVal[i];
254
 			// quick tests showed that even if one changes only the fields e and f or uses createSVGTransformFromMatrix
359
 			// quick tests showed that even if one changes only the fields e and f or uses createSVGTransformFromMatrix
255
 			// the brower may add a SVG_TRANSFORM_MATRIX instead of a SVG_TRANSFORM_TRANSLATE
360
 			// the brower may add a SVG_TRANSFORM_MATRIX instead of a SVG_TRANSFORM_TRANSLATE
256
-			if (baseVal.type === SVGTransform.SVG_TRANSFORM_TRANSLATE || baseVal.type === SVGTransform.SVG_TRANSFORM_MATRIX) {
257
-				translate = baseVal;
361
+			if (baseVal.type === SVGTransform.SVG_TRANSFORM_MATRIX) {
362
+				transform = baseVal;
258
 				break;
363
 				break;
259
 			}
364
 			}
260
 		}
365
 		}
261
-		if (translate == null) {
262
-			translate = elem.transform.baseVal.createSVGTransformFromMatrix(Tools.svg.createSVGMatrix());
263
-			elem.transform.baseVal.appendItem(translate);
366
+		if (transform == null) {
367
+			transform = elem.transform.baseVal.createSVGTransformFromMatrix(Tools.svg.createSVGMatrix());
368
+			elem.transform.baseVal.appendItem(transform);
264
 		}
369
 		}
265
-		return translate.matrix;
370
+		return transform.matrix;
266
 	}
371
 	}
267
 
372
 
268
 	function draw(data) {
373
 	function draw(data) {
274
 				case "update":
379
 				case "update":
275
 					var elem = Tools.svg.getElementById(data.id);
380
 					var elem = Tools.svg.getElementById(data.id);
276
 					if (!elem) throw new Error("Mover: Tried to move an element that does not exist.");
381
 					if (!elem) throw new Error("Mover: Tried to move an element that does not exist.");
277
-					var tmatrix = get_translate_matrix(elem);
278
-					tmatrix.e = data.deltax || 0;
279
-					tmatrix.f = data.deltay || 0;
382
+					var tmatrix = get_transform_matrix(elem);
383
+					for (i in data.transform) {
384
+						tmatrix[i] = data.transform[i]
385
+					}
280
 					break;
386
 					break;
281
 				case "copy":
387
 				case "copy":
282
 					var newElement = Tools.svg.getElementById(data.id).cloneNode(true);
388
 					var newElement = Tools.svg.getElementById(data.id).cloneNode(true);
303
 			}
409
 			}
304
 		}
410
 		}
305
 		if (button) {
411
 		if (button) {
306
-			button.clickCallback();
412
+			button.clickCallback(x, y, evt);
307
 		} else if (pointInTransformedBBox([x, y], selectionRect.transformedBBox(scale))) {
413
 		} else if (pointInTransformedBBox([x, y], selectionRect.transformedBBox(scale))) {
308
 			hideSelectionButtons();
414
 			hideSelectionButtons();
309
 			startMovingElements(x, y, evt);
415
 			startMovingElements(x, y, evt);
323
 			if (selected_els.length == 0) {
429
 			if (selected_els.length == 0) {
324
 				hideSelectionUI();
430
 				hideSelectionUI();
325
 			}
431
 			}
326
-		}
432
+		} else if (selectorState == selectorStates.transform)
433
+			resetSelectionRect();
327
 		if (selected_els.length != 0) showSelectionButtons();
434
 		if (selected_els.length != 0) showSelectionButtons();
328
-		translation_elements = [];
435
+		transform_elements = [];
329
 		selectorState = selectorStates.pointing;
436
 		selectorState = selectorStates.pointing;
330
 	}
437
 	}
331
 
438
 
332
 	function moveSelector(x, y, evt) {
439
 	function moveSelector(x, y, evt) {
333
 		if (selectorState == selectorStates.selecting) {
440
 		if (selectorState == selectorStates.selecting) {
334
 			updateRect(x, y, selectionRect);
441
 			updateRect(x, y, selectionRect);
335
-		} else if (selectorState == selectorStates.moving) {
336
-			moveSelection(x, y, selectionRect);
442
+		} else if (selectorState == selectorStates.transform && currentTransform) {
443
+			currentTransform(x, y);
337
 		}
444
 		}
338
 	}
445
 	}
339
 
446
 

+ 16
- 0
client-data/tools/hand/handle.svg View File

1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<svg role="img" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
3
+ <title>Instagram icon</title>
4
+ <g transform="matrix(2.3668 2.3668 -2.3668 2.3668 13.98 -131.11)" fill="#ff002d">
5
+  <g transform="translate(-.5821 .16648)" fill="#f00">
6
+   <rect transform="rotate(-45)" x="-2.9234" y="40.131" width="5.7222" height="5.8388" ry=".34186" fill="#bdaddf" fill-opacity=".99078" stroke="#000" stroke-linejoin="round" stroke-width=".23901"/>
7
+  </g>
8
+ </g>
9
+ <metadata>
10
+  <rdf:RDF>
11
+   <cc:Work rdf:about="">
12
+    <dc:title>Instagram icon</dc:title>
13
+   </cc:Work>
14
+  </rdf:RDF>
15
+ </metadata>
16
+</svg>

Loading…
Cancel
Save