改编规范示例时,我的 topojson 不会显示

My topojson won't display when adapting a canonical example

我开始研究 D3 以创建一个 choropleth/heatmap 并按年份筛选。

问题:

我想显示这个topojson file. I've tried to adapt Mike Bostock's topojson example here。但是,当我为我的 topojson 调整示例时,控制台中没有显示任何错误。

我的代码如下所示:

var svg = d3.select("svg");
var path = d3.geoPath();
d3.json("aisp.topojson", function(error, aisp) {
  if (error) throw error;

svg.append("g")
  .attr("class", "states")
.selectAll("path")
 .data(topojson.feature(aisp, aisp.objects.convert).features)
.enter().append("path")
.attr("d", path);


svg.append("path")
  .attr("class", "state-borders")
  .attr("d", path(topojson.mesh(aisp, aisp.objects.convert, function(a, b) { return a !== b; })));
}); 

问题

使用此块作为示例可能会有问题,因为它不使用投影。该示例使用一个预投影的 topojson,其坐标为像素坐标 space - 它旨在显示在 900 x 600 像素 window 上,并且输入文件中的坐标值范围在边界内[0,0] 和 [900,600] 的框。因此,该示例未使用地理投影。

地理坐标不会完全落在这个范围内。

为什么什么都不画?

与示例不同,您的 topojson 要素包含地理坐标 - 纬度和经度。

要在 d3 或任何其他框架或程序中投影地理特征,必须应用投影将三维坐标中的地理坐标 space 转换为适合显示在二维 svg 上的平面笛卡尔坐标或canvas网格。

您没有对特征应用必要的投影。当您使用 geoPath 时,您通常需要指定一个 geoProjection:

var path = d3.geoPath().projection(d3.geoProjection)

但是,您没有使用投影,因此 d3 默认为空投影。对于你topojson/geojson中的每个坐标,输入的x和y值作为像素坐标,没有transform/translate/scaling完成。

由于您的要素位于西半球,因此 x(经度)值为负。具有负 x 值的像素位于屏幕左侧。

南半球的值为负值,因此它们也会被绘制出屏幕。在这种情况下,在 svg 或 canvas 上方 - 因为 y 值从屏幕顶部的零开始,并随着向下移动而增加。

最后,如果您在地球的东北象限中有任何要素,它们将显示为它们的坐标为正(假设您的 svg 为 90 像素高和 180 像素宽)。但是,它们会倒置,因为 y 值随着移动 "up" 一张地图而增加,但在 svg/canvas 坐标 space 中它们随着移动 "up" 一张地图而减小。

解决问题

您将需要使用投影。最基本的设置可能是使用像墨卡托这样的简单投影,并使用 fitSize 或 fitExtent 自动缩放和居中要显示的功能。为此,您可以使用类似的东西:

var projection = d3.geoMercator();
var path = d3.geoPath().projection(projection);

// once topojson is loaded:
projection.fitSize([width,height],geojson object);

你是怎么得到geojson的?您已经是:

topojson.feature(aisp, aisp.objects.convert)  // convert topojson to geojson.

您需要传递 geojson 对象,而不是它包含的特征数组,因此我们为什么不将 topojson.feature(aisp, aisp.objects.convert).features 与 .fitSize 一起使用。

FitSize 获取宽度和高度并设置投影的比例并转换为适当的值。 FitExtent 用两个点标记特征边界框的左上角和右下角:projection.fitExtent([[x1,y1],[x2,y2]],geojson);

这种方法不设置更复杂的投影参数,例如旋转或圆锥投影,例如阿尔伯斯、平行线,但在许多情况下就足够了。

示例

Here's 一个你的 fitSize 地图示例(我更改了文件名)。