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

点击图表分类时如何高亮该分类下的所有柱状条?

问题描述

我已经给图表设置了点击事件,可以根据点击的分类修改部分数据,但用户体验不佳。现在希望实现点击某分类时高亮该分类下的所有柱状条,当前代码如下:

原代码
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、高亮状态判断复杂),以下是简化且正确的实现:

核心逻辑

  1. 新增变量保存当前高亮的分类索引,用于判断是否需要取消高亮
  2. 点击时,若当前点击的索引已高亮,则取消所有高亮;否则高亮该索引下的所有柱状条
  3. 直接通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 04:23:20