web icon indicating copy to clipboard operation
web copied to clipboard

D3 Force example nodes not draggable

Open moklick opened this issue 1 year ago • 14 comments

While the simulation is running, the nodes are not draggable https://reactflow.dev/learn/layouting/layouting#d3-force

moklick avatar Jul 10 '24 10:07 moklick

They are draggable for me (Mac, safari 17.5), although performance is notably worse than it used to be.

hayleigh-dot-dev avatar Jul 18 '24 14:07 hayleigh-dot-dev

They are only draggable after the simulation stops running, for me.

BensEye avatar Jul 21 '24 11:07 BensEye

I have worked through this problem myself with V11. It was quite tricky to get all the interactivity to play ball. I'm about to update v12, so once I've checked that none of my solution breaks I will post a link.

buchananwill avatar Jul 21 '24 21:07 buchananwill

I've copied over the simplest solution I found to get the node dragging to function correctly with d3 force layouting. Here's my fork of the example repo:

https://github.com/buchananwill/quizzical-lamarr-tv8srd.git

The gist of the solution is to use the callbacks for onNodeDragStart/onNodeDrag/onNodeDragStop to assign the currently dragging node to a ref:

    const draggingNodeRef = useRef(undefined);
    const [initialized, {toggle, isRunning}] = useLayoutedElements(draggingNodeRef);

    const onNodeDragStart = useCallback(
        (_event, node) => {
            draggingNodeRef.current = {...node};
        },
        []
    );

    const onNodeDragStop = useCallback(() => {
        draggingNodeRef.current = undefined;
    }, []);

    const onNodeDrag = useCallback(
        (_event, node) => {
            draggingNodeRef.current = {...node};
        },
        []
    );

This ref is passed into the useLayoutedElements hook, so the memoized function can always guarantee to see a non-stale reference. I made a few other minor changes to tidy up some janky behaviour, like copying the xyflow positions back onto the sim nodes before restarting the sim - otherwise the nodes forget where you might have dragged them to and hop back to the last position the sim remembers.

Feel free to copy my change/fork back into the example version for the web docs.

buchananwill avatar Jul 21 '24 23:07 buchananwill

Thanks for sharing your solution @buchananwill ! We will have a look

moklick avatar Sep 11 '24 08:09 moklick

Some observations on the website example (https://reactflow.dev/learn/layouting/layouting#d3-force):

  1. the nodes are draggable in Safari
  2. the nodes are not draggable in Chrome/Firefox
  3. (very weird) if you open the dev tool on Chrome, the nodes are draggable

All above are after starting force simulation, i.e., auto-layout in effect.

lihebi avatar Sep 22 '24 05:09 lihebi

I observed all of these behaviours as well, both in the example site, and my own project. The solution I posted is how I fixed it in my own project, and also applies to the example site.

On Sun, 22 Sept 2024, 06:01 Hebi Li, @.***> wrote:

Some observations on the website example ( https://reactflow.dev/learn/layouting/layouting#d3-force):

  1. the nodes are draggable in Safari
  2. the nodes are not draggable in Chrome/Firefox
  3. (very weird) if you open the dev tool on Chrome, the nodes are draggable

All above are after starting force simulation, i.e., auto-layout in effect.

— Reply to this email directly, view it on GitHub https://github.com/xyflow/web/issues/429#issuecomment-2365468410, or unsubscribe https://github.com/notifications/unsubscribe-auth/BBL2M6IAK7J4TROJ3YKTVXTZXZFMPAVCNFSM6AAAAABKUT5ZB6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNRVGQ3DQNBRGA . You are receiving this because you were mentioned.Message ID: @.***>

buchananwill avatar Sep 22 '24 13:09 buchananwill

Thanks @buchananwill , I actually did try the codesandbox link on your repo. The behavior is exactly the same as the website example (all 1,2,3 above). I'm surprised that it works on your side. I'm on MacOS 15.0, Chrome 128.0.6613.138 (Official Build).

lihebi avatar Sep 23 '24 05:09 lihebi

Ah, you're right. I checked against my main project I copied from and I'd missed one detail: the current drag position needs to come directly from the ref, not the scoped list of nodes (which is stale).

      getNodes().forEach((node, i) => {
        const dragging = draggingNodeRef?.current?.id === node.id;

        // Setting the fx/fy properties of a node tells the simulation to "fix"
        // the node at that position and ignore any forces that would normally
        // cause it to move.
        if (dragging) {
          // These two lines were wrong.
          nodes[i].fx = draggingNodeRef?.current?.position.x; 
          nodes[i].fy = draggingNodeRef?.current?.position.y;
        } else {
          delete nodes[i].fx;
          delete nodes[i].fy;
        }
      });

buchananwill avatar Sep 23 '24 12:09 buchananwill

Please try the codesandbox again and let me know if it works for you now!

buchananwill avatar Sep 23 '24 12:09 buchananwill

Awesome, it works! Thanks for the quick response and debugging.

lihebi avatar Sep 23 '24 18:09 lihebi

:-) you're welcome!

On Mon, 23 Sept 2024, 19:32 Hebi Li, @.***> wrote:

Awesome, it works! Thanks for the quick response and debugging.

— Reply to this email directly, view it on GitHub https://github.com/xyflow/web/issues/429#issuecomment-2369064805, or unsubscribe https://github.com/notifications/unsubscribe-auth/BBL2M6N54CPBHEAXIAWIWSLZYBNFLAVCNFSM6AAAAABKUT5ZB6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNRZGA3DIOBQGU . You are receiving this because you were mentioned.Message ID: @.***>

buchananwill avatar Sep 23 '24 19:09 buchananwill

Hey @buchananwill thank you so much for investigating! I can confirm that your repo/sandbox works outside of safari: it's so strange that it works at all in safari 🧐

We're in the process of reworking how we host our examples (#501) but I'll make sure these changes are added and we'll shout you out when things go live 💕. Until then I'll leave the issue open in case anyone else needs to find it.

hayleigh-dot-dev avatar Oct 01 '24 08:10 hayleigh-dot-dev

Feel free to tag in me in anything else that is a puzzle. I've got a bit of free time at this week and have been using xyflow quite a bit lately. 🙏

On Tue, 1 Oct 2024, 09:16 Hayleigh Thompson, @.***> wrote:

Hey @buchananwill https://github.com/buchananwill thank you so much for investigating! I can confirm that your repo/sandbox works outside of safari: it's so strange that it works at all in safari 🧐

We're in the process of reworking how we host our examples (#501 https://github.com/xyflow/web/pull/501) but I'll make sure these changes are added and we'll shout you out when things go live 💕. Until then I'll leave the issue open in case anyone else needs to find it.

— Reply to this email directly, view it on GitHub https://github.com/xyflow/web/issues/429#issuecomment-2385098031, or unsubscribe https://github.com/notifications/unsubscribe-auth/BBL2M6PCLRQOWNBM5ZZXFILZZJK7NAVCNFSM6AAAAABKUT5ZB6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGOBVGA4TQMBTGE . You are receiving this because you were mentioned.Message ID: @.***>

buchananwill avatar Oct 01 '24 09:10 buchananwill

I've keep running into this issue even though I have a mostly working graph setup. Today I found that adding the useNodesData() hook into one of the node component implementations I have, breaks the dragging behaviour again. I worked around it by instead subscribing to the higher up context I am wrapping my xyflow setup in.

const { nodes } = useNodeContext<OrganizationDto>();

This doesn't trigger re-renders from selection/movement updates, because it's the external data, rather than the full UI state. So, it'll re-render if a node is added, or the "business" data on any node changes, but not the UI-level state changes.

Does this give any clues about why the dragging behaviour would break in the first place?

buchananwill avatar Oct 16 '24 20:10 buchananwill

Looks like Hayleigh fixed this here: https://github.com/xyflow/web/commit/63d216b6f179409c8b9ebbd1966dd3df2d6bed38

Looks good to me on all browsers.

Thanks @hayleigh-dot-dev 🙃

printerscanner avatar Mar 25 '25 15:03 printerscanner