文章目录
- ⭐前言
- ⭐使用dataZoom api实现echart的同步缩放
- 💖 vue2实现echarts多图表同步缩放
- 💖 vue3实现echarts多图表同步缩放
- ⭐结束
⭐前言
大家好!我是yma16,本文分享在vue2和vue3中配置echarts的多图表同步缩放
背景:
解决echarts的多图表x轴同步联动的问题
⭐使用dataZoom api实现echart的同步缩放
echarts的datazoom api对外暴露
原理:
echarts的实例存在datazoom缩放的方法,
所以只需要在datazoom事件触发其他图表的datazoom即可实现同步缩放
dispatchAction({type: 'dataZoom',// 可选,dataZoom 组件的 index,多个 dataZoom 组件时有用,默认为 0dataZoomIndex: number,// 开始位置的百分比,0 - 100start: number,// 结束位置的百分比,0 - 100end: number,// 开始位置的数值startValue: number,// 结束位置的数值endValue: number
})
注意:
x轴的范围要一致,不然可能会出现偏移
💖 vue2实现echarts多图表同步缩放
用变量记录echarts的实例,渲染完毕再触发datazoom
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>echarts 滚动事件</title><!-- vue2 生产环境版本,优化了尺寸和速度 --><script src="https://cdn.jsdelivr.net/npm/vue@2"></script><script src="./echarts.js"></script></head><style>#app {position: absolute;height: 100vh;width: 100vw;}</style><body><div id="app"><div>first<div id="first" style="width: 900px;height:400px;"></div>second<div id="second" style="width: 900px;height:400px;"></div>third<div id="third" style="width: 900px;height:400px;"></div></div></div><script type="text/javascript">const instanceVue = {el: '#app',name: 'ecahrts',data() {return {firstChart: null,secondChart: null,thirdChart: null,maxNum:1000,};},mounted() {this.initSecondData()this.initThirdData()this.initFirstData()},methods: {initFirstData() {// 基于准备好的dom,初始化echarts实例var myChart = echarts.init(document.getElementById('first'));// 指定图表的配置项和数据let base = +new Date(1968, 9, 3);let oneDay = 24 * 3600 * 500;let date = [];let data = [Math.random() * 300];for (let i = 1; i < this.maxNum; i++) {var now = new Date((base += oneDay));date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));data.push(Math.round((Math.random() - 0.5) * 20 + data[i - 1]));}const option = {tooltip: {trigger: 'axis',position: function(pt) {return [pt[0], '10%'];}},title: {left: 'center',text: 'Large Area Chart'},toolbox: {feature: {dataZoom: {yAxisIndex: 'none'},restore: {},saveAsImage: {}}},xAxis: {type: 'category',boundaryGap: false,data: date},yAxis: {type: 'value',boundaryGap: [0, '100%']},dataZoom: [{type: 'inside',start: 0,end: 10},{start: 0,end: 10}],series: [{name: 'Fake Data',type: 'bar',symbol: 'none',sampling: 'lttb',itemStyle: {color: 'rgb(255, 70, 131)'},areaStyle: {color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{offset: 0,color: 'rgb(255, 158, 68)'},{offset: 1,color: 'rgb(255, 70, 131)'}])},data: data}]};// 使用刚指定的配置项和数据显示图表。myChart.setOption(option);// 监听this.firstChart = myChart;this.asyncZoom()},asyncZoom() {const that = thisthis.firstChart.on('datazoom', function(params) {[that.secondChart, that.thirdChart].forEach(item => {console.log('item',item)item && item.dispatchAction({ // 触发 dataZoom 事件type: 'dataZoom',zoomLock: true, // 锁定整个图表的缩放功能xAxisIndex: params.xAxisIndex, // xAxisIndex 为当前操作的 xAxisIndex,用于确定对应的 xAxis 对象yAxisIndex: params.yAxisIndex, // yAxisIndex 为当前操作的 yAxisIndex,用于确定对应的 yAxis 对象start: params.start, // start 为当前操作的时间范围起始值end: params.end // end 为当前操作的时间范围结束值});})})},initSecondData() {// 基于准备好的dom,初始化echarts实例const myChart = echarts.init(document.getElementById('second'));// 指定图表的配置项和数据let base = +new Date(1968, 9, 3);let oneDay = 24 * 3600 * 500;const date = []const yData1 = [Math.random() * 300]const yData2 = [Math.random() * 100]for (let i = 1; i < this.maxNum; i++) {var now = new Date((base += oneDay));date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'))yData1.push(Math.round((Math.random() - 0.5) * 20 + yData1[i - 1]));yData2.push(Math.round((Math.random() - 0.5) * 20 + yData2[i - 1]));}const option = {title: {text: 'line'},tooltip: {trigger: 'axis'},legend: {},toolbox: {show: true,feature: {dataZoom: {yAxisIndex: 'none'},dataView: {readOnly: false},magicType: {type: ['line', 'bar']},restore: {},saveAsImage: {}}},xAxis: {type: 'category',boundaryGap: false,data: date},yAxis: {type: 'value',axisLabel: {formatter: '{value} °C'}},series: [{name: 'Highest',type: 'line',data: yData1,markPoint: {data: [{type: 'max',name: 'Max'},{type: 'min',name: 'Min'}]},markLine: {data: [{type: 'average',name: 'Avg'}]}},{name: 'Lowest',type: 'line',data: yData2,markPoint: {data: [{name: '周最低',value: -2,xAxis: 1,yAxis: -1.5}]},markLine: {data: [{type: 'average',name: 'Avg'},[{symbol: 'none',x: '90%',yAxis: 'max'},{symbol: 'circle',label: {position: 'start',formatter: 'Max'},type: 'max',name: '最高点'}]]}}]};myChart.setOption(option);this.secondChart = myChart;},initThirdData() {// 基于准备好的dom,初始化echarts实例const myChart = echarts.init(document.getElementById('third'));// 指定图表的配置项和数据let base = +new Date(1968, 9, 3);let oneDay = 24 * 3600 * 500;const date = []const yData1 = [Math.random() * 300]for (let i = 1; i < this.maxNum; i++) {var now = new Date((base += oneDay));date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'))yData1.push(Math.round((Math.random() - 0.5) * 20 + yData1[i - 1]));}option = {toolbox: {show: true,feature: {dataZoom: {yAxisIndex: 'none'},dataView: {readOnly: false},magicType: {type: ['line', 'bar']},restore: {},saveAsImage: {}}},tooltip:{trigger:'axis'},legend: {},grid: {left: '3%',right: '4%',bottom: '3%',containLabel: true},xAxis: [{type: 'category',boundaryGap: false,data: date}],yAxis: [{type: 'value',}],series: [{name: 'Direct',type: 'bar',data: yData1}]};myChart.setOption(option);this.thirdChart = myChart;}}}// 实例化new Vue(instanceVue);</script></body>
</html>
代码在insidecode,如下运行即可
效果:
💖 vue3实现echarts多图表同步缩放
用state存储echarts实例,渲染完之后触发dataZoom
<template><div><!-- 折线图--><div id="first" :style="{ width, height }"></div><!-- 柱状图--><div id="second" :style="{ width, height }"></div><div id="third" :style="{ width, height }"></div><div id="fourth" :style="{ width, height }"></div></div>
</template>
<script lang="ts" setup>import { reactive, onMounted } from 'vue';import * as echarts from 'echarts';const state: any = reactive({maxNum: 100,// 折线图lineChart1: null,// 柱状图1barChart1: null,// 柱状图2barChart2: null,// 柱状图3barChart3: null,});function asyncZoom() {console.log(' state.lineChart1', state.lineChart1);state?.lineChart1?.on('datazoom', function (params) {[state.barChart1, state.barChart2, state.barChart2, state.barChart3].forEach((item) => {console.log('item', item);item &&item.dispatchAction({// 触发 dataZoom 事件type: 'dataZoom',zoomLock: true, // 锁定整个图表的缩放功能xAxisIndex: params.xAxisIndex, // xAxisIndex 为当前操作的 xAxisIndex,用于确定对应的 xAxis 对象yAxisIndex: params.yAxisIndex, // yAxisIndex 为当前操作的 yAxisIndex,用于确定对应的 yAxis 对象start: params.start, // start 为当前操作的时间范围起始值end: params.end, // end 为当前操作的时间范围结束值});});});}function renderLineChart4(val: any): any {// const { setOptions } = useECharts(chartLineRef1 as Ref<HTMLDivElement>);const myChart = echarts.init(document.getElementById('fourth'));if (!myChart) {return;}// 指定图表的配置项和数据let base = +new Date(1968, 9, 3);let oneDay = 24 * 3600 * 500;const date = [];const yData1 = [Math.random() * 300];for (let i = 1; i < state.maxNum; i++) {var now = new Date((base += oneDay));date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));yData1.push(Math.round((Math.random() - 0.5) * 20 + yData1[i - 1]));}const option = {toolbox: {show: true,feature: {dataZoom: {yAxisIndex: 'none',},dataView: {readOnly: false,},magicType: {type: ['line', 'bar'],},restore: {},saveAsImage: {},},},legend: {},grid: {left: '3%',right: '4%',bottom: '3%',containLabel: true,},xAxis: [{type: 'category',boundaryGap: false,data: date,},],yAxis: [{type: 'value',},],series: [{name: 'Direct',type: 'bar',data: yData1,},],};console.log('option', option);myChart.setOption(option, true);// dom.setOption(option, true);state.barChart3 = myChart;}function renderLineChart3(val: any): any {// const { setOptions } = useECharts(chartLineRef1 as Ref<HTMLDivElement>);const myChart = echarts.init(document.getElementById('third'));if (!myChart) {return;}// 指定图表的配置项和数据let base = +new Date(1968, 9, 3);let oneDay = 24 * 3600 * 500;const date = [];const yData1 = [Math.random() * 300];for (let i = 1; i < state.maxNum; i++) {var now = new Date((base += oneDay));date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));yData1.push(Math.round((Math.random() - 0.5) * 20 + yData1[i - 1]));}const option = {toolbox: {show: true,feature: {dataZoom: {yAxisIndex: 'none',},dataView: {readOnly: false,},magicType: {type: ['line', 'bar'],},restore: {},saveAsImage: {},},},legend: {},grid: {left: '3%',right: '4%',bottom: '3%',containLabel: true,},xAxis: [{type: 'category',boundaryGap: false,data: date,},],yAxis: [{type: 'value',},],series: [{name: 'Direct',type: 'bar',data: yData1,},],};console.log('option', option);myChart.setOption(option, true);// dom.setOption(option, true);state.barChart2 = myChart;}function renderLineChart2(val: any): any {// const { setOptions } = useECharts(chartLineRef1 as Ref<HTMLDivElement>);const myChart = echarts.init(document.getElementById('second'));if (!myChart) {return;}let base = +new Date(1968, 9, 3);let oneDay = 24 * 3600 * 500;const date = [];const yData1 = [Math.random() * 300];const yData2 = [Math.random() * 100];for (let i = 1; i < state.maxNum; i++) {var now = new Date((base += oneDay));date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));yData1.push(Math.round((Math.random() - 0.5) * 20 + yData1[i - 1]));yData2.push(Math.round((Math.random() - 0.5) * 20 + yData2[i - 1]));}const option = {title: {text: 'line',},tooltip: {trigger: 'axis',},legend: {},toolbox: {show: true,feature: {dataZoom: {yAxisIndex: 'none',},dataView: {readOnly: false,},magicType: {type: ['line', 'bar'],},restore: {},saveAsImage: {},},},xAxis: {type: 'category',boundaryGap: false,data: date,},yAxis: {type: 'value',axisLabel: {formatter: '{value} °C',},},series: [{name: 'Highest',type: 'line',data: yData1,markPoint: {data: [{type: 'max',name: 'Max',},{type: 'min',name: 'Min',},],},markLine: {data: [{type: 'average',name: 'Avg',},],},},{name: 'Lowest',type: 'line',data: yData2,markPoint: {data: [{name: '周最低',value: -2,xAxis: 1,yAxis: -1.5,},],},markLine: {data: [{type: 'average',name: 'Avg',},[{symbol: 'none',x: '90%',yAxis: 'max',},{symbol: 'circle',label: {position: 'start',formatter: 'Max',},type: 'max',name: '最高点',},],],},},],};console.log('option', option);myChart.setOption(option, true);// dom.setOption(option, true);state.barChart1 = myChart;}function renderLineChart1(val: any): any {// const { setOptions } = useECharts(chartLineRef1 as Ref<HTMLDivElement>);const myChart = echarts.init(document.getElementById('first'));if (!myChart) {return;}// 指定图表的配置项和数据let base = +new Date(1968, 9, 3);let oneDay = 24 * 3600 * 500;let date = [];let data = [Math.random() * 300];for (let i = 1; i < state.maxNum; i++) {var now = new Date((base += oneDay));date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));data.push(Math.round((Math.random() - 0.5) * 20 + data[i - 1]));}const option = {tooltip: {trigger: 'axis',position: function (pt) {return [pt[0], '10%'];},},title: {left: 'center',text: 'Large Area Chart',},toolbox: {feature: {dataZoom: {yAxisIndex: 'none',},restore: {},saveAsImage: {},},},xAxis: {type: 'category',boundaryGap: false,data: date,},yAxis: {type: 'value',boundaryGap: [0, '100%'],},dataZoom: [{type: 'inside',start: 0,end: 10,},{start: 0,end: 10,},],series: [{name: 'Fake Data',type: 'bar',symbol: 'none',sampling: 'lttb',itemStyle: {color: 'rgb(255, 70, 131)',},data: data,},],};console.log('option', option);myChart.setOption(option, true);state.lineChart1 = myChart;asyncZoom();}onMounted(() => {renderLineChart4();renderLineChart3();renderLineChart2();renderLineChart1();});
</script>
效果
⭐结束
本文分享结束, 💖 感谢你的阅读💖
如有不足或者错误欢迎指出!