如何将工具提示添加到 d3.js 路径?

How to add a tooltip to a d3.js path?

我正在使用 d3.js 拓扑和 d3.js 路径从 geojson 数据构建平面图。为了澄清起见,我还使用了 vue.js。我想在用户将鼠标悬停在房间上时添加工具提示(又名 d3.js 路径)。首先,当用户将鼠标悬停在路径上时,我只添加了一个控制台日志,但那没有用。我注意到,每次我加载应用程序时,它都会执行控制台日志,但不会在用户单击/悬停在 d3.js 路径上时执行。我听到有人说我必须创建一个不可见的圆形或矩形,将工具提示 属性 绑定到它,但我不认为一旦平面图变得复杂,该路线就不会起作用。我现在不关心向工具提示添加任何实际数据,但稍后我会想要。有人可以指出我正确的方向吗?谢谢。

const data = {
  "type": "FeatureCollection",
  "features": [{
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              0, 0
            ],
            [
              0, 11.4
            ],
            [
              7, 11.4
            ],
            [
              7, 0
            ],
            [
              0, 0
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              7, 0
            ],
            [
              7, 11.4
            ],
            [
              12, 11.4
            ],
            [
              12, 0
            ],
            [
              7, 0
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              12, 0
            ],
            [
              12, 11.4
            ],
            [
              19, 11.4
            ],
            [
              19, 0
            ],
            [
              12, 0
            ]
          ]
        ]
      }
    }
  ]
};
var svg = d3.select("svg")
var width = +svg.attr("width")
var height = +svg.attr("height")

svg.attr("transform", "translate(" + width / 2 + ",0)")

var projection = d3.geoIdentity().fitSize([width, height], data)
var path = d3.geoPath(projection)

svg.selectAll("path")
  .data(data.features)
  .enter()
  .append("path")
  .attr("d", path)
  .attr("fill", "grey")
  .attr("fill-opacity", .2)
  .attr("stroke", "black")
  .attr("stroke-width", 1.5)
  .on("mouseover", console.log("hello"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="400" height="200"></svg>

有几种方法可以做到这一点。最简单但也是最有限的方法是在每个 path 中创建一个 <title> element。它会在悬停时显示,因为它是浏览器原生的。

const data = {
  "type": "FeatureCollection",
  "features": [{
      "type": "Feature",
      "properties": { "name": "Kitchen" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              0, 0
            ],
            [
              0, 11.4
            ],
            [
              7, 11.4
            ],
            [
              7, 0
            ],
            [
              0, 0
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": { "name": "Living room" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              7, 0
            ],
            [
              7, 11.4
            ],
            [
              12, 11.4
            ],
            [
              12, 0
            ],
            [
              7, 0
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": { "name": "Toilet" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              12, 0
            ],
            [
              12, 11.4
            ],
            [
              19, 11.4
            ],
            [
              19, 0
            ],
            [
              12, 0
            ]
          ]
        ]
      }
    }
  ]
};
var svg = d3.select("svg")
var width = +svg.attr("width")
var height = +svg.attr("height")

svg.attr("transform", "translate(" + width / 2 + ",0)")

var projection = d3.geoIdentity().fitSize([width, height], data)
var path = d3.geoPath(projection)

svg.selectAll("path")
  .data(data.features)
  .enter()
  .append("path")
  .attr("d", path)
  .attr("fill", "grey")
  .attr("fill-opacity", .2)
  .attr("stroke", "black")
  .attr("stroke-width", 1.5)
  .append("title")
  // Do this to maintain access to the features you drew
  .datum(function(d) { return d; })
  .text(function(d) {
    return d.properties.name;
  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="400" height="200"></svg>

更复杂的可以使用绝对定位div,例如:

const data = {
  "type": "FeatureCollection",
  "features": [{
      "type": "Feature",
      "properties": {
        "name": "Kitchen"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              0, 0
            ],
            [
              0, 11.4
            ],
            [
              7, 11.4
            ],
            [
              7, 0
            ],
            [
              0, 0
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "name": "Living room"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              7, 0
            ],
            [
              7, 11.4
            ],
            [
              12, 11.4
            ],
            [
              12, 0
            ],
            [
              7, 0
            ]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "name": "Toilet"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              12, 0
            ],
            [
              12, 11.4
            ],
            [
              19, 11.4
            ],
            [
              19, 0
            ],
            [
              12, 0
            ]
          ]
        ]
      }
    }
  ]
};
var svg = d3.select("svg")
var width = +svg.attr("width")
var height = +svg.attr("height")
var tooltip = d3.select("#tooltip")

svg.attr("transform", "translate(" + width / 2 + ",0)")

var projection = d3.geoIdentity().fitSize([width, height], data)
var path = d3.geoPath(projection)

svg.selectAll("path")
  .data(data.features)
  .enter()
  .append("path")
  .attr("d", path)
  .attr("fill", "grey")
  .attr("fill-opacity", .2)
  .attr("stroke", "black")
  .attr("stroke-width", 1.5)
  .on("mousemove", function(d) {
    // +3 as some offset to make sure spawning the tooltip doesn't
    // accidentally also cause unhover and thus removing itself
    tooltip
      .html(d.properties.name)
      .style("display", "block")
      .style("left", d3.event.x + 3 + 'px')
      .style("top", d3.event.y + 3 + 'px');
  })
  .on("mouseleave", function() {
    tooltip
      .style("display", null)
      .style("left", null)
      .style("top", null);
  });
#tooltip {
  position: absolute;
  top: 0;
  left: 0;
  display: none;
  border: solid 1px red;
  padding: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="400" height="200"></svg>
<div id="tooltip"></div>