Skip to content

Commit

Permalink
Add handle to scale selection
Browse files Browse the repository at this point in the history
  • Loading branch information
sents committed Jun 2, 2021
1 parent fd1da74 commit 5086d9a
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 49 deletions.
4 changes: 2 additions & 2 deletions client-data/js/board.js
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,9 @@ function messageForTool(message) {
else Tools.pendingMessages[name].push(message);
}

if (message.tool !== 'Hand' && message.deltax != null && message.deltay != null) {
if (message.tool !== 'Hand' && message.transform != null) {
//this message has special info for the mover
messageForTool({ tool: 'Hand', type: 'update', deltax: message.deltax || 0, deltay: message.deltay || 0, id: message.id });
messageForTool({ tool: 'Hand', type: 'update', transform: message.transform, id: message.id});
}
}

Expand Down
25 changes: 18 additions & 7 deletions client-data/js/intersect.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,29 @@ if (!SVGGraphicsElement.prototype.transformedBBox || !SVGGraphicsElement.prototy
[pointInTransformedBBox,
transformedBBoxIntersects] = (function () {

var applyTransform = function (m,t) {
var transformRelative = function (m,t) {
return [
m.a*t[0]+m.c*t[1],
m.b*t[0]+m.d*t[1]
]
}

var transformAbsolute = function (m,t) {
return [
m.a*t[0]+m.c*t[1]+m.e,
m.b*t[0]+m.d*t[1]+m.f
]
}

SVGGraphicsElement.prototype.transformedBBox = function (scale=1) {
bbox = this.getBBox();
tmatrix = this.getCTM();
tmatrix.e /= scale;
tmatrix.f /= scale;
return {
r: [bbox.x + tmatrix.e/scale, bbox.y + tmatrix.f/scale],
a: applyTransform(tmatrix,[bbox.width/scale,0]),
b: applyTransform(tmatrix,[0,bbox.height/scale])
r: transformAbsolute(tmatrix,[bbox.x/scale,bbox.y/scale]),
a: transformRelative(tmatrix,[bbox.width/scale,0]),
b: transformRelative(tmatrix,[0,bbox.height/scale])
}
}

Expand All @@ -53,10 +62,12 @@ if (!SVGGraphicsElement.prototype.transformedBBox || !SVGGraphicsElement.prototy
height: this.height.baseVal.value
};
tmatrix = this.getCTM();
tmatrix.e /= scale;
tmatrix.f /= scale;
return {
r: [bbox.x + tmatrix.e/scale, bbox.y + tmatrix.f/scale],
a: applyTransform(tmatrix,[bbox.width/scale,0]),
b: applyTransform(tmatrix,[0,bbox.height/scale])
r: transformAbsolute(tmatrix,[bbox.x/scale,bbox.y/scale]),
a: transformRelative(tmatrix,[bbox.width/scale,0]),
b: transformRelative(tmatrix,[0,bbox.height/scale])
}
}

Expand Down
187 changes: 147 additions & 40 deletions client-data/tools/hand/hand.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@
var selectorStates = {
pointing: 0,
selecting: 1,
moving: 2
transform: 2
}
var selected = null;
var selected_els = [];
var selectionRect = createSelectorRect();
var selectionRectTranslation;
var translation_elements = [];
var selectionRectTransform;
var currentTransform = null;
var transform_elements = [];
var selectorState = selectorStates.pointing;
var last_sent = 0;

Expand All @@ -57,11 +58,18 @@
me.style.display = "";
},
duplicateSelection);
var selectionButtons = [deleteButton, duplicateButton];
var scaleHandle = createButton("scaleHandle", "handle", 14, 14,
function(me, bbox, s) {
me.width.baseVal.value = me.origWidth / s;
me.height.baseVal.value = me.origHeight / s;
me.x.baseVal.value = bbox.r[0] + bbox.a[0] - me.origWidth/(2*s);
me.y.baseVal.value = bbox.r[1] + bbox.b[1] - me.origHeight/(2*s);
me.style.display = "";
},
startScalingTransform);
var selectionButtons = [deleteButton, duplicateButton, scaleHandle];

function getScale() {
return Tools.drawingArea.getCTM().a;
}
var getScale = Tools.getScale;

function getParentMathematics(el) {
var target;
Expand Down Expand Up @@ -171,18 +179,50 @@

function startMovingElements(x, y, evt) {
evt.preventDefault();
selectorState = selectorStates.moving;
selectorState = selectorStates.transform;
currentTransform = moveSelection;
selected = { x: x, y: y };
// Some of the selected elements could have been deleted
selected_els = selected_els.filter(function(el) {
return Tools.svg.getElementById(el.id) !== null;
});
translation_elements = selected_els.map(function(el) {
var tmatrix = get_translate_matrix(el);
return { x: tmatrix.e, y: tmatrix.f };
transform_elements = selected_els.map(function(el) {
var tmatrix = get_transform_matrix(el);
return {
a: tmatrix.a, b: tmatrix.b, c: tmatrix.c,
d: tmatrix.d, e: tmatrix.e, f: tmatrix.f
};
});
var tmatrix = get_transform_matrix(selectionRect);
selectionRectTransform = { x: tmatrix.e, y: tmatrix.f };
}

function startScalingTransform(x, y, evt) {
evt.preventDefault();
hideSelectionButtons();
selectorState = selectorStates.transform;
var scale = getScale();
var bbox = selectionRect.transformedBBox(scale);
selected = {
x: bbox.r[0],
y: bbox.r[1],
w: bbox.a[0],
h: bbox.b[1],
s: scale
};
transform_elements = selected_els.map(function(el) {
var tmatrix = get_transform_matrix(el);
return {
a: tmatrix.a, b: tmatrix.b, c: tmatrix.c,
d: tmatrix.d, e: tmatrix.e, f: tmatrix.f
};
});
var tmatrix = get_translate_matrix(selectionRect);
selectionRectTranslation = { x: tmatrix.e, y: tmatrix.f };
var tmatrix = get_transform_matrix(selectionRect);
selectionRectTransform = {
a: tmatrix.a, d: tmatrix.d,
e: tmatrix.e, f: tmatrix.f
};
currentTransform = scaleSelection;
}

function startSelector(x, y, evt) {
Expand All @@ -195,7 +235,7 @@
selectionRect.width.baseVal.value = 0;
selectionRect.height.baseVal.value = 0;
selectionRect.style.display = "";
tmatrix = get_translate_matrix(selectionRect);
tmatrix = get_transform_matrix(selectionRect);
tmatrix.e = 0;
tmatrix.f = 0;
}
Expand All @@ -217,19 +257,73 @@
var dx = x - selected.x;
var dy = y - selected.y;
var msgs = selected_els.map(function(el, i) {
return {
type: "update",
id: el.id,
deltax: dx + translation_elements[i].x,
deltay: dy + translation_elements[i].y
};
})
var oldTransform = transform_elements[i];
return {
type: "update",
id: el.id,
transform: {
a: oldTransform.a,
b: oldTransform.b,
c: oldTransform.c,
d: oldTransform.d,
e: dx + oldTransform.e,
f: dy + oldTransform.f
}
};
})
var msg = {
_children: msgs
};
var tmatrix = get_transform_matrix(selectionRect);
tmatrix.e = dx + selectionRectTransform.x;
tmatrix.f = dy + selectionRectTransform.y;
var now = performance.now();
if (now - last_sent > 70) {
last_sent = now;
Tools.drawAndSend(msg);
} else {
draw(msg);
}
}

function scaleSelection(x, y) {
var rx = (x - selected.x)/(selected.w);
var ry = (y - selected.y)/(selected.h);
var scale = getScale();
var msgs = selected_els.map(function(el, i) {
var oldTransform = transform_elements[i];
var x = el.transformedBBox(scale).r[0];
var y = el.transformedBBox(scale).r[1];
var a = oldTransform.a * rx;
var d = oldTransform.d * ry;
var e = selected.x * (1 - rx) - x * a +
(x * oldTransform.a + oldTransform.e) * rx
var f = selected.y * (1 - ry) - y * d +
(y * oldTransform.d + oldTransform.f) * ry
return {
type: "update",
id: el.id,
transform: {
a: a,
b: oldTransform.b,
c: oldTransform.c,
d: d,
e: e,
f: f
}
};
})
var msg = {
_children: msgs
};
var tmatrix = get_translate_matrix(selectionRect);
tmatrix.e = dx + selectionRectTranslation.x;
tmatrix.f = dy + selectionRectTranslation.y;

var tmatrix = get_transform_matrix(selectionRect);
tmatrix.a = rx;
tmatrix.d = ry;
tmatrix.e = selectionRectTransform.e +
selectionRect.x.baseVal.value * (selectionRectTransform.a - rx)
tmatrix.f = selectionRectTransform.f +
selectionRect.y.baseVal.value * (selectionRectTransform.d - ry)
var now = performance.now();
if (now - last_sent > 70) {
last_sent = now;
Expand All @@ -246,23 +340,34 @@
rect.height.baseVal.value = Math.abs(y - selected.y);
}

function get_translate_matrix(elem) {
function resetSelectionRect() {
var bbox = selectionRect.transformedBBox(getScale());
var tmatrix = get_transform_matrix(selectionRect);
selectionRect.x.baseVal.value = bbox.r[0];
selectionRect.y.baseVal.value = bbox.r[1];
selectionRect.width.baseVal.value = bbox.a[0];
selectionRect.height.baseVal.value = bbox.b[1];
tmatrix.a = 1; tmatrix.b = 0; tmatrix.c = 0;
tmatrix.d = 1; tmatrix.e = 0; tmatrix.f = 0;
}

function get_transform_matrix(elem) {
// Returns the first translate or transform matrix or makes one
var translate = null;
var transform = null;
for (var i = 0; i < elem.transform.baseVal.numberOfItems; ++i) {
var baseVal = elem.transform.baseVal[i];
// quick tests showed that even if one changes only the fields e and f or uses createSVGTransformFromMatrix
// the brower may add a SVG_TRANSFORM_MATRIX instead of a SVG_TRANSFORM_TRANSLATE
if (baseVal.type === SVGTransform.SVG_TRANSFORM_TRANSLATE || baseVal.type === SVGTransform.SVG_TRANSFORM_MATRIX) {
translate = baseVal;
if (baseVal.type === SVGTransform.SVG_TRANSFORM_MATRIX) {
transform = baseVal;
break;
}
}
if (translate == null) {
translate = elem.transform.baseVal.createSVGTransformFromMatrix(Tools.svg.createSVGMatrix());
elem.transform.baseVal.appendItem(translate);
if (transform == null) {
transform = elem.transform.baseVal.createSVGTransformFromMatrix(Tools.svg.createSVGMatrix());
elem.transform.baseVal.appendItem(transform);
}
return translate.matrix;
return transform.matrix;
}

function draw(data) {
Expand All @@ -274,9 +379,10 @@
case "update":
var elem = Tools.svg.getElementById(data.id);
if (!elem) throw new Error("Mover: Tried to move an element that does not exist.");
var tmatrix = get_translate_matrix(elem);
tmatrix.e = data.deltax || 0;
tmatrix.f = data.deltay || 0;
var tmatrix = get_transform_matrix(elem);
for (i in data.transform) {
tmatrix[i] = data.transform[i]
}
break;
case "copy":
var newElement = Tools.svg.getElementById(data.id).cloneNode(true);
Expand All @@ -303,7 +409,7 @@
}
}
if (button) {
button.clickCallback();
button.clickCallback(x, y, evt);
} else if (pointInTransformedBBox([x, y], selectionRect.transformedBBox(scale))) {
hideSelectionButtons();
startMovingElements(x, y, evt);
Expand All @@ -323,17 +429,18 @@
if (selected_els.length == 0) {
hideSelectionUI();
}
}
} else if (selectorState == selectorStates.transform)
resetSelectionRect();
if (selected_els.length != 0) showSelectionButtons();
translation_elements = [];
transform_elements = [];
selectorState = selectorStates.pointing;
}

function moveSelector(x, y, evt) {
if (selectorState == selectorStates.selecting) {
updateRect(x, y, selectionRect);
} else if (selectorState == selectorStates.moving) {
moveSelection(x, y, selectionRect);
} else if (selectorState == selectorStates.transform && currentTransform) {
currentTransform(x, y);
}
}

Expand Down
16 changes: 16 additions & 0 deletions client-data/tools/hand/handle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5086d9a

Please sign in to comment.