vue2、vue3分别配置echarts多图表的同步缩放

news/2025/1/7 22:02:31/

文章目录

    • ⭐前言
    • ⭐使用dataZoom api实现echart的同步缩放
      • 💖 vue2实现echarts多图表同步缩放
      • 💖 vue3实现echarts多图表同步缩放
    • ⭐结束

⭐前言

大家好!我是yma16,本文分享在vue2和vue3中配置echarts的多图表同步缩放
背景:
解决echarts的多图表x轴同步联动的问题

⭐使用dataZoom api实现echart的同步缩放

echarts的datazoom api对外暴露
echarts-datazoom

原理:
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,如下运行即可


效果:
vue2-datazoom-chart

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

效果
vue3-dataZoom

⭐结束

本文分享结束, 💖 感谢你的阅读💖
如有不足或者错误欢迎指出!
scene-line-sky


http://www.ppmy.cn/news/411701.html

相关文章

XP经典壁纸,多少人曾爱慕你年轻时的容颜

本文转载自 IT之家&#xff0c;原文链接&#xff1a;Click me 如果你曾经使用过Windows XP操作系统的话&#xff0c;你就一定见过这张最为经典的桌面壁纸。据悉&#xff0c;这张蓝天白云绿草的壁纸被命名为“欢乐”&#xff08;Bliss&#xff09;&#xff0c;并很有可能是这个…

NOTA-(COOt-Bu)3-Bn-NCS:一款多功能四氮杂环螯合剂标记

文章关键词&#xff1a;双功能螯合剂&#xff0c;大环化合物&#xff0c;有机双功能DOTA&#xff0c;金属离子螯合剂&#xff0c;四氮杂环螯合剂标记 【产品描述】 NOTA及其衍生物是新型双功能整合剂之一。NOTA及其衍生物具有良好的配位和鳌合能力&#xff0c;可作为过渡金属离…

海康监控摄像头的萤石云远程访问

海康威视最国内最大的安防厂家之一&#xff0c;也是安防行业最具有影响力的厂家&#xff0c;市场上海康威视的产品占有率约为60%&#xff0c;特别是后端DVR与NVR产品在安防领域主导地位不可动摇&#xff0c;很多用户不清楚海康威视产品的远程设置&#xff0c;不能进行远程访问&…

小区的安防系统

声明 以下内容&#xff0c;来自KBdancer 作者原创&#xff0c;由于传播&#xff0c;利用此文所提供的信息而造成的任何直接或间接的后果和损失&#xff0c;均由使用者本人负责&#xff0c;长白山攻防实验室以及文章作者不承担任何责任。 0x01 前言 博主从小就是一个喜欢把事…

机房动环状态综合触摸屏监控解决方案

随着移动互联网、电子商务等迅速扩张&#xff0c;大型互联网企业的用户数再创新高&#xff0c;数据量爆发式增长&#xff0c;企业对IDC资源的需求越来越大。机房状态安全的重要性对于一个企业来说一直以来都是一个令人头疼的问题。因此&#xff0c;我们推出了动环状态网络触摸屏…

宇视网络视频录像机人机实况画面偏色排查步骤

步骤一 当我们发现人机实况画面出现偏色的情况&#xff0c;首先需要确认的是整个显示屏画面均偏色还是只有个别的实况通道画面偏色。若整个显示屏画面均偏色&#xff0c;我们下一步需要按步骤二进行排查&#xff0c;若只有个别的实况通道画面偏色&#xff0c;则按步骤四进行排…

智能穿戴显示屏怎样操作?智能穿戴显示屏具有怎么功能?

随着科技时代的来临&#xff0c;相信每一个人都有一台智能化设备。智能设备不仅在我们日常生活中随处可见&#xff0c;而且智能设备的发展已经渗透到了我们所能看到的每一个角落。智能穿戴技术作为中心是虚拟现实的技术&#xff0c;它不仅实现了便携收发通讯的功能&#xff0c;…

配电室环境监控系统的站端监控屏柜功能介绍

随着无人值守配电室的普及和贯彻&#xff0c;加强对配电室环境的监测&#xff0c;保障供电安全&#xff0c;已成为非常重要的工作。当电力设备出现故障或现场发生异常时&#xff08;如:设备短路、电缆温度过高、进水、非法闯入等&#xff09;&#xff0c;配电室环境监控系统能及…