gpt4 book ai didi

javascript - 为什么 D3 无法正确渲染 TopoJSON?

转载 作者:太空宇宙 更新时间:2023-11-04 15:53:09 25 4
gpt4 key购买 nike

我正在尝试使用 D3.jsTopoJSON 渲染瑞士 map 。底层JSON可以找到here 。首先我尝试关注this tutorial在我无法渲染任何看起来像 map 一样远程的东西之后,我发现 this question on here带有一个工作示例的链接。从我获取当前正在使用的代码的位置:

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<style>
path {
fill: #ccc;
}
</style>
</head>

<body>
<h1>topojson simplified Switzerland</h1>
<script>
var width = window.innerWidth,
height = window.innerHeight;

var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);

var projection = d3.geo.mercator()
.scale(500)
.translate([-900, 0]);

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

d3.json("ch-cantons.json", function(error, topology) {
if (error) throw error;

svg.selectAll("path")
.data(topojson.feature(topology, topology.objects.cantons).features).enter().append("path").attr("d", path);
});
</script>
</body>

</html>

由于 JSON 看起来没问题(在复制/粘贴后正确渲染的一些在线平台上进行了检查)并且只有很少的代码可能会出错,我认为错误出在投影参数中。摆弄了一下无法使其发挥作用。因此,我们将非常感谢任何帮助!

最佳答案

你是对的,错误在于投影。但是,错误取决于您的数据是投影还是未投影(经纬度对)。

未投影的数据

如果您有 WGS84 格式的数据 - 即经纬度对,那么您会遇到以下问题:

使用您的投影,但仅更改数据源,我得到这样的结果(我剃掉了右侧的空海洋):

enter image description here

要正确居中墨卡托,您需要知道感兴趣区域的中心坐标。这通常是相当普遍的,对于瑞士我可能会尝试 47N 8.25E。

一旦你有了这个坐标,你需要把它放在中间。一种方法是绕 x 轴旋转并以 y 为中心:

var projection = d3.geo.mercator()
.scale(3500)
.rotate([-8.25,0])
.center([0,47])
.translate([width/2,height/2])

请注意,x 旋转为负,您正在投影下方旋转地球仪。

另一个选项是在 x 和 y 上旋转,当您接近两极时,这可能是首选选项 - 因为墨卡托畸变在高纬度地区变得不可行。这种方法看起来像:

var projection = d3.geo.mercator()
.scale(4000)
.rotate([-8.25,-47])
.center([0,0])
.translate([width/2,height/2])

再次注意负旋转值。第二种选择需要更高的比例值,因为这种方法本质上将瑞士视为墨卡托投影上的零,零 - 并且沿着赤道的土地面积被最小化。

使用第二个预测,我得到: enter image description here

因此,您必须稍微调整一下比例,但现在您应该能够看到您的数据(假设您的数据是正确的经纬度对)。

预计数据

根据下面的评论(其中包含链接的 json 文件),我们可以看到这是您的问题。

对此有两种可能的解决方案:

  1. 将数据转换为经纬度对
  2. 使用地理变换

选项一是最简单的,您将取消数据投影 - 这需要知道当前的投影。在 GIS 软件中,通常会将其投影为 WGS84,这可以说不是真正的投影,而是基准。获得经纬度对后,您可以按照上述步骤获取未投影的数据。

选项二完全跳过 d3.geoProjection。相反,我们将创建一个转换函数,将投影坐标转换​​为所需的 SVG 坐标。

地理投影如下所示:

function scale (scaleFactor) {
return d3.geo.transform({
point: function(x, y) {
this.stream.point(x * scaleFactor, (y * scaleFactor);
}
});
}

并且像投影一样使用:

var path = d3.geo.path().projection(scale(0.1));

它只是获取已经是笛卡尔坐标的 x,y 坐标流并以指定的方式转换它们。

要平移 map 使其居中,您需要知道中心坐标。您可以使用 path.bounds 找到它:

var bounds = path.bounds(features);
var centerX = (bounds[0][0] + bounds[1][0])/2;
var centerY = (bounds[0][1] + bounds[1][1])/2;

Path.bounds 返回要素的左上角和右下角。这是关键部分,您可以制作自动缩放功能,那里有很多示例,但我喜欢经常手动缩放。如果 map 居中,这很容易。对于您的 map ,您的 geoTransform 可能如下所示:

function scale (scaleFactor,cx,cy,width,height) {
return d3.geo.transform({
point: function(x, y) {
this.stream.point((x-cx) * scaleFactor + width/2, (y-cy) * scaleFactor +height/2);
}
});
}

这里 cxcy 指的是特征的中间,宽度和高度指的是 svg 元素的宽度和高度 - 我们不需要特征聚集在 SVG 点 [0,0]。

总而言之,这给了我们类似的东西(比例因子为 0.002):

enter image description here

这是更新的 JSbin:http://jsbin.com/wolamuzeze/edit?html,output

请记住,比例取决于窗口大小,因为您的宽度/高度与您的情况下的窗口大小相关。最好通过自动设置缩放级别来解决此问题,但如果您有标签(例如),这可能会产生问题。

这个答案也可能有帮助:Scaling d3 v4 map to fit SVG (or at all)

关于javascript - 为什么 D3 无法正确渲染 TopoJSON?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42953285/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com