Indeed, this is very specific to a package, more specifically, @vasturiano‘s React Force Graph. But, since it makes heavy use of the HTML Canvas and D3.js, I thought maybe someone here could shed a light on how to solve it.
What I would like to do has already been reported on issue #433 of that project, but it hasn’t received any answers. Anyways, I would like to add text on top of nodes, with said text not overflowing out of the node circle boundary, something like this:
I think the best you can do right now is something like this — I’ve only been able to do something like it through React Force 3D actually —:
By using the example of 2D Text Nodes provided by @vasturiano (ctx.fillText(...)
), I’ve managed to add text to circular nodes, but it somehow ends up behind it, no matter where I put it:
<ForceGraph2D
graphData={dataMemo}
nodeCanvasObjectMode={() => "before"}
nodeCanvasObject={(node, ctx) => {
ctx.beginPath();
ctx.arc(node.x!, node.y!, NODE_R * 1.4, 0, 2 * Math.PI, false);
ctx.fill();
ctx.fillText("hello", node.x!, node.y!);
}
/>
Does anyone know how to stack the text and delimit it properly? I expected the text to at least be on top of the node circles, since it’s supposedly only drawn later on, I believe (I don’t think there’s a z-index on <canvas>
so I don’t think that’s a feasible direction).
@vasturiano provided me a link to how to do the bounded text: Mike Bostock – Fit Text to Circle, while also noting that this is something related to HTML Canvas, not his project itself.
2
Answers
Your question has multiple questions hidden in one, you are dealing with a complex problem…
My answer will not be a fix to your problem, but should send you in the right direction.
Start by reading more about how is text aligned when you do draw it in a canvas:
CanvasRenderingContext2D
:textAlign
propertyCanvasRenderingContext2D
:textBaseline
propertyNow your problem, you have to calculate if the text fits in the given circle, for that you need to know or at least get approximations on the size of your text, more reading:
CanvasRenderingContext2D
:measureText()
methodTextMetrics
With all that you should be able to calculate if the text fits, if not, split it or try something to "make it fit" and you loop until you get something that fits.
Here is some code I had for some other project…
In that code I change the font size to make the letter look nicer in the circle
Below are a simplified version of the code you provided in the github question:
https://github.com/vasturiano/react-force-graph/issues/433#issuecomment-1807292462
If we are going to troubleshoot drawing overlap, we don’t need a bunch of node, one will suffice and you don’t need all the other fancy hover functionality…
simple drawing:
Now let’s change to draw after
nodeCanvasObjectMode={node => 'after' }
We can see the difference
That center light blue circle is not the code in the paintRing is something else so I will set the:
nodeRelSize={0}
and we can do all the drawing in the paintRingYou can do a lot of things but you have to experiment with the tools you are using…
I have never used this
ForceGraph2D
before, this is just me testing a few stuff