如何在 echarts 堆叠条形图的顶部添加总和 [根据所选系列更新]

How can I add a sum at the top of an echarts stacked bar chart [which updates based on selected series]

关于如何在 echarts 上的堆叠条形图顶部添加 'total' 标签的问题已经得到解答(例如 this one

但是,我还希望在使用图例 selected/deselected 系列时重新计算此总数(包括如果我在下面的示例中取消选择标签所附加的最终系列)。这可能吗?

另一个问题的示例代码:

//example data
this.mySeries = [{
    name: 'Dataset 1',
    type: 'bar',
    stack: 'Stack 1',
    data: [120, 132, 101, 134, 90, 230, 210]
  },
  {
    name: 'Dataset 2',
    type: 'bar',
    stack: 'Stack 1',
    data: [220, 182, 191, 234, 290, 330, 310]
  },
  {
    name: 'Dataset 3',
    type: 'bar',
    stack: 'Stack 1',
    data: [820, 932, 901, 934, 1290, 1330, 1320],
  }
];

//function for formatter
genFormatter = (series) => {
  return (param) => {
    console.log(param);
    let sum = 0;
    series.forEach(item => {
      sum += item.data[param.dataIndex];
    });
    return sum
  }
};

//inside your chart options place this
series: series.map((item, index) => Object.assign(item, {
  type: 'bar',
  stack: true,
  label: {
    show: index === series.length - 1,
    formatter: genFormatter(series),
    fontSize: 20,
    color: 'black',
    position: 'top'
  },
})),

是的,这是可能的。您需要添加处理程序,以便在图例中的选定系列发生变化时进行监听。参见 legendselectchanged 事件。

在您的事件处理程序中,您需要过滤选择了哪些系列并重新计算总和,然后将标签附加到最后一个系列。

为了将总和标签附加到最后一个系列,您可以创建这样的函数:

const seriesHandler = series => {
    return series.map((serie, index) => {
        if (index === series.length - 1) {
            return {
                ...serie,
                label: {
                    normal: {
                        show: true,
                        position: 'top',
                        formatter: params => {
                            let total = 0
                            series.forEach(s => {
                                total += s.data[params.dataIndex]
                            })
                            return total
                        }
                    }
                }
            }
        } else {
            return serie
        }
    })
}

并像这样创建 legendselectchanged 事件处理程序:

const handleLegendSelectChanged = (event, series) => {
    const includedSeriesNames = []
    for (const [name, value] of Object.entries(event.selected)) {
        if (value) {
            includedSeriesNames.push(name)
        }
    }

    const includedSeries = series.filter(serie => {
        return includedSeriesNames.includes(serie.name)
    })

    return seriesHandler(includedSeries)
}

基本上它过滤显示(包括)哪个系列,并将总和标签附加到最后一个系列。

请参阅下面的完整示例:

<!DOCTYPE html>
<html style="height: 100%">

<head>
    <meta charset="utf-8">
</head>

<body style="height: 100%; margin: 0">
    <div id="container" style="height: 100%"></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.8.0/echarts.js"
        integrity="sha512-5/8+cwsZ4fICxk706J4H0/UMZT2LKivISN26mgN86wCD4AHFvdFOBm/95z3dKLpnaHNzzwKuoBtrbKv+++SLTg=="
        crossorigin="anonymous"></script>
    <script type="text/javascript">
        const mySeries = [
            {
                name: 'Dataset 1',
                type: 'bar',
                stack: 'Stack 1',
                data: [120, 132, 101, 134, 90, 230, 210]
            },
            {
                name: 'Dataset 2',
                type: 'bar',
                stack: 'Stack 1',
                data: [220, 182, 191, 234, 290, 330, 310]
            },
            {
                name: 'Dataset 3',
                type: 'bar',
                stack: 'Stack 1',
                data: [820, 932, 901, 934, 1290, 1330, 1320],
            }
        ];

        const seriesHandler = series => {
            return series.map((serie, index) => {
                if (index === series.length - 1) {
                    return {
                        ...serie,
                        label: {
                            normal: {
                                show: true,
                                position: 'top',
                                formatter: params => {
                                    let total = 0
                                    series.forEach(s => {
                                        total += s.data[params.dataIndex]
                                    })
                                    return total
                                }
                            }
                        }
                    }
                } else {
                    return serie
                }
            })
        }

        const handleLegendSelectChanged = (event, series) => {
            const includedSeriesNames = []
            for (const [name, value] of Object.entries(event.selected)) {
                if (value) {
                    includedSeriesNames.push(name)
                }
            }

            const includedSeries = series.filter(serie => {
                return includedSeriesNames.includes(serie.name)
            })

            return seriesHandler(includedSeries)
        }

        const dom = document.getElementById("container");
        const myChart = echarts.init(dom);

        const option = {
            tooltip: {
                trigger: 'axis',
                axisPointer: {
                    type: 'shadow'
                }
            },
            toolbox: {
                show: true,
                orient: 'vertical',
                left: 'right',
                top: 'center',
                feature: {
                    dataView: { show: false, readOnly: false },
                    magicType: { show: true, type: ['line', 'bar', 'stack', 'tiled'] },
                    restore: { show: true },
                    saveAsImage: { show: true }
                }
            },
            grid: {
                left: '3%',
                right: '4%',
                bottom: '3%',
                containLabel: true
            },
            yAxis: {
                type: 'value'
            },
            xAxis: {
                type: 'category',
                data: ["Jen\n2018", "Feb\n2018", "Mar\n2018", "Apr\n2018", "May\n2018", "Jun\n2018", "Jul\n2018"]
            },
            legend: {
                data: ['Dataset 1', 'Dataset 2', 'Dataset 3']
            },
        };;

        myChart.setOption({
            ...option,
            series: seriesHandler(mySeries)
        })

        myChart.on('legendselectchanged', event => {
            myChart.setOption({
                series: handleLegendSelectChanged(event, mySeries)
            })
        })
    </script>
</body>

</html>