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
相关产品推荐
相关产品推荐

