Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I find the projection of an existing D3 path

I am using D3 to render a vector map, based off of a GeoJSON dataset.

I have an existing path and I need to transform the path using a tween. To do this I need to use D3 to lookup the current projection object for this path. However, I can't seem to figure out the syntax to achieve this. Is it possible to look up the projection of an existing D3 path?

I can look up the path with:

const mapPath = d3.select('path.states');

But, I'm not sure where to go from there to get the projection object from this path. Thanks for any help or direction you might be able to provide.

like image 854
bryan kennedy Avatar asked Oct 19 '22 06:10

bryan kennedy


1 Answers

Since (based on the discussion in the comments) it sounds like the code that used a projection to render the map lives in the same app as the code that needs that projection elsewhere in the app, then this is really a question of app architecture — not projection detection. There are certainly ways to architect it such that the projection is "handed down" to the subroutine that need it, but that really depends on the frameworks and your implementation so far etc.

So without getting into architecture, another way to do this, is following Mark's suggestion (and in fact indicated by the code snippet in your original question) using d3's data binding to hang the projection off of the DOM node that the projection helped produce. IMO, compared with an app architecture solution, using data binding for this purpose is the lesser option, because it could make your code harder to follow bug prone. But it will work and, in a simple app at least, it's reasonable to do it this way. So...

Presumably, somewhere you have code that created and rendered the paths, and it might look something like this:

var projection = d3.geo.mercator();
var mapG = svg.append('g').attr('class', 'map');
var mapG.selectAll('path').data(myMapData).enter()
  .append('path')
  .attr("d", d3.geo.path().projection(projection));

I'm sure yours looks different, but hopefully it's close to the above, because I need to point out that the are N paths, corresponding to N entries in myMapData, and that each path already has a datum associated with it (the datum of the geo feature it represents). So a good place to hang your projection is NOT on the paths (because there are multiples, and they have have data bound to them already) but rather on the parent of the paths — mapG in this case. The way you do it is using .datum() to bind the projection to the DOM node:

mapG.datum(projection);

Now, from that other place in your code, where you need to look up the projection, you'd use datum() to extract it:

var mapG = d3.select('svg g.map')
var projection = mapG.datum()
like image 152
meetamit Avatar answered Oct 21 '22 02:10

meetamit