d3 - 我可以以某种方式组合两个投影,还是投影一个投影?

d3 - may I somehow compose two projections, or project a projection?

我想创建一个在 Z 轴上向后倾斜的地图,就好像您看到它平放在 table 上一样。没问题:使用 Mike Bostock 的 custom projection 方法,定义一个简单的转换,当它向顶部移动时缩小,收工。

除了在这个过程中我了解到 d3 默认为 Albers USA 投影,并且使用我的自定义投影将阿拉斯加和夏威夷放回到正确的位置(我不想要)。

此外,我还没有意识到波多黎各不在 Albers USA 投影中,所以我实际上想切换到 Albers USA + PR

如果可以的话,我宁愿不重新制作投影,因为总有一天我会找到一个也有其他各种美国领土的阿尔伯斯。

投影是否可以以某种方式组合?

在不知道您实施的具体细节的情况下,我 forked Mike Bostock's Block AlbersUSA + PR 展示了一种可以做到这一点的方法。

它的核心是使用 Albers USA 投影,其中包括所要求的波多黎各。这是正常的 D3 projection:

var albersUsaPrProj = albersUsaPr()
    .scale(1070)
    .translate([width / 2, height / 2]);

接下来,我对 table 实施了一个相当简单的投影,它可能需要一些改进,但应该足以让您入门。这个使用 d3.geo.transform() to create a stream wrapper for the calculations needed to project the map on the desktop. The wrapped stream listener 只需要实现 point 方法,该方法将使用 xy 屏幕坐标调用,这些坐标是地理投影的结果。

// The scale is used for convenient calculations only.
var yScale = d3.scale.linear()
               .domain([0,height])
               .range([0.25,1]);

var desktopProj = d3.geo.transform({
  point: function(x,y) {
    this.stream.point((x - 0.5*width) * yScale(y) + (0.5*width), y);
  }
});

通过创建一个实现 .stream() 方法的对象,可以轻松地将两个投影合并到一个新的流包装器中。

var combinedProj = {
  stream: function(s) {
      return albersUsaPrProj.stream(desktopProj.stream(s));
  }
};

根据 projection.stream(listener) 上的文档:

Returns a projecting stream wrapper for the specified listener. Any geometry streamed to the wrapper is projected before being streamed to the wrapped listener.

这将首先让 albersUsaPrProj 处理地图的 Albers USA 投影,然后将生成的屏幕坐标流式传输到 desktopProj

然后可以将此组合投影传递给 path.projection([projection]):

For more control over the stream transformation, the projection may be specified as an object that implements the stream method. (See example.) The stream method takes an output stream as input, and returns a wrapped stream that projects the input geometry; in other words, it implements projection.stream.

这给了我们最后的决定,因为

var path = d3.geo.path()
    .projection(combinedProj);