vasturiano / three-spritetext

A sprite based text component for ThreeJS
https://vasturiano.github.io/three-spritetext/example/basic/
MIT License
341 stars 46 forks source link

Crash when dragging nodes together with SpriteText #47

Open alierdogan7 opened 4 months ago

alierdogan7 commented 4 months ago

Hi @vasturiano, I render SpriteTexts with your nice library threesprite-text along with SphereGeometry in the same Mesh object, as you adviced in one of issues in order to display 2D text over nodes.

(node) => {
      const material = new THREE.MeshLambertMaterial({
        color: node !== hoverNode ? "gray" : "red",
        transparent: true,
        opacity: 0.75,
      });

      let geometry = new THREE.SphereGeometry(24, 32, 16);
      const meshObject = new THREE.Mesh(geometry, material);
      if (node.id) {
        const labelText = new SpriteText(node.id!.toString());
        labelText.color = "red";
        labelText.fontWeight = "bold";
        labelText.textHeight = 30;
        labelText.position.set(25, 25, 25);
        meshObject.add(labelText);
      }
      return meshObject;
    }

image

It works great, but if I try to drag nodes by clicking the sprite text instead of the sphere object it causes multiple crashes in the internals of ThreeJS library's DragControls as below:

image

I prepared this codesandbox for minimal reproducable example: https://codesandbox.io/p/sandbox/react-force-graph-threesprite-text-6mpzsk

As a workaround I thought disabling the mouse over events on SpriteTexts so that clicking on texts won't cause a drag event but couldn't find a way to do so.

Also, if I disable either showing spritetexts or highlighting nodes on hover, the crash goes away.

Do you have any suggestions to prevent the crash?

Thanks for the great library and support!

vasturiano commented 1 month ago

@alierdogan7 thanks for reaching out.

This issue is happening because you are regenerating Three objects at every node hover. That's due to hoverNode being a dependency of the renderNodeThreeObject React hook. The consequence is that by the time the drag controls is dragging the node, your hook has refreshed and replaced the dragging node with an identical but totally different object, leading to the error you see above. The issue is aggravated by the fact that the text sprite is a child of the main node object, so when the drag controls look up the chain for the common ancestor it doesn't find it and throws an exception.

I think perhaps the better way to handle this is to leave the sphere as the default node and simply extend it via nodeThreeObjectExtend={true}. That way you can manipulate its color independently of the text sprite generation, and avoid any problems related to react refreshes altogether.

I've modded your sandbox here where you can see it working: https://codesandbox.io/p/sandbox/react-force-graph-threesprite-text-forked-dtfxds

alierdogan7 commented 1 month ago

Thanks for taking time and suggesting a solution that works. I wish the best for you!