当我尝试使用经典示例进行适应时,我的topojson无法显示。

3

我开始学习D3,以便创建一个可以按年份过滤的区域地图/热力图。

问题:

我想展示这个topojson文件。我尝试调整Mike Bostock的topojson示例(在此处)来适应我的topojson,但是当我将示例适应我的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有问题,它以这样的方式结束:...[-10,-21],[-6,-22],[-9 - Gerardo Furtado
错误来自于这段代码:aisp.convert - 这是未定义的,你需要使用 aisp.objects.convert(在附加网格时,而不是初始路径)。 (当我查看它时,topojson 检查通过了,但是我相信一旦错误消失,你会有一个不同的问题,“我的要素在哪里?”) - Andrew Reid
@GerardoFurtado,我打开它时,d3加载正常,并在GitHub上显示,最后看到的是:...1.3:CRS84"}}}。我发现GitHub有时会截断长的地理/拓扑JSON文件,原因不明 - 这曾经给我带来了很多烦恼。 - Andrew Reid
1
是的,我尝试了10次,终于看到正确的结果了。可能是我的连接超时了...或者像你说的那样,是GitHub出了问题。 - Gerardo Furtado
@AndrewReid 谢谢!你说得对。现在我正在尝试找出我的功能在哪里。这是一个投影问题吗?我应该编辑帖子还是在这里开一个新问题? - abaporu
显示剩余2条评论
1个回答

5

问题

使用此块作为示例可能存在问题,因为它没有使用投影。该示例使用预投影的topojson,其坐标处于像素坐标空间中 - 它设计为在900 x 600像素窗口上显示,输入文件中的坐标值范围位于[0,0]和[900,600]的边界框内。因此,该示例不使用地理投影。

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

为什么没有绘制任何内容?

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

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

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

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

然而,您没有使用投影,因此d3默认使用空投影。对于您的topojson/geojson中的每个坐标,输入的x和y值被视为像素坐标,不进行任何变换/平移/缩放。

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

南半球的值为负值,因此它们也将在屏幕外绘制。在这种情况下,在svg或画布上方 - 因为y值从屏幕顶部从零开始增加。

最后,如果您在地球的东北象限中有任何要素,则它们将显示为其坐标将是正数(假设您的svg高90像素,宽180像素)。但是,它们将颠倒,因为当一个人在svg/canvas坐标空间中向上移动地图时,y值会减小,而不是增加。

解决方法

您将需要使用投影来解决这个问题。最基本的设置可能是使用简单的投影(例如墨卡托投影),并使用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对象,而不是它包含的要素数组,因此我们不会在.fitSize中使用topojson.feature(aisp, aisp.objects.convert).features

FitSize需要一个宽度和高度,并将投影的比例和平移设置为适当的值。FitExtent取两个点标记要素边界框的左上角和右下角:projection.fitExtent([[x1,y1],[x2,y2]],geojson);

这种方法不设置投影的更复杂参数,如旋转或圆锥投影(例如Albers,平行线),但在许多情况下已足够。

示例

这里有一个使用fitSize的地图示例(我更改了文件名)。


点赞了...现在猜猜这个州和国家是哪个(不用 GitHub 的帮助)。 - Gerardo Furtado
我知道这个国家 - 我也知道你为什么会知道。但是这个州呢?如果我把它与一个城市联系起来而不是一个州,可能就猜不到了。 - Andrew Reid
里约热内卢。该州的名称与城市相同(就像纽约州和纽约市一样 - 但是,与里约不同,纽约的首都不是纽约)。 - Gerardo Furtado
是的,但那些名字是例外。我脑海中唯一可能想到的名字是Espirito Santo,因为Fundao水坝灾难在工作中相当热门。 - Andrew Reid
完美,感谢 @AndrewReid 的解释和Geraldo的跟进 :) - abaporu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接