Search code examples
javascriptd3.jsprojectionvoronoi

Can d3 voronoi map work well with any other projection besides geoAlbers?


I'm learning voronoi map from the example link https://bl.ocks.org/mbostock/7608400

But it doesn't work when I wanna change the projection to mercator.Why?

This is the only code I change:

var projection = d3.geoMercator()
    .translate([width / 2, height / 2])
    .scale(1280);

Solution

  • Yes, a voronoi should work with any projection - it uses the projected points in svg coordinate space. If you see points, you can make a voronoi.

    The issue is you need to modify the parameters of the projection. An Albers projection requires two secant lines or parallels where the ellipsoid of the earth intersects the cone of the projection (or alternatively, one tangent line or parallel). Rarely are these set to the equator, so D3 has default settings of an Albers projection to be suited to and centered on the US as it doesn't make much sense to leave all the defaults to zero.

    Most other projections in D3 have their default settings resulting in a map centered at [0,0], which is the prime meridian and the equator, just off the coast of Africa. Consequently, that's where you are looking when you set the projection as you have - no visible points, no visible voronoi (other than perhaps the periphery.

    If you were to set your scale to be much smaller, say 170, you would see the your map, but all the features would be in the top left corner:

    enter image description here

    Instead of just zooming out, we can use the default centering coordinates of the Albers to center the Mercator:

    projection.center([-96,39])

    If you are too zoomed in, lower the scale value, and increase it if you are zoomed out too far. Because Mercator's distortion of size gets pretty bad near the poles, you will likely need to scale out.

    Here's what I get with the example's code and this projection, zooming out a bit, but depending on if you want Alaska or not, you might want to zoom in or out:

    var projection = d3.geoMercator()
        .translate([width / 2, height / 2])
        .scale(600)
        .center([-96,39])
    

    enter image description here