点击按钮时仅淡化D3.js中已连接节点颜色的问题排查
修复D3.js节点高亮问题:仅高亮有连接的节点
我看到你的问题啦——点击按钮后所有节点都被淡化,而不是只淡化无连接的节点,问题主要出在两个地方:neighboring函数的实现逻辑错误,以及点击事件里的节点判断逻辑有误。
问题分析
neighboring函数的错误:你用了links.forEach(...),但forEach方法没有返回值(始终返回undefined),所以不管节点是否有连接,这个函数都会返回undefined,在opacity判断时会被当成false,导致所有节点都被设为低透明度。- 错误的节点选择:代码里
d = d3.select(node);是错的,node是所有节点的选择集,不是单个节点,这让你的相邻判断完全失去了目标。
修正方案
我们需要重新实现一个判断节点是否有连接的函数,然后在点击事件里正确判断每个节点是否存在连接:
修正后的完整代码
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="http://d3js.org/d3.v3.min.js"></script> <style> rect { fill: none; pointer-events: all; } .node { fill: blue; } .link { stroke: #999; } </style> </head> <body> <script> var width = 960, height = 500; var fill = d3.scale.category20(); var data = {nodes: [], links: []}; var force = d3.layout.force() .size([width, height]) .nodes(data.nodes) .linkDistance(80) .charge(-60) .on("tick", tick); var svg = d3.select("body").append("svg") .attr("width", width) .attr("height", height) .on('dblclick', dblclick); svg.append("rect") .attr("width", width) .attr("height", height); var nodes = force.nodes(), links = force.links(), node = svg.selectAll(".node"), link = svg.selectAll(".link"); restart(); function dblclick() { var point = d3.mouse(this), node = {x: point[0], y: point[1]}, n = nodes.push(node); nodes.forEach(function(target) { var x = target.x - node.x, y = target.y - node.y; if (Math.sqrt(x * x + y * y) < 50) { links.push({source: node, target: target}); } }); restart(); } function tick() { link.attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }); node.attr("cx", function(d) { return d.x; }) .attr("cy", function(d) { return d.y; }); } //Toggle stores whether the highlighting is on var toggle = 0; // 修正:判断节点是否存在连接(有邻居) function hasNeighbor(node) { return links.some(function(d) { return d.source === node || d.target === node; }); } //change color after button click d3.select("body").append("button").text("Next") .on("click", function() { if (toggle == 0) { //Reduce the opacity of nodes WITHOUT connections node.style("opacity", function (o) { // 修正:用hasNeighbor判断当前节点是否有连接 return hasNeighbor(o)? 1 : 0.1; }); toggle = 1; } else { //Put them back to opacity=1 node.style("opacity", 1); link.style("opacity", 1); toggle = 0; } }); function restart() { link = link.data(links); link.enter().insert("line", ".node") .attr("class", "link"); node = node.data(nodes); node.enter().insert("circle") .attr("class", "node") .attr("r", 10) .style("fill", "blue"); force.start(); } </script> </body> </html>
关键改动点
- 替换
neighboring为hasNeighbor函数:使用links.some(...)来检查是否存在任何与当前节点相关的链接,some会在找到符合条件的元素时立刻返回true,否则返回false,完美适配我们的判断需求。 - 修正点击事件里的opacity判断逻辑:直接针对每个节点
o,调用hasNeighbor(o)判断它是否有连接,有连接则保持不透明度1,无连接则设为0.1。
现在点击按钮后,所有有连接的节点会保持正常显示,没有连接的孤立节点会被淡化,符合你的需求。
内容的提问来源于stack exchange,提问作者Asia
相关产品推荐
相关产品推荐

