Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserving Node Positions after Page Refresh #543

Open
ScriabinOp8No12 opened this issue Oct 18, 2024 · 0 comments
Open

Preserving Node Positions after Page Refresh #543

ScriabinOp8No12 opened this issue Oct 18, 2024 · 0 comments

Comments

@ScriabinOp8No12
Copy link

ScriabinOp8No12 commented Oct 18, 2024

Hello Vasturiano, thank you for the great package! I'm using the 2D version of react-force-graph.

What's the best way to keep the nodes and links in the same place after a page refresh?

Storing the x and y values of each node and trying to render that causes issues because the force is applied to them on component mount / page refresh. However, if I use fx and fy instead of x and y, then the nodes are draggable but the force is turned off it seems. Below is a simple component I made where it loads the x and y positions from local storage. When I refresh the page, it loads the nodes in almost the right place, just that the force applies to it, pushing them farther apart.

import React, { useCallback, useEffect, useRef, useState } from 'react';
import { ForceGraph2D } from 'react-force-graph';

const LockedNodesGraph = () => {
  const fgRef = useRef();
  const [graphData, setGraphData] = useState({
    nodes: [
      { id: 1, name: 'Node 1' },
      { id: 2, name: 'Node 2' },
      { id: 3, name: 'Node 3' },
      { id: 4, name: 'Node 4' },
    ],
    links: [
      { source: 1, target: 2 },
      { source: 2, target: 3 },
      { source: 3, target: 4 },
    ],
  });

  useEffect(() => {
    const storedPositions = JSON.parse(localStorage.getItem('nodePositions')) || {};
    setGraphData(prevData => ({
      ...prevData,
      nodes: prevData.nodes.map(node => ({
        ...node,
        x: storedPositions[node.id]?.x,
        y: storedPositions[node.id]?.y,
      })),
    }));
  }, []);

  const handleEngineStop = useCallback(() => {
    fgRef.current.d3Force('center', null);
    const nodePositions = {};
    graphData.nodes.forEach(node => {
      nodePositions[node.id] = { x: node.x, y: node.y };
    });
    localStorage.setItem('nodePositions', JSON.stringify(nodePositions));
  }, [graphData.nodes]);

  const nodeCanvasObject = useCallback((node, ctx, globalScale) => {
    const label = node.name;
    const fontSize = 12/globalScale;
    const nodeRadius = 5;

    ctx.fillStyle = '#4285F4'; 
    ctx.beginPath();
    ctx.arc(node.x, node.y, nodeRadius, 0, 2 * Math.PI, false);
    ctx.fill();

    ctx.font = `${fontSize}px Sans-Serif`;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillStyle = 'black';
    ctx.fillText(label, node.x, node.y + nodeRadius + fontSize);
  }, []);

  useEffect(() => {
    const forceGraph = fgRef.current;
    if (forceGraph) {
      forceGraph.d3Force('link').distance(70);
      forceGraph.d3Force('charge').strength(-50);
      forceGraph.d3Force('charge').distanceMax(150);
    }
  }, [graphData, fgRef]); 


  return (
    <ForceGraph2D
      ref={fgRef}
      graphData={graphData}
      nodeLabel="name"
      onEngineStop={handleEngineStop}
      cooldownTicks={100}
      nodeCanvasObject={nodeCanvasObject}
      nodePointerAreaPaint={(node, color, ctx) => {
        ctx.fillStyle = color;
        ctx.beginPath();
        ctx.arc(node.x, node.y, 7, 0, 2 * Math.PI, false);
        ctx.fill();
      }}
    />
  );
};

export default LockedNodesGraph;

Please let me know if my question was clear and if you need any more information to help me out!

@ScriabinOp8No12 ScriabinOp8No12 changed the title Preserving Node Positions after Refresh and Graph Changes Preserving Node Positions after Page Refresh Oct 18, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant