改编规范示例时,我的 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 地图示例(我更改了文件名)。
我开始研究 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 地图示例(我更改了文件名)。