white / client-data /tools /hand /hand.js
hanahana05's picture
Upload folder using huggingface_hub
34e0b30 verified
/**
* 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 hand() {
//Code isolation
var selectorStates = {
pointing: 0,
selecting: 1,
transform: 2,
};
var selected = null;
var selected_els = [];
var selectionRect = createSelectorRect();
var selectionRectTransform;
var currentTransform = null;
var transform_elements = [];
var selectorState = selectorStates.pointing;
var last_sent = 0;
var blockedSelectionButtons = Tools.server_config.BLOCKED_SELECTION_BUTTONS;
var selectionButtons = [
createButton(
"delete",
"delete",
24,
24,
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];
me.y.baseVal.value = bbox.r[1] - (me.origHeight + 3) / s;
me.style.display = "";
},
deleteSelection,
),
createButton(
"duplicate",
"duplicate",
24,
24,
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] + (me.origWidth + 2) / s;
me.y.baseVal.value = bbox.r[1] - (me.origHeight + 3) / s;
me.style.display = "";
},
duplicateSelection,
),
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,
),
];
for (i in blockedSelectionButtons) {
delete selectionButtons[blockedSelectionButtons[i]];
}
var getScale = Tools.getScale;
function getParentMathematics(el) {
var target;
var a = el;
var els = [];
while (a) {
els.unshift(a);
a = a.parentElement;
}
var parentMathematics = els.find(function (el) {
return el.getAttribute("class") === "MathElement";
});
if (parentMathematics && parentMathematics.tagName === "svg") {
target = parentMathematics;
}
return target || el;
}
function deleteSelection() {
var msgs = selected_els.map(function (el) {
return {
type: "delete",
id: el.id,
};
});
var data = {
_children: msgs,
};
Tools.drawAndSend(data);
selected_els = [];
hideSelectionUI();
}
function duplicateSelection() {
if (!(selectorState == selectorStates.pointing) || selected_els.length == 0)
return;
var msgs = [];
var newids = [];
for (var i = 0; i < selected_els.length; i++) {
var id = selected_els[i].id;
msgs[i] = {
type: "copy",
id: id,
newid: Tools.generateUID(id[0]),
};
newids[i] = id;
}
Tools.drawAndSend({ _children: msgs });
selected_els = newids.map(function (id) {
return Tools.svg.getElementById(id);
});
}
function createSelectorRect() {
var shape = Tools.createSVGElement("rect");
shape.id = "selectionRect";
shape.x.baseVal.value = 0;
shape.y.baseVal.value = 0;
shape.width.baseVal.value = 0;
shape.height.baseVal.value = 0;
shape.setAttribute("stroke", "black");
shape.setAttribute("stroke-width", 1);
shape.setAttribute("vector-effect", "non-scaling-stroke");
shape.setAttribute("fill", "none");
shape.setAttribute("stroke-dasharray", "5 5");
shape.setAttribute("opacity", 1);
Tools.svg.appendChild(shape);
return shape;
}
function createButton(
name,
icon,
width,
height,
drawCallback,
clickCallback,
) {
var shape = Tools.createSVGElement("image", {
href: "tools/hand/" + icon + ".svg",
width: width,
height: height,
});
shape.style.display = "none";
shape.origWidth = width;
shape.origHeight = height;
shape.drawCallback = drawCallback;
shape.clickCallback = clickCallback;
Tools.svg.appendChild(shape);
return shape;
}
function showSelectionButtons() {
var scale = getScale();
var selectionBBox = selectionRect.transformedBBox();
for (var i = 0; i < selectionButtons.length; i++) {
selectionButtons[i].drawCallback(
selectionButtons[i],
selectionBBox,
scale,
);
}
}
function hideSelectionButtons() {
for (var i = 0; i < selectionButtons.length; i++) {
selectionButtons[i].style.display = "none";
}
}
function hideSelectionUI() {
hideSelectionButtons();
selectionRect.style.display = "none";
}
function startMovingElements(x, y, evt) {
evt.preventDefault();
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;
});
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 bbox = selectionRect.transformedBBox();
selected = {
x: bbox.r[0],
y: bbox.r[1],
w: bbox.a[0],
h: bbox.b[1],
};
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 = {
a: tmatrix.a,
d: tmatrix.d,
e: tmatrix.e,
f: tmatrix.f,
};
currentTransform = scaleSelection;
}
function startSelector(x, y, evt) {
evt.preventDefault();
selected = { x: x, y: y };
selected_els = [];
selectorState = selectorStates.selecting;
selectionRect.x.baseVal.value = x;
selectionRect.y.baseVal.value = y;
selectionRect.width.baseVal.value = 0;
selectionRect.height.baseVal.value = 0;
selectionRect.style.display = "";
tmatrix = get_transform_matrix(selectionRect);
tmatrix.e = 0;
tmatrix.f = 0;
}
function calculateSelection() {
var selectionTBBox = selectionRect.transformedBBox();
var elements = Tools.drawingArea.children;
var selected = [];
for (var i = 0; i < elements.length; i++) {
if (
transformedBBoxIntersects(selectionTBBox, elements[i].transformedBBox())
)
selected.push(Tools.drawingArea.children[i]);
}
return selected;
}
function moveSelection(x, y) {
var dx = x - selected.x;
var dy = y - selected.y;
var msgs = selected_els.map(function (el, i) {
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 msgs = selected_els.map(function (el, i) {
var oldTransform = transform_elements[i];
var x = el.transformedBBox().r[0];
var y = el.transformedBBox().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_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;
Tools.drawAndSend(msg);
} else {
draw(msg);
}
}
function updateRect(x, y, rect) {
rect.x.baseVal.value = Math.min(x, selected.x);
rect.y.baseVal.value = Math.min(y, selected.y);
rect.width.baseVal.value = Math.abs(x - selected.x);
rect.height.baseVal.value = Math.abs(y - selected.y);
}
function resetSelectionRect() {
var bbox = selectionRect.transformedBBox();
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 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_MATRIX) {
transform = baseVal;
break;
}
}
if (transform == null) {
transform = elem.transform.baseVal.createSVGTransformFromMatrix(
Tools.svg.createSVGMatrix(),
);
elem.transform.baseVal.appendItem(transform);
}
return transform.matrix;
}
function draw(data) {
if (data._children) {
batchCall(draw, data._children);
} else {
switch (data.type) {
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_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);
newElement.id = data.newid;
Tools.drawingArea.appendChild(newElement);
break;
case "delete":
data.tool = "Eraser";
messageForTool(data);
break;
default:
throw new Error(
"Mover: 'move' instruction with unknown type. ",
data,
);
}
}
}
function clickSelector(x, y, evt) {
selectionRect = selectionRect || createSelectorRect();
for (var i = 0; i < selectionButtons.length; i++) {
if (selectionButtons[i].contains(evt.target)) {
var button = selectionButtons[i];
}
}
if (button) {
button.clickCallback(x, y, evt);
} else if (
pointInTransformedBBox([x, y], selectionRect.transformedBBox())
) {
hideSelectionButtons();
startMovingElements(x, y, evt);
} else if (Tools.drawingArea.contains(evt.target)) {
hideSelectionUI();
selected_els = [getParentMathematics(evt.target)];
startMovingElements(x, y, evt);
} else {
hideSelectionButtons();
startSelector(x, y, evt);
}
}
function releaseSelector(x, y, evt) {
if (selectorState == selectorStates.selecting) {
selected_els = calculateSelection();
if (selected_els.length == 0) {
hideSelectionUI();
}
} else if (selectorState == selectorStates.transform) resetSelectionRect();
if (selected_els.length != 0) showSelectionButtons();
transform_elements = [];
selectorState = selectorStates.pointing;
}
function moveSelector(x, y, evt) {
if (selectorState == selectorStates.selecting) {
updateRect(x, y, selectionRect);
} else if (selectorState == selectorStates.transform && currentTransform) {
currentTransform(x, y);
}
}
function startHand(x, y, evt, isTouchEvent) {
if (!isTouchEvent) {
selected = {
x: document.documentElement.scrollLeft + evt.clientX,
y: document.documentElement.scrollTop + evt.clientY,
};
}
}
function moveHand(x, y, evt, isTouchEvent) {
if (selected && !isTouchEvent) {
//Let the browser handle touch to scroll
window.scrollTo(selected.x - evt.clientX, selected.y - evt.clientY);
}
}
function press(x, y, evt, isTouchEvent) {
if (!handTool.secondary.active) startHand(x, y, evt, isTouchEvent);
else clickSelector(x, y, evt, isTouchEvent);
}
function move(x, y, evt, isTouchEvent) {
if (!handTool.secondary.active) moveHand(x, y, evt, isTouchEvent);
else moveSelector(x, y, evt, isTouchEvent);
}
function release(x, y, evt, isTouchEvent) {
move(x, y, evt, isTouchEvent);
if (handTool.secondary.active) releaseSelector(x, y, evt, isTouchEvent);
selected = null;
}
function deleteShortcut(e) {
if (e.key == "Delete" && !e.target.matches("input[type=text], textarea"))
deleteSelection();
}
function duplicateShortcut(e) {
if (e.key == "d" && !e.target.matches("input[type=text], textarea"))
duplicateSelection();
}
function switchTool() {
onquit();
if (handTool.secondary.active) {
window.addEventListener("keydown", deleteShortcut);
window.addEventListener("keydown", duplicateShortcut);
}
}
function onquit() {
selected = null;
hideSelectionUI();
window.removeEventListener("keydown", deleteShortcut);
window.removeEventListener("keydown", duplicateShortcut);
}
var handTool = {
//The new tool
name: "Hand",
shortcut: "h",
listeners: {
press: press,
move: move,
release: release,
},
onquit: onquit,
secondary: {
name: "Selector",
icon: "tools/hand/selector.svg",
active: false,
switch: switchTool,
},
draw: draw,
icon: "tools/hand/hand.svg",
mouseCursor: "move",
showMarker: true,
};
Tools.add(handTool);
Tools.change("Hand"); // Use the hand tool by default
})(); //End of code isolation