D3js 从 GeoJSON 生成路径

D3js generate paths from GeoJSON

我是 D3js 和 GeoJSON 的新手,想知道如何从 GeoJSON 文件渲染我的多边形。

我的 GeoJSON 文件来自 ESRI Shapefile,没有 prj 文件,所以我没有关于投影的信息,但它绝对不是 WGS 84。

使用第三方工具,我可以将 GeoJSON 转换为 SVG,格式如下所示: (我有超过 65000 条路径。)

<path style="fill=blue;stroke-width:0.035;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 297.378906 316.671875 L 298.539063 316.628906 " transform="matrix(1,0,0,-1,0,842)"/>

当我打开这个 svg 文件时,它看起来像这样,这是正确的:

所以现在我想直接从 GeoJSON 文件中使用 d3js 生成这些路径,但它不知何故搞砸了:

到目前为止,这是我的代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

</style>

<body>
    <script src="https://d3js.org/d3.v5.min.js" charset="utf-8"></script>
    <script src="https://d3js.org/topojson.v1.min.js"></script>

    <script>
        var width = 960,
            height = 1160;

        var svgContainer = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height)
            .style("border", "2px solid steelblue");


        const xhr = new XMLHttpRequest();
        xhr.open('GET', 'poly.json');
        xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.responseType = 'json';
        xhr.onload = function () {
            if (xhr.status !== 200) return

            var projection = d3.geoAlbers()
                .scale(1)
                .translate([0, 0]);

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

            var b = path.bounds(xhr.response),
                s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
                t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];

            projection
                .scale(s)
                .translate(t);

            svgContainer.append("rect")
                .attr('width', width)
                .attr('height', height)
                .style('stroke', 'black')
                .style('fill', 'orange');

                svgContainer.selectAll("path").data(xhr.response.features).enter().append("path")
                    .attr("d", path)
                    .style("fill", "red")
                    .style("stroke-width", "1")
                    .style("stroke", "blue")    
        };
        xhr.send();
    </script>

谁能告诉我如何使用 d3js 生成我的路径,就像第三方工具一样?

编辑:这是我的 GeoJSON 数据: https://jsonblob.com/b6664214-4b12-11e9-bbf0-3d8b9aa005c2

您正在使用投影:d3.geoAlbers(),它采用 latitude/longitude 对并将它们投影到笛卡尔网格。但是,您还注意到您的数据不使用 latitude/longitude 对(省略细节,因此它不使用 WGS84)。所有 d3.geoProjections 都采用球坐标并将它们投影到二维网格,但您的数据已经是笛卡尔坐标,因此我们需要一种不同的方法。

而是使用 d3.geoIdentity(),它的默认形式与空投影相同:值被视为像素值并照此映射。但是,它也允许我们利用一些标准的 d3.geoProjection 方法,例如缩放和平移。

更重要的是,它允许我们访问方法 .fitSize(或 fitExtent),它允许我们平移和缩放恒等变换,以便我们的特征居中并缩放到我们的地图大小。 fitSize 方法采用以像素为单位的宽度和高度、显示特征的区域以及 geojson object(不是特征数组)。

var projection = d3.geoIdentity()
  .fitSize([width,height],geojsonObject)

现在很多投影坐标系的左下角都是[0,0],但是SVG的左上角是[0,0],如果需要的话我们也可以在y轴上翻转:

var projection = d3.geoIdentity()
  .reflectY(true)
  .fitSize([width,height],geojsonObject)

Here's 没有 y 反射的演示(您很可能需要它)

此方法随 d3v4+ 一起提供,让我们避免使用旧的 v3 手动居中和缩放对象的方式:

  var projection = d3.geoAlbers()
      .scale(1)
      .translate([0, 0]);

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

  var b = path.bounds(xhr.response),
  s = .95 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
  t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];

  projection
    .scale(s)
    .translate(t);  

但是,如果您希望用您的特征覆盖其他数据,您需要拥有具有相同投影的数据,或者您需要知道数据的投影是什么,以便您可以重新投影一些或所有数据集的通用格式。如果我不得不猜测,我会说您的投影是 UTM zone 32N(基于字段名称)。通常,如果您有一个数百万的 north/south 值,那么您正在处理 UTM,因为它代表距赤道的米数。如果放置在 UTM 区域 32N,您可能会看到:

我现在很感兴趣,假设我得到了投影,我猜是墓地,因为这些地块很小,1.3m x 3m,而且它们的对齐方式表明不是建筑物,而且它位于什么地方看起来像专用绿地space,其他用途跟周边相比就太密集了

如果这看起来正确,那么您可以将其用作 prj 文件(数据可能不正确,这可能会引起一些偏移:

PROJCS["WGS_1984_UTM_Zone_32N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",9.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]