添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
精彩文章免费看

echarts 趋势图拖拽缩放的方式配置y轴方向的上下限,附源码

接上一篇: echarts 直角坐标系中多个系列多个y轴展示方案
因为最近比较忙,一直没时间写这个。之前有小伙伴在评论区留言想要知道这个效果怎么写的,这里把代码贴下。

这个点击上下缩放的效果是之前别的项目上的,在某些特殊功能上还是比较有用的。但因为封装的功能和我这边的需求不一致,而且不是很好理解,然后我就参考了下代码自己写了一套,有需要的小伙伴可以参考下,主要是思路。

效果图 (简书这个图片经常加载不出来,不知道你们是否能看到下面这个gif)

1.点击线条高亮,这里采用的是降低其他线条的透明度
2.初始可以缩放,初始时需要重新更改y轴的max和min,扩大范围
3.在y轴缩放时需要将dataZoom事件返回的start,end换算为 startValue 和 endValue,因为start,end是百分比,我们扩大了纵向的范围的,不能使用百分比
4.为了不让x轴跳动,组件内设置x轴的onZero为false,脱离y轴0刻度
5.保留x轴缩放功能,内部缩放的方式在高亮时被禁用,slider方式无限制

二、扩展功能,可以定时刷新图表需要考虑的功能点有:

1.需要保证选择线的高亮不变
2.y轴缩放不变
3.x轴缩放不变
4.legend的选中状态不变
以上功能都需要在各自触发时将信息存储起来,由组件内部会在合适的地方记录这些信息,initYZoom方法第三个参数是是否开启状态继承,默认是true,即后续chart更新将保留之前的状态

当前代码需要的依赖包

"echarts": "^5.3.3","element-ui": "^2.7.2","vue": "^2.5.2","less": "^3.9.0","less-loader": "^4.1.0"
注意:这是vue2的demo!,vue3可自行修改代码

代码如下 github地址

dragLineMixin.js 这里用mixin的方式,可自行更改为你喜欢的方式

* 纵向缩放chart扩展插件 * @author:yangfeng * @time: 20220817 注意事项: 1.y轴必须是value类型,使用前提dataZoom需要指定xAxisIndex 和yAxisIndex 2.可以不设置y轴max,min,不设置会取对应系列的最大最小值,若设置了则初始以设置的为准 3.每个y轴都必须有一个唯一dataZoom匹配,因为缩放的是dataZoom 4.保留横向缩放功能 5.因为y轴要缩放用,则x轴会被设置为脱离y轴0刻度 export default { data() { return { yDataZoomTimer: null,// y轴缩放时用于节流 saveInfo: {}, // 存储缩放后的状态信息,针对定时任务的场景 methods: { isNull(val) { return val === null || val === void 0 || val === '' || (val).toString() === 'NaN' // y轴缩放配置 start ---------------- // 清除用于节流缩放的定时器 clearYDataZoomTimer() { this.yDataZoomTimer && clearTimeout(this.yDataZoomTimer) // 重新给y轴赋值足够大的max,min值【这样初始就可以缩放】,并给对应y轴dataZoom赋值startValue和endValue setYMaxMin(option) { if (!option || !option.yAxis) return if (!Array.isArray(option.yAxis)) { // y轴修改为数组 option.yAxis = [option.yAxis] option.yAxis.map((item, yAxisIndex) => { let { } = this.getSeriesItemYMaxMin(option, option.series.find(subItem => subItem.yAxisIndex === yAxisIndex)) // 根据数据获取最大最小值 // 没有给y轴设置最大最小值,则使用数据中的极值 let yMax = !this.isNull(item.max) ? item.max : max let yMin = !this.isNull(item.min) ? item.min : min // console.log(item, max, min,) // console.log('xxx', yMax, yMin) // 修改当前y轴对应的dataZoom startValue和endValue let findZoom = option.dataZoom.find(subItem => subItem.yAxisIndex === yAxisIndex) if (findZoom) { // 有对应的dataZoom delete findZoom.start delete findZoom.end let seriesItem = option.series.find(subItem => subItem.yAxisIndex === yAxisIndex) findZoom.startValue = yMin findZoom.endValue = yMax findZoom.id = `yZoom-${yAxisIndex}-${seriesItem.name}` // seriesItem,给对应dataZoom赋值id this.$set(findZoom, 'disabled', true) // 给option的dataZoom设置此属性,重要!! // 重新设置最大最小值, 放大缩小最大最小值,这样初始就可以拖动了 - 解决初始没法拖动的问题 let rang = Math.abs(yMax - yMin) item.max = yMax + rang * 10000 // 这里设置一万倍 item.min = yMin - rang * 10000 // 让x轴脱离y轴0刻度 if (Array.isArray(option.xAxis)) { option.xAxis.map(item => { !item.axisLine && (item.axisLine = {}) item.axisLine.onZero = false } else { !option.xAxis.axisLine && (option.xAxis.axisLine = {}) option.xAxis.axisLine.onZero = false * 获取当前系列的y值最大最小值 * @option: chart 的optin配置 * @seriesItem:需要找极值的series项 * @return {max,min} getSeriesItemYMaxMin(option, seriesItem) { let yDATA = [] // 取出对应series的y值 seriesItem.data.map(item => { // 取出 if (this.isNull(item)) return if (Array.isArray(item)) { // 数组取第二项 yDATA.push(item[1]) } else if (typeof item === 'object') { // 针对echarts 的data数据类型进行取值 yDATA.push(item.value) } else { // 数值类型 yDATA.push(item) // 取出对应series的y值最大最小值 return { max: Math.max(...yDATA), min: Math.min(...yDATA) // 关闭缩放并取消高亮 closeZoomHighLight(option) { option.dataZoom.map(item => { if (item.type !== 'slider') { // slider的保持缩放, item.disabled = true // 取消高亮 // myChart.dispatchAction({ // type: 'downplay', // seriesIndex: option.series.map((item, index) => index) // }); // console.log(option, 111) // 设置透明度来达到高亮效果 option.series.map(item => { !item.lineStyle && (item.lineStyle = {}) item.lineStyle.opacity = 1 !item.itemStyle && (item.itemStyle = {}) item.itemStyle.opacity = 1 * 高亮缩放指定seriesIndex的项,只有高亮的系列或者slider类型的才能缩放 openZoomHighLight(option, seriesIndex) { let yAxisIndex = option.series[seriesIndex].yAxisIndex let findItem = option.dataZoom.find(item => item.yAxisIndex === yAxisIndex) findItem.disabled = false // myChart.dispatchAction({ // type: 'highlight', // seriesIndex: seriesIndex // }); // 设置透明度来达到高亮效果 option.series.map(item => { !item.lineStyle && (item.lineStyle = {}) item.lineStyle.opacity = 0.3 !item.itemStyle && (item.itemStyle = {}) item.itemStyle.opacity = 0.3 option.series[seriesIndex].lineStyle.opacity = 1 option.series[seriesIndex].itemStyle.opacity = 1 // console.log(option.series) * 点击到系列上,高亮此系列 * @option * @seriesIndex:需要高亮系列的索引 highLightSeries(option, seriesIndex) { if (seriesIndex !== null && seriesIndex > -1) { this.closeZoomHighLight(option) // 关闭所有缩放 this.openZoomHighLight(option, seriesIndex) // 开启缩放并选中 * 取消高亮系列 closeHighLightSeries(option) { this.closeZoomHighLight(option) // 关闭所有缩放 // 开启x轴缩放 - 没有指定yAxisIndex的,认定为x轴 option.dataZoom.map(item => { if (this.isNull(item.yAxisIndex)) { item.disabled = false * 开启y轴缩放功能 * @option:该echarts的option * @chartInstance: echart 渲染的实例,用于绑定事件 * @keepAlive: Boolean 是否继承上次的缩放状态,针对定时刷新图表情况,能保留之前x,y缩放、高亮、legend选中状态 * Object:若是对象类型,该对象将会和之前存储的saveInfo对象合并【针对某些不需要完全继承上次状态的场景,在改组件外部修改了状态信息,需要以修改的为准】 initYZoom(option, chartInstance, keepAlive = true) { if (!chartInstance) { console.error('echarts 实例不存在, 开启y轴缩放失败') return // option属性赋值 this.setYMaxMin(option) // 重新给y轴赋值max,min值 // 给x轴对应的系列赋值id option.dataZoom.map((item, index) => { if (!item.id) { item.id = `${item.xAxisIndex}-${item.type}-${index}-zoom` // console.log(option, 6666) if (keepAlive) { // 继承上次缩放状态 this.extendZoomInfo(option, chartInstance, keepAlive) } else { this.saveInfo = {} // 清空 // 利用getZr方法获取点击事件,点击开启缩放 chartInstance.getZr().on('click', (params) => { // console.log(params, 222) let target = params.target if (target) { // 点击线条,开启缩放 let seriesIndex = target.seriesIndex || null // 【注意:echarts 版本不一样这里可能不一样】 if (!seriesIndex) { Object.keys(target).map(key => { if (~key.indexOf('__ec_inner_')) { 'seriesIndex' in target[key] && (seriesIndex = target[key].seriesIndex) this.highLightSeries(option, seriesIndex) } else { // 未点击线条,闭关缩放功能并取消高亮 this.closeHighLightSeries(option) this.$emit('dataYZoom', params, this.saveZoomInfo(option)) // 将缩放后的上下限抛出,方便父组件使用 // 因为在取消缩放后 echarts并没有保存缩放值,而且还需要对超出显示范围的缩放进行处理。因此这里需要dataZoom方法 chartInstance.on('dataZoom', (params) => { // console.log(params, 'dataZoom') let dataZoomId; // 缩放的dataZoom id let start; // 当前缩放开始百分比 let end; // 当前缩放结束百分比 if (params.batch) { // 【注意:echarts 版本不一样这里可能不一样】 let data = params.batch[0] dataZoomId = data.dataZoomId // 当前缩放的dataZoom start = data.start end = data.end } else { dataZoomId = params.dataZoomId start = params.start end = params.end // 对x轴缩放时,存储start end if (dataZoomId && !dataZoomId.startsWith('yZoom-')) { this.setXDataZoom(option, chartInstance, {id: dataZoomId, start, end}) // 存储x轴缩放信息 // 换算为比例 start = start / 100 end = end / 100 this.clearYDataZoomTimer() // 清除定时器 // 对某条线进行缩放时,将对应y轴dataZoom的startValue和endValue重新赋值【因为更改了y轴min和max,直接返回的start 和end是百分比,不能直接使用】 if (dataZoomId && dataZoomId.startsWith('yZoom-')) { // 是y轴缩放的逻辑 // 根据y轴的最大最小值将当前缩放的start end 换算为startValue和endValue let currentDataZoom = option.dataZoom.find(item => item.id === dataZoomId) if (!currentDataZoom) return // 对应的y轴 let yAxisIndex = currentDataZoom.yAxisIndex let {max, min} = option.yAxis[yAxisIndex] // 这里的最大最小值是放大了区间后的值 let rang = Math.abs(max - min) let startValue = min + rang * start // 注意都是min开始的,因为start、end是占比 let endValue = min + rang * end // 注意都是min开始的,因为start、end是占比 // 处理边界条件,缩放时保证所有数据都在可视区域内 let seriesItem = option.series[yAxisIndex] // 获取对应的series项 let {max: yMax, min: yMin} = this.getSeriesItemYMaxMin(option, seriesItem) // console.log('y值', `${yMin}-${yMax}`,`${startValue}-${endValue}`) // 超出范围处理,保证缩放后的数据都在可视范围内 let dispatchZoom = false // 是否调用dispatchAction if (yMax > endValue) { endValue = yMax dispatchZoom = true if (yMin < startValue) { startValue = yMin dispatchZoom = true // console.log(currentDataZoom.startValue,'-',currentDataZoom.endValue) // 保存当前缩放值 currentDataZoom.startValue = startValue currentDataZoom.endValue = endValue if (dispatchZoom) { // 只有在超出界限的时候才需要调用这个,如果不限定每次都调用这个将会出现卡顿 this.yDataZoomTimer = setTimeout(() => { // 节流,防止数据量太大的卡顿 let dataZoomIndex = option.dataZoom.findIndex(item => item.id === dataZoomId) chartInstance.dispatchAction({ type: 'dataZoom', dataZoomIndex, // 开始位置的数值 startValue: startValue, // 结束位置的数值 endValue: endValue // console.log(startValue,'-', endValue, dataZoomIndex, option.dataZoom[dataZoomIndex]) this.$emit('dataYZoom', params, this.saveZoomInfo(option)) // 将缩放后的上下限抛出,方便父组件使用 // }) // legend 选择 chartInstance.on('legendselectchanged', (params) => { // console.log(params.selected, 555) this.saveZoomInfo(option, { legendSelected: params.selected // 记录legend的选中状态 // y轴缩放加载完成事件 this.$emit('dataYZoomFinished', this.saveZoomInfo(option)) * 获取y轴可缩放的对应系列当前上下限 * @option: chart的option 配置 * @return [{seriesName:系列名,upper:上限,lower:下限}] getSeriesUpperLower(option) { let arr = option.dataZoom.filter(item => item.id && item.id.startsWith('yZoom-')) let resArr = arr.map(item => { let IdInfo = item.id.split('-') return { seriesName: IdInfo[2], upper: item.endValue, // 上限 lower: item.startValue, // 下限 return resArr // 获取当前高亮的系列 getHighLightSeriesName(option) { let filterArr = option.series.filter(item => item.lineStyle && item.lineStyle.opacity === 1) // console.log(option,filterArr, 'nnn') if (filterArr.length > 1) { // 多个则说明没有选择 return '' } else if (filterArr.length === 1) { return filterArr[0].name } else { return '' * 缩放时存储x轴的缩放信息 setXDataZoom(option, chartInstance, {id, start, end}) { let findItem = option.dataZoom.find(item => item.id === id) let xAxisIndex = findItem.xAxisIndex || 0 // xAxisIndex可能为数组 // 将缩放相同x轴的dataZoom,缩放设置为当前值 option.dataZoom.map((item, index) => { if (Array.isArray(xAxisIndex) || Array.isArray(item.xAxisIndex)) { // 是数组 if (JSON.stringify(item.xAxisIndex) === JSON.stringify(xAxisIndex)) { item.start = start item.end = end } else if (item.xAxisIndex === xAxisIndex) { item.start = start item.end = end // chartInstance.dispatchAction({ // type: 'dataZoom', // index, // // 开始位置的数值 // start, // // 结束位置的数值 // end // }) // console.log(option, 'xxxxxxxx') this.saveZoomInfo(option) * 存储必要的缩放的信息,若有定时任务让图形可继承上次状态 * @option: 当前chart option * @obj:其他信息 saveZoomInfo(option, obj) { // console.log(option, 222) // x轴对应的dataZoom的缩放信息 let xDataZoomInfo = [] option.dataZoom.map(item => { if (!item.id.startsWith('yZoom-')) { xDataZoomInfo.push({ id: item.id, start: item.start, end: item.end let info = { seriesInfo: this.getSeriesUpperLower(option), // 每个系列的上下限 xDataZoomInfo, // x轴对应的dataZoom的缩放信息 highLightSeriesName: this.getHighLightSeriesName(option) // 当前高亮的seriesName this.saveInfo = { ...this.saveInfo, ...info, ...obj // console.log(info, 7777) return this.saveInfo // 继承之前的缩放状态 start ---------- extendZoomInfo(option, chartInstance, obj) { // 传递了对象的以对象为准 if (obj && typeof obj === 'object' && Object.keys(obj).length) { this.saveInfo = { ...this.saveInfo, ...obj if (!this.saveInfo || !Object.keys(this.saveInfo).length) return let oldInfo = this.saveInfo // console.log(this.saveInfo, 333) // 保持高亮状态 let seriesName = oldInfo.highLightSeriesName if (seriesName) { let seriesIndex = option.series.findIndex(item => item.name === seriesName) this.highLightSeries(option, seriesIndex) // 保持y轴缩放 let seriesInfo = oldInfo.seriesInfo if (seriesInfo && seriesInfo.length) { option.dataZoom.map(item => { if (item.id && item.id.startsWith('yZoom-')) { let IdInfo = item.id.split('-') let findInfo = seriesInfo.find(sub => sub.seriesName === IdInfo[2]) if (findInfo) { // 更新为上次的上下限 item.endValue = findInfo.upper item.startValue = findInfo.lower // 保持x轴缩放 let xDataZoomInfo = oldInfo.xDataZoomInfo if (xDataZoomInfo && xDataZoomInfo.length) { option.dataZoom.map(item => { if (!item.id.startsWith('yZoom-')) { let findInfo = xDataZoomInfo.find(sub => sub.id === item.id) if (findInfo) { item.start = findInfo.start item.end = findInfo.end // 继承之前legend的选中状态 let legendSelected = oldInfo.legendSelected // 格式如[true,false,xxx] if (option.legend && legendSelected && Object.keys(legendSelected).length) { option.legend.selected = legendSelected // 继承之前的缩放状态 end ---------- // y轴缩放配置 end ---------------- beforeDestroy() { this.clearYDataZoomTimer() // 清除定时器

dragLineChart.vue

可拖拽组件 <template> <div class="chart-base"> <div style="width:100%;height:100%;" :id="id" ref="chartRef"></div> <div v-if="isChartNull(option)" class="noData">暂无数据</div> </template> <script> import * as echarts from 'echarts' import dragLineMixin from './dragLineMixin' export default { name: 'dragLineChart', mixins: [dragLineMixin], data() { return { myChart: '', props: { id: { type: String, default: 'ChartBox' option: { type: Object, default() { return {} mounted() { // this.myChart = this.$echarts.init(this.$refs.chartRef) this.myChart = echarts.init(this.$refs.chartRef) this.drawLine() // this.initEvent() // event methods: { isChartNull(chartOption) { let bool = true if (chartOption && chartOption.series) { if (Object.prototype.toString.call(chartOption.series) === '[object Array]') { chartOption.series.map(item => { if (item.data && item.data.length) bool = false } else { chartOption.series.data && chartOption.series.data.length && (bool = false) return bool initEvents() { this.myChart.on('dataZoom', (params) => { this.$emit('dataZoom', params) drawLine() { // 绘制图表 this.myChart.clear() this.myChart.setOption(this.option) this.initEvents() resetChartData() { // 刷新数据 this.myChart.setOption(this.option, true) /* showLoading() { // 显示加载动画 this.myChart.showLoading() hideLoading() { // 关闭加载动画 this.myChart.hideLoading() watch: { option: { deep: true, handler: function (value) { this.resetChartData() beforeDestroy() { this.myChart && this.myChart.dispose() </script> <style scoped> .chart-base { position: relative; width: 100%; height: 100%; text-align: initial; .noData { width: 200px; height: 100px; line-height: 100px; position: absolute; left: 50%; top: 50%; margin-left: -100px; margin-top: -50px; font-size: 28px; </style>

index.vue 这个是调用的例子,模拟了数据

<template>
    <div class="wrap">
      <!--路径图2-->
      <div class="com-box">
        <h1>可拖拽缩放的方式配置上下限
          <el-button type="primary" @click="openTimerTick(true)" v-if="!timer">开启定时任务</el-button>
          <el-button type="primary" @click="openTimerTick(false)" v-else>关闭定时任务</el-button>
        <div class="flex-box">
          <div class="info">
              右侧趋势图上下限为:<br/>
              <template v-for="(item,index) in chartInfoArr">
                <div :style="{color: item.color}">{{ item.seriesName }}<br/>
                  <div class="input-box">
                    <span>下限:</span>
                    <el-input v-model="item.lower" type="number" :disabled="!!timer" placeholder="下限" :style="{color: item.color}" @change="changeUpLow"/>
                    <span>上限:</span>
                    <el-input v-model="item.upper" type="number" :disabled="!!timer" placeholder="上限" :style="{color: item.color}" @change="changeUpLow"/>
              </template>
          <div class="line-chart" style="height: 700px;">
            <drag-line-chart :option="chartOption"
                             @dataYZoom="chartDataZoom"
                             @dataYZoomFinished="(val)=>chartDataZoom(null,val)"
                             ref="dragLineChart"/>
</template>
<script>
import dragLineChart from './common/dragLineChart'
export default {
  name: 'eharts',
  components: {
    dragLineChart,
  data() {
    return {
      chartOption: {},
      chartData: [], // 记录chart原始数据
      chartDataMaxMin: { // 记录图表数据的上下限,格式{lineSeriesName:{max:xx,min:xx}}
      chartInfoArr: [], // 显示右侧图表的上下限并可编辑
      timer: null
  methods: {
    // 范围内随机数
    rand(m, n) {
      return Math.ceil(Math.random() * (n-m) + m)
    // 重新刷新chart
    changeUpLow() {
      let option = this.chartOption
      // console.log(option, 111)
      this.chartInfoArr.map(item => {
        this.chartDataMaxMin[item.seriesName] = { // 记录当前上下限
          max: +item.upper,
          min: +item.lower
      this.renderChart(this.chartData) // 修改上下限后重新渲染chart
    // 显示上下限具体信息
    chartDataZoom(params, ulInfoArr) {
      // console.log(ulInfoArr, 3333)
      let {color} = this.getOption()
      let chartInfoArr = []
      ulInfoArr.seriesInfo.map(({seriesName, upper, lower}) => {
        this.chartDataMaxMin[seriesName] = { // 记录当前上下限
          max: upper,
          min: lower
        let colorIndex = this.chartOption.series.findIndex(subItem => subItem.name === seriesName)
        chartInfoArr.push({
          color: color[colorIndex],
          seriesName,
          upper: (upper).toFixed(2),
          lower: (lower).toFixed(2)
      this.chartInfoArr = chartInfoArr
    getOption() {
      let option = {
        tooltip: {
          trigger: 'axis'
        legend: {},
        grid: [{
          show: false,
          left: '3%',
          right: '4%',
          bottom: 380,
          top: 50,
          containLabel: false
          show: false,
          left: '3%',
          right: '4%',
          bottom: 80,
          top: 400,
          containLabel: false
        xAxis: [{
          // scale:true,
          type: 'category',
          boundaryGap: false,
          splitLine: {show: false},
          gridIndex:0,
          // scale:true,
          type: 'category',
          boundaryGap: false,
          splitLine: {show: false},
          gridIndex:1,
        yAxis: [],
        series: []
      return {
        option,
        color: [
          '#fab83e',
          '#e733a3',
          '#7482f2',
          '#51bcff',
          '#47d5e4',
    renderChart(resData) {
      this.chartData = resData // 记录原始数据
      // console.log(resData, 11)
      // option赋值
      let {option, color} = this.getOption()
      let yAxis = [] // y轴
      let dataZoom = [ // 缩放设置
          type: 'inside',
          id: 'x-inside-zoom0',
          xAxisIndex: [0]
          type: 'slider',
          id: 'x-slider-zoom0',
          xAxisIndex: [0],
          top: 350,
          height:20,
          type: 'inside',
          id: 'x-inside-zoom1',
          xAxisIndex: [1]
          type: 'slider',
          id: 'x-slider-zoom1',
          xAxisIndex: [1],
          bottom:30,
          height:20
      resData.map((item, index) => {
        let {data, name} = item
        let maxMin = this.chartDataMaxMin[name]
        let showLine = false
        let gridIndex = index < 2 ? 0 : 1 // 前面两条线放上面,后面的放下面
        yAxis.push({
          type: 'value',
          max: maxMin.max, // 上下浮动
          min: maxMin.min,
          axisLine: {show: showLine},
          axisTick: {show: showLine},
          axisLabel: {show: showLine},
          splitLine: {show: showLine},
          gridIndex: gridIndex,
        option.series.push({
          name: name,
          type: 'line',
          triggerLineEvent: true,
          yAxisIndex: index,
          xAxisIndex:gridIndex,
          data: data,
          symbol: 'none',
          lineStyle: {
            color: color[index]
          itemStyle: {
            color: color[index]
          // animation:false
        dataZoom.push({
          type: 'inside',
          // disabled: true,
          yAxisIndex: index,
      option.yAxis = yAxis
      option.dataZoom = dataZoom
      // console.log(option, 5555)
      this.chartOption = option
      // 以外部设置线的上下限为准,不使用内部的y方向上下限,两种方式
      // 方式一:通过设置keepAlive.seriesInfo为对象的方式覆盖原有状态,这样y轴的max和min可以不指定
      // this.$refs['dragLineChart'].initYZoom(this.chartOption, this.$refs['dragLineChart'].myChart, {
      //   // 以当前上下限为准,y轴上下限交由外部控制,不传则完全交由内部控制
      //   seriesInfo: Object.keys(this.chartDataMaxMin).map(seriesName => {
      //     return {
      //       seriesName,
      //       lower: +this.chartDataMaxMin[seriesName].min,
      //       upper: +this.chartDataMaxMin[seriesName].max
      //     }
      //   })
      // })
      // 方式二:通过设置keepAlive.seriesInfo为false的方式,这样内部将以y轴的max,min作为上下限,因为这里手动维护了chartDataMaxMin
      this.$refs['dragLineChart'].initYZoom(this.chartOption, this.$refs['dragLineChart'].myChart, {seriesInfo:false})
    getChartData() {
      // 构造测试数据
      let resData = []
      for (let j = 0; j <= 4; j++) {
        resData.push({
          name: `line${j + 1}`,
          data: []
      for (let i = 1; i < 300; i++) {
        resData[0].data.push([i, this.rand(30, 100)])
        resData[1].data.push([i, this.rand(-30, -3)])
        resData[2].data.push([i, this.rand(5000, 6000)])
        resData[3].data.push([i, this.rand(0, 10)])
        resData[4].data.push([i, this.rand(800, 900)])
      // 构造初始数据的上下限
      resData.map(item => {
        let dataY = item.data.map(item => item[1])
        let max = Math.max(...dataY)
        let min = Math.min(...dataY)
        let jc = Math.abs(max - min)
        this.chartDataMaxMin[item.name] = {
          max: max + 0.1 * jc, // 上下浮动
          min: min - 0.1 * jc,
      this.renderChart(resData)
    // 定时任务相关 start --------------------
    // 清除定时器
    clearTimerTick() {
      this.timer && clearTimeout(this.timer)
      this.timer = null
    // 开启定时任务,模拟定时刷新数据的情况,
    openTimerTick(bool) {
      if (bool) {
        this.timer = setTimeout(() => {
          // 构造测试数据
          let resData = this.chartData
          let x = resData[0].data[resData[0].data.length - 1][0] + 1
          // 末尾追加一项
          resData[0].data.push([x, this.rand(30, 100)])
          resData[1].data.push([x, this.rand(-30, -3)])
          resData[2].data.push([x, this.rand(5000, 6000)])
          resData[3].data.push([x, this.rand(0, 10)])
          resData[4].data.push([x, this.rand(800, 900)])
          // 删除首项
          resData.map(item => {
            item.data = item.data.slice(1)
          this.renderChart(resData)
          this.openTimerTick(true)
        }, 1000)
      } else {
        this.clearTimerTick()
    // 定时任务相关 end --------------------
  mounted() {
    this.getChartData()
  beforeDestroy() {
    this.clearTimerTick()
</script>
<style scoped lang="less">
.wrap {
  background: #f8f8f8;
  overflow: hidden;
  display: flex;
  justify-content: space-around;
  /*flex-direction: ;*/
  flex-wrap: wrap;
  align-items: center;
.line-chart {
  width: 100%;
  height: 330px;
  flex: auto;
.com-box {
  margin: 60px;
  width: 100%;
  background: rgba(255, 255, 255, 1);
  box-shadow: -.02rem .07rem .15rem 1px rgba(203, 204, 204, 0.18);
  border-radius: .03rem;
  /*margin: 20px auto;*/
  box-sizing: border-box;
  padding: 15px 60px;
  /deep/ .el-input__inner{
    height: 35px;
    line-height: 35px;
.info {
  font-size: 20px;
  text-align: left;
  width: 1000px;
  margin-right: 10px;
  line-height: 40px;
  border: 1px solid #cccccc;
  box-sizing: border-box;
  padding: 5px;
.flex-box {
  display: flex;
  justify-content: space-between;
  align-content: flex-start;
  margin-top: 10px;
.input-box {
  display: flex;
  justify-content: space-between;
  align-content: center;
  margin-bottom: 5px;
  > span {
    align-self: center;
    flex: none;
    width: 50px;
    margin-right: 5px;
.content-info{
  text-align: left;
  line-height: 30px;
  font-size: 16px;
    padding: 10px;
</style>

组件使用注意事项:

1.每条线也就是每个series对应一个y轴,每个y轴对应一个dataZoom【纵向缩放原理其实就是借用的echarts 的dataZoom功能实现的】
2.在取得chart 实例后,最后调用initYZoom方法开启纵向缩放功能,内部需要chart 实例绑定事件,如click, 缩放,legend点击
3.这里组件通过mixin的方式嵌入到基础chart中【也可以单独抽离成js文件引入,但是需要在合适的地方将内部用于节流的定时器清除,vue 的$set也要修改,然后自己找准时机将chart更新】
4.组件支持使用多个x轴,保留缩放功能,但在高亮时禁用内部x轴缩放

可参考下面这个最基础配置帮助理解上面的代码,功能都是在这上面衍生出来的

option = {
  xAxis: [
      type: 'category',
      gridIndex: 0,
      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
      type: 'category',
      gridIndex: 1,
      data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  grid: [
      show: false,
      left: '3%',
      right: '4%',
      bottom: 380,
      top: 50,
      containLabel: false
      show: false,
      left: '3%',
      right: '4%',
      bottom: 80,
      top: 400,
      containLabel: false
  yAxis: [
      type: 'value',
      gridIndex: 0
      type: 'value',
      gridIndex: 1
  dataZoom: [
    // x轴缩放
      type: 'inside',
      top: 500,
      xAxisIndex: 0
      type: 'slider',
      top: 350,
      xAxisIndex: 0
      type: 'inside',
      xAxisIndex: 1
      type: 'slider',
      xAxisIndex: 1
    // y轴缩放
      type: 'inside',
      yAxisIndex: 0
      type: 'inside',
      yAxisIndex: 1
  series: [
      data: [150, 230, 224, 218, 135, 147, 260],
      type: 'line',
      xAxisIndex: 0,
      yAxisIndex: 0
      data: [150, 230, 224, 218, 135, 147, 260],
      type: 'line',
      xAxisIndex: 1,
      yAxisIndex: 1

若对你有帮助,请点个赞吧,若能打赏不胜感激,谢谢支持!
本文地址:https://www.jianshu.com/p/755db59cf4e4?v=1682584623209,转载请注明出处,谢谢。

最后编辑于:2023-04-28 10:52