Using d3.geo.greatArc with a world map

616 views
Skip to first unread message

Ilya Boyandin

unread,
Mar 27, 2012, 8:28:10 AM3/27/12
to d3...@googlegroups.com
When using d3.geo.greatArc to show connections between the world's countries some of the lines have to go out of the screen and reappear on the other side of the view (e.g. between the US and Indonesia). In d3 they are not properly split in two separate parts, so horizontal lines connecting the parts are drawn across the whole screen.

It is not obvious to me how d3 should properly split the lines, because it depends on the parameters of the projection. But I came up with a workaround which modifies the SVG path produced by d3. It checks the distances between the consecutive points and compares them to the average. If the distance between two consecutive points is more than twice the average, the path is split between these points.

Is there a better way of doing this?


Here is an example: http://bl.ocks.org/2209220

This is where the workaround is applied:

.attr("d", function(d) { return splitPath(path(arc(d))); })

And this is the function itself:

        function splitPath(path) {
          var avgd = 0, i, d;
          var c, pc, dx, dy;
          var points = path.split("L");
          if (points.length < 2) return path;
          var newpath = [ points[0] ];
          var coords = points.map(function(d, i) {
// remove M and split
            return d.substr(i > 0 ? 0 : 1).split(",");
          });

          // calc avg dist between points
          for (i = 1; i < coords.length; i++) {
            pc = coords[i-1]; c = coords[i];
            dx = c[0] - pc[0]; dy = c[1] - pc[1];
            d = Math.sqrt(dx*dx + dy*dy);
            c.push(d); // push dist as last elem of c
            avgd += d;
          }
          avgd /= coords.length - 1;

          // for points with long dist from prev use M instead of L
          for (i = 1; i < coords.length; i++) {
            c = coords[i];
            newpath.push((c[2] > 2 * avgd ? "M" : "L") + points[i]);
          }
          return newpath.join();
        }

Dario

unread,
Dec 18, 2012, 9:02:21 AM12/18/12
to d3...@googlegroups.com
Hey, Great job with the split function. I'm using it on a map as well. However, when doing cross-browser testing i've realised firefox doesn't display any links:

I'm currently trying to debug it, so if i find a way to get it to work, i'll post the workaround here.

Cheers

Dario

Ilya Boyandin

unread,
Dec 18, 2012, 9:19:40 AM12/18/12
to d3...@googlegroups.com
Oops,

thanks Dario! This might be due to the transparency gradients which I used for the flow lines.

Ilya

Dario Villanueva Ablanedo

unread,
Dec 18, 2012, 9:34:21 AM12/18/12
to d3...@googlegroups.com
nope, it's to do with the fact that firefox defaults to a comma as a separator on array.join()


so it can be easily fixed if you just return array.join('') instead

cheers

Dario

Ilya Boyandin

unread,
Dec 18, 2012, 9:44:15 AM12/18/12
to d3...@googlegroups.com
It worked, thanks again!

On Tue, Dec 18, 2012 at 3:34 PM, Dario Villanueva Ablanedo <dario.vi...@gmail.com> wrote:
''

Reply all
Reply to author
Forward
0 new messages