使用D3.js从Overpass API生成的OSM XML绘制点时遇类型错误
解决D3.js加载OSM XML绘制圆形时的TypeError错误
问题描述
尝试用D3.js读取Overpass API生成的OSM XML文件,绘制对应node元素的圆形时,触发错误:TypeError: null is not an object (evaluating 'node.getAttribute')
XML文件包含4个带经纬度的node元素,但无法正常渲染。
错误原因及修正步骤
缺少SVG容器
原代码中d3.select("svg")找不到对应元素,返回null,后续获取宽高时直接报错。需要在HTML的<body>里添加指定宽高的SVG标签。数据格式不兼容
documentElement.getElementsByTagName("node")返回的是HTMLCollection对象,D3无法直接处理这类类数组结构,需要转换为普通数组。错误的图形元素标签
原代码append自定义的myCircles标签,SVG无法识别,应该使用标准的<circle>元素。未进行地理投影转换
XML中的经纬度是地理坐标,需要通过D3的投影方法转换为SVG画布的像素坐标,不能直接作为cx、cy属性值。
修正后的完整代码
HTML代码
<!DOCTYPE html> <html> <meta charset="utf-8"> <head> <script type="text/javascript" src="https://d3js.org/d3.v4.js"></script> </head> <body> <!-- 添加带宽高的SVG容器 --> <svg width="800" height="600"></svg> <script> var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"); var projection = d3.geoMercator() .scale(21000000) .center([-122.29576905, 37.890256]) .translate([width / 2, height / 2]) // 调整平移参数让图形居中 d3.xml("entrance-exit.xml", function(error, xml) { // 将HTMLCollection转换为数组 var nodesArray = Array.from(xml.documentElement.getElementsByTagName("node")); svg .selectAll("circle") .data(nodesArray) .enter() .append("circle") // 使用标准circle元素 .attr("cx", function(d) { // 投影转换:先转成[lon, lat]格式,再获取x坐标 return projection([d.getAttribute("lon"), d.getAttribute("lat")])[0]; }) .attr("cy", function(d) { return projection([d.getAttribute("lon"), d.getAttribute("lat")])[1]; }) .attr("r", 8) .style("fill", "blue") .attr("stroke", "black") .attr("stroke-width", 1) .attr("fill-opacity", 1); }) </script> </body> </html>
XML文件(无需修改)
<?xml version="1.0" encoding="UTF-8"?> <osm version="0.6" generator="Overpass API 0.7.59 e21c39fe"> <note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note> <meta osm_base="2022-11-01T11:22:37Z"/> <bounds minlat="37.8885000" minlon="-122.2966000" maxlat="37.8906000" maxlon="-122.2945000"/> <node id="10054221950" lat="37.8899635" lon="-122.2960219"> <tag k="entrance" v="yes"/> </node> <node id="10054221951" lat="37.8894885" lon="-122.2951210"> <tag k="entrance" v="yes"/> <tag k="wheelchair" v="yes"/> </node> <node id="10091017732" lat="37.8894072" lon="-122.2952833"> <tag k="entrance" v="yes"/> <tag k="ref" v="25"/> </node> <node id="10091017733" lat="37.8894276" lon="-122.2951869"> <tag k="entrance" v="yes"/> <tag k="ref" v="26"/> </node> </osm>
关键修正说明
- 新增
<svg width="800" height="600"></svg>作为绘图容器,确保D3能获取到有效的SVG元素 - 使用
Array.from()将HTMLCollection转为数组,让D3可以正常绑定数据 - 替换
append("myCircles")为append("circle"),使用SVG标准图形元素 - 通过
projection([lon, lat])将地理坐标转换为SVG画布的像素坐标,正确计算cx和cy值
内容的提问来源于stack exchange,提问作者organon
相关产品推荐
相关产品推荐

