Graph View Folders

Hi, I’m working on an enhancement for the graph view to include folders, as I’ve sketched here:

I’m making some progress, but there is still a delay between the movement of the nodes and the folders when I use the mouse to pan or zoom, or when I use the buttons to zoom.

I figured out how to include smooth panning when using the keyboard by studying the renderCallback function. For the X-coordinate it looks like this:

   mapXtoViewport(x: number): number
   {  
      if (!this.renderer.panning)  // Keyboard panning is active [sic]
         return x * this.renderer.scale + this.renderer.panX + 1000 * this.renderer.panvX / 60;
      else
      {
         // ?
      }
   }

But panning with the mouse and zooming still creates a delay in the positions of the folders.

I don’t understand renderCallback well enough, which explains this. (The internal rendering loop apparently assumes 60 FPS).

There are some variables in the renderer object that could be used somewhere in the graph worker thread that calculate the nodes’ positions, but I’m not sure:

renderer.panX
renderer.panvX
renderer.mouseX
renderer.scale
renderer.targetScale
renderer.zoomCenterX

Do you have an idea what’s missing in my mapXtoViewport function?

1 Like

Dear Obsidian team,

I’d really like to finish my plugin, at least as a proof of concept.

But there are two problems that I cannot solve, even after weeks of analyzing minified JavaSript code. :joy:

1. How do I synchronize panning and zooming for new elements in the graph view (from keys, mouse and touch input)?

I’ve synchronized my code with the renderCallback function and I’m using the positions from the nodes for the shapes of the folders. Theoretically(?), this should work…

nativeRenderCallback = this.renderer.renderCallback;
this.renderer.renderCallback = (...args) =>
{
   nativeRenderCallback(args);  // Call the original render callback function.           
   this.applyForces();          // Apply new forces to nodes in renderer.nodes.
   this.update();               // Update folder shapes.
};

2. How do I tell the graph worker thread to use my changes for the positions of the nodes I made in renderer.nodes?

(They get overwritten by the values that are stored within the worker thread).

I’ve tried a few variations by telling it through:

renderer.worker.postMessage(/* ? */);

But nothing worked.

Can you help me out, please?
Thanks in advance!

Just in case there’s a chance that this feature finds its way into Obsidian’s core functionality, I’d like to share my findings with you. But implemented as a plugin, I’m expecting too many performance issues.

Algorithm Description
Welzel’s Algorithm Finds the minimum enclosing circle around a bunch of nodes if the folders should look like pretty circles.
Quickhull Finds the outer nodes of a cloud of nodes that comprise a convex hull. Perhaps it could speed up overall performance if it is used before Welzel’s Algorithm to reduce its input parameters.
Centripetal Catmul-Rom Splines This smoothes the shape of the polygon hull.

Graph View Folders

1 Like

Hey @Mutzu

Love what you’ve managed to accomplish here. There’s probably thousands of people who’d love to see this implemented as a core feature!

I don’t suppose you’ve made any more progress on this since your last update?

Hi @hu4d,

Thank you! I stopped working on it. The expected effort to make it work smoothly and seamlessly as a plugin was beyond reasonable limits. :upside_down_face:
For example, Obsidian uses WebAssembly with a quadtree data structure to optimize the calculation of forces.