You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 20:14:51