首页 > 解决方案 > 如何将工具提示添加到 d3.js 路径?

问题描述

我正在使用 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>

标签: vue.jsd3.jstooltip

解决方案


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

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>


推荐阅读