vasturiano / 3d-force-graph

3D force-directed graph component using ThreeJS/WebGL
https://vasturiano.github.io/3d-force-graph/example/large-graph/
MIT License
4.48k stars 803 forks source link

Redo/Undo feature #647

Open DanielChuDC opened 8 months ago

DanielChuDC commented 8 months ago

Is your feature request related to a problem? Please describe. Hi @vasturiano, would like to ask if it is possible to redo/undo certain operation such as dragging a node/ link, changing the node/link color. I would like to get the previous state of graph after the operation but not sure how to do it. thanks in advanced!

Describe the solution you'd like An API can let redo/undo happen

Describe alternatives you've considered My current implementation of undo is try to save a ForceGraph3DInstance before the operation happen. then I set back the previous graph to my current graph. But the color is not changing.

export function setPrevGraphtoCurrGraph(preGraph: ForceGraph3DInstance) {
    // Graph = preGraph 
    Graph.nodeColor(preGraph.nodeColor())
}
vasturiano commented 8 months ago

@DanielChuDC it's difficult to say without more context of the app. Could you make a simple reproducing example on https://codesandbox.io/ for instance?

DanielChuDC commented 8 months ago

Hi @vasturiano , thank you for replying! the link is here

in case the link not working, I paste the code here. Basically, I want to preserve the previous state of graph, so that I can redo/ undo the actions to the graph.

import "./styles.css";
import ForceGraph3D from '3d-force-graph';

const N = 20;
const gData = {
  nodes: [...Array(N).keys()].map((i) => ({ id: i })),
  links: [...Array(N).keys()]
    .filter((id) => id)
    .map((id) => ({
      source: id,
      target: Math.round(Math.random() * (id - 1))
    }))
};

const Graph = ForceGraph3D()(
  document.getElementById("3d-graph")
).graphData(gData);

function nodeColorOddNumber(node) {
  let color='yellow'
  if(node.id % 2 === 1)
  {
    return color
  }
  return 'red';
}
let preGraph = Graph // preserve the previous state of graph

Graph.nodeColor((node) =>
  nodeColorOddNumber(node)
)

// Undo
Graph.nodeColor( preGraph.nodeColor())
vasturiano commented 8 months ago

@DanielChuDC thanks for making the example.

The reason why no change happens when you do Graph.nodeColor( preGraph.nodeColor()) is because that's the exact same function reference actually. You have preGraph = Graph therefore your undo operation is the same as Graph.nodeColor(Graph.nodeColor()) which does absolutely nothing.

Taking a step back, if you want to preserve state what you want to memorize is not the reference to ForceGraph3D as that won't achieve much. You probably want to have a single reference to ForceGraph3D and just memorize the dataset.

For instance when you swap the dataset with something new, and later wish to undo it:

const newData = ...;

const prevData = Graph.graphData();
Graph.graphData(newData);

...

// undo
Graph.graphData(prevData);