@cr8rcho/alkahest 0.1.12 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/dashboard.html +56 -5
- package/package.json +1 -1
|
@@ -606,18 +606,54 @@
|
|
|
606
606
|
const DRAG_THRESHOLD = 4;
|
|
607
607
|
let down = null; // {node|null, x, y, moved, pointerId}
|
|
608
608
|
|
|
609
|
+
// Active pointers for multi-touch. Two pointers down → pinch-to-zoom.
|
|
610
|
+
const pointers = new Map(); // pointerId -> {x, y}
|
|
611
|
+
let pinch = null; // { dist, midX, midY } for the running gesture
|
|
612
|
+
|
|
613
|
+
function startPinch() {
|
|
614
|
+
const pts = [...pointers.values()];
|
|
615
|
+
const dx = pts[0].x - pts[1].x, dy = pts[0].y - pts[1].y;
|
|
616
|
+
const rect = svg.getBoundingClientRect();
|
|
617
|
+
pinch = {
|
|
618
|
+
dist: Math.hypot(dx, dy) || 1,
|
|
619
|
+
midX: (pts[0].x + pts[1].x) / 2 - rect.left,
|
|
620
|
+
midY: (pts[0].y + pts[1].y) / 2 - rect.top,
|
|
621
|
+
};
|
|
622
|
+
// a pinch is purely a zoom — abandon any in-progress tap / pan / node drag
|
|
623
|
+
dragging = null; panStart = null; down = null;
|
|
624
|
+
}
|
|
625
|
+
|
|
609
626
|
function onNodeDown(ev, n) {
|
|
610
627
|
ev.stopPropagation();
|
|
611
|
-
|
|
628
|
+
pointers.set(ev.pointerId, { x: ev.clientX, y: ev.clientY });
|
|
612
629
|
svg.setPointerCapture(ev.pointerId);
|
|
630
|
+
if (pointers.size === 2) { startPinch(); return; }
|
|
631
|
+
down = { node: n, x: ev.clientX, y: ev.clientY, moved: false, pointerId: ev.pointerId };
|
|
613
632
|
}
|
|
614
633
|
svg.addEventListener("pointerdown", (ev) => {
|
|
634
|
+
pointers.set(ev.pointerId, { x: ev.clientX, y: ev.clientY });
|
|
635
|
+
svg.setPointerCapture(ev.pointerId);
|
|
636
|
+
if (pointers.size === 2) { startPinch(); return; }
|
|
615
637
|
if (down) return; // already started on a node
|
|
616
638
|
down = { node: null, x: ev.clientX, y: ev.clientY, moved: false, pointerId: ev.pointerId };
|
|
617
639
|
panStart = { x: ev.clientX - tx, y: ev.clientY - ty };
|
|
618
|
-
svg.setPointerCapture(ev.pointerId);
|
|
619
640
|
});
|
|
620
641
|
svg.addEventListener("pointermove", (ev) => {
|
|
642
|
+
if (pointers.has(ev.pointerId)) pointers.set(ev.pointerId, { x: ev.clientX, y: ev.clientY });
|
|
643
|
+
if (pinch && pointers.size >= 2) {
|
|
644
|
+
const pts = [...pointers.values()];
|
|
645
|
+
const dx = pts[0].x - pts[1].x, dy = pts[0].y - pts[1].y;
|
|
646
|
+
const dist = Math.hypot(dx, dy) || 1;
|
|
647
|
+
const rect = svg.getBoundingClientRect();
|
|
648
|
+
const mx = (pts[0].x + pts[1].x) / 2 - rect.left, my = (pts[0].y + pts[1].y) / 2 - rect.top;
|
|
649
|
+
// pan by how far the two-finger midpoint moved, then zoom around that midpoint
|
|
650
|
+
tx += mx - pinch.midX; ty += my - pinch.midY;
|
|
651
|
+
const nk = Math.min(4, Math.max(0.2, k * (dist / pinch.dist)));
|
|
652
|
+
tx = mx - (mx - tx) * (nk / k); ty = my - (my - ty) * (nk / k); k = nk;
|
|
653
|
+
pinch.dist = dist; pinch.midX = mx; pinch.midY = my;
|
|
654
|
+
applyTransform();
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
621
657
|
if (!down) return;
|
|
622
658
|
if (!down.moved && Math.hypot(ev.clientX - down.x, ev.clientY - down.y) > DRAG_THRESHOLD) {
|
|
623
659
|
down.moved = true;
|
|
@@ -627,8 +663,21 @@
|
|
|
627
663
|
if (dragging) { const w = toWorld(ev.clientX, ev.clientY); dragging.x = w.x; dragging.y = w.y; dragging.vx = 0; dragging.vy = 0; } // free 2D since it's force-based
|
|
628
664
|
else if (panStart) { tx = ev.clientX - panStart.x; ty = ev.clientY - panStart.y; applyTransform(); }
|
|
629
665
|
});
|
|
630
|
-
|
|
631
|
-
|
|
666
|
+
function onPointerUp(ev) {
|
|
667
|
+
pointers.delete(ev.pointerId);
|
|
668
|
+
if (pinch) {
|
|
669
|
+
if (pointers.size < 2) {
|
|
670
|
+
pinch = null;
|
|
671
|
+
if (pointers.size === 1) {
|
|
672
|
+
// one finger left after a pinch → resume panning from there (no jump)
|
|
673
|
+
const [id, p] = [...pointers.entries()][0];
|
|
674
|
+
down = { node: null, x: p.x, y: p.y, moved: true, pointerId: id };
|
|
675
|
+
panStart = { x: p.x - tx, y: p.y - ty };
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return; // a pinch gesture never counts as a tap
|
|
679
|
+
}
|
|
680
|
+
if (ev.type !== "pointercancel" && down && !down.moved) { // didn't move = tap
|
|
632
681
|
if (down.node) select(down.node);
|
|
633
682
|
else clearSelection();
|
|
634
683
|
} else if (dragging) {
|
|
@@ -636,7 +685,9 @@
|
|
|
636
685
|
alpha = 0.06;
|
|
637
686
|
}
|
|
638
687
|
dragging = null; panStart = null; down = null;
|
|
639
|
-
}
|
|
688
|
+
}
|
|
689
|
+
svg.addEventListener("pointerup", onPointerUp);
|
|
690
|
+
svg.addEventListener("pointercancel", onPointerUp);
|
|
640
691
|
svg.addEventListener("wheel", (ev) => {
|
|
641
692
|
ev.preventDefault();
|
|
642
693
|
const rect = svg.getBoundingClientRect();
|