蓝戒的博客


echart图表自适应宽度失效问题探究

前情介绍:

最近做的一个vue项目中,使用echart图表组件展示数据,展示方式是点击按钮弹出弹层,在弹层中展示图表,使用vue组件方式:通过监听数据变化,在调用图表组件的页面中使用如下方法刷新数据:

this.$nextTick(function() {
 // 在这里赋值图表数据,渲染视图
})


问题描述:

弹出层的图表展示有时无法100%自适应宽度,图表数据展示如果是在页面中正常初始化就展示没有问题,但是如果是在初始化的弹层里默认为display:none,弹层显示的时候,图表自适应宽度计算会有一定几率出现宽度不准,查看dom节点样式设置宽度为100px,canvas宽度设置100px。

分析原因:

echart自适应中使用resize()方法,监听窗口的变化来修改echart图表来实现自适应,然而在初始化时样式为隐藏,弹出展示不能很好的计算弹层宽度,而使用了100%的宽度值为100px,出现自适应宽度样式显示不正常问题。

解决思路:

是点击弹层是动态设置组件宽度为固定值,监听弹层宽度变化自适应修改图表canvas宽度值。

示例:

1) 页面调用组件:

    <bar-chart-obj :width="echartWidth" :chart-data="barChartDataObj" />

2) 组件源码:

<template>
  <div :class="className" :style="{height:height,width:width}" @click="handleSetBarChartData(chartData)" />
</template>

<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import { debounce } from '@/utils'

export default {
  props: {
    className: {
      type: String,
      default: 'chart'
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: String,
      default: '350px'
    },
    autoResize: {
      type: Boolean,
      default: true
    },
    chartData: {
      type: Object,
      required: true
    }
  },
  data() {
    return {
      chart: null
    }
  },
  watch: {
    chartData: {
      deep: true,
      handler(val) {
        this.setOptions(val)
      }
    }
  },
  mounted() {
    this.initChart()
    if (this.autoResize) {
      this.__resizeHandler = debounce(() => {
        if (this.chart) {
          this.chart.resize()
        }
      }, 100)
      window.addEventListener('resize', this.__resizeHandler)
    }
    // this.__resizeHandler = debounce(() => {
    //   if (this.chart) {
    //     this.chart.resize()
    //   }
    // }, 100)
    // window.addEventListener('resize', this.__resizeHandler)
    // 监听侧边栏的变化
    const sidebarElm = document.getElementsByClassName('sidebar-container')[0]
    sidebarElm.addEventListener('transitionend', this.__resizeHandler)
  },
  beforeDestroy() {
    // if (!this.chart) {
    //   return
    // }
    // window.removeEventListener('resize', this.__resizeHandler)
    // this.chart.dispose()
    // this.chart = null
    if (!this.chart) {
      return
    }
    if (this.autoResize) {
      window.removeEventListener('resize', this.__resizeHandler)
    }

    const sidebarElm = document.getElementsByClassName('sidebar-container')[0]
    sidebarElm.removeEventListener('transitionend', this.__resizeHandler)

    this.chart.dispose()
    this.chart = null
  },
  methods: {
    handleSetBarChartData(chartData) {
      this.$emit('handleSetBarChartData', chartData)
    },
    setOptions({ expectedData, actualData } = {}) {
      this.chart.setOption({
        color: ['#3398DB'],
        tooltip: {
          trigger: 'axis',
          axisPointer: { // 坐标轴指示器,坐标轴触发有效
            type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: [
          {
            type: 'category',
            data: expectedData, // ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
            axisTick: {
              alignWithLabel: true
            }
          }
        ],
        yAxis: [
          {
            type: 'value'
          }
        ],
        series: [
          {
            name: '消耗工时',
            type: 'bar',
            barWidth: '60%',
            data: actualData // [10, 52, 200, 334, 390, 330, 220]
          }
        ]
      })
    },
    initChart() {
      this.chart = echarts.init(this.$el, 'macarons')
      this.setOptions(this.chartData)
    }
  }
}
</script>

3) 页面自适应实现:

export default {
  data() {    
     return {
        echartWidth: '100%'
     }
  },
  mounted() {
    this.resetChart()
  },
  methods: {
    resetChart() {
      const that = this
      window.onresize = () =&gt; {
        return (() =&gt; {
          // 获取弹层里图标外层宽度
          var cardBoxUser = document.querySelector('.box-card-user.item')
          var canvasUserWidth = document.querySelector('.box-card-user.item .chart div')
          // 显示弹层时
          if (that.dialogUserDetail === true) {
            that.echartWidth = cardBoxUser.offsetWidth + 'px'
            canvasUserWidth.style.width = that.echartWidth
          }
        })()
      }
    }
  },
  watch: {
    echartWidth(val) {
      if (!this.timer) {
        this.echartWidth = val
        this.timer = true
        const that = this
        setTimeout(function() {
          // console.log(that.echartWidth)
          that.timer = false
        }, 400)
      }
    }
  }
}

OK,这样就解决了echart图表在弹层中自适应宽度失效问题啦。

本文固定链接: http://www.webzsky.com/?p=1284 | 蓝戒的博客

cywcd
该日志由 cywcd 于2018年10月09日发表在 javascript 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: echart图表自适应宽度失效问题探究 | 蓝戒的博客
关键字:

echart图表自适应宽度失效问题探究:等您坐沙发呢!

发表评论


快捷键:Ctrl+Enter
来自的朋友,欢迎您 点击这里 订阅我的博客 o(∩_∩)o~~~
×