Jason Wright Jason Wright - 8 months ago 88
Javascript Question

Multiple paths with d3.js and google maps API

I'm trying to add an overlay of some paths defined by GeoJSON data using the Google Maps API. I started by using the examples in this thread and it worked fine with my data -- until I tried using two different paths. The paths need to be rendered with different colors, so I can't combine the datasets.

I've encountered an issue where not all of the paths will render fully. Here's the gist of what I'm attempting to do:

path2 = d3.geo.path().projection(googleMapProjection);
path4 = d3.geo.path().projection(googleMapProjection);

.attr("d", path2) // update existing paths
.attr("stroke", "red")
.attr("d", path4) // update existing paths
.attr("stroke", "green")

To show some examples:

http://jsfiddle.net/HWxKu/ -- Notice that the red path renders, but the green path never shows up. (Zoom in a bit.)

http://jsfiddle.net/X644x/ -- The only different is that I switched the order of the two svg.selectAll statements. The green path mostly renders, and bits of the red path render after you zoom in a bit.

Can anyone explain what might be happening? My thought is that either the Google Maps API is imposing some kind of limit on the overlay (perhaps a timeout?), or is something asynchronous happening here? I'm a novice to d3, so any explanation is greatly appreciated.


You're using the enter() selection wrong. The first set of statements to set "d" and "stroke" doesn't do anything at all because there are no paths yet. You need to put these after appending the new elements.

The second problem is that with the second statement, you're overwriting the first paths. By default, D3 matches new to existing data by the array index. That is, the first new feature is matched to the first existing path and so on. You need to supply a function to tell D3 how to match.

The code I think you want looks like this.

   .data(line2_geoJson.features, function(d) { return d.properties.route_id; })
   .attr("d", path2)
   .attr("stroke", "red");

   .data(line4_geoJson.features, function(d) { return d.properties.route_id; })
   .attr("d", path4)
   .attr("stroke", "green");