简体   繁体   中英

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

There are already answered questions on how to add a 'total' label on top of a stacked bar chart on echarts (eg this one )

However, I also want this total to recalculate when series are selected/deselected using the legend (including if I deselect the final series to which the label is attached in the example below). Is this possible?

Example code from the other question:

 //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' }, })),

Yes, it is possible. You need to add handler that listen when selected series in the legend changed. See legendselectchanged event.

In your event handler, you need to filter which series are selected and recalculate the sum, and then attach the label to the last series.

In order to attach sum label to the last series, you can create a function like this:

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
        }
    })
}

And create legendselectchanged event handler like this:

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)
}

Basically it filter which series is shown (included), and attach sum label to the last series.

See complete example below:

 <: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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM