From 1901cc55805642946af2811f380f1b2bb256e10e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 02:34:29 +0000 Subject: [PATCH 1/3] Initial plan From 715f6ee2afd86d5c68ce3ff9344fc08e37e4cd5c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 02:41:18 +0000 Subject: [PATCH 2/3] Optimize link processing and hover handler for performance - Use Map lookup (O(1)) instead of Array.find() (O(n)) for sphere lookups during link processing - Track highlighted lines to reset only those on hover instead of all 23,427 lines Co-authored-by: Amonsuzuki <159198433+Amonsuzuki@users.noreply.github.com> --- src/components/ThreeScene.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/ThreeScene.tsx b/src/components/ThreeScene.tsx index cf53102..d5dcb57 100644 --- a/src/components/ThreeScene.tsx +++ b/src/components/ThreeScene.tsx @@ -51,6 +51,7 @@ const [labelPositions, setLabelPositions] = useState< const defaultLineOpacity = 0.1; let outlineMesh: THREE.Mesh | null = null; let previouslyHoveredSphere: THREE.Mesh | null = null; + let highlightedLines: THREE.Line[] = []; type OverlayInfo = { overlay: HTMLDivElement, node: THREE.Object3D }; let neighborOverlays: OverlayInfo[] = []; @@ -166,6 +167,7 @@ const [labelPositions, setLabelPositions] = useState< const sphereGroup = new THREE.Group(); const lineGroup = new THREE.Group(); const nodeMap: { [key: string]: THREE.Vector3 } = {}; + const sphereByLabel = new Map(); data.nodes.forEach((node) => { //const material = new THREE.MeshNormalMaterial(); @@ -192,6 +194,7 @@ const [labelPositions, setLabelPositions] = useState< sphere.userData.displayUrl = `https://scrapbox.io/${projectName}/${node.text}`; sphere.userData.label = node.text; sphereGroup.add(sphere); + sphereByLabel.set(node.text, sphere); /* sphereGroup.add(sphere); @@ -220,8 +223,8 @@ const [labelPositions, setLabelPositions] = useState< const line = new THREE.Line(lineGeometry, lineMaterial); lineGroup.add(line) - const sourceSphere = sphereGroup.children.find(o => o.userData.displayUrl?.endsWith(link.source)); - const targetSphere = sphereGroup.children.find(o => o.userData.displayUrl?.endsWith(link.target)); + const sourceSphere = sphereByLabel.get(link.source); + const targetSphere = sphereByLabel.get(link.target); if (sourceSphere && targetSphere) { const sourceWorldPos = new THREE.Vector3(); sourceSphere.getWorldPosition(sourceWorldPos); @@ -331,11 +334,13 @@ const [labelPositions, setLabelPositions] = useState< ); const urlDisplay = urlDisplayRef.current; - lineGroup.children.forEach(line => { - if ((line as THREE.Line).material instanceof THREE.LineBasicMaterial) { - ((line as THREE.Line).material as THREE.LineBasicMaterial).opacity = defaultLineOpacity; + // Reset only previously highlighted lines instead of all lines + highlightedLines.forEach(line => { + if (line.material instanceof THREE.LineBasicMaterial) { + (line.material as THREE.LineBasicMaterial).opacity = defaultLineOpacity; } }); + highlightedLines = []; if (outlineMesh) { scene.remove(outlineMesh); @@ -426,6 +431,7 @@ const [labelPositions, setLabelPositions] = useState< lines.forEach((line) => { const mat = line.material as THREE.LineBasicMaterial; mat.opacity = 1.0; + highlightedLines.push(line); }); } } From eadffeb92740b6c7d49c28463a54c35791785cbb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 27 Nov 2025 02:43:39 +0000 Subject: [PATCH 3/3] Add missing semicolon for code style consistency Co-authored-by: Amonsuzuki <159198433+Amonsuzuki@users.noreply.github.com> --- src/components/ThreeScene.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ThreeScene.tsx b/src/components/ThreeScene.tsx index d5dcb57..9adef07 100644 --- a/src/components/ThreeScene.tsx +++ b/src/components/ThreeScene.tsx @@ -221,7 +221,7 @@ const [labelPositions, setLabelPositions] = useState< opacity: defaultLineOpacity }); const line = new THREE.Line(lineGeometry, lineMaterial); - lineGroup.add(line) + lineGroup.add(line); const sourceSphere = sphereByLabel.get(link.source); const targetSphere = sphereByLabel.get(link.target);