trujello
trujello

Reputation: 145

Issues with 3d-force-graph node updates

I'm making an application where a viewer can use a dat.gui menu to update their Three.js animation. Specifically, I'm using 3d-force-graph.

When the users makes a change, I do the following:

  1. swap the old .json runnning their animation with the new one required to render their choice
  2. run a function called vertexControl which changes the nodes of their new animation (e.g., color change).

Simple example:

const settings = {
    num : 5,
}
const gui = new dat.GUI();
gui.add(settings, 'num', 1, 10).step(1).onChange( function update(n) { 
    Graph.jsonUrl('new_json'+ n.toString() +'.json'); //a built-in of 3d-force-graph to update the .json
    vertexControl() //Graph is now updated, so change the vertices
}

The problem: Before the Graph object can be updated with the new .json, vertexControl gets ahead of itself and executes. As a result, the desired changes to the nodes does not happen.

What I've tried 3d-force-graph has a method .refresh() but that doesn't seem to do anything in my case. I've also tried callbacks and other solutions on StackOverflow which address questions along the lines of "How to make function2 execute after function1." They don't seem to work for this, which is very surprising and strange. What definitely works is setting up a ridiculous setTimeout and guessing the milliseconds of when Graph is updated. However, what I'm trying to do is extremely basic, so there has to be a sensible way to do this (right?).

Upvotes: 1

Views: 574

Answers (1)

M -
M -

Reputation: 28497

The problem is that Graph.jsonUrl() has to load that JSON asynchronously, but vertexControl() is performed immediately, before the JSON has finished loading. I'm looking at the force-graph docs, and sadly there is no built-in way to perform a callback for when the JSON finishes loading. You might have to load the JSON yourself with THREE.FileLoader so you can invoke your own callback after loading is complete:

// FileLoader can help you load JSON files yourself
var fileLoader = new THREE.FileLoader();
const settings = {
    num : 5,
}
const gui = new dat.GUI();
gui.add(settings, 'num', 1, 10).step(1).onChange( function update(n) {
    fileLoader.load(
        'new_json'+ n.toString() +'.json',

        // Callback for when JSON file has finished loading
        function(response) {
            // Convert response text to JSON object
            const newData = JSON.parse(response);

            // Pass resulting object to Graph
            Graph.graphData(newData);   

            // Now you can run VertexControl
            vertexControl();
        }
    );
}

The first argument to fileLoader.load is the file path, and the second argument is the callback function to perform AFTER the file has finished loading. That way you can update your graph data first, and then run vertexControl without having to wait further.

Upvotes: 1

Related Questions