原始效果:柱状图

二开效果:

核心逻辑
同时显示百分比和原始值
 label: {
      show: true,
      position: 'inside',
      formatter: (params) => {
        const rawValue = rawData[params.seriesIndex][params.dataIndex];
        const percentage = Math.round(params.value * 1000) / 10;
        return `${rawValue} \n(${percentage}%)`;
      }
    }, 
显示汇总值
// Add a new series for displaying total values
series.push({
    name: 'Total',
    type: 'bar',
    stack: 'total',
    itemStyle: {
        color: 'rgba(0,0,0,0)' // 透明颜色
    },
    label: {
        show: true,
        position: 'top',
        formatter: params => `Total: ${totalData[params.dataIndex]}`
    },
    data: totalData.map(value => 0.01) // 微小的值以便能显示标签但不影响图形
}); 
代码解释
新增显示总值的系列:
- 您添加了一个名为
 'Total'的新系列到series数组中。- 这个系列使用
 type: 'bar',并且堆叠在名为'total'的堆栈中,这与其他系列使用的堆栈名称一致。这确保了柱状图的对齐,即使该系列是不可见的。透明的柱状图:
itemStyle被设置为color: 'rgba(0,0,0,0)',使得该系列的柱状图完全透明。这是一个巧妙的方法,可以确保这些柱状图不增加任何可见的元素到图表中,但仍然可以在它们上面放置标签。标签配置:
label对象中的show: true确保显示标签。position设置为'top',因此标签显示在每个柱状图堆栈的顶部。formatter函数自定义了标签的文本。它使用params.dataIndex获取totalData中对应的值,并显示为Total: {value}。这提供了关于每个类别(星期几)中所有堆叠元素的总值的清晰信息。带有微小值的数据:
- 该系列的
 data数组被设置为totalData.map(value => 0.01)。这将每个数据点设置为一个非常小的值(0.01)。这些微小的值的目的是为标签创建一个占位符,而不影响图表的实际可视化。由于柱状图本身是透明的,这个值确保了标签可以正确地定位和显示,而不会为柱状图增加任何视觉重量。分析:
- 使用透明的柱状图来显示标签:通过使用透明的柱状图,您可以在柱状图堆栈的顶部放置标签,而不会改变图表的视觉外观。这是一种常见的技术,当您希望添加额外的信息而不影响数据的可视化时。
 - 数据中的微小值:使用微小值(0.01)确保标签与柱状图相关联,但不会显著地影响堆叠柱状图的高度。这在ECharts中尤其有用,因为标签是与特定的数据点相关联的。
 - 堆叠配置:使用相同的堆叠标识符('total')使透明柱状图与其余堆叠柱状图完美对齐,确保标签位置的一致性。
 这种方法对于突出显示总值,同时保持数据可视化的完整性非常有效。这是一个为图表提供额外信息而不使其变得混乱或扭曲的巧妙解决方案。
完整版代码
// There should not be negative values in rawData
const rawData = [
  [100, 302, 301, 334, 390, 330, 320],
  [320, 132, 101, 134, 90, 230, 210],
  [220, 182, 191, 234, 290, 330, 310],
  [150, 212, 201, 154, 190, 330, 410],
  [820, 832, 901, 934, 1290, 1330, 1320]
];
const totalData = [];
for (let i = 0; i < rawData[0].length; ++i) {
  let sum = 0;
  for (let j = 0; j < rawData.length; ++j) {
    sum += rawData[j][i];
  }
  totalData.push(sum);
}
const grid = {
  left: 100,
  right: 100,
  top: 50,
  bottom: 50
};
const series = [
  'Direct',
  'Mail Ad',
  'Affiliate Ad',
  'Video Ad',
  'Search Engine'
].map((name, sid) => {
  return {
    name,
    type: 'bar',
    stack: 'total',
    barWidth: '60%',
    label: {
      show: true,
      position: 'inside',
      formatter: (params) => {
        const rawValue = rawData[params.seriesIndex][params.dataIndex];
        const percentage = Math.round(params.value * 1000) / 10;
        return `${rawValue} \n(${percentage}%)`;
      }
    },
    data: rawData[sid].map((d, did) =>
      totalData[did] <= 0 ? 0 : d / totalData[did]
    )
  };
});
// Add a new series for displaying total values
series.push({
    name: 'Total',
    type: 'bar',
    stack: 'total',
    itemStyle: {
        color: 'rgba(0,0,0,0)' // 透明颜色
    },
    label: {
        show: true,
        position: 'top',
        formatter: params => `Total: ${totalData[params.dataIndex]}`
    },
    data: totalData.map(value => 0.01) // 微小的值以便能显示标签但不影响图形
});
option = {
  legend: {
    selectedMode: false
  },
  grid,
  yAxis: {
    type: 'value'
  },
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  series
};
                


















