使用D3鼠标悬停无法访问GeoJSON属性元素,返回Undefined
问题:D3.js鼠标悬停时无法访问GeoJSON的properties字段显示站点名称
使用GeoJSON数据制作调查站点地图,鼠标悬停高亮功能正常,但tooltip尝试访问d.properties.site_name时控制台返回undefined。单独测试GeoJSON时能正常提取site_name,问题大概率出在鼠标悬停的事件处理代码中。
测试GeoJSON获取site_name的代码
var siteNames = boundaries_json.features.map(function(d) { return d.properties.site_name; // 正常访问properties中的site_name });
鼠标悬停相关代码
g.selectAll("path.boundaries") .data(boundaries_json.features) .enter() .append("path") .attr("fill", "#ccc") .attr('class', 'map') .attr("d", geoPath) .on("mouseover", function(event, d) { d3.select(this) .attr("fill", '#808080') .attr("stroke", "#ff0000") .attr("stroke-width", "0.3"); d3.select(this).raise(); d3.select("#tooltip") .style("visibility", "visible") .text(d.properties.site_name) .style("top", (d3.event.pageY + 10) + "px") .style("left", (d3.event.pageX + 10) + "px"); }) .on("mouseout", function(event, d) { d3.select(this) .attr("fill", "#ccc") .attr("stroke", null) .attr("stroke-width", null); d3.select("#tooltip").style("visibility", "hidden"); });
GeoJSON结构示例
var boundaries_json = { "type": "FeatureCollection", "name": "ypp_boundaries", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, "features": [ { "type": "Feature", "properties": { "site_id": "ST", "site_name": "Stean Moor", "resp_person": "[PLACEHOLDER]", "region_id": "NID", "date_added": "2009-01-01", "area": 132 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [ -1.905702715935964, 54.122415089551261 ], [ -1.906621702930786, 54.122290229958068 ], ... ] ] ] } } // 更多features... ];
问题原因及解决方案
核心问题是D3版本与事件处理函数的参数顺序不匹配:
- D3 v5及更早版本:事件监听器的参数顺序是
(d, i),其中d是绑定的GeoJSON Feature对象,i是索引,事件对象通过d3.event获取。 - D3 v6及之后版本:参数顺序改为
(event, d),事件对象作为第一个参数传入,d是绑定的Feature对象。
你的代码中同时混用了新老版本的写法,导致d的指向错误,进而d.properties.site_name返回undefined,针对不同版本修改如下:
若使用D3 v6+
保留function(event, d)的参数顺序,将d3.event.pageY/d3.event.pageX替换为event.pageY/event.pageX(d3.event在v6中已废弃):
.on("mouseover", function(event, d) { d3.select(this) .attr("fill", '#808080') .attr("stroke", "#ff0000") .attr("stroke-width", "0.3"); d3.select(this).raise(); d3.select("#tooltip") .style("visibility", "visible") .text(d.properties.site_name) .style("top", (event.pageY + 10) + "px") .style("left", (event.pageX + 10) + "px"); })
若使用D3 v5或更早版本
将事件处理函数的参数顺序改为(d, i),继续使用d3.event获取事件对象:
.on("mouseover", function(d, i) { d3.select(this) .attr("fill", '#808080') .attr("stroke", "#ff0000") .attr("stroke-width", "0.3"); d3.select(this).raise(); d3.select("#tooltip") .style("visibility", "visible") .text(d.properties.site_name) .style("top", (d3.event.pageY + 10) + "px") .style("left", (d3.event.pageX + 10) + "px"); })
另外,建议统一元素class名称:你用selectAll("path.boundaries")选择元素,但append的path class是map,后续维护时可能出现选择器不匹配的问题,可改为attr('class', 'boundaries')或attr('class', 'map boundaries')。
内容的提问来源于stack exchange,提问作者thepeatles
相关产品推荐
相关产品推荐

