简体   繁体   中英

How to reset force directed graph to its original position?

I have a force directed graph with nodes and links and i would like to reset the graph to its original position after hitting reset. I managed to achive the reset result by creating another graph, which has the coordinates of the force directed graph: https://jsfiddle.net/Lf0jcnt1/1/

For the reset method, I used this function:

  function reset(source) {
    source.selectAll("circle")
      .transition()
      .duration(750)
      .style("fill","red")
      .attr("cx", function(d) {
        console.log("Initial X position from RESET is " + d.c);
        return (d.c)
      })
      .attr("cy", function(d) {
        return (d.z)
      })
  }

Where data is appended like this:

  var circle_data = d3.range(nodes_len).map(function(i) {
    return {
      c: x_nodes[i],
      z:y_nodes[i]
    };
  });

The problem is that the force directed graph won't reset the nodes position to their original ones when clicking the reset button, the nodes will get translated in different positions than the original.

Below is the code for the forced graph:

    constructor(nodes: Node[], links: Link[], options: { width: number, height: number }) {
        this.nodes = nodes;
        this.links = links;
        this.options = options;
      
        this.simulation = forceSimulation<Node, Link>()
            .force('links', forceLink(this.links).distance(FORCES.DISTANCE).strength(FORCES.LINKS))
            .force('collide', forceCollide((node: Node) => node.radius * 2 + 30))
            .force('center', forceCenter(this.options.width / 2, this.options.height / 2))
            .force('cluster', forceCluster((node: Node, index: number, data: Node[]) => {
                const numberOfGroups = this.nodes.map(n => n.group).filter((value, i, array) => array.indexOf(value) === i).length;

                for (let i = 0; i < numberOfGroups; i++) {
                    if (node.group === i + 1) {
                        const max = data.filter(n => n.group === i + 1).map(n => n.instancesCount).sort((n1, n2) => n1 - n2).pop();
                        return data.filter(n => n.group === i + 1).filter(n => n.instancesCount === max).pop();
                    }
                }
            }).strength(FORCES.CLUSTER))
            .nodes(this.nodes)
            ;

        this.simulation.on('tick', () => {
            this.ticker.next();
        });

        
        this.simulation.on('end', () => { 
            console.log("end of simulation values);
            this.xNodeValues = this.nodes.map( (node)=> node.x);
            this.yNodeValues = this.nodes.map( (node)=> node.y);
        });

    }

For the force directed graph, I tried to use the same reset method as before, but replace c and z with x and y, but the translation effect takes place, not the reset to the original place. Any idea on how to solve this?

You can create a "snapshot" of the nodes at the inital position JSON.stringify

this.savedNodes = JSON.stringify(nodes)

And when the reset button is clicked, you can load it back to the class and to the simulation:

this.nodes = JSON.parse(this.savedNodes)
this.simulation.nodes(this.nodes).restart()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM