this.handleDown(e, "canvas")}
@pointermove=${(e: any) =>
this.handleMove(e, "canvas", (delta) => this.moveCanvas(delta))}
@pointerup=${(e: any) => this.handleUp(e)}
@pointercancel=${(e: any) => this.handleUp(e)}
>
this.handleDown(e, "element")}
@pointermove=${(e: any) =>
this.handleMove(e, "element", (delta) => {
const target = e.target as HTMLElement;
const child = target.assignedSlot ? target : target.closest('[slot]') || target;
this.moveElement(child as SupportedNode, delta);
})}
>
`;
}
handleDown(event: PointerEvent, type: DragType) {
if (this.dragType === "none") {
event.preventDefault();
this.dragType = type;
(event.target as Element).setPointerCapture(event.pointerId);
this.pointerMap.set(event.pointerId, {
id: event.pointerId,
startPos: { x: event.clientX, y: event.clientY },
currentPos: { x: event.clientX, y: event.clientY },
});
}
}
handleMove(
event: PointerEvent,
type: DragType,
onMove: (delta: Offset) => void
) {
if (this.dragType === type) {
event.preventDefault();
const saved = this.pointerMap.get(event.pointerId)!;
const current = { ...saved.currentPos };
saved.currentPos = { x: event.clientX, y: event.clientY };
const delta = {
x: saved.currentPos.x - current.x,
y: saved.currentPos.y - current.y,
};
onMove(delta);
}
}
handleUp(event: PointerEvent) {
this.dragType = "none";
(event.target as Element).releasePointerCapture(event.pointerId);
}
moveCanvas(delta: Offset) {
this.offset.x += delta.x;
this.offset.y += delta.y;
this.style.setProperty("--offset-x", `${this.offset.x}px`);
this.style.setProperty("--offset-y", `${this.offset.y}px`);
this.container.style.setProperty("--pan-x", `${this.offset.x}px`);
this.container.style.setProperty("--pan-y", `${this.offset.y}px`);
}
moveElement(child: SupportedNode, delta: Offset) {
const getNumber = (key: string) => {
const saved = (child as HTMLElement).style.getPropertyValue(key);
if (saved.length > 0) {
return parseFloat(saved.replace("px", ""));
}
return 0;
};
const dx = getNumber("--dx") + delta.x;
const dy = getNumber("--dy") + delta.y;
(child as HTMLElement).style.setProperty("--dx", `${dx}px`);
(child as HTMLElement).style.setProperty("--dy", `${dy}px`);
}
}
interface Offset {
x: number;
y: number;
}
interface PointerData {
id: number;
startPos: Offset;
currentPos: Offset;
}