D3.js 绘制 geojson 不正确

IT技术 javascript d3.js openstreetmap geojson
2021-02-01 00:14:57

我正在尝试可视化俄罗斯地区。我从拿到的数据在这里,验证在这里,一切都很好-图片

但是当我尝试绘制它时,我只收到一个大的黑色矩形。

var width = 700, height = 400;

var svg = d3.select(".graph").append("svg")
        .attr("viewBox", "0 0 " + (width) + " " + (height))
        .style("max-width", "700px")
        .style("margin", "10px auto");


d3.json("83.json", function (error, mapData) {
    var features = mapData.features;

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

    svg.append("g")
            .attr("class", "region")
            .selectAll("path")
            .data(features)
            .enter()
            .append("path")
            .attr("d", path)
});

示例 - http://ustnv.ru/d3/index.html Geojson 文件 - http://ustnv.ru/d3/83.json

2个回答

问题是坐标的缠绕顺序(请参阅此块)。大多数工具/实用程序/库/验证器并不真正关心缠绕顺序,因为它们将 geoJSON 视为包含笛卡尔坐标。D3 并非如此 - D3 使用椭球数学 - 这样做的好处包括能够轻松穿过反子午线并能够选择倒多边形。

使用椭球坐标的结果是错误的缠绕顺序将创建地球上所有不是您的目标的特征(倒多边形)。您的多边形实际上包含两种缠绕顺序的组合。您可以通过检查 svg 路径来看到这一点:

在此处输入图片说明

这里的一条路径似乎是准确绘制的,而它上面的另一条路径覆盖了整个星球——除了它应该占据的部分(它应该占据的空间被覆盖整个世界的其他路径覆盖)。

这可以很容易修复 - 您只需要重新排序坐标 - 但是由于您的功能包含同一集合中的两个绕组,因此使用诸如turf.js 之类的库来创建正确的新数组会更容易伤口特征:

    var fixed = features.map(function(feature) {
        return turf.rewind(feature,{reverse:true});
    })

请注意反向缠绕顺序 - 通过一个奇怪的怪癖,D3,这可能是最普遍的平台,其中缠绕顺序实际上并不遵循关于缠绕顺序的 geoJSON 规范(RFC 7946),它使用相反的缠绕顺序,请参阅此评论迈克·博斯托克:

我很失望 RFC 7946 将相反的缠绕顺序标准化为 D3、Shapefiles 和 PostGIS。而且我没有看到 D3 改变其行为的简单方法,因为它会破坏 D3 使用的所有现有(球形)GeoJSON。来源

通过倒回每个多边形,我们得到了一个更有用的地图:

在此处输入图片说明

一项改进,但这些投影设置的功能有点小。

通过添加 fitSize 方法来缩放和平移,我们得到了一个更好看的地图(请参阅此处的块):

在此处输入图片说明

你可以从这里倒回你的 geojson:davidb.dev/tools/rewind-geojson-online
2021-03-15 00:14:57
OP 没有绕线的结果,这几乎是屏幕上的蚂蚁,让我想起了这个Bostock 教程第 2 步中的地图,他说“小制图师现在会宣布工作做得很好,然后回家喝啤酒” .. . 哦,我崩溃了!
2021-04-04 00:14:57
就我而言,当我这样做时,d3.select("body").append("svg")已经是休息和喝啤酒的时间了......
2021-04-05 00:14:57
我记得那句台词,欣赏他的幽默感 - 还记得在我最初尝试 d3 时通过该教程工作。但是,一旦您获得了数据并且可以以某种形式显示它,那就是喝啤酒的好时机,通常这已经成功了一半。
2021-04-06 00:14:57
拉了 10 小时的头发后,我找到了这颗宝石,谢谢!
2021-04-07 00:14:57

这是您问题的快速解决方案,投影需要稍作调整,fill:#000默认情况下路径也具有并且stroke: #FFF可以使其更清晰。

var width = 700, height = 400;

var svg = d3.select(".graph").append("svg")
        .attr("viewBox", "0 0 " + (width) + " " + (height))
        .style("max-width", "700px")
        .style("margin", "10px auto");


d3.json("mercator_files/83.json", function (error, mapData) {
    var features = mapData.features;


    var center = d3.geoCentroid(mapData);
    //arbitrary
    var scale  = 7000;
    var offset = [width/2, height/2];
    var projection = d3.geoMercator().scale(scale).center(center)
      .translate(offset);

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

    svg.append("g")
            .attr("class", "region")
            .selectAll("path")
            .data(features)
            .enter()
            .append("path")
            .attr("d", path)
});
虽然路径样式和投影需要调整,但我看不出这是如何解决核心问题的:特征是倒置的,因此覆盖了整个地图平面。使用您的代码,我发现这一点,并非所有功能都可见(所有功能都已绘制)并且路径仍然超出了 svg 的范围(这就是为什么fitSize()/fitExtent()无法使用这些功能,这也可能导致不稳定的行为d3.geoCentroid()
2021-04-03 00:14:57