首页 > 解决方案 > 使用 d3 库从 geoJSON 查询和图像中绘制 svg 点

问题描述

我可以绘制图像地图并且可以检索几何路径,但是尽管 geoData 链接正确,但它并未在地图中绘制任何几何图形。从堆栈和其他地方看到一些示例,示例与此类似。

知道为什么没有读取数据(我假设问题在于正在检索的数据)?

提前致谢

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<body>
    <div id="map" style="position:absolute; width:400px; height:600px; overflow:hidden; border: 1px solid red;">
        <img
            src="https://sig.cm-figfoz.pt/arcgis/rest/services/Internet/MunisigWeb_DadosContexto/MapServer/export?dpi=96&transparent=true&format=png8&layers=show:1,2,4,7,8,12,13&bbox=-58842.91417500004,43056.64792531277,-58667.48812500015,43317.59417468761&bboxSR=3763&imageSR=3763&size=400,595&f=image">
    </div>
    <svg overflow="hidden" width="400" height="600" id="map_gc"
        style="touch-action: none; will-change: transform; overflow: visible; position: absolute; transform: translate3d(0x, 0px, 0px);">
    </svg>
    <script>
        var width = 400;
        var height = 600;

        var chosenProjection = d3.geoMercator()
            .scale(0)
            .translate([0, 0])

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

        var OutputJSON = "https://sig.cm-figfoz.pt/arcgis/rest/services/Internet/MunisigWeb_DadosContexto/MapServer/12/query?where=NOMERUA+LIKE+%27%25Beco+da+F%C3%A9%25%27+AND+LUG11DESIG+LIKE+%27%25Franco%25%27&text=&objectIds=&time=&geometry=&geometryType=esriGeometryPolygon&inSR=&spatialRel=esriSpatialRelIntersects&relationParam=&outFields=&returnGeometry=true&returnTrueCurves=false&maxAllowableOffset=&geometryPrecision=&outSR=&returnIdsOnly=false&returnCountOnly=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&returnZ=false&returnM=false&gdbVersion=&returnDistinctValues=false&resultOffset=&resultRecordCount=&queryByDistance=&returnExtentsOnly=false&datumTransformation=&parameterValues=&rangeValues=&f=pjson"

        d3.json(OutputJSON, function (error, data) {

            d3.select("svg").append("path")
                .attr("d", path(data));
        });
    </script>
</body>

标签: javascriptd3.jsmap-projections

解决方案


从 d3v5 开始,d3.json 返回一个承诺。您需要使用格式d3.json("url").then(function(data) {...而不是d3.json("url", function(data) { ...)

此外,您的数据实际上不是 geojson。ESRI 有自己的 json 格式,这与geojson非常不同。似乎 ESRI 最近在其产品中内置了更多 geojson 支持,但也有很多选项可以将 shapefile 转换为 geojson(与其他格式相比,ESRI 的 json 格式相对较少)。有关在线 shapefile → geojson 转换工具,请参见mapshaper 。无效的 geojson 不会对 D3 产生错误,它只是不会导致 d3.geoPath 返回任何路径数据。所以。要解决这个问题,您需要使用有效的 geojson 数据源。

修复上述两点后,您将成功加载数据并将路径附加到 SVG。

除了,这将导致您的下一个问题:我的功能在哪里?以上两点可能会解决您最紧迫的问题,但可能会导致一个新问题,我将简要介绍一下:

我的功能在哪里?

您没有在图像和“geojson”之间对齐坐标。图像有一个以像素为单位的坐标系:左上角的像素位于 [0,0] 处,右下角的像素位于 [400,595] 处。您的 json 坐标绝对超出此范围,例如[-58696.7258,43252.2659].

看来您可能已经通过使用 D3 投影预料到了这一点。虽然这是一个单独的问题,但您已将比例值设置为 0。比例值确定地图的宽度:默认值约为 152,这意味着单个弧度(经度)应延伸到 152 个像素。零值意味着单个弧度应该完全不跨越任何像素,这意味着该特征无论如何都不可见。

您的“geojson”数据被投影,因为它不包含三维地球上的经纬度对。相反,它包含二维曲面上的笛卡尔点。D3 地理预测采用前者。因此,如果我们想使用这种类型的投影,我们可以“取消投影”数据,以便它使用 WGS84 坐标。在此之后,我们需要创建一个与图像匹配的投影。

或者,我们可以对数据应用变换,以便变换后的数据与图像占据相同的坐标空间。

选项 1:取消投影数据:

如果

  • 我们知道geojson使用什么坐标系
  • 我们知道图像的地理范围
  • 我们知道用于创建图像的投影类型/坐标系

我们可以取消投影数据并将其投影以匹配图像。

对于未投影的数据,我们可以将带有 WGS84 坐标的 geojson 传递给 d3.geoPath - 但是,这不是图像的坐标系(因为 [400,595] 不是有效的长/纬度对)。我们需要匹配两个坐标系。

然后,我们模拟用于创建图像的投影,通过遵循这样的过程d3-geoProjection 匹配到某个任意投影。(另见

由于图像源的投影很可能不在以像素为基本单位的坐标系中,因此我们需要以度为单位获取其边界框,以正确缩放投影的 geojson。没有这个,我们就无法知道[0,0]对应的地理点像素。

选项 2:转换数据

如果

  • image 和 geojson 都使用相同的投影
  • 具有相同的程度

然后我们可以使用变换来对齐两者。我们可以通过使用d3.geoIdentity()which 包含一个名为 的方法来做到这一点fitExtent([[left,top],[right,bottom]],geojsonObject)

由于图像的坐标以像素为单位,我们需要将 geojson 的坐标压缩/拉伸到与图像相同的像素范围,fitExtent 就是这样做的(上/左/下/右值以像素为单位)。如果图像锚定在 [0,0],那么我们将使用:d3.geoIdentity().fitExtent([[0,0],[400,595]],geojsonObject)

我们可能需要在 y 轴上镜像 geojson,因为地理惯例通常会在向北移动时增加 y 值,而 SVG 在向下移动屏幕时会增加 y 值,我们可以使用 identity.reflectY() 来实现这一点。

如果范围不同——我们仍然可以使用 d3.geoTransform 创建一个变换函数,只是会变得更复杂一些。


无论哪种方式,只有使用附加信息,我们才能尝试对齐两个不同的坐标系:像素与任意投影坐标系。如果您需要,一个新问题应该包含此信息以提供明确的答案。


推荐阅读