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

D3.js柱状图鼠标悬停高亮当前柱子并淡化其余柱子问题排查

柱状图鼠标悬停高亮单根柱子的解决方案

需求:鼠标悬停柱状图某根柱子时,仅该柱子保持全透明度,其余柱子及对应文本全部淡出。当前实现了鼠标悬停时所有元素淡出,无法仅高亮当前选中的柱子,核心问题出在事件参数处理和filter判断逻辑上。

错误原因

  • 事件参数错误:D3 v6+版本中,事件处理函数的参数顺序是(event, datum),你原来的function(d)里的d实际是事件对象,而非绑定的数据,导致传递给fade函数的selectedBar不是目标柱子的数据。
  • filter判断逻辑错误:你尝试用对象全等或不存在的x属性判断,但rollup返回的是[zipcode, count]形式的数组数据,应该通过唯一标识(zipcode,即数组第一个元素d[0])来区分选中项和其他项。

修正后的完整代码

const filmPermits = await d3.json(
    'https://data.cityofnewyork.us/resource/tg4x-b46p.json',
);

const byZipCode = d3.rollup(
    filmPermits,
    (v) => v.length,
    (d) => d['zipcode_s'],
);

const WIDTH = 1400;
const HEIGHT = 600;

const svg = app.append('svg');
svg.style('background', '#FCF9F5');
svg.attr('width', WIDTH);
svg.attr('height', HEIGHT + 100);
svg.attr('viewBox', `0 0 ${WIDTH} ${HEIGHT}`);

const x_scale = d3
    .scaleBand()
    .domain(Array.from(byZipCode.keys()))
    .range([0, WIDTH]);

const largestValue = d3.max(Array.from(byZipCode.values()));

const y_scale = d3.scaleLinear().domain([0, largestValue]).range([0, HEIGHT]);

var colorScale = d3
    .scaleOrdinal()
    .domain(Array.from(byZipCode.keys()))
    .range(['#7A3E65', '#A84448', '#E9A178']);

const bars = svg
    .selectAll('rect')
    .data(byZipCode)
    .join('rect')
    .attr('x', (d) => x_scale(d[0]))
    .attr('y', (d) => HEIGHT - y_scale(d[1]))
    .attr('width', () => x_scale.bandwidth())
    .attr('height', (d) => y_scale(d[1]))
    .attr('fill', (d) => colorScale(d[0]))
    // 修正事件参数,获取绑定的数据
    .on('mouseover', function(event, d) {
        fade(0.2, d);
    })
    .on('mouseout', function(event, d) {
        fade(1, d);
    });

const text = svg
    .selectAll('text')
    .data(byZipCode)
    .enter()
    .append('text')
    .text((item) => {
        return `${item[1]} times`; // 修正文本显示,仅展示次数
    })
    .attr('x', (d) => x_scale(d[0]))
    .attr('y', (d) => HEIGHT - y_scale(d[1]) - 10)
    .style('font-family', 'Monospace')
    .attr('fill', (d) => colorScale(d[0]))
    // 修正事件参数
    .on('mouseover', function(event, d) {
        fade(0.2, d);
    })
    .on('mouseout', function(event, d) {
        fade(1, d);
    });

// 修正fade函数的判断逻辑
function fade(opacity, selectedData) {
    d3.selectAll('rect')
        .filter(function(d) {
            // 通过唯一的zipcode区分选中项与其他元素
            return d[0] !== selectedData[0];
        })
        .transition()
        .style('opacity', opacity);
    
    d3.selectAll('text')
        .filter(function(d) {
            return d[0] !== selectedData[0];
        })
        .transition()
        .style('opacity', opacity);
}

关键修正点

  • 调整事件回调参数,确保传递给fade函数的是柱子绑定的真实数据,而非事件对象
  • 修改fade函数的filter逻辑,通过zipcode(数组第一个元素)作为唯一标识,精准筛选需要淡出的元素
  • 优化文本显示,避免将完整数组转为字符串,仅展示许可次数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 14:48:09