3

There are plenty of examples of drawing SVG paths from D3 geo data using D3's path projection tools. For example, here's one I wrote earlier (D3 v3) and here's a recent example using D3 v4.

They all look something like this:

  svg.append("path")
      .data(topojson.feature(datafile, datafile.objects.featureOfInterest))
      .attr("class", "land")
      .attr("d", pathDefinitionObject);

...where the data file is read and associated with some SVG, creating linked empty paths, then a D3 path definition object associated with a certain projection looks at the data and uses it to add SVG path definition strings to the d attributes of those paths.

What I want is, those path definition strings, but as strings, without touching any SVG. I want to use those strings with Raphael so that I can draw paths on browsers that don't support SVG, because a particular project requires supporting institutional clients who due to legacy software requirements and corporate policies haven't upgraded from IE8 (I know, I know...).

D3 is clearly capable of defining those strings, but I can't see an obvious way of getting the path definition object to output the strings without being linked to a DOM SVG element.

How can I just get the strings, without any SVG on the page?


I'm trying to use a minimal set of D3 v4's "microlibraries" for this, so bonus points for an answer with the fewest D3 dependencies (especially if it can avoid D3-selection.js which is quite large - ideally I'd like to only use D3's data processing and not use its DOM manipulation at all for this project).

Community
  • 1
  • 1
user56reinstatemonica8
  • 32,576
  • 21
  • 101
  • 125

1 Answers1

4

Building off your linked v4 example the minimalist code to just get the land paths d attribute would be:

<!DOCTYPE html>
<meta charset="utf-8">

<script src="//d3js.org/d3-array.v1.min.js"></script>
<script src="//d3js.org/d3-geo.v1.min.js"></script>
<script src="//d3js.org/d3-request.v1.min.js"></script>
<script src="//d3js.org/d3-dispatch.v1.min.js"></script>
<script src="//d3js.org/d3-collection.v1.min.js"></script>
<script src="//d3js.org/topojson.v1.min.js"></script>

<script>

var projection = d3.geoAlbers()
    .scale(1280)
    .translate([500, 500]);

var path = d3.geoPath()
    .projection(projection)
    .pointRadius(1.5);

d3.json("https://gist.githubusercontent.com/mbostock/4090846/raw/d534aba169207548a8a3d670c9c2cc719ff05c47/us.json", function(error, us){
  if (error) throw error;

  var topo = topojson.feature(us, us.objects.land);
  console.log(path(topo));

});

</script>

If you are not using d3.json, you can drop the d3-request, d3-dispatch and d3-collection libraries.

Mark
  • 106,305
  • 20
  • 172
  • 230
  • Great! Can't believe all I had to do was pass the geojson object to the path object! This outputs one mega-string of every feature in the featureCollection combined into one `M...ZM...ZM...Z` compound string, but it's easy to just run a `for` loop around `topo.features` to separate them out – user56reinstatemonica8 Jul 27 '16 at 13:45