D3.js路径描边交互设置问题(鼠标悬停、右键菜单)
解决D3.js路径仅描边触发交互的问题
当前你的路径设置了填充色,导致鼠标悬停或右键点击路径的整个区域(包括填充部分)都会触发事件。要实现仅描边触发交互,只需利用SVG的pointer-events属性:
- 给路径添加
pointer-events: stroke,该属性会限制鼠标事件仅在元素的描边区域触发 - 如果不需要路径填充,也可以直接设置
fill: none,这样路径的点击区域就只有描边本身
关键修改部分
在路径的属性配置中添加一行代码即可:
links = linksContainer.selectAll(".link") .data(data.links) .enter() .append("path") .attr("class", "link") .attr("fill", "lightgray") .attr("stroke", "black") .attr("stroke-width", "2px") .attr("cursor", "pointer") .attr("pointer-events", "stroke") // 关键:仅描边响应鼠标事件 .on("mouseover", function(d) { d3.select(this).attr("stroke", "red") }) .on("mouseout", function(d) { d3.select(this).attr("stroke", "black") }) .on("contextmenu", function(d) { alert("ContextMenu selected") })
若无需填充色,直接设置fill: none也能达到效果,此时甚至可以省略pointer-events配置:
.attr("fill", "none")
完整修改后的代码
JavaScript
var width = window.innerWidth, height = window.innerHeight; var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) .call(d3.zoom().on("zoom", function (event) { svg.attr("transform", event.transform) })) .append("g") //////////////////////// // outer force layout var data = { "nodes": [{ "id": "A", }, { "id": "B", }, { "id": "C", }], "links": [{ "source": "A", "target": "B" }, { "source": "B", "target": "C" }, { "source": "C", "target": "A" }] } var simulation = d3.forceSimulation() .force("size", d3.forceCenter(width / 2, height / 2)) .force("charge", d3.forceManyBody().strength(-200)) .force("link", d3.forceLink().id(function (d) { return d.id }).distance(250)) linksContainer = svg.append("g").attr("class", "linkscontainer") nodesContainer = svg.append("g").attr("class", "nodesContainer") links = linksContainer.selectAll(".link") .data(data.links) .enter() .append("path") .attr("class", "link") .attr("fill", "lightgray") .attr("stroke", "black") .attr("stroke-width", "2px") .attr("cursor", "pointer") .attr("pointer-events", "stroke") .on("mouseover", function(d) { d3.select(this).attr("stroke", "red") }) .on("mouseout", function(d) { d3.select(this).attr("stroke", "black") }) .on("contextmenu", function(d) { alert("ContextMenu selected") }) nodes = nodesContainer.selectAll(".nodes") .data(data.nodes, function (d) { return d.id; }) .enter() .append("g") .attr("class", "nodes") .call(d3.drag() .on("start", dragStarted) .on("drag", dragged) .on("end", dragEnded) ) nodes.selectAll("circle") .data(d => [d]) .enter() .append("circle") .attr("class", "circle") .style("stroke", "blue") .attr("r", 40) simulation .nodes(data.nodes) .on("tick", tick) simulation .force("link") .links(data.links) function tick() { links.attr("d", function (d) { var dx = (d.target.x - d.source.x), dy = (d.target.y - d.source.y), dr = Math.sqrt(dx * dx + dy * dy) return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; }) nodes .attr("transform", d => `translate(${d.x}, ${d.y})`); } function dragStarted(event, d) { if (!event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; } function dragged(event, d) { d.fx = event.x; d.fy = event.y; } function dragEnded(event, d) { if (!event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; }
CSS
.nodes { fill: whitesmoke; cursor: pointer; }
HTML
<!DOCTYPE html> <html lang="de"> <head> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0"> <meta charset="utf-8"> <script src="https://code.jquery.com/jquery-3.6.3.js"></script> <script src="https://d3js.org/d3.v7.min.js"></script> <script src="https://kit.fontawesome.com/98a5e27706.js" crossorigin="anonymous"></script> </head> <body> </body> </html>
内容的提问来源于stack exchange,提问作者ICoded
相关产品推荐
相关产品推荐

