105 lines
3.4 KiB
JavaScript
105 lines
3.4 KiB
JavaScript
// Let's set up pointer tracking. We can use the main div as the pointer target.
|
|
// Note that we may later add pointer handlers on layered elements
|
|
const pointer = {x: undefined, y: undefined};
|
|
// Trace the path of the cursor
|
|
const pointerHistory = [];
|
|
const maxHistory = 50;
|
|
const dropTargetMaxRange = 20;
|
|
const drag = {
|
|
start: {x: undefined, y: undefined, t: undefined},
|
|
element: undefined,
|
|
placeholder: undefined,
|
|
}
|
|
|
|
function startDrag({element, x, y}) {
|
|
drag.element = element;
|
|
drag.start = {x, y, t: currentTime};
|
|
// We use a placeholder to represent the new position
|
|
const {x: ox, y: oy, width, height} = element.el.getBoundingClientRect();
|
|
drag.placeholder = elements.add({
|
|
...element,
|
|
id: `${this.id}-placeholder`,
|
|
classes: [...Array.from(element.el.classList.values()), "moving", "placeholder"],
|
|
width, height, x, y,
|
|
});
|
|
drag.element.el.classList.add("moving");
|
|
mainDiv.classList.add("dragging");
|
|
}
|
|
|
|
function initializePointer() {
|
|
mainDiv.addEventListener("pointermove", (e) => {
|
|
const {clientX: x, clientY: y} = e;
|
|
Object.assign(pointer, {x, y});
|
|
|
|
if (drag.start.t) {
|
|
const displacement = {
|
|
x: x - drag.start.x,
|
|
y: y - drag.start.y,
|
|
};
|
|
const {x: ox, y: oy} = drag.element.el.getBoundingClientRect();
|
|
drag.placeholder.setPosition({
|
|
x: ox + displacement.x,
|
|
y: oy + displacement.y,
|
|
});
|
|
|
|
// We can check here if we're near one or more drop targets to offer.
|
|
// We should indicate which available drop target is currently active.
|
|
// If there are multiple options, we can show them.
|
|
// const placeholder;
|
|
// const nearbyTargets = Array.from(elements.values()).filter(({el}) => {
|
|
// const {x, y, width, height} = el.getBoundingClientRect();
|
|
// const linearDist = minLinearDist(el.getBoundingClientRect(), );
|
|
// if (linearDist <= dropTargetMaxRange) {
|
|
// Visually activate the drop target
|
|
// }
|
|
//})
|
|
}
|
|
});
|
|
|
|
mainDiv.addEventListener("pointerup", (e) => {
|
|
if (!drag.start.t) return;
|
|
const {clientX: x, clientY: y} = e;
|
|
// Displacement
|
|
const d = {
|
|
x: x - drag.start.x,
|
|
y: y - drag.start.y,
|
|
};
|
|
const {x: ox, y: oy, width, height} = drag.element.el.getBoundingClientRect();
|
|
drag.element.setPosition({ x: ox + d.x, y: oy + d.y}).setSize(width, height);
|
|
drag.element.el.classList.remove("moving");
|
|
elements.remove(drag.placeholder.id);
|
|
drag.start = {};
|
|
drag.placeholder = undefined;
|
|
drag.element = undefined;
|
|
mainDiv.classList.remove("dragging");
|
|
});
|
|
}
|
|
|
|
function updatePointerHistory({decay} = {decay: true}) {
|
|
if (pointer.x === undefined || pointer.y === undefined) return;
|
|
if (!pointerHistory.length) {
|
|
pointerHistory.push({...pointer, t: currentTime});
|
|
return;
|
|
}
|
|
const lastPointer = pointerHistory[pointerHistory.length - 1];
|
|
if (decay || pointer.x !== lastPointer.x || pointer.y !== lastPointer.y) {
|
|
pointerHistory.push({...pointer, t: currentTime});
|
|
}
|
|
while (pointerHistory.length > maxHistory) {
|
|
pointerHistory.shift();
|
|
}
|
|
}
|
|
|
|
function drawPointerHistory() {
|
|
if (pointerHistory.length < 2) return;
|
|
for (let i = 1; i < pointerHistory.length; i++) {
|
|
fgCtx.beginPath();
|
|
const opacity = i / pointerHistory.length;
|
|
fgCtx.strokeStyle = `rgba(128, 0, 0, ${opacity})`;
|
|
fgCtx.moveTo(pointerHistory[i - 1].x, pointerHistory[i - 1].y);
|
|
fgCtx.lineTo(pointerHistory[i].x, pointerHistory[i].y);
|
|
fgCtx.stroke();
|
|
}
|
|
}
|
|
|