AngularJS中Highcharts分组堆叠柱状图实现问题求助
解决方案
一、先调整数据结构
原数据格式不适合图表库直接处理,先转成结构化的键值对,方便后续生成图表系列:
// 转换后的结构化数据 const rawData = { 'JAN': { '2023': {'Asset 1':5, 'Asset 2':4, 'Asset 3':5}, '2024': {'Asset 1':6, 'Asset 2':7, 'Asset 3':6} }, 'FEB': { '2023': {'Asset 1':3, 'Asset 2':6, 'Asset 3':7}, '2024': {'Asset 1':1, 'Asset 2':2, 'Asset 3':5} } // 其他月份数据... };
二、基于Chart.js+AngularJS实现需求
这里用angular-chart.js插件(适配AngularJS的Chart.js封装),核心思路是:
- 给每个资产生成两个系列(2023/2024),通过
stack属性区分年份堆叠组 - 自定义图例逻辑,把同资产的两个系列合并成一个图例条目
- 自定义图例点击事件,实现点击单个资产时同时切换两年数据的显示/隐藏
1. 控制器代码(AngularJS)
angular.module('myAssetApp', ['chart.js']) .controller('AssetChartCtrl', function($scope) { // 提取基础数据 $scope.months = Object.keys(rawData); $scope.assets = Object.keys(rawData['JAN']['2023']); $scope.datasets = []; // 生成Chart.js所需的系列数据 $scope.assets.forEach(asset => { // 生成该资产的2023年数据数组 const data2023 = $scope.months.map(month => rawData[month]['2023'][asset]); // 生成该资产的2024年数据数组 const data2024 = $scope.months.map(month => rawData[month]['2024'][asset]); // 给同资产的两年数据用同一种颜色(也可固定配色) const assetColor = `rgba(${Math.floor(Math.random()*200)}, ${Math.floor(Math.random()*200)}, ${Math.floor(Math.random()*200)}, 0.7)`; // 2023年系列 $scope.datasets.push({ label: `${asset} (2023)`, data: data2023, backgroundColor: assetColor, stack: '2023', // 标记为2023堆叠组 legendGroup: asset, // 自定义分组,用于图例合并 hidden: false }); // 2024年系列 $scope.datasets.push({ label: `${asset} (2024)`, data: data2024, backgroundColor: assetColor, stack: '2024', // 标记为2024堆叠组 legendGroup: asset, hidden: false }); }); // 图表基础数据 $scope.chartData = { labels: $scope.months, datasets: $scope.datasets }; // 图表配置(核心是自定义图例) $scope.chartOptions = { responsive: true, scales: { x: { stacked: false, // X轴不堆叠,让同月份的2023/2024柱形并列 title: { display: true, text: '月份' } }, y: { stacked: true, // Y轴堆叠,同年份下的资产数值叠加 title: { display: true, text: '数值' } } }, plugins: { legend: { // 自定义图例生成逻辑:合并同资产的两个系列 labels: { generateLabels: function(chart) { const groupedLegends = {}; chart.data.datasets.forEach((dataset, idx) => { const assetGroup = dataset.legendGroup; if (!groupedLegends[assetGroup]) { groupedLegends[assetGroup] = { text: assetGroup, fillStyle: dataset.backgroundColor, datasetIndices: [idx], hidden: dataset.hidden }; } else { groupedLegends[assetGroup].datasetIndices.push(idx); // 只要有一个系列隐藏,就标记为隐藏状态 groupedLegends[assetGroup].hidden = groupedLegends[assetGroup].hidden || dataset.hidden; } }); return Object.values(groupedLegends); } }, // 自定义图例点击事件:切换同资产下所有系列的显示状态 onClick: function(event, legendItem, legend) { legendItem.datasetIndices.forEach(idx => { const dataset = legend.chart.data.datasets[idx]; dataset.hidden = !dataset.hidden; }); legend.chart.update(); } } } }; });
2. HTML视图代码
<div ng-controller="AssetChartCtrl"> <canvas id="assetDebugChart" class="chart chart-bar" chart-data="chartData.datasets" chart-labels="chartData.labels" chart-options="chartOptions"> </canvas> </div>
三、核心逻辑说明
- 堆叠分组:通过
stack属性将2023和2024的系列分别归入不同堆叠组,实现同月份两年柱形并列、同年份资产数值堆叠的效果。 - 图例合并:利用自定义
legendGroup标记同资产的系列,在图例生成时合并成单个条目,避免重复显示。 - 交互控制:自定义图例点击事件,点击单个资产条目时,同步切换该资产下2023/2024两个系列的显示状态,满足单独查看某资产的需求。
内容的提问来源于stack exchange,提问作者Dotan Beck
相关产品推荐
相关产品推荐

