echarts正负条形图的使用

234 阅读2分钟

最近在做项目的时候需要用到echarts中的正负条形图,根据服务端返回的数据进行展示,使用过程中处理了一些自定义展示的方法,现对属性的使用进行总结:

<!-- 正负柱状图 -->
<template>
    <div :id="id" :class="className" :style="{ height: newHeight, width: width }" />
</template>

<script>
import * as echarts from 'echarts';

export default {
    name: 'PlusAndMinusBarChart',
    props: {
        className: {
            type: String,
            default: 'chart'
        },
        id: {
            type: String,
            default: 'chart'
        },
        width: {
            type: String,
            default: '85%'
        },
        height: {
            type: String,
            default: '350px'
        },
        chartData: { // 封装的数据集合,通过外部传入
            type: Object,
            default: () => {
                return {};
            }
        }
    },
    data() {
        return {
            chart: null,
            newHeight: null
        };
    },
    watch: {
        chartData: {
            deep: true,
            handler(val) {
                this.handleHeight();
                this.setOptions(val);
            }
        }
    },
    created() {
        this.handleHeight();
    },
    mounted() {
        this.$nextTick(() => {
            this.initChart();
        });
    },
    beforeDestroy() {
        if (!this.chart) {
            return;
        }
        this.chart.dispose();
        this.chart = null;
    },
    methods: {
        handleHeight() {
            if (this.chartData.yAxis.data.length > 7) {
                this.newHeight = `${this.chartData.yAxis.data.length * 50}px`;
            } else {
                this.newHeight = this.height;
            }
        },
        initChart() {
            this.chart = echarts.init(document.getElementById(this.id));
            this.setOptions(this.chartData);
        },
        setOptions(data = {}) {
            this.chart.setOption({
                title: {
                    text: data.title // 标题
                },
                tooltip: { // 鼠标经过时,展示的tips
                    trigger: 'axis',
                    axisPointer: {
                        type: 'shadow'
                    },
                    formatter: function (params) { // 处理需要展示的数据
                        let res = `<div>${params[0].name}</div>`;
                        let explain = '';
                        params.forEach((v, i) => {
                            let newVal = '';
                            let filterNumLabel = '';
                            explain = data.series.filterTypeExplain[v.dataIndex];
                            if (i === 2) {
                                filterNumLabel = '';
                                data.series.numeric3.forEach((item) => {
                                    if (Math.abs(item) === Math.abs(v.value)) {
                                        newVal = `${item}%`;
                                    }
                                });
                            } else {
                                filterNumLabel = data.series[`filterNum${i + 1}`][v.dataIndex];
                                newVal = data.type === 'number' ? v.value : `${v.value}%`;
                            }
                            res += `<div style="display:flex;align-items:center">     
                                        <span
                                            style="display:inline-block;
                                            margin-right:5px;
                                            border-radius:10px;
                                            width:10px;
                                            height:10px;
                                            background-color:${v.color}"
                                        ></span>
                                        <span>${v.seriesName}: ${newVal};</span>
                                    </div>`;
                            res +=
                                filterNumLabel || filterNumLabel === 0
                                    ? ` <div>过滤数量: ${filterNumLabel};</div>`
                                    : '';
                        });
                        res += explain
                            ? ` <div style="white-space: pre-wrap;word-break: break-all;word-wrap: break-word">注释: ${explain};</div>`
                            : '';
                        return res;
                    },
                    extraCssText: 'max-width:500px;' // 额外附加到浮层的 css 样式,设定宽度,方便注释数据过长时,进行换行展示
                },
                color: ['rgb(84, 112, 198)', 'rgb(145, 204, 117)', 'rgb(250, 200, 88)'],// 柱状图的颜色,会依次循环从该列表中取颜色作为系列颜色
                legend: {
                    top: '20px', // 图例组件离容器上侧的距离
                    data: [data.series.name1, data.series.name2, data.series.name3] // 图例的数据数组
                },
                grid: {
                    left: '3%', // 组件离容器左侧的距离
                    right: '10%', // 组件离容器右侧的距离
                    bottom: '3%', // 组件离容器下侧的距离
                    containLabel: true // 区域是否包含坐标轴的【刻度标签】
                },
                xAxis: [ // 横坐标
                // 此为:横坐标左右都需要显示不同的名称
                    {
                        name: data.yAxis.name,
                        type: 'value',
                        nameLocation: 'start', // 坐标轴名称显示在横坐标的最右侧
                        nameTextStyle: { // 坐标轴名称的样式
                            fontWeight: 600,
                            fontSize: 14
                        },
                        axisLabel: {
                            show: true, // 是否显示刻度标签
                            formatter: (value) => { // 自定义方法,根据不同条件显示不同坐标轴刻度
                                if (value < 0) {
                                    return `${-value} %`;
                                } else {
                                    return data.type === 'number' ? value : `${value} %`;
                                }
                            }
                        }
                    },
                    {
                        name: data.xAxis.name,
                        type: 'value',
                        position: 'bottom', // 坐标轴名称显示在横坐标的最左侧
                        nameTextStyle: { 
                            fontWeight: 600,
                            fontSize: 14
                        },
                        axisLabel: {
                            show: true,
                            formatter: (value) => {
                                if (value < 0) {
                                    return `${-value} %`;
                                } else {
                                    return data.type === 'number' ? value : `${value} %`;
                                }
                            }
                        }
                    }
                ],
                yAxis: [ // 纵坐标
                    {
                        axisTick: {
                            show: false, // 是否显示坐标轴刻度
                            length: 50
                        },
                        type: 'category', // 为该类型时类目数据可自动从 【series.data】或 【dataset.source】中取,或者可通过 【yAxis.data】设置展示的纵坐标类目数据
                        data: data.yAxis.data
                    }
                ],
                series: [
                    {
                        name: '图1', // 名称
                        type: 'bar', // bar:柱状图,line:折线/面积图,pie:饼图 等
                        label: { // 图形上的文本标签,可用于说明图形的一些数据信息,比如值,名称等
                            show: true, // 是否显示标签
                            position: 'right', // 标签显示的位置
                            formatter: (params) => { // 自定义方法,根据不同条件显示不同标签
                                return data.type === 'number' ? params.value : `${params.value} %`;
                            }
                        },
                        emphasis: {
                            focus: 'series' // 聚焦当前高亮的数据所在的系列的所有图形
                        },
                        itemStyle: { // 当前图形柱状图显示的样式
                            normal: {
                                color: 'rgb(84, 112, 198)' // 展示柱状图的颜色
                            }
                        },

                        data: data.series.numeric1 // 柱状图展示的数据集合
                    },
                    {
                        name: '图2',
                        type: 'bar',
                        stack: 'Total',
                        label: {
                            show: true,
                            position: 'right',
                            formatter: (params) => {
                                return data.type === 'number' ? params.value : `${params.value} %`;
                            }
                        },
                        emphasis: {
                            focus: 'series'
                        },
                        itemStyle: {
                            normal: {
                                color: 'rgb(145, 204, 117)'
                            }
                        },
                        data: data.series.numeric2
                    },
                    {
                        name: '相对变化',
                        type: 'bar',
                        stack: 'Total',
                        label: {
                            show: true,
                            position: 'left',
                            formatter: (params) => {
                                let str = '';
                                data.series.numeric3.forEach((item) => {
                                    if (Math.abs(item) === Math.abs(params.value)) {
                                        str = `${item} %`;
                                    }
                                });
                                return str;
                            }
                        },
                        itemStyle: {
                            normal: {
                                color: (params) => { 
                                // 根据不同条件展示不同颜色柱状图
                                    let str = '';
                                    data.series.numeric3.forEach((item) => {
                                        if (Math.abs(item) === Math.abs(params.value)) {
                                            if (item < 0) {
                                            // 值小于0 的时候展示红色
                                                str = '#a90000';
                                            } else {
                                            // 值大于等于0 的时候展示其它颜色
                                                str = 'rgb(250, 200, 88)';
                                            }
                                        }
                                    });
                                    return str;
                                }
                            }
                        },
                        emphasis: {
                            focus: 'series'
                        },
                        data: data.series.numeric4
                    }
                ]
            });
        }
    }
};
</script>

注意:

  1. 左侧【相对变化】中值为0的时候,显示的标签会在右侧,值的数据量级过大时会出现样式重叠(项目中处理方式:值为0的时候不展示该文本标签的数据信息);
  2. 图形的高度不要固定,可以给个初始高度值,动态根据要展示的数据来动态获取需要展示的高度;
  3. 横坐标左右需要显示不同的名称,注意刻度问题,量级不同,刻度不同,展示的数据信息,有的过长,有的过短;