diff --git a/bun.lockb b/bun.lockb index 9994845..7f89963 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 630c0fd..a2e6014 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "graphology": "^0.25.4", "graphology-operators": "^1.6.0", "graphology-traversal": "^0.3.1", + "object-hash": "^3.0.0", "svgdom": "^0.1.19", "web-tree-sitter": "^0.23.2" }, @@ -28,6 +29,7 @@ "@sveltejs/vite-plugin-svelte": "^3.1.2", "@types/bun": "latest", "@types/eslint__js": "^8.42.3", + "@types/object-hash": "^3.0.6", "@types/svgdom": "^0.1.2", "eslint": "^9.12.0", "graphology-utils": "^2.5.2", diff --git a/src/components/WebviewRenderer.svelte b/src/components/WebviewRenderer.svelte index 01dd277..667a402 100644 --- a/src/components/WebviewRenderer.svelte +++ b/src/components/WebviewRenderer.svelte @@ -3,12 +3,15 @@ import { functionNodeTypes, type Language } from "../control-flow/cfg"; import { Graphviz } from "@hpcc-js/wasm-graphviz"; import { initialize as initializeUtils, type Parsers } from "./utils"; - import { createEventDispatcher } from "svelte"; + import { createEventDispatcher, onMount } from "svelte"; import { type ColorList, getLightColorList } from "../control-flow/colors"; import { Renderer, type RenderOptions } from "./renderer.ts"; + import Panzoom, { type PanzoomObject } from "@panzoom/panzoom"; + import objectHash from "object-hash"; type CodeAndOffset = { code: string; offset: number; language: Language }; + let resultHash: string = ""; let parsers: Parsers; let graphviz: Graphviz; let dot: string; @@ -70,6 +73,13 @@ dot = renderResult.dot; getNodeOffset = renderResult.getNodeOffset; + // TODO: Only reset when we move between functions + const newHash = objectHash(functionSyntax.startPosition); + if (newHash !== resultHash) { + panzoom.reset(); + resultHash = newHash; + } + return renderResult.svg; } @@ -123,28 +133,73 @@ node: target.id, offset: getNodeOffset(target.id), }); + console.log(target.id); + panToNode(target.id); + } + + let zoomable: Element; + let parent: Element; + let panzoom: PanzoomObject; + function initPanzoom() { + panzoom = Panzoom(zoomable, { maxScale: 100, minScale: 1 }); + zoomable.parentElement.addEventListener("wheel", panzoom.zoomWithWheel); + } + + function panToNode(nodeId: string) { + const node = zoomable.querySelector(`#${nodeId}`); + // Find the midpoint for the screen and the node to center on + const findMidpoint = (el: Element) => { + const boundingClientRect = el.getBoundingClientRect(); + return { + x: boundingClientRect.x + boundingClientRect.width / 2, + y: boundingClientRect.y + boundingClientRect.height / 2, + }; + }; + const parentMidpoint = findMidpoint(parent); + const nodeMidpoint = findMidpoint(node); + + // Find the diff between them - that is our relative pan + const panDiff = { + x: parentMidpoint.x - nodeMidpoint.x, + y: parentMidpoint.y - nodeMidpoint.y, + }; + // Relative movement is scaled by the scale, so we need to undo that scaling. + const scale = panzoom.getScale(); + panzoom.pan(panDiff.x / scale, panDiff.y / scale, { + animate: true, + relative: true, + }); + console.log(parentMidpoint, nodeMidpoint, panDiff, scale); } + + onMount(() => { + initPanzoom(); + }); -{#await initialize() then} - - - -