D3js从GeoJSON生成路径 [英] D3js generate paths from GeoJSON

查看:65
本文介绍了D3js从GeoJSON生成路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm new to D3js and GeoJSON and would like to know how can I can render my polygons from GeoJSON file.

我的GeoJSON文件来自ESRI Shapefile,而没有prj文件,因此我没有有关投影的信息,但绝对不是WGS 84.

My GeoJSON file comes from ESRI Shapefile without prj File, so I have no Information about the projection but its definitely not WGS 84.

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

With an third party tool I can convert my GeoJSON to SVG and the format looks like this: (I have more then 65000 paths.)

<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文件时,它看起来像这样,这是正确的:

When I open this svg file it looks like this, which is correct:

因此,现在我想直接从GeoJSON文件中使用d3js生成这些路径,但是还是有些混乱:

So now I would like to generate these paths with d3js from GeoJSON file directly but it's somehow messed up:

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

This is my Code so far:

<!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生成类似于第三方工具的路径?

Can anyone tell me how I can generate my paths like the third party tool with d3js?

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

Here is my GeoJSON data: https://jsonblob.com/b6664214-4b12-11e9-bbf0-3d8b9aa005c2

推荐答案

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

You are using a projection: d3.geoAlbers() that takes latitude/longitude pairs and projects them to a Cartesian grid. But, you also note that your data does not use latitude/longitude pairs (omitting details, therefore it doesn't use WGS84). All d3.geoProjections take spherical coordinates and project them to two dimensional grids, but your data is Cartesian already, so we need a different approach.

相反,请使用d3.geoIdentity(),其默认格式与空投影相同:将值视为像素值并进行映射.但是,它也允许我们使用一些标准的d3.geoProjection方法,例如缩放和翻译.

Instead, use a d3.geoIdentity(), which in its default form is the same as a null projection: values are treated as pixel values and are mapped as such. But, it also allows us to tap some standard d3.geoProjection methods, such as scale and translate.

更重要的是,它允许我们访问方法.fitSize(或fitExtent),该方法使我们可以转换和缩放标识变换,从而使要素居中并缩放到地图大小. fitSize方法采用以像素为单位的宽度和高度,显示要素的区域以及geojson object (不是要素数组).

More importantly it lets us access the method .fitSize (or fitExtent), which lets us translate and scale the identity transform such that our feature is centered and scaled to our map size. The fitSize method takes a width and height in pixels, the area in which to display the features, and a geojson object (not an array of features).

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

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

Now as many projected coordinate systems have [0,0] in the bottom left, but SVG has [0,0] in the top left, we can also apply a flip on the y axis if necessary:

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

这里是没有y反射的演示(您将需要它很有可能)

Here's a demo without y reflection (you'll need it most likely)

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

This method ships with d3v4+, and lets us avoid the use of the old v3 manual way of centering and scaling objects:

  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区域32N(基于字段名称).通常,如果您拥有以百万为单位的北/南值,则您正在使用UTM,因为它代表距赤道的米.如果放置在UTM区域32N中,您可能正在看:

But, if you wish to overlay other data with your features, you'll need to either have data that has the same projection, or you need to know what the projection of your data is so that you can reproject some or all of the datasets to a common format. If I had to guess, I'd say that your projection is UTM zone 32N (based on field names). Generally if you have a north/south value in the millions, you are dealing with UTM as this represents meters from the equator. If placed with UTM zone 32N, you might be looking at:

现在我很感兴趣,假设我得到了投影,我猜想墓地是小块,只有1.3mx 3m,而且它们的对齐方式建议不是建筑物,并且它的位置看起来像专用绿色空间和其他用途与周围地区相比会太密集

如果看起来正确,则可以将其用作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]]

这篇关于D3js从GeoJSON生成路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆