refactor IdentityGraph component to improve touch event handling and state management with IndexedDB

This commit is contained in:
2025-12-29 12:27:30 -06:00
parent bab846cd83
commit 0b90005bf7

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import { onMount } from 'svelte';
import { goto } from '$app/navigation';
import {
Plus,
Upload,
@@ -675,7 +676,11 @@
}
async function saveGraph() {
const data = { nodes, links, transform };
const data = {
nodes: JSON.parse(JSON.stringify(nodes)),
links: JSON.parse(JSON.stringify(links)),
transform: JSON.parse(JSON.stringify(transform)),
};
await saveToIndexedDB('graph-v1', data);
}
@@ -814,7 +819,7 @@
nodes = normalizeNodes(demoData.nodes);
links = demoData.links;
centerView();
window.history.replaceState({}, '', window.location.pathname);
goto(window.location.pathname, { replaceState: true });
return true;
}
@@ -837,7 +842,7 @@
} else {
centerView();
}
window.history.replaceState({}, '', window.location.pathname);
goto(window.location.pathname, { replaceState: true });
return true;
}
} catch (e) {
@@ -1153,7 +1158,9 @@
}
function handleNodeTouchStart(e: TouchEvent, nodeId: string) {
e.preventDefault();
if (e.cancelable) {
e.preventDefault();
}
const touch = e.touches[0];
if (!touch) return;
clearTouchHold();
@@ -1190,6 +1197,39 @@
}, 300);
}
function nodeTouchStartAction(node: Element, nodeId: string) {
let currentHandler: EventListener | null = null;
let currentId = nodeId;
const setupHandler = (id: string) => {
if (currentHandler) {
node.removeEventListener('touchstart', currentHandler);
}
currentHandler = (e: Event) => {
if (e instanceof TouchEvent) {
handleNodeTouchStart(e, id);
}
};
node.addEventListener('touchstart', currentHandler, { passive: false });
currentId = id;
};
setupHandler(nodeId);
return {
update(newNodeId: string) {
if (newNodeId !== currentId) {
setupHandler(newNodeId);
}
},
destroy() {
if (currentHandler) {
node.removeEventListener('touchstart', currentHandler);
}
}
};
}
function handleMouseMove(e: MouseEvent) {
const mouse = getScreenCoords(e);
const dx = mouse.x - lastMouse.x;
@@ -1296,14 +1336,18 @@
}
function handleTouchStart(e: TouchEvent) {
e.preventDefault();
if (e.cancelable) {
e.preventDefault();
}
if (e.touches.length === 0) return;
const touch = e.touches[0];
handleMouseDown(touchToMouseEvent(touch, 'mousedown'));
}
function handleTouchMove(e: TouchEvent) {
e.preventDefault();
if (e.cancelable) {
e.preventDefault();
}
if (e.touches.length === 0) return;
const touch = e.touches[0];
if (touchHoldTimeout && !isLongPressing) {
@@ -1319,7 +1363,9 @@
}
function handleTouchEnd(e: TouchEvent) {
e.preventDefault();
if (e.cancelable) {
e.preventDefault();
}
const wasLongPressing = isLongPressing;
clearTouchHold();
if (wasLongPressing) {
@@ -1701,6 +1747,23 @@
}
}
$effect(() => {
const element = containerElement;
if (element) {
element.addEventListener('touchstart', handleTouchStart, { passive: false });
element.addEventListener('touchmove', handleTouchMove, { passive: false });
element.addEventListener('touchend', handleTouchEnd, { passive: false });
element.addEventListener('touchcancel', handleTouchEnd, { passive: false });
return () => {
element.removeEventListener('touchstart', handleTouchStart);
element.removeEventListener('touchmove', handleTouchMove);
element.removeEventListener('touchend', handleTouchEnd);
element.removeEventListener('touchcancel', handleTouchEnd);
};
}
});
onMount(() => {
const log = (msg: string) => {
console.log(msg);
@@ -1932,10 +1995,6 @@
onmousemove={handleMouseMove}
onmouseup={handleMouseUp}
onmouseleave={handleMouseUp}
ontouchstart={handleTouchStart}
ontouchmove={handleTouchMove}
ontouchend={handleTouchEnd}
ontouchcancel={handleTouchEnd}
tabindex="0"
onkeydown={handleKeydown}
role="application"
@@ -2185,7 +2244,7 @@
role="button"
tabindex="0"
onmousedown={(e) => handleNodeMouseDown(e, node.id)}
ontouchstart={(e) => handleNodeTouchStart(e, node.id)}
use:nodeTouchStartAction={node.id}
onmouseenter={() => (hoverNodeId = node.id)}
onmouseleave={() => (hoverNodeId = null)}
onkeydown={(e) => e.key === 'Enter' && (selectedNodeId = node.id)}