ECharts图表联动

1.小节概述

    当多个图表一起展现时,有时图表之间的数据是有关系的,这时候需要图表之间能否联动起来。例如有个地图展示了河南省各个区域(豫东、豫西、豫南、豫北、豫中)的销售额,另外有个柱状图展示了各个市区的销售额,那么在点击地图上某个区域时,柱状图也同时联动展示该区域辖下的各个市区的销售额数据。在本小节中,主要介绍在当前Vue项目中使用EventBus配合echarts实例中事件绑定API实现上述的图表联动场景。

2.操作步骤

2.1.准备工作

1.在主页HomeView.vue中,存放文字链接(图表联动),点击跳转对应的路由页面(chartLinkage),在router的index.js中配置路由信息。在chartLinkage演示页面中,进行左右栅格布局,准备存放地图(展示区域销售额)和柱状图(展示市区销售额)。

2.在RAP接口管理平台中新建接口,提供区域销售额数据以及各区域辖下的市区销售额数据。

3.在src/components/linkage下创建CascadeMap.vue,引入Echarts地图展示区域销售额数据,并放到chartLinkage演示页面中的左侧区域,参考代码:

注意事项:前面小节中,我们是通过document.getElementById进行获取元素的,这个方法其实有个明显的弊端(最终多个组件都要放到一起,假如一不小心设置的元素id有重复就会出现问题),所以此处及后续将使用ref进行获取DOM元素。

<template>
    <div class="mainDiv">
        <div class="titleDiv">区域销售金额</div>
        <div class="chartDiv" ref="chart"></div>
    </div>
</template>

<script>
import HenanAreaMap from '@/assets/maps/HenanArea.json'
import elementResizeDetectorMaker from 'element-resize-detector'

const erd = elementResizeDetectorMaker()

export default {
    data() {
        return {
            chartData: {},
        }
    },
    name: 'CascadeMap',
    mounted() {
        this.getChartData().then(() => {
            // 数据请求到后渲染图表
            this.renderChart()
        })
    },
    beforeDestroy() {
        erd.uninstall(this.$refs.chart)
    },
    methods: {
        // 请求数据回来
        async getChartData() {
            this.chartData = await this.$axios({ url: 'sales/cas' })
        },
        // 渲染图表
        renderChart() {
            // 使用registerMap注册地图json数据
            this.$echarts.registerMap('HenanArea', HenanAreaMap)
            let myChart = this.$echarts.init(this.$refs.chart)
            let chartData = this.chartData
            var option = {
                tooltip: {},
                visualMap: {
                    min: 3000,
                    max: 30000,
                    left: 'left',
                    top: 'bottom',
                    text: ['高', '低'],
                    inRange: {
                        color: ['#e0ffff', '#5470C6'],
                    },
                    show: true,
                },
                series: [
                    {
                        name: '销售额',
                        type: 'map',
                        map: 'HenanArea',
                        zoom: 1.2,
                        label: {
                            show: true,
                            fontSize: 14,
                            color: '#640000',
                            formatter: '{b}\n{c}',
                        },
                        data: chartData.data.areaData,
                        select: {
                            itemStyle: {
                                // 设置地图点击后的颜色
                                color: null,
                            },
                        },
                    },
                ],
            }
            // 使用刚指定的配置项和数据显示图表
            myChart.setOption(option)
            // 监听图表所在容器,大小有变化时自适应
            erd.listenTo(this.$refs.chart, function () {
                myChart.resize()
            })
        },
    },
}
</script>

<style scoped>
.titleDiv {
    cursor: pointer;
}
</style>

4.在src/components/linkage下创建CascadeBar.vue,引入Echarts柱状图展示市区销售额数据(默认展示全部市区数据),并放到chartLinkage演示页面中的右侧区域,参考代码:

<template>
    <div class="mainDiv">
        <div class="titleDiv">{{ title }}</div>
        <div class="chartDiv" ref="chart"></div>
    </div>
</template>

<script>
import elementResizeDetectorMaker from 'element-resize-detector'

const erd = elementResizeDetectorMaker()

export default {
    data() {
        return {
            chartData: {},
            title: '河南省各市销售额',
        }
    },
    name: 'CascadeBar',
    mounted() {
        this.getChartData().then(() => {
            // 数据请求到后渲染图表
            this.renderChart()
        })
    },
    beforeDestroy() {
        erd.uninstall(this.$refs.chart)
    },
    methods: {
        // 请求数据回来
        async getChartData() {
            this.chartData = await this.$axios({ url: 'sales/cas' })
        },
        // 渲染图表
        renderChart() {
            let myChart = this.$echarts.init(this.$refs.chart)
            let chartData = this.chartData
            var option = {
                tooltip: {
                    show: true,
                    textStyle: {
                        color: '#000000',
                        fontStyle: 'normal',
                        fontSize: 14,
                        align: 'center',
                    },
                },
                legend: {
                    show: true,
                    data: ['销额'],
                    icon: 'roundRect',
                    x: 'center',
                    y: 'bottom',
                    padding: [0, 0, 10, 0],
                    textStyle: {
                        fontStyle: 'normal',
                        fontSize: 12,
                    },
                },
                grid: {
                    top: '10%',
                    bottom: '10%',
                    left: '3%',
                    right: '3%',
                    containLabel: true,
                },
                xAxis: {
                    type: 'category',
                    data: chartData.data.allCityData.city,
                    axisTick: {
                        show: true,
                        alignWithLabel: true,
                    },
                    axisLabel: {
                        show: true,
                        interval: 0,
                    },
                    splitLine: {
                        show: false,
                    },
                },
                yAxis: {
                    type: 'value',
                    splitLine: {
                        // 分隔线设置
                        show: true,
                        lineStyle: {
                            color: ['#E5EAF3'],
                            width: 1,
                            type: 'dashed',
                        },
                    },
                },
                series: [
                    {
                        name: '销量',
                        type: 'bar',
                        data: chartData.data.allCityData.amount,
                        label: {
                            show: true,
                            position: 'top',
                            fontSize: 11,
                        },
                        itemStyle: {
                            // 顺时针设置圆角:左上、右上、右下、左下
                            borderRadius: [6, 6, 0, 0],
                            // 根据值的情况设置不同颜色
                            color: function (params) {
                                let colorList = ['#5470C6', '#91CC75', '#FAC858', '#EE6666']
                                let amount = params.data
                                if (amount >= 7000) {
                                    return colorList[0]
                                } else if (amount < 7000 && amount >= 5000) {
                                    return colorList[1]
                                } else if (amount < 5000 && amount >= 3000) {
                                    return colorList[2]
                                } else {
                                    return colorList[3]
                                }
                            },
                        },
                    },
                ],
            }
            // 使用刚指定的配置项和数据显示图表
            myChart.setOption(option)
            // 监听图表所在容器,大小有变化时自适应
            erd.listenTo(this.$refs.chart, function () {
                myChart.resize()
            })
        },
    },
}
</script>

<style scoped>
.titleDiv {
    cursor: pointer;
}
</style>

2.2.组件间通信

1.两个图表组件(地图和柱状图)已经呈现,数据也已经渲染。那么要想联动,就需要图表间可以进行通信,例如点击左侧区域能够触发右侧图表组件方法进行数据更新。此处采用的是EventBus进行组件间通信,首先在main.js中全局初始化EventBus,如下图:

2.接下来将使用EventBus配合echarts实例中事件绑定来实现点击区域同时柱状图数据更新。

2.3.实现图表联动

1.在地图组件中向EventBus发送事件,并传递参数(所点击的区域快信息)。当然,由于点击图表区域块触发CascadeBar显示对应区域的数据,那么同理设置点击其他地方(此处设置的是点击标题的div容器)触发CascadeBar回归到所有区域下的数据展示。所以,在地图组件中有两处地方需要向EventBus发送事件,参考代码:

注意事项:1.在echarts点击事件绑定时,因为echarts当中的this并不是vue的实例vueComponent,需要先定义一个变量名 _this=this 进行接收。2.在鼠标划过地图时,默认有高亮颜色显示,可以通过绑定mouseover事件设置鼠标移入区域时颜色不变。

<template>
    <div class="mainDiv">
        <div class="titleDiv" @click="cascadeHenan">区域销售金额</div>
        <div class="chartDiv" ref="chart"></div>
    </div>
</template>

<script>
import HenanAreaMap from '@/assets/maps/HenanArea.json'
import elementResizeDetectorMaker from 'element-resize-detector'

const erd = elementResizeDetectorMaker()

export default {
    data() {
        return {
            chartData: {},
        }
    },
    name: 'CascadeMap',
    mounted() {
        this.getChartData().then(() => {
            // 数据请求到后渲染图表
            this.renderChart()
        })
    },
    beforeDestroy() {
        // 移除元素监听
        erd.uninstall(this.$refs.chart)
    },
    methods: {
        // 请求数据回来
        async getChartData() {
            this.chartData = await this.$axios({ url: 'sales/cas' })
        },
        cascadeHenan() {
            this.$EventBus.$emit('casAreaChart', '河南省')
        },
        // 渲染图表
        renderChart() {
            // 使用registerMap注册地图json数据
            this.$echarts.registerMap('HenanArea', HenanAreaMap)
            let myChart = this.$echarts.init(this.$refs.chart)
            let chartData = this.chartData
            var option = {
                tooltip: {},
                visualMap: {
                    min: 3000,
                    max: 30000,
                    left: 'left',
                    top: 'bottom',
                    text: ['高', '低'],
                    inRange: {
                        color: ['#e0ffff', '#5470C6'],
                    },
                    show: true,
                },
                series: [
                    {
                        name: '销额',
                        type: 'map',
                        map: 'HenanArea',
                        zoom: 1.2,
                        label: {
                            show: true,
                            fontSize: 14,
                            color: '#640000',
                            formatter: '{b}\n{c}',
                        },
                        data: chartData.data.areaData,
                        select: {
                            itemStyle: {
                                // 设置地图点击后的颜色
                                color: null,
                            },
                        },
                    },
                ],
            }
            // 使用刚指定的配置项和数据显示图表
            myChart.setOption(option)
            // 设置点击事件,和市区销售额数据进行图表联动
            // 因为echarts当中的this并不是vue的实例vueComponent,需要定义一个变量名接收
            let _this = this
            myChart.on('click', function (params) {
                _this.$EventBus.$emit('casAreaChart', params.name)
            })
            // 设置鼠标移入区域颜色不变
            myChart.on('mouseover', function (params) {
                if (params.data.value != undefined) {
                    myChart.dispatchAction({
                        type: 'downplay',
                    })
                }
            })
            // 监听图表所在容器,大小有变化时自适应
            erd.listenTo(this.$refs.chart, function () {
                myChart.resize()
            })
        },
    },
}
</script>

<style scoped>
.titleDiv {
    cursor: pointer;
}
</style>

2.在柱状图组件中进行EventBus监听接收事件,接收地图组件传递过来的区域参数,然后更新echarts配置数据。当然,在柱状图组件被销毁前,需要把EventBus监听事件给移除,以免下次再重复创建监听。参考代码:

<template>
    <div class="mainDiv">
        <div class="titleDiv">{{ title }}</div>
        <div class="chartDiv" ref="chart"></div>
    </div>
</template>

<script>
import elementResizeDetectorMaker from 'element-resize-detector'

const erd = elementResizeDetectorMaker()

export default {
    data() {
        return {
            chartData: {},
            title: '河南省各市销售额',
        }
    },
    name: 'CascadeBar',
    mounted() {
        this.getChartData().then(() => {
            // 数据请求到后渲染图表
            this.renderChart()
        })
        // EventBus监听接收事件
        this.$EventBus.$on('casAreaChart', (data) => {
            this.title = data + '各市销售额'
            let myChart = this.$echarts.getInstanceByDom(this.$refs.chart)
            if (data == '河南省') {
                myChart.setOption({
                    xAxis: {
                        data: this.chartData.data.allCityData.city,
                    },
                    series: [
                        {
                            data: this.chartData.data.allCityData.amount,
                        },
                    ],
                })
            } else {
                myChart.setOption({
                    xAxis: {
                        data: this.chartData.data.areaCityData[data].city,
                    },
                    series: [
                        {
                            data: this.chartData.data.areaCityData[data].amount,
                        },
                    ],
                })
            }
        })
    },
    beforeDestroy() {
        // 移除EventBus监听
        this.$EventBus.$off('casAreaChart')
        // 移除元素监听
        erd.uninstall(this.$refs.chart)
    },
    methods: {
        // 请求数据回来
        async getChartData() {
            this.chartData = await this.$axios({ url: 'sales/cas' })
        },
        // 渲染图表
        renderChart() {
            let myChart = this.$echarts.init(this.$refs.chart)
            let chartData = this.chartData
            var option = {
                tooltip: {
                    show: true,
                    textStyle: {
                        color: '#000000',
                        fontStyle: 'normal',
                        fontSize: 14,
                        align: 'center',
                    },
                },
                legend: {
                    show: true,
                    data: ['销额'],
                    icon: 'roundRect',
                    x: 'center',
                    y: 'bottom',
                    padding: [0, 0, 10, 0],
                    textStyle: {
                        fontStyle: 'normal',
                        fontSize: 12,
                    },
                },
                grid: {
                    top: '10%',
                    bottom: '10%',
                    left: '3%',
                    right: '3%',
                    containLabel: true,
                },
                xAxis: {
                    type: 'category',
                    data: chartData.data.allCityData.city,
                    axisTick: {
                        show: true,
                        alignWithLabel: true,
                    },
                    axisLabel: {
                        show: true,
                        interval: 0,
                    },
                    splitLine: {
                        show: false,
                    },
                },
                yAxis: {
                    type: 'value',
                    splitLine: {
                        // 分隔线设置
                        show: true,
                        lineStyle: {
                            color: ['#E5EAF3'],
                            width: 1,
                            type: 'dashed',
                        },
                    },
                },
                series: [
                    {
                        name: '销额',
                        type: 'bar',
                        data: chartData.data.allCityData.amount,
                        label: {
                            show: true,
                            position: 'top',
                            fontSize: 11,
                        },
                        itemStyle: {
                            // 顺时针设置圆角:左上、右上、右下、左下
                            borderRadius: [6, 6, 0, 0],
                            // 根据值的情况设置不同颜色
                            color: function (params) {
                                let colorList = ['#5470C6', '#91CC75', '#FAC858', '#EE6666']
                                let amount = params.data
                                if (amount >= 7000) {
                                    return colorList[0]
                                } else if (amount < 7000 && amount >= 5000) {
                                    return colorList[1]
                                } else if (amount < 5000 && amount >= 3000) {
                                    return colorList[2]
                                } else {
                                    return colorList[3]
                                }
                            },
                        },
                    },
                ],
            }
            // 使用刚指定的配置项和数据显示图表
            myChart.setOption(option)
            // 监听图表所在容器,大小有变化时自适应
            erd.listenTo(this.$refs.chart, function () {
                myChart.resize()
            })
        },
    },
}
</script>

<style scoped>
.titleDiv {
    cursor: pointer;
}
</style>

3.至此,图表联动处理完成,启动Vue项目,查看联动效果。

3.小节总结

    当多个ECharts图表呈现的数据存在关系时,有时需要能够进行图表联动。在本小节中,通过使用EventBus解决组件间通信,并配合echarts实例中点击事件绑定实现了图表间的联动。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值