d3-area-label icon indicating copy to clipboard operation
d3-area-label copied to clipboard

[Question] Using this package for server-side D3 rendering

Open ErikBoesen opened this issue 2 years ago • 2 comments

Hello and thank you for writing an excellent package!

I'm attempting to use it for generating graphs of Spotify users' listening history (example). As I built out the rendering code, the large quantity of data and rendered SVG components led to huge slowdowns of my browser. Due to that and other operational constraints, I decided to instead render the graphic on the server-side and send the SVG file to my front end. I am using JSDOM to simulate a DOM for D3 rendering (something similar to this) and that's generally working alright.

However, the one issue I'm having is with this line: https://github.com/curran/d3-area-label/blob/master/src/area-label.js#L79

SVGElement.getBBox() is undefined in the context of JSDOM. This of course makes sense, as JSDOM does not actually lay out and render elements, and rather handles only DOM manipulation. I have been tweaking the dependency code of d3-area-label and struggling to reproduce the functionality of getBBox in a way that can enable the package to properly position and scale labels.

As you mentioned in #26, measuring text labels is quite tricky. That said, I thought it would be worth reaching out to ask if you have any insight on how I might be able to tweak d3-area-label to support JSDOM or another non-browser environment.

Please let me know if you have any thoughts, and thanks again for creating this!

ErikBoesen avatar Aug 10 '23 03:08 ErikBoesen

Thanks for dropping this note!

Some approaches I can think of trying:

  • Detect if we're in a server environment, and if so swap out that measuring logic with a rough approximation of width based on character count and font size. It won't be exact but would probably be close. This should be, in theory, fairly low hanging fruit. I'd welcome a PR with this change!
  • If accuracy is desired, maybe the Canvas API could be used in a Node environment using node-canvas to measure the text exactly. Once the first solution is working, we could try this approach in place of the approximation.
  • Probably overkill, but it's also possible to spin up a headless Chrome instance on the server using something like Puppeteer. Then the code could run in that browser context inside the server, with full access to the CSS and SVG runtimes that support measuring text with the right font.

curran avatar Aug 14 '23 14:08 curran

Here's an example that uses the canvas API to measure text: https://observablehq.com/@fil/automated-label-placement-france#textMeasure

Fil avatar Aug 14 '23 16:08 Fil