如何在AmCharts 5堆叠柱状图中按值排序列内分段
问题描述
使用AmCharts 5创建堆叠柱状图时,需要实现每列的分段按数值从小到大排序,最大数值的分段始终位于列顶部的效果。现有代码及数据格式如下:
现有图表代码
// Get chart div by id var chartDiv = document.getElementById(selector); const data = JSON.parse(chartDiv.getAttribute('data-chart')); const fontSize = 12; const markerSize = 12; var root = am5.Root.new(selector); var chart = root.container.children.push( am5xy.XYChart.new(root, { panY: false, layout: root.verticalLayout, dy: 10, }) ); // Create X-axis let xAxis = chart.xAxes.push( am5xy.CategoryAxis.new(root, { categoryField: "week_ending_date", renderer: am5xy.AxisRendererX.new(root, {}) }) ); let xRenderer = xAxis.get("renderer"); xRenderer.labels.template.setAll({ fontSize: fontSize }); xAxis.data.setAll(data); // Create Y-Axis var yAxis = chart.yAxes.push( am5xy.ValueAxis.new(root, { renderer: am5xy.AxisRendererY.new(root, {}), }) ); let yRenderer = yAxis.get("renderer"); yRenderer.labels.template.setAll({ fontSize: fontSize }); // Add series function makeSeries(name, fieldName, colorHex) { var series = chart.series.push(am5xy.ColumnSeries.new(root, { name: name, stacked: true, xAxis: xAxis, yAxis: yAxis, baseAxis: xAxis, valueYField: fieldName, categoryXField: "week_ending_date", fill: colorHex, })); series.columns.template.setAll({ tooltipText: "{name} - {valueY}", tooltipY: am5.percent(90) }); series.data.setAll(data); series.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Label.new(root, { text: "{valueX}", fill: root.interfaceColors.get("alternativeText"), centerY: am5.p50, centerX: am5.p50, populateText: true, fontSize: 12, }) }); }); legend.data.push(series); } // Add series for each site in the data let sites = Object.keys(data[0]) sites.shift() sites.forEach((site, index) => { makeSeries(site, site, COLOR_SCHEME[index]); })
数据格式
[ { "week_ending_date": "2022-10-02", "site A": 100, "site B": 150, "site C": 200 }, { "week_ending_date": "2022-10-09", "site A": 400, "site B": 150, "site C": 50 }, ... ]
例如第一列希望site C位于顶部,第二列希望site A位于顶部,查阅官方文档未找到直接排序分段的属性,需实现该需求。
实现方案
该需求可通过预处理数据+动态绑定堆叠顺序字段实现,核心是让每个数据点的分段根据自身数值动态调整堆叠层级,具体步骤如下:
1. 预处理数据,生成每个站点的堆叠权重
遍历原始数据,为每个日期条目计算各站点数值的排序,并添加stackOrder字段记录每个站点的堆叠权重(数值越大,权重越高,堆叠位置越靠上):
// 预处理数据,添加堆叠排序字段 data.forEach(item => { // 提取所有站点的键值对,排除日期字段 const siteEntries = Object.entries(item) .filter(([key]) => key !== "week_ending_date"); // 按数值从小到大排序,最大数值的站点排在最后 siteEntries.sort((a, b) => a[1] - b[1]); // 为每个站点分配堆叠权重,索引越大权重越高 item.stackOrder = {}; siteEntries.forEach(([site], index) => { item.stackOrder[site] = index; }); });
2. 修改系列配置,绑定堆叠顺序字段
修改makeSeries函数,为ColumnSeries添加stackOrderField配置,绑定到预处理的stackOrder[站点名称]字段,让系列根据每个数据点的权重自动调整堆叠顺序:
function makeSeries(name, fieldName, colorHex) { var series = chart.series.push(am5xy.ColumnSeries.new(root, { name: name, stacked: true, xAxis: xAxis, yAxis: yAxis, baseAxis: xAxis, valueYField: fieldName, categoryXField: "week_ending_date", fill: colorHex, // 绑定堆叠顺序字段,使用当前站点的权重值 stackOrderField: `stackOrder.${name}` })); series.columns.template.setAll({ tooltipText: "{name} - {valueY}", tooltipY: am5.percent(90) }); series.data.setAll(data); // 修正原代码错误:子弹文本应显示valueY而非valueX series.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Label.new(root, { text: "{valueY}", fill: root.interfaceColors.get("alternativeText"), centerY: am5.p50, centerX: am5.p50, populateText: true, fontSize: 12, }) }); }); legend.data.push(series); }
关键说明
stackOrderField是AmCharts 5堆叠系列的内置配置字段,用于控制同组系列的堆叠顺序,数值大的系列会被渲染在更上方。- 预处理数据时按数值从小到大排序,确保最大数值的站点获得最大的权重索引,从而堆叠在列的顶部。
- 原代码中子弹文本使用
{valueX}是错误的,改为{valueY}才能正确显示分段的数值。
内容的提问来源于stack exchange,提问作者James Dernie
相关产品推荐
相关产品推荐

