D3.js - 由于投影错误,在地图上绘制点失败
D3.js - Drawing points on map fails due to wrong projection
我目前正在做一个项目,该项目使用 D3.js.
根据 JSON 文件中的地理数据绘制地图
现在我有另一个包含位置的 JSON 文件,我想将这些位置绘制为地图上的点。
我这样做如下:
svg.selectAll('circle')
.data(redCrossLocations.features)
.enter()
.append('circle')
.attr('cx', function(d) {
var x = d.geometry.x
var y = d.geometry.y
return projection([x.toString(), y.toString()])[0]
})
.attr('cy', function(d) {
var x = d.geometry.x
var y = d.geometry.y
return projection([x.toString(), y.toString()])[1]
})
.attr('r', 10)
.attr('text',function(d) {
return d.attributes.DienstSt
})
.style('fill', 'yellow')
但是当我查看带有 Firebug 的圆圈时,这些圆圈的 cx
和 cy
值非常高,根本不适合地图坐标。因此,这些点未定位且在地图上不可见。
这是用 Firebug 调查 html 时的样子:
<svg id="chart-330a29bc-10a6-422f-b7a4-b79213e63a0f" viewBox="0 0 1700 850">
<g transform="">
<svg width="425" height="425">
<rect width="850" height="850" style="stroke: black; fill: none;">
<path d="M406.7479670817884,199.90340867304621L407.06008919224314,199.57933852526912L407.7100188308723,198.8568991193315L408.1015443102342,198.34893921523326L408.14613950961393,198.29087863446694L408.68509042962614,197.6062181990019L408.79620200385034,197.4452283080136L409.08485295673836,197.0327872268681L409.31646456821454,196.6144688478962L409.62291817269215,195.96797874850017L409.78145919928556,195.49428734522007L409.912011977608,194.9738064907906L409.986809685407,194.39973754590756L410.0058080374765,193.7122278...00837217,205.1538807821671L401.9104729365481,204.65327053784495L402.62461611946765,203.79979531967183L403.17787116003547,203.1799602826395L403.20639083074093,203.1993550356201L403.308689649577,203.08799997778988L403.42697542668066,202.95942665539405L403.5903878256004,202.78322302641755L405.8101836239257,200.80217267343687L405.8688615178462,200.74629337105216L405.89149125655877,200.7271611214237L405.95836191302715,200.66712537209605L406.1133158381808,200.52594198620864L406.3833670058257,200.28190447086672Z" style="fill: red; stroke-width: 1; stroke: black;">
<circle cx="189993884.995462" cy="-29942.633406634715" r="10" text="Salzburg Stadt" style="fill: yellow;">
<circle cx="186702567.5263016" cy="6214.613271863014" r="10" text="Lamprechtshausen" style="fill: yellow;">
<circle cx="191422937.49531066" cy="NaN" r="10" text="Mattsee" style="fill: yellow;">
<circle cx="196518708.70128453" cy="NaN" r="10" text="Straßwalchen" style="fill: yellow;">
希望对大家有所帮助,附上地图生成代码:
const svg = d3.select(`#${chartId}`)
svg
.append("svg")
.attr("width", width / 2).attr("height", height / 2)
var center = d3.geo.centroid(salzburg)
var scale = 1;
var offset = [width / 2, height / 2];
var projection =
d3.geo.mercator()
.scale(scale)
.center(center)
.translate(offset);
// create the path
var path = d3.geo.path().projection(projection);
// using the path determine the bounds of the current map and use
// these to determine better values for the scale and translation
var bounds = path.bounds(salzburg);
var hscale = scale * width / (bounds[1][0] - bounds[0][0]);
var vscale = scale * height / (bounds[1][1] - bounds[0][1]);
var scale = (hscale < vscale) ? hscale : vscale;
var offset = [width - (bounds[0][0] + bounds[1][0]) / 2.1,
height - (bounds[0][1] + bounds[1][1]) / 2.4];
projection = d3.geo.mercator().center(center)
.scale(scale).translate(offset);
path = path.projection(projection);
svg.append("rect").attr('width', width).attr('height', height)
.style('stroke', 'black').style('fill', 'none');
svg.selectAll("path").data(salzburg.features).enter().append("path")
.attr("d", path)
.style("fill", "red")
.style("stroke-width", "1")
.style("stroke", "black")
redCrossLocations
看起来像这样:
"features": [{
"attributes": {
"OBJECTID": 1,
"DienstSt": "Salzburg Stadt",
"Art": "Bezirksstelle",
"Ort": "Salzburg",
"Strasse": "Sterneckstraße",
"Hnr": "32",
"Bezirk": "Stadt Salzburg und Flachgau",
"Typ": null
},
"geometry": {
"x": 429395.48199999984,
"y": 296716.59500000067
}
}, {
"attributes": {
"OBJECTID": 2,
"DienstSt": "Lamprechtshausen",
"Art": "Ortsstelle",
"Ort": "Lamprechtshausen",
"Strasse": "Schulstraße",
"Hnr": "1",
"Bezirk": "Stadt Salzburg und Flachgau",
"Typ": null
},
"geometry": {
"x": 421963.38900000043,
"y": 317197.9179999996
}
},
...
有谁知道,为什么我得到这个绝对错误的点坐标?
首先,当搜索从您的 redCrossLocations
获取的详细信息时,它似乎是从这个 source 下载的。检查完整文件会发现您的地理输入数据存在两个问题:
您的 JSON 似乎是 Esri 的 JSON format,而 D3 期望 GeoJSON 作为其输入。因为您的 JSON 与 GeoJSON 不兼容,您必须转换它。
该文件有一个定义 "spatialReference":{"wkid":31258,"latestWkid":31258}
,它指的是投影坐标系 MGI_Austria_GK_M31 (EPSG::31258) which is also not the right one to use when it comes to D3. To make it usable for D3 you need to transform it to the geographic coodinate system WGS 84 (EPSG::4326)。
幸运的是,您可以使用 ogr2ogr 工具一次性完成两种转换 运行:
ogr2ogr -f "GeoJSON" -t_srs "EPSG::4326" "RotesKreuz_Dienststellen.json"
此外,还有一个选项 -s_srs
可用,用于明确指定源坐标系 (-s_srs "EPSG:31258"
),这在您的情况下不需要,因为它将从输入文件派生。
还有一个ogr2ogr web client可以在线进行转换和转换。使用该表格,您可以上传文件并将 "Target SRS" 指定为 EPSG:4326
,这将转换坐标系并将其转换为 GeoJSON.
我目前正在做一个项目,该项目使用 D3.js.
根据 JSON 文件中的地理数据绘制地图现在我有另一个包含位置的 JSON 文件,我想将这些位置绘制为地图上的点。
我这样做如下:
svg.selectAll('circle')
.data(redCrossLocations.features)
.enter()
.append('circle')
.attr('cx', function(d) {
var x = d.geometry.x
var y = d.geometry.y
return projection([x.toString(), y.toString()])[0]
})
.attr('cy', function(d) {
var x = d.geometry.x
var y = d.geometry.y
return projection([x.toString(), y.toString()])[1]
})
.attr('r', 10)
.attr('text',function(d) {
return d.attributes.DienstSt
})
.style('fill', 'yellow')
但是当我查看带有 Firebug 的圆圈时,这些圆圈的 cx
和 cy
值非常高,根本不适合地图坐标。因此,这些点未定位且在地图上不可见。
这是用 Firebug 调查 html 时的样子:
<svg id="chart-330a29bc-10a6-422f-b7a4-b79213e63a0f" viewBox="0 0 1700 850">
<g transform="">
<svg width="425" height="425">
<rect width="850" height="850" style="stroke: black; fill: none;">
<path d="M406.7479670817884,199.90340867304621L407.06008919224314,199.57933852526912L407.7100188308723,198.8568991193315L408.1015443102342,198.34893921523326L408.14613950961393,198.29087863446694L408.68509042962614,197.6062181990019L408.79620200385034,197.4452283080136L409.08485295673836,197.0327872268681L409.31646456821454,196.6144688478962L409.62291817269215,195.96797874850017L409.78145919928556,195.49428734522007L409.912011977608,194.9738064907906L409.986809685407,194.39973754590756L410.0058080374765,193.7122278...00837217,205.1538807821671L401.9104729365481,204.65327053784495L402.62461611946765,203.79979531967183L403.17787116003547,203.1799602826395L403.20639083074093,203.1993550356201L403.308689649577,203.08799997778988L403.42697542668066,202.95942665539405L403.5903878256004,202.78322302641755L405.8101836239257,200.80217267343687L405.8688615178462,200.74629337105216L405.89149125655877,200.7271611214237L405.95836191302715,200.66712537209605L406.1133158381808,200.52594198620864L406.3833670058257,200.28190447086672Z" style="fill: red; stroke-width: 1; stroke: black;">
<circle cx="189993884.995462" cy="-29942.633406634715" r="10" text="Salzburg Stadt" style="fill: yellow;">
<circle cx="186702567.5263016" cy="6214.613271863014" r="10" text="Lamprechtshausen" style="fill: yellow;">
<circle cx="191422937.49531066" cy="NaN" r="10" text="Mattsee" style="fill: yellow;">
<circle cx="196518708.70128453" cy="NaN" r="10" text="Straßwalchen" style="fill: yellow;">
希望对大家有所帮助,附上地图生成代码:
const svg = d3.select(`#${chartId}`)
svg
.append("svg")
.attr("width", width / 2).attr("height", height / 2)
var center = d3.geo.centroid(salzburg)
var scale = 1;
var offset = [width / 2, height / 2];
var projection =
d3.geo.mercator()
.scale(scale)
.center(center)
.translate(offset);
// create the path
var path = d3.geo.path().projection(projection);
// using the path determine the bounds of the current map and use
// these to determine better values for the scale and translation
var bounds = path.bounds(salzburg);
var hscale = scale * width / (bounds[1][0] - bounds[0][0]);
var vscale = scale * height / (bounds[1][1] - bounds[0][1]);
var scale = (hscale < vscale) ? hscale : vscale;
var offset = [width - (bounds[0][0] + bounds[1][0]) / 2.1,
height - (bounds[0][1] + bounds[1][1]) / 2.4];
projection = d3.geo.mercator().center(center)
.scale(scale).translate(offset);
path = path.projection(projection);
svg.append("rect").attr('width', width).attr('height', height)
.style('stroke', 'black').style('fill', 'none');
svg.selectAll("path").data(salzburg.features).enter().append("path")
.attr("d", path)
.style("fill", "red")
.style("stroke-width", "1")
.style("stroke", "black")
redCrossLocations
看起来像这样:
"features": [{
"attributes": {
"OBJECTID": 1,
"DienstSt": "Salzburg Stadt",
"Art": "Bezirksstelle",
"Ort": "Salzburg",
"Strasse": "Sterneckstraße",
"Hnr": "32",
"Bezirk": "Stadt Salzburg und Flachgau",
"Typ": null
},
"geometry": {
"x": 429395.48199999984,
"y": 296716.59500000067
}
}, {
"attributes": {
"OBJECTID": 2,
"DienstSt": "Lamprechtshausen",
"Art": "Ortsstelle",
"Ort": "Lamprechtshausen",
"Strasse": "Schulstraße",
"Hnr": "1",
"Bezirk": "Stadt Salzburg und Flachgau",
"Typ": null
},
"geometry": {
"x": 421963.38900000043,
"y": 317197.9179999996
}
},
...
有谁知道,为什么我得到这个绝对错误的点坐标?
首先,当搜索从您的 redCrossLocations
获取的详细信息时,它似乎是从这个 source 下载的。检查完整文件会发现您的地理输入数据存在两个问题:
您的 JSON 似乎是 Esri 的 JSON format,而 D3 期望 GeoJSON 作为其输入。因为您的 JSON 与 GeoJSON 不兼容,您必须转换它。
该文件有一个定义
"spatialReference":{"wkid":31258,"latestWkid":31258}
,它指的是投影坐标系 MGI_Austria_GK_M31 (EPSG::31258) which is also not the right one to use when it comes to D3. To make it usable for D3 you need to transform it to the geographic coodinate system WGS 84 (EPSG::4326)。
幸运的是,您可以使用 ogr2ogr 工具一次性完成两种转换 运行:
ogr2ogr -f "GeoJSON" -t_srs "EPSG::4326" "RotesKreuz_Dienststellen.json"
此外,还有一个选项 -s_srs
可用,用于明确指定源坐标系 (-s_srs "EPSG:31258"
),这在您的情况下不需要,因为它将从输入文件派生。
还有一个ogr2ogr web client可以在线进行转换和转换。使用该表格,您可以上传文件并将 "Target SRS" 指定为 EPSG:4326
,这将转换坐标系并将其转换为 GeoJSON.