From 96010fde0c8cb439db8ffbfe2602f972f54c0d87 Mon Sep 17 00:00:00 2001
From: Matthias Konitzny <konitzny@ibr.cs.tu-bs.de>
Date: Thu, 6 Jan 2022 11:37:48 +0100
Subject: [PATCH] Fixed memory leak. Implemented configurable link width.

---
 config.js        |  3 ++
 display/graph.js | 81 +++++++++++++++++-------------------------------
 2 files changed, 32 insertions(+), 52 deletions(-)

diff --git a/config.js b/config.js
index 42eee97..9a3a271 100644
--- a/config.js
+++ b/config.js
@@ -10,6 +10,9 @@ export const COLOR_PALETTE = [
     "rgb(255, 255, 255)",
 ];
 
+export const LINK_WIDTH = 3;
+export const HOVER_LINK_WIDTH = 6;
+
 // Just renaming a variable which is given by the PHP script. This avoids errors in all other files.
 export const PLUGIN_PATH = ks_global.plugin_path;
 export var SPACE = ks_global.space_id;
diff --git a/display/graph.js b/display/graph.js
index 97648bb..b4938c8 100644
--- a/display/graph.js
+++ b/display/graph.js
@@ -52,15 +52,16 @@ export default class Graph {
      */
     async loadGraph(spaceId) {
         this.gData = await loadGraphJson(spaceId);
+
         this.graph = ForceGraph3D({
             extraRenderers: [new CSS3DRenderer()],
             rendererConfig: { antialias: true },
         })(document.getElementById("3d-graph"))
             .graphData(this.gData)
             .nodeLabel("hidden") // Just a value that is not present as node attribute.
-            .nodeAutoColorBy("group")
-            .nodeColor((node) => this.getNodeColor(node))
-            .linkWidth((link) => this.getLinkWidth(link))
+            //.nodeAutoColorBy("group")
+            //.nodeColor((node) => this.getNodeColor(node))
+            //.linkWidth((link) => this.getLinkWidth(link))
             .onNodeClick((node) => {
                 this.focusOnNode(node);
                 if (MODE === "default") {
@@ -71,14 +72,17 @@ export default class Graph {
                 this.onNodeHover(node);
                 this.updateHighlight();
             })
-            .onLinkHover((link) => this.onLinkHover(link))
+            .onLinkHover((link, previousLink) =>
+                this.onLinkHover(link, previousLink)
+            )
             //.linkColor((link) => this.getLinkColor(link))
             .linkPositionUpdate((line, { start, end }) =>
                 this.updateLinkPosition(line, start, end)
             )
-            .linkOpacity(0.8)
+            //.linkOpacity(0.8)
             .nodeThreeObjectExtend(false)
             .nodeThreeObject((node) => this.drawNode(node))
+            //.linkThreeObject((link) => this.drawLink(link))
             .onEngineTick(() => this.initializeModel())
             .width(Helpers.getWidth())
             .height(Helpers.getHeight());
@@ -183,11 +187,17 @@ export default class Graph {
         this.hoverNode = node || null;
     }
 
-    onLinkHover(link) {
+    onLinkHover(link, previousLink) {
         this.highlightNodes.clear();
         this.highlightLinks.clear();
+        if (previousLink) {
+            // A bit hacky, but the alternative would require additional data structures
+            previousLink.__lineObj.material.linewidth = Config.LINK_WIDTH;
+        }
 
         if (link) {
+            link.__lineObj.material.linewidth = Config.HOVER_LINK_WIDTH;
+
             this.highlightLinks.add(link);
             this.highlightNodes.add(link.source);
             this.highlightNodes.add(link.target);
@@ -329,10 +339,10 @@ export default class Graph {
 
     updateHighlight() {
         // trigger update of highlighted objects in scene
-        this.graph
-            .nodeColor(this.graph.nodeColor())
-            .linkWidth(this.graph.linkWidth())
-            .linkDirectionalParticles(this.graph.linkDirectionalParticles());
+        // this.graph
+        //     .nodeColor(this.graph.nodeColor())
+        //     .linkWidth(this.graph.linkWidth())
+        //     .linkDirectionalParticles(this.graph.linkDirectionalParticles());
     }
 
     updateNodeMap() {
@@ -403,26 +413,19 @@ export default class Graph {
         geometry.setPositions([0, 0, 0, 1, 1, 1]);
         geometry.setColors(colors);
 
-        // const material = new THREE.LineBasicMaterial({
-        //     vertexColors: THREE.VertexColors,
-        // });
-
         const material = new LineMaterial({
             color: 0xffffff,
-            linewidth: 3, // in world units with size attenuation, pixels otherwise
+            linewidth: Config.LINK_WIDTH, // in world units with size attenuation, pixels otherwise
             vertexColors: true,
 
-            resolution: new THREE.Vector2(1920, 1080), // to be set by renderer, eventually
+            resolution: new THREE.Vector2(
+                window.screen.width,
+                window.screen.height
+            ), // Set the resolution to the maximum width and height of the screen.
             dashed: false,
             alphaToCoverage: true,
         });
 
-        // const geometry = new THREE.BufferGeometry();
-        // geometry.setAttribute(
-        //     "position",
-        //     new THREE.BufferAttribute(new Float32Array(2 * 3), 3)
-        // );
-        // geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
         const line = new Line2(geometry, material);
         line.computeLineDistances();
         line.scale.set(1, 1, 1);
@@ -436,17 +439,13 @@ export default class Graph {
 
         const startR = 4;
         const endR = 4;
-        // const startR = Graph.nodeRelSize();
-        // const endR = Graph.nodeRelSize();
         const lineLen = Math.sqrt(
             ["x", "y", "z"]
                 .map((dim) => Math.pow((end[dim] || 0) - (start[dim] || 0), 2))
                 .reduce((acc, v) => acc + v, 0)
         );
 
-        //const linePos = line.geometry.getAttribute("position");
-
-        const test = [startR / lineLen, 1 - endR / lineLen]
+        const positions = [startR / lineLen, 1 - endR / lineLen]
             .map((t) =>
                 ["x", "y", "z"].map(
                     (dim) => start[dim] + (end[dim] - start[dim]) * t
@@ -454,32 +453,10 @@ export default class Graph {
             )
             .flat();
 
-        // start = line.geometry.getAttribute("instanceStart");
-        // end = line.geometry.getAttribute("instanceEnd");
-        //
-        // start.setXYZ(0, ...test[0]);
-        // start.needsUpdate = true;
-        // end.setXYZ(1, ...test[1]);
-        // end.needsUpdate = true;
-        // line.geometry.attributes.position.needsUpdate = true;
-        // line.geometry.computeBoundingBox();
-        // line.geometry.computeBoundingSphere();
-
-        line.geometry.setPositions(test); // This seems to cause memory leaks :(
-        line.geometry.getAttribute("position").needsUpdate = true;
-        line.computeLineDistances();
+        line.geometry.setPositions(positions);
+        //line.geometry.getAttribute("position").needsUpdate = true;
+        //line.computeLineDistances();
 
-        // calculate coordinate on the node's surface instead of center
-        // linePos.set(
-        //     [startR / lineLen, 1 - endR / lineLen]
-        //         .map((t) =>
-        //             ["x", "y", "z"].map(
-        //                 (dim) => start[dim] + (end[dim] - start[dim]) * t
-        //             )
-        //         )
-        //         .flat()
-        // );
-        // linePos.needsUpdate = true;
         return true;
     }
 
-- 
GitLab