Search code examples
javascripthtmlsvgd3.jszombie.js

D3 renders SVG. How can I get that SVG programmatically?


I have a page that runs javascript on load that renders a map in SVG using d3. I want to automatically get a copy of that HTML + SVG. I can't just curl the the server -- that just returns the HTML of the page before the javascript runs. I guess I could use selenium or zombiejs -- but is there an easier way?


Solution

  • We had to do something very similar lately. Here are few things we tried:

    • Using jsdom
    • Use phantomjs to visit the page and grab output
    • Rewrite using some server side language + data format
    • Don't manipulate DOM at all

    JSDOM

    Ya, it supports SVG, but NOT SVG 1.1. Which means the text element doesn't work among other things. It may eventually have this support though.

    PhantomJS

    This worked but it is potentially slow. The only way you can tell if the SVG is done rendering is by adding a class or element to the page and have phantom wait for that object to appear. Once it does grab the svg element using standard DOM operations. For about 1k objects on screen after a few ajax calls this took maybe 5 seconds. 6k objects, it took around a minute.

    Rewrite on the server side

    Ultimately, we had to do this since we had a LOT of objects on screen. We had some data model that we took and mimic'd the output. This is faster since it's string based and doesn't require a bunch of DOM look ups/writes and not spinning up a leaky browser is also a plus. The down side is that you'll have 2 implementations of the same code.

    Don't use D3 or Raphael

    If you are able to write SVG using strings/templates then you can use the same JS on the client and server side. This by far seems like the best approach in retrospect. If I was able to go back I'd have acted more disgruntled towards the fact that we were using Raphael and just pushed hard on using handlebars, backbone, rendr and a node server.