You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于条件实现d3.dispatch交互逻辑?

使用d3.dispatch实现D3.js矩形交互逻辑的修正方案

问题分析

你的代码主要存在三个核心问题:

  1. 触发two事件时未传递当前选中的矩形ID参数,导致回调无法获取判断依据
  2. two事件的回调中,attr('opacity')的处理逻辑错误,没有正确关联传入的参数
  3. 调用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>

关键修改说明

  1. 事件命名优化:将原事件名one、two改为更具语义的resetOpacity、highlightRect,提升代码可读性
  2. 参数传递修正:在mousemove中调用dispatch.call时,增加currData作为第三个参数,传递给highlightRect事件
  3. 回调逻辑修正:highlightRect事件直接使用传入的currData参数,为每个矩形判断并设置对应的透明度
  4. 上下文绑定正确:确保dispatch.call的第二个参数是目标D3选择集,保证回调中this指向正确的元素集合

内容的提问来源于stack exchange,提问作者smpa01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 08:54:56