4 ms·
Does anyone know if there is a good way to do server-side rendering (svg files) of D3 charts while being able to reuse the same code in a browser? We do a lot
by blaze33 10y ago
Does anyone know if there is a good way to do server-side rendering (svg files) of D3 charts while being able to reuse the same code in a browser?
We do a lot of charts at work to visualize electricity consumption and are currently thinking about how to rewrite the js we've accumulated over the years. I've found some attempts at doing server-side rendering but nothing really compelling for now...
D3 is a well thought out library to do interactive visualizations in the browser and having an easy way to do svg exports (for things like automated emails) would be a big plus. Doing screenshots through selenium ain't always so pleasant ;)
- m0j0l 10y agoNot sure if it fits your use case, but; for one project I needed to have charts that the user could modify in their browser, and once they were happy they could hit 'download PDF' to get a PDF version. Achieved this by (admittedly slightly clunky way) of sucking the SVG out of the chart and sending it to the server via ajax. Server intercepts SVG and passes it to inkscape which does pretty good command line svg -> pdf... then, sends back completed PDF. One gotcha is that you won't get any CSS this way, so all styling has to be done via SVG props.
- e1g 10y agoThat's exactly what we are doing but running the SVG code through Apache Batik Rasterizer to turn it into png. I like this approach because the user can customise the chart in the front end and then the same resulting svg code is rendered by the backend. The only issue is styling as you mentioned.
- Frencil 10y ago> One gotcha is that you won't get any CSS this way, so all styling has to be done via SVG props. There actually is a way to bake stylesheets directly into the SVG in a way that at least Inkscape can read, but it's tricky. We're successfully doing this in a graphing library tuned for genetic data that's built on top of d3 called LocusZoom. The first step is to get the content of the stylesheet into a string. We do that here with a CORS request in case the stylesheet is being loaded over a CDN, as javascript won't be able to access the content of CDN-loaded stylesheets from document.styleSheets: https://github.com/statgen/locuszoom/blob/v0.4.0/assets/js/app/Instance.js#L808 https://github.com/statgen/locuszoom/blob/v0.4.0/assets/js/a... Since the stylesheet doesn't change once the page is loaded this only needs to happen once. From there, in our case, we have a dynamic/interactive SVG plot so the download needs to bundle up the current state of the SVG on request. Here's the method that does that: https://github.com/statgen/locuszoom/blob/v0.4.0/assets/js/app/Instance.js#L783 https://github.com/statgen/locuszoom/blob/v0.4.0/assets/js/a... Other than what no doubt looks familiar for pulling the raw SVG markup into a string we also insert a tag right after the opening <svg> tag that looks like this: "<style type=\"text/css\"><![CDATA[ " + this.css_string + " ]]></style>" Where this.css_string is our stylesheet content. We then base64 encode the string and stick in the href of an <a> tag styled to look like a download button as seen here: https://github.com/statgen/locuszoom/blob/v0.4.0/assets/js/app/Instance.js#L748 https://github.com/statgen/locuszoom/blob/v0.4.0/assets/js/a... The end result is a download SVG link/button that is 100% client-side with our chosen stylesheet embedded. Now, I have noticed that some styles defined in the stylesheet are valid in the browser but fail in InkScape and other SVG viewers. A prime example would be setting a stroke or fill to "transparent". InkScape doesn't interpret this properly and you can end up with solid black, just about the exact opposite of transparent. Keeping this in mind I stick to defining explicit "fill-opacity" and "stroke-opacity" values in the stylesheet for SVG elements and everything plays nice. A working demo of this can be seen here: http://statgen.github.io/locuszoom/plot_builder.html http://statgen.github.io/locuszoom/plot_builder.html
- monfera 10y agoD3 is great for updating / augmenting a server generated chart on the client side, with one caveat. Usually it's good practice to do the D3 DOM binding with a key (similar to the react key, but is a function; second argument to .data()). This allows the proper identification of a data point to be identified when it comes to enter, update or exit. However, with server-generated contents, you don't have the __data__ properties on the DOM elements initially. So, before there's any addition/deletion/update on the client side, it's best to establish the binding and populate __data__. An alternative is, if your use case permits, to not use the key function and work off of DOM element sequence. Either way, the best resource IMO is the GUP I, II, III series from Mike: https://bl.ocks.org/mbostock/3808234 https://bl.ocks.org/mbostock/3808234
- dnprock 10y agoYou can use PhantomJS to generate image for D3 charts. A server package solution is here: https://github.com/vidalab/banquo-server https://github.com/vidalab/banquo-server. Another possibility is to use wkhtmlpdf to generate PDF: https://github.com/wkhtmltopdf/wkhtmltopdf https://github.com/wkhtmltopdf/wkhtmltopdf
- simonw 10y agoA really quick and easy way to do server-side rendering is to use a third-party hosted service such as https://www.url2png.com/ https://www.url2png.com/ - set up a webapp somewhere that uses D3 to render your graph, then pass the URL to that page to url2png (using carefully selected height/width options) to render a .png version of your dynamic graph. $29/month gets you up to 5,000 renders, so it's a very inexpensive option (compared to building and running your own server-side rendering tech).
- neurotech1 10y agoUse the Node.JS package on the server, then convert the SVG to PNG. https://www.npmjs.com/package/d3 https://www.npmjs.com/package/d3 One minor caution is to avoid using CSS to style the SVG, because won't convert to PNG properly. Use ImageMagick or the svg2png (PhantomJS based) package to convert. https://www.npmjs.com/package/imagemagick-native https://www.npmjs.com/package/imagemagick-native https://www.npmjs.com/package/svg2png https://www.npmjs.com/package/svg2png