如何基于条件实现d3.dispatch交互逻辑?
使用d3.dispatch实现D3.js矩形交互逻辑的修正方案
问题分析
你的代码主要存在三个核心问题:
- 触发
two事件时未传递当前选中的矩形ID参数,导致回调无法获取判断依据 two事件的回调中,attr('opacity')的处理逻辑错误,没有正确关联传入的参数- 调用
dispatch.call时参数传递不完整,未将需要的变量传递给事件回调
修正后的完整代码
JavaScript部分
const data = [ { "id": 1 }, { "id": 2 }, { "id": 3 }, { "id": 4 }, { "id": 5 }, { "id": 6 }, { "id": 7 }, { "id": 8 } ]; const svgns = 'http://www.w3.org/2000/svg'; const width = 600; const height = 450; const posX = 40; const posY = 20; const heightRect = 40; const widthRect = 40; const padding = 10; const svg = d3.select('body') .append('svg') .attr('xmlns', svgns) .attr('viewBox', `0 0 ${width} ${height}`); const bgRect = svg.append('rect') .classed('boundary', true) .attr('x', '0') .attr('y', '0') .attr('width', `${width}`) .attr('height', `${height}`) .attr('fill', `#E6E6E6`); // 构建颜色比例尺 const interpolatorSequentialMultiHueName = [ 'd3.interpolateViridis' ]; const xColorScale = d3.scaleSequential() .domain(d3.extent(data, d => d.id)) .interpolator(eval(`${interpolatorSequentialMultiHueName[0]}`)); // 创建矩形元素 const rect = svg.append('g') .classed('rectContainer', true) .selectAll('rect') .data(data) .join('rect') .attr('x', `${posX}`) .attr('y', ((d, i) => posY + heightRect * i + padding * i)) .attr('width', `${widthRect}`) .attr('height', `${heightRect}`) .attr('fill', d => xColorScale(d.id)) .attr('opacity', '0.5'); // 创建交互监听矩形 const listener = d3.select('rect') .clone() .raise() .attr('x', `${posX}`) .attr('y', () => posY) .attr('width', `${widthRect}`) .attr('height', () => { const node = rect.nodes(); const len = node.length - 1; return node[len].y.baseVal.value + node[len].height.baseVal.value - node[0].y.baseVal.value; }) .attr('fill', 'none') .attr('class', 'listener') .style("pointer-events", "all"); // 初始化d3.dispatch const dispatch = d3.dispatch('resetOpacity', 'highlightRect'); // 重置所有矩形透明度的事件处理 dispatch.on('resetOpacity', function() { this.attr('opacity', '0.5'); }); // 高亮选中矩形的事件处理,接收当前选中的ID参数 dispatch.on('highlightRect', function(currData) { this.attr('opacity', d => (d.id === currData) ? '1' : '0.5'); }); // 绑定鼠标事件到监听矩形 listener.on('mouseover', function() { dispatch.call('resetOpacity', rect); }) .on('mouseout', function() { dispatch.call('resetOpacity', rect); }) .on('mousemove', function(event) { const points = d3.pointer(event); const pointY = points[1]; // 筛选当前鼠标悬停的矩形 const selOne = rect.nodes().filter(a => { const y = a.y.baseVal.value <= pointY && pointY <= a.height.baseVal.value + a.y.baseVal.value; return y; }); // 获取当前选中矩形的ID const currData = selOne.length === 1 ? selOne[0].__data__.id : null; // 触发高亮事件,传递选中ID参数,上下文为所有矩形元素 dispatch.call('highlightRect', d3.selectAll('.rectContainer>rect'), currData); });
HTML部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>D3 Dispatch Interaction</title> </head> <script type="text/javascript" src="https://d3js.org/d3.v7.min.js"></script> <body> </body> <script src="min.js"></script> </html>
关键修改说明
- 事件命名优化:将原事件名
one、two改为更具语义的resetOpacity、highlightRect,提升代码可读性 - 参数传递修正:在
mousemove中调用dispatch.call时,增加currData作为第三个参数,传递给highlightRect事件 - 回调逻辑修正:
highlightRect事件直接使用传入的currData参数,为每个矩形判断并设置对应的透明度 - 上下文绑定正确:确保
dispatch.call的第二个参数是目标D3选择集,保证回调中this指向正确的元素集合
内容的提问来源于stack exchange,提问作者smpa01
相关产品推荐
相关产品推荐

