react-force-graph icon indicating copy to clipboard operation
react-force-graph copied to clipboard

Formatting Node labels (not the hovering label) Force-graph 2D

Open nalindeepan007 opened this issue 2 years ago • 14 comments

@vasturiano Currently, node labels are displaying like this, with nodeCanvasObject the text is spilling out of circular node:

image

How can I set node labels like this when the text is longer (or a full sentence), so that it can wrap inside the circular node... image

Thanks

nalindeepan007 avatar Mar 30 '23 08:03 nalindeepan007

I would also very much like to know how to do this.

psygo avatar Nov 08 '23 11:11 psygo

I've created a question on StackOverflow about this: Adding Bounded Text to React Force 2D (HTML Canvas)

psygo avatar Nov 08 '23 17:11 psygo

@psygo this question is kind of beyond the scope of this package. Since you're defining your own custom node (via nodeCanvasObject) you're really in full control on how to write the text in your custom node.

But in any case, you can find some examples around on how to wrap text inside a circle in a Canvas environment. For example: https://observablehq.com/@mbostock/fit-text-to-circle

vasturiano avatar Nov 09 '23 21:11 vasturiano

Thank you for the helpful answer, @vasturiano !

I think that now probably at least half the problem should hopefully be solved with that link.

But do you know how to draw the text on top of the nodes? For some reason, adding ctx.fillText("hello", node.x!, node.y!) to your Highligh nodes/links example keeps drawing the text behind the nodes. I've also tried variations with nodeCanvasObjectMode, with no success.

image

psygo avatar Nov 11 '23 23:11 psygo

@psygo for that you just need to set nodeCanvasObjectMode="after".

vasturiano avatar Nov 12 '23 14:11 vasturiano

Strange, cause I did try various combinations of before, after, and replace for nodeCanvasObjectMode in that example, and none of them worked to draw on top of the node.

psygo avatar Nov 12 '23 14:11 psygo

Do you have a repro example?

vasturiano avatar Nov 12 '23 21:11 vasturiano

The pictures I was providing in previous comments were very basically the Highlight nodes/links example you provided in the documentation. The only thing I did was add ctx.fillText("hello", node.x!, node.y!) to paintRing:

...

const paintRing = useCallback(
  (node, ctx) => {
    // add ring just for highlighted nodes
    ctx.beginPath();
    ctx.arc(
      node.x,
      node.y,
      NODE_R * 1.4,
      0,
      2 * Math.PI,
      false
    );
    ctx.fillStyle = node === hoverNode ? "red" : "orange";
    ctx.fill();

    // Doesn't seem to matter if I put it before or after `ctx.fill()`
    ctx.fillText("hello", node.x!, node.y!)  
  },
  [hoverNode]
);

return (
  <ForceGraph2D
    graphData={data}
    nodeRelSize={NODE_R}
    autoPauseRedraw={false}
    linkWidth={(link) =>
      highlightLinks.has(link) ? 5 : 1
    }
    linkDirectionalParticles={4}
    linkDirectionalParticleWidth={(link) =>
      highlightLinks.has(link) ? 4 : 0
    }
    // Doesn't seem to work to draw text on top of the node
    // nodeCanvasObjectMode="after"
    nodeCanvasObjectMode={(node) =>
      highlightNodes.has(node) ? "before" : undefined
    }
    nodeCanvasObject={paintRing}
    onNodeHover={handleNodeHover}
    onLinkHover={handleLinkHover}
  />
);

Screenshot_2023-11-12-21-03-07_5120x1080

psygo avatar Nov 13 '23 00:11 psygo

@psygo see my second response in StackOverflow ...

heldersepu avatar Nov 13 '23 01:11 heldersepu

Here is a more complete test: https://raw.githack.com/heldersepu/hs-scripts/master/HTML/ForceGraph2D.html

image

Actual code: https://github.com/heldersepu/hs-scripts/blob/master/HTML/ForceGraph2D.html

heldersepu avatar Nov 13 '23 02:11 heldersepu

To address the original question from @nalindeepan007 ... wrapping text inside the circular node is not an easy task, you have to come up with an algorithm that suits your needs, there is no magic bullet for that

heldersepu avatar Nov 13 '23 15:11 heldersepu

Thank you for the helpful answer, @heldersepu ! I had actually tried much of what you've shown here, but somehow it didn't work, I don't know why. Thank you for showing that it does work.

To address the original question from @nalindeepan007 ... wrapping text inside the circular node is not an easy task,

I haven't had the time (more like the energy...) to test it, but doesn't the link Mike Bostock's tutorial on how to fit text to a circle provided by @vasturiano solve that issue? (That tutorial seems to target <svg>s though, not the <canvas>)

psygo avatar Nov 14 '23 00:11 psygo

@psygo Yes, that ("Fit Text to Circle") is just an example of how to fit text into an circle in SVG, but some of that logic can still apply to any other context, you just have to put the time an fill in the gaps...

@vasturiano I think you can close this issue as out of scope

heldersepu avatar Nov 14 '23 13:11 heldersepu

Somebody provided an answer as to how to fit the text to a circle with <canvas> here. That piece of code is a bit difficult to understand, and when I used it in React, it behaved a bit weirdly on the first render, but it seems to work fine. Anyways, I'm gonna leave it here if anyone finds it useful.

psygo avatar Dec 10 '23 14:12 psygo