如何用amCharts5 XY柱状堆叠系列制作镜像条形图
实现amCharts5镜像水平条形图(对比current/previous数据)
核心思路
镜像条形图的关键是将其中一组数据(比如previous)转为负值,使其向X轴左侧延伸,另一组(current)保持正值向右侧延伸,同时调整轴和系列的显示逻辑,让标签显示绝对值,优化视觉效果。
完整实现代码
假设你的数据数组中每个对象可补充category字段(无此字段可通过索引生成),以下是适配amCharts5的完整配置:
// 初始化图表 const root = am5.Root.new("chartdiv"); // 设置主题 root.setThemes([am5themes_Animated.new(root)]); // 创建图表容器 const chart = root.container.children.push( am5xy.XYChart.new(root, { panX: false, panY: false, wheelX: "none", wheelY: "none" }) ); // 定义数据(基于你的数据源补充category字段) const data = [ { category: "Item 1", current: 61, previous: 29 }, { category: "Item 2", current: 60, previous: 29 }, { category: "Item 3", current: 55, previous: 35 } ]; // 创建Y轴(类别轴) const yAxis = chart.yAxes.push( am5xy.CategoryAxis.new(root, { categoryField: "category", renderer: am5xy.AxisRendererY.new(root, { inversed: true, cellStartLocation: 0.1, cellEndLocation: 0.9 }) }) ); yAxis.data.setAll(data); // 创建X轴(数值轴) const xAxis = chart.xAxes.push( am5xy.ValueAxis.new(root, { min: -100, // 根据数据最大值调整范围 max: 100, renderer: am5xy.AxisRendererX.new(root, { // 自定义刻度标签,显示绝对值 label: { text: function(axisItem) { return Math.abs(axisItem.value) + "%"; } } }) }) ); // 创建current系列(右侧条形) const currentSeries = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Current", xAxis: xAxis, yAxis: yAxis, valueXField: "current", categoryYField: "category", sequencedInterpolation: true }) ); currentSeries.columns.template.setAll({ fill: am5.color(0x0057e7), stroke: am5.color(0x0057e7), width: am5.percent(40) // 控制条形宽度,避免重叠 }); // 添加条形内部标签 currentSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Label.new(root, { text: "{valueX}%", fill: am5.color(0xffffff), centerX: am5.p50, centerY: am5.p50 }) }); }); currentSeries.data.setAll(data); // 创建previous系列(左侧条形,使用负值实现镜像) const previousSeries = chart.series.push( am5xy.ColumnSeries.new(root, { name: "Previous", xAxis: xAxis, yAxis: yAxis, // 将previous转为负值,实现向左延伸 valueXField: function(item) { return -item.previous; }, categoryYField: "category", sequencedInterpolation: true }) ); previousSeries.columns.template.setAll({ fill: am5.color(0xd62d20), stroke: am5.color(0xd62d20), width: am5.percent(40) }); // 添加条形内部标签,显示绝对值 previousSeries.bullets.push(function() { return am5.Bullet.new(root, { sprite: am5.Label.new(root, { text: "{valueX.abs}%", fill: am5.color(0xffffff), centerX: am5.p50, centerY: am5.p50 }) }); }); previousSeries.data.setAll(data); // 添加图例 const legend = chart.children.push(am5.Legend.new(root, {})); legend.data.setAll(chart.series.values); // 添加光标交互 chart.set("cursor", am5xy.XYCursor.new(root, {}));
关键配置说明
- 数据镜像处理:
previousSeries通过valueXField的回调函数将previous值转为负值,实现向左延伸的镜像效果。 - X轴标签优化:通过自定义
label.text回调,让X轴刻度显示绝对值,避免负号干扰阅读。 - 条形宽度控制:设置
width: am5.percent(40)确保两组条形在同一Y轴类别下不会重叠。 - 内部标签显示:
previousSeries的标签使用{valueX.abs}显示绝对值,保证数据可读性。
常见问题排查
- 若之前尝试负值未成功,大概率是X轴的
min/max范围设置错误,导致负值部分被截断。需确保X轴min小于数据中最大负值的绝对值,max大于最大正值。 - 若数据源无
category字段,可通过遍历数组为每个对象添加category: "Item " + (index+1)来生成类别标识。
内容的提问来源于stack exchange,提问作者Christopher
相关产品推荐
相关产品推荐

