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

如何用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, {}));

关键配置说明

  1. 数据镜像处理:previousSeries通过valueXField的回调函数将previous值转为负值,实现向左延伸的镜像效果。
  2. X轴标签优化:通过自定义label.text回调,让X轴刻度显示绝对值,避免负号干扰阅读。
  3. 条形宽度控制:设置width: am5.percent(40)确保两组条形在同一Y轴类别下不会重叠。
  4. 内部标签显示:previousSeries的标签使用{valueX.abs}显示绝对值,保证数据可读性。

常见问题排查

  • 若之前尝试负值未成功,大概率是X轴的min/max范围设置错误,导致负值部分被截断。需确保X轴min小于数据中最大负值的绝对值,max大于最大正值。
  • 若数据源无category字段,可通过遍历数组为每个对象添加category: "Item " + (index+1)来生成类别标识。

内容的提问来源于stack exchange,提问作者Christopher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 20:40:18