javascript - OSM API 方式节点排序不正确
问题描述
所以我的目标是能够从 OSM 中提取给定的 Way 以显示在 Leaflet 地图上。但是,当我尝试使用给定的方式时,响应中的节点似乎没有正确排序。
import axios from 'axios'
import xml2js from 'xml2js'
let parser = new xml2js.Parser()
export default {
async getStpPolygon () {
let xml = await axios.get('https://www.openstreetmap.org/api/0.6/way/39394541/full')
return parseNodes(xml)
},
async getMplsPolygon () {
let xml = await axios.get('https://www.openstreetmap.org/api/0.6/way/93481561/full')
return parseNodes(xml)
}
}
async function parseNodes (xml) {
return new Promise((resolve, reject) => {
parser.parseString(xml.data, (err, data) => {
if (err) reject(err)
let output = data.osm.node.map((node) => {
return [
parseFloat(node.$.lat),
parseFloat(node.$.lon)
]
})
resolve(output)
})
})
}
这是官方 OSM 地图上显示方式 的示例...
提前感谢您的帮助!
解决方案
下面是 XML 的样子:
<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="CGImap 0.6.1 (18903 thorn-01.openstreetmap.org)" copyright="OpenStreetMap and contributors" attribution="http://www.openstreetmap.org/copyright" license="http://opendatacommons.org/licenses/odbl/1-0/">
<node id="1083701880" visible="true" version="1" changeset="6873749" timestamp="2011-01-05T16:51:40Z" user="neuhausr" uid="16591" lat="44.9751170" lon="-93.2758411"/>
<node id="1083701882" visible="true" version="1" changeset="6873749" timestamp="2011-01-05T16:51:40Z" user="neuhausr" uid="16591" lat="44.9746502" lon="-93.2772842"/>
<node id="1083701938" visible="true" version="1" changeset="6873749" timestamp="2011-01-05T16:51:41Z" user="neuhausr" uid="16591" lat="44.9727679" lon="-93.2778367"/>
<node id="1083701987" visible="true" version="1" changeset="6873749" timestamp="2011-01-05T16:51:42Z" user="neuhausr" uid="16591" lat="44.9730222" lon="-93.2787594"/>
<node id="1083701993" visible="true" version="1" changeset="6873749" timestamp="2011-01-05T16:51:42Z" user="neuhausr" uid="16591" lat="44.9737736" lon="-93.2793709"/>
<node id="1083702026" visible="true" version="1" changeset="6873749" timestamp="2011-01-05T16:51:43Z" user="neuhausr" uid="16591" lat="44.9754130" lon="-93.2765707"/>
<way id="93481561" visible="true" version="1" changeset="6873749" timestamp="2011-01-05T16:51:43Z" user="neuhausr" uid="16591">
<nd ref="1083701993"/>
<nd ref="1083701987"/>
<nd ref="1083701938"/>
<nd ref="1083701880"/>
<nd ref="1083702026"/>
<nd ref="1083701882"/>
<nd ref="1083701993"/>
<tag k="amenity" v="university"/>
<tag k="name" v="University of St. Thomas"/>
</way>
</osm>
请注意, OSM XML 格式中描述了两种类型的信息:
- 节点列表
节点是 OpenStreetMap 数据模型中的核心元素之一。它由空间中的单个点组成,由其纬度、经度和节点 ID 定义。
- 一种公开引用节点的有序
nd
标签列表的方法。
一种方式是节点的有序列表[...]
因此,要以正确的顺序获取坐标,您必须将解析函数修改为:
async function parseNodes (xml) {
return new Promise((resolve, reject) => {
parser.parseString(xml.data, (err, data) => {
if (err) reject(err)
//map node ids to their coordinates
const refs = {};
data.osm.node.forEach((node) => {
const attrs = node.$;
refs[attrs.id] = [+attrs.lat, +attrs.lon];
});
// return the coordinates in the correct order
const output = data.osm.way.nd.map((nd) => {
const id = nd.$.ref;
return refs[id];
});
resolve(output)
})
})
}
和一个演示
async function getStpPolygon () {
const resp = await axios.get('https://www.openstreetmap.org/api/0.6/way/93481561/full')
const json = xml2js(resp.data, {compact: true});
const refs = {};
json.osm.node.forEach((node) => {
const attrs = node._attributes;
refs[attrs.id] = [+attrs.lat, +attrs.lon];
});
return json.osm.way.nd.map((nd) => {
const id = nd._attributes.ref;
return refs[id];
});
};
var map = L.map('map').setView([44.97386, -93.27569], 15);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
getStpPolygon().then((points) => {
L.polyline(points).addTo(map);
});
#map { width: 100%; height:200px }
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.4.0/dist/leaflet.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/xml-js@1.6.11/dist/xml-js.min.js"></script>
<script src="https://unpkg.com/leaflet@1.4.0/dist/leaflet.js"></script>
<div id="map"></div>
推荐阅读
- javascript - 使用 javascript 删除 html 元素
- python-3.x - Django - 选择 [列] AS
- python - unittest mock.patch 仅一次
- vega-lite - 如何在 Vega Lite 中的两个连接图上对齐 x 轴刻度
- beautifulsoup - 如何使用beautifulsoup从html中下拉大tbody
- html - 在旁边元素中制作导航
- excel - 如何创建具有重复排名号的排名列?(Excel)
- java - Proguard - java.lang.IllegalArgumentException:找不到常见的超类
- python - Python tempfile.mkstemp(): AttributeError: 'function' object has no attribute 'mkstemp'
- sql - 带条件的 Oracle SQL 合并语句