使用 d3 库从 geoJSON 查询和图像绘制 svg 点
Draw svg points from geoJSON query and image using d3 library
我可以绘制图像地图并且可以检索几何路径,但是尽管 geoData link 是正确的,但它没有在地图中绘制任何几何图形。
从 stack 和其他地方看到了一些例子,这些例子与这个相似。
知道为什么数据没有被读取吗(我假设问题在于正在检索的数据)?
提前致谢
<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=¶meterValues=&rangeValues=&f=pjson"
d3.json(OutputJSON, function (error, data) {
d3.select("svg").append("path")
.attr("d", path(data));
});
</script>
</body>
从 d3v5 开始,d3.json returns 一个承诺。您需要使用格式 d3.json("url").then(function(data) {...
而不是 d3.json("url", function(data) { ...)
此外,您的数据实际上不是 geojson。 ESRI 有自己的 json 格式,非常 而不是 geojson。似乎 ESRI 最近在其产品中内置了更多的 geojson 支持,但也有很多选项可以将 shapefile 转换为 geojson(与其他格式相比,ESRI 的 json 格式相对少见格式)。请参阅 mapshaper 获取在线 shapefile → geojson 转换工具。无效的 geojson 不会生成 D3 错误,它只是不会导致 d3.geoPath 返回任何路径数据。所以。要解决此问题,您需要使用有效的 geojson 数据源。
解决以上两点后,您将成功加载数据并将路径附加到您的 SVG。
除此之外,这会引出您的下一个问题:我的功能在哪里?以上两点可能会解决您最紧迫的问题,但它可能会导致一个新问题,我将简要介绍一下:
我的特色在哪里?
您没有在图像和“geojson”之间对齐坐标。该图像具有以像素为单位的坐标系:左上角的像素位于 [0,0],右下角的像素位于 [400,595]。您的 json 坐标明显超出此范围,例如 [-58696.7258,43252.2659]
.
看来您可能已经通过使用 D3 投影预料到了这一点。 虽然这是一个单独的问题,但您已将比例值设置为 0。比例值决定了地图的宽度:默认值约为 152,这意味着单个弧度(经度)应该拉伸 152 个像素。零值意味着单个弧度不应跨越任何像素,这意味着该特征无论如何都不可见。
您的“geojson”数据是投影的,因为它不包含三维地球上的经纬度对。相反,它包含二维表面上的笛卡尔点。 D3 地理投影采用前者。所以,如果我们想使用那种类型的投影,我们可以“取消投影”数据,以便它使用 WGS84 坐标。
在此之后我们需要创建一个与图像相匹配的投影。
或者,我们可以对数据应用变换,使变换后的数据占据与图像相同的坐标 space。
选项 1:取消投影数据:
如果
- 我们知道 geojson 使用什么坐标系
- 我们知道图片的地理范围
- 我们知道用于创建图像的投影type/coordinate系统
我们可以取消投影数据并将其投影以匹配图像。
对于未投影的数据,我们可以将带有 WGS84 坐标的 geojson 传递给 d3.geoPath - 然而,这不是图像的坐标系(因为 [400,595] 不是有效的 long/lat 对)。我们需要匹配两个坐标系。
然后我们通过 to match a d3-geoProjection to some arbitrary projection. (see ).
等过程模拟用于创建图像的投影
由于图像源的投影很可能不在以像素为基本单位的坐标系中,我们需要获取其边界框(以度为单位)以正确缩放投影的地理区域json.没有这个我们就不知道像素点[0,0]对应的是什么地理点。
选项 2:转换数据
如果:
- 图像和地理json使用相同的投影
- 程度相同
然后我们可以使用变换来对齐两者。我们可以通过使用 d3.geoIdentity()
来做到这一点,其中包含一个名为 fitExtent([[left,top],[right,bottom]],geojsonObject)
.
的方法
由于图像的坐标以像素为单位,我们需要 compress/stretch geojson 的坐标与图像的像素范围相同,fitExtent 就是这样做的(top/left/bottom/right值以像素为单位)。如果图像锚定在 [0,0] 那么我们将使用:d3.geoIdentity().fitExtent([[0,0],[400,595]],geojsonObject)
我们可能需要在 y 轴上镜像 geojson,因为地理惯例通常在向北移动时增加 y 值,而 SVG 在向下移动屏幕时增加 y 值,我们可以使用 identity.reflectY() 来实现这一点。
如果范围不同 - 我们仍然可以使用 d3.geoTransform 创建转换函数,只是会变得有点复杂。
无论哪种方式,只有通过附加信息,我们才能尝试对齐两个不同的坐标系:像素与任意投影坐标系。如果您需要,一个新问题应该包含此信息以提供明确的答案。
我可以绘制图像地图并且可以检索几何路径,但是尽管 geoData link 是正确的,但它没有在地图中绘制任何几何图形。 从 stack 和其他地方看到了一些例子,这些例子与这个相似。
知道为什么数据没有被读取吗(我假设问题在于正在检索的数据)?
提前致谢
<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=¶meterValues=&rangeValues=&f=pjson"
d3.json(OutputJSON, function (error, data) {
d3.select("svg").append("path")
.attr("d", path(data));
});
</script>
</body>
从 d3v5 开始,d3.json returns 一个承诺。您需要使用格式 d3.json("url").then(function(data) {...
而不是 d3.json("url", function(data) { ...)
此外,您的数据实际上不是 geojson。 ESRI 有自己的 json 格式,非常 而不是 geojson。似乎 ESRI 最近在其产品中内置了更多的 geojson 支持,但也有很多选项可以将 shapefile 转换为 geojson(与其他格式相比,ESRI 的 json 格式相对少见格式)。请参阅 mapshaper 获取在线 shapefile → geojson 转换工具。无效的 geojson 不会生成 D3 错误,它只是不会导致 d3.geoPath 返回任何路径数据。所以。要解决此问题,您需要使用有效的 geojson 数据源。
解决以上两点后,您将成功加载数据并将路径附加到您的 SVG。
除此之外,这会引出您的下一个问题:我的功能在哪里?以上两点可能会解决您最紧迫的问题,但它可能会导致一个新问题,我将简要介绍一下:
我的特色在哪里?
您没有在图像和“geojson”之间对齐坐标。该图像具有以像素为单位的坐标系:左上角的像素位于 [0,0],右下角的像素位于 [400,595]。您的 json 坐标明显超出此范围,例如 [-58696.7258,43252.2659]
.
看来您可能已经通过使用 D3 投影预料到了这一点。 虽然这是一个单独的问题,但您已将比例值设置为 0。比例值决定了地图的宽度:默认值约为 152,这意味着单个弧度(经度)应该拉伸 152 个像素。零值意味着单个弧度不应跨越任何像素,这意味着该特征无论如何都不可见。
您的“geojson”数据是投影的,因为它不包含三维地球上的经纬度对。相反,它包含二维表面上的笛卡尔点。 D3 地理投影采用前者。所以,如果我们想使用那种类型的投影,我们可以“取消投影”数据,以便它使用 WGS84 坐标。 在此之后我们需要创建一个与图像相匹配的投影。
或者,我们可以对数据应用变换,使变换后的数据占据与图像相同的坐标 space。
选项 1:取消投影数据:
如果
- 我们知道 geojson 使用什么坐标系
- 我们知道图片的地理范围
- 我们知道用于创建图像的投影type/coordinate系统
我们可以取消投影数据并将其投影以匹配图像。
对于未投影的数据,我们可以将带有 WGS84 坐标的 geojson 传递给 d3.geoPath - 然而,这不是图像的坐标系(因为 [400,595] 不是有效的 long/lat 对)。我们需要匹配两个坐标系。
然后我们通过
由于图像源的投影很可能不在以像素为基本单位的坐标系中,我们需要获取其边界框(以度为单位)以正确缩放投影的地理区域json.没有这个我们就不知道像素点[0,0]对应的是什么地理点。
选项 2:转换数据
如果:
- 图像和地理json使用相同的投影
- 程度相同
然后我们可以使用变换来对齐两者。我们可以通过使用 d3.geoIdentity()
来做到这一点,其中包含一个名为 fitExtent([[left,top],[right,bottom]],geojsonObject)
.
由于图像的坐标以像素为单位,我们需要 compress/stretch geojson 的坐标与图像的像素范围相同,fitExtent 就是这样做的(top/left/bottom/right值以像素为单位)。如果图像锚定在 [0,0] 那么我们将使用:d3.geoIdentity().fitExtent([[0,0],[400,595]],geojsonObject)
我们可能需要在 y 轴上镜像 geojson,因为地理惯例通常在向北移动时增加 y 值,而 SVG 在向下移动屏幕时增加 y 值,我们可以使用 identity.reflectY() 来实现这一点。
如果范围不同 - 我们仍然可以使用 d3.geoTransform 创建转换函数,只是会变得有点复杂。
无论哪种方式,只有通过附加信息,我们才能尝试对齐两个不同的坐标系:像素与任意投影坐标系。如果您需要,一个新问题应该包含此信息以提供明确的答案。