点击图表分类时如何高亮该分类下的所有柱状条?
问题描述
我已经给图表设置了点击事件,可以根据点击的分类修改部分数据,但用户体验不佳。现在希望实现点击某分类时高亮该分类下的所有柱状条,当前代码如下:
原代码
this.fireProgressionChart = new Chart(this.fireProgressionCanvas.nativeElement, { data: { datasets: [{ type: 'bar', label: 'Expenses', data: [], backgroundColor: 'rgb(178, 69, 69)', }, { type: 'bar', label: 'Passive Income', backgroundColor: 'rgb(12, 133, 75)', data: [], }, { type: 'bar', label: 'Asset + Passive Income', backgroundColor: 'rgb(49, 74, 138)', data: [], }], labels: this.getNwProgressionLabels(), }, options: { plugins: { datalabels: { display: false, anchor: 'center', align: 'bottom', formatter: Math.round, font: { weight: 'bold' } }, legend: { display: false, position: 'top' }, }, onClick: (event, elements, chart) => { const xScale = chart.scales['x']; const canvasPosition = getRelativePosition(event, chart); let xIndex:any = 0 xIndex = xScale.getValueForPixel(canvasPosition.x); console.log("xIndex:", xIndex) const age = this.fireProgressionChart.data.labels[xIndex] let barColors:any = { 'Expenses': '#b24545', 'Passive Income': '#0c854b', 'Asset + Passive Income': '#314a8a', }; const datasets:any = chart.data.datasets; // Dataset and its color const backgroundColors = Object.entries(barColors).map( ([k, v], i) => v ); // Set color to each bar datasets.forEach((ds:any, i:any) => { if (Array.isArray(ds.backgroundColor)) return; ds.backgroundColor = backgroundColors; }); const highlightedCategoryIndex = datasets[0].backgroundColor.every( (c:any) => c !== 'gray' ) ? -1 : datasets[0].backgroundColor.findIndex((c:any) => c !== 'gray'); for (let dsIndex = 0; dsIndex < datasets.length; dsIndex++) { datasets[dsIndex] = { ...datasets[dsIndex], backgroundColor: datasets[dsIndex].backgroundColor.map((x:any, i:any) => { const label = datasets[i].label; // For un-toggle/un-check for highlighted bar if (highlightedCategoryIndex === xIndex) return barColors[label]; return xIndex === i ? barColors[label] : 'gray'; }), }; } this.fireProgressionChart.update() } } })
修正方案
原代码存在逻辑错误(比如错误获取dataset的label、高亮状态判断复杂),以下是简化且正确的实现:
核心逻辑
- 新增变量保存当前高亮的分类索引,用于判断是否需要取消高亮
- 点击时,若当前点击的索引已高亮,则取消所有高亮;否则高亮该索引下的所有柱状条
- 直接通过dataset的label匹配对应颜色,避免索引混乱
修正后的代码
// 新增变量保存当前高亮的索引,初始为-1表示无高亮 let highlightedXIndex = -1; this.fireProgressionChart = new Chart(this.fireProgressionCanvas.nativeElement, { data: { datasets: [{ type: 'bar', label: 'Expenses', data: [], backgroundColor: 'rgb(178, 69, 69)', }, { type: 'bar', label: 'Passive Income', backgroundColor: 'rgb(12, 133, 75)', data: [], }, { type: 'bar', label: 'Asset + Passive Income', backgroundColor: 'rgb(49, 74, 138)', data: [], }], labels: this.getNwProgressionLabels(), }, options: { plugins: { datalabels: { display: false, anchor: 'center', align: 'bottom', formatter: Math.round, font: { weight: 'bold' } }, legend: { display: false, position: 'top' }, }, onClick: (event, elements, chart) => { const xScale = chart.scales['x']; const canvasPosition = getRelativePosition(event, chart); const xIndex = xScale.getValueForPixel(canvasPosition.x); const barColors = { 'Expenses': '#b24545', 'Passive Income': '#0c854b', 'Asset + Passive Income': '#314a8a', }; const datasets = chart.data.datasets; // 判断是否取消当前高亮 if (highlightedXIndex === xIndex) { // 取消高亮:所有柱状条恢复原色 datasets.forEach(ds => { ds.backgroundColor = barColors[ds.label]; }); highlightedXIndex = -1; } else { // 高亮目标分类:目标索引用原色,其余用灰色 datasets.forEach(ds => { ds.backgroundColor = ds.data.map((_, idx) => idx === xIndex ? barColors[ds.label] : '#cccccc' ); }); highlightedXIndex = xIndex; } this.fireProgressionChart.update(); } } })
关键修改点
- 移除了原代码中复杂的颜色数组和高亮索引判断逻辑,改用直观变量保存状态
- 修复了
label获取错误的问题,直接使用当前dataset的ds.label匹配颜色 - 简化颜色设置逻辑,每个dataset的
backgroundColor直接根据索引生成数组 - 支持点击已高亮的分类取消高亮,提升用户体验
内容的提问来源于stack exchange,提问作者Moblize IT
相关产品推荐
相关产品推荐

