Vue中使用ECharts畫散點圖加均值線與陰影區域


[本文出自天外歸雲的博客園]

需求

1. Vue中使用ECharts畫散點圖

2. 在圖中加入加均值線

3. 在圖中標注出陰影區域

實現

實現這個需求,要明確兩點:

1. 知道如何在vue中使用echarts

2. 要知道如何在echarts散點圖中畫均值線和陰影區域

在下面的代碼option對象的series屬性中用到了markLine和markArea,標注最值用到了markPoint。

所以去官方文檔搜索標線、標點、標圖的關鍵字要搜mark。

如何在vue中使用echarts見文末。

需要注意的是vue的渲染時序,不要在頁面沒有渲染完就開始畫圖,那會找不到你定位id的元素。

如何解決找不到元素的問題呢?網上說是在mounted函數中調用nextTick,這種方法可以試試,我是沒成功。所以我自己發明的解法如下:

以下的方法要放到vue文件的watch中,目的是監控showInfo和findAll兩個變量的值的變化,一旦變量值變化則執行調用:

showInfo: function() {
  // 元素顯示了開始畫線,待優化,可以細分到不用showInfo控制,用每個chart的v-if分別進行控制,因為有時候可能沒有圖表數據
  if (this.showInfo === true) {
    this.findAll = false
    this.timer = setInterval(() => {
      this.findElements()
    }, 1000)
  }
},
findAll: function() {
  if (this.findAll === true) {
    console.log('Timer stop.')
    clearInterval(this.timer)
  }
}

其中用到的變量都要在data函數中聲明賦適當的初始值:

1. this.showInfo控制頁面元素的v-if顯示開關,而showInfo變量的初始值一般為false,在mounted函數中我們可以把它的值設置為true,等頁面加載完后打開顯示開關

2. this.timer是定時器,這里用到setInterval函數做一個定時的查詢,用來定時查找頁面上用來畫echarts的div是否已經出現在頁面,都找到了就停止定時查找

3. this.findAll是一個signal,一旦為true說明所有元素都已找到,立即清空定時器this.timer,不再定時查詢

以下代碼放到vue文件的methods中,是watch變量所用到的一些輔助函數:

findElements() {
  if (this.findEleById('test_id_1')) {
    this.if_find_test_img_1_id = true
  }
  if (this.findEleById('test_id_2')) {
    this.if_find_test_img_2_id = true
  }
  if (this.findEleById('test_id_3')) {
    this.if_find_test_img_3_id = true
  }
  if (this.if_find_test_img_1_id && this.if_find_test_img_2_id && this.if_find_test_img_3_id) {
    this.findAll = true
  }
},
findEleById(ele_id) {
  var ele = document.getElementById(ele_id)
  if (ele !== null) {
    console.log('發現id為' + ele_id + '的元素')
    return true
  }
  return false
}

ECharts設置相關的核心代碼如下:

<template>
  <el-row>
    <el-col :span="24">
      <div id="chartDivId" :style="{width: '100%', height: '500px'}"></div>
    </el-col>
  </el-row>
</template>
<script>
export default{
  data() {
    return {
      imgData : {
        'columns': ['c1','c2','c3'],
        'rows': [
          {
            'c1': 'v1',
            'c2': 'v2',
            'c3': 'v3'
          },
        ],
        'mean': 2,
        'y_top': 3,
        'y_bottom': 1
      },
      methods: {
        // 畫圖函數,傳入散點圖所在div的id和圖表數據
        drawImgChart(chartDivId, imgData) {
          // 基於准備好的dom,初始化echarts實例
          const myChart = this.$echarts.init(document.getElementById(chartDivId))// 繪制圖表
          var option = {
            tooltip: {
              trigger: 'axis',
              showDelay: 0,
              axisPointer: {
                show: true,
                type: 'cross',
                lineStyle: {
                  type: 'dashed',
                  width: 1
                }
              }
            },
            visualMap: {
              min: 0,
              max: imgData.mean, // 漸變色最深色對應的y軸坐標
              dimension: 1,
              precision: 3,
              orient: 'vertical',
              right: 10,
              top: 'center',
              text: ['HIGH', 'LOW'],
              calculable: true,
              inRange: {
                color: ['#f2c31a', '#24b7f2']
              }
            },
            xAxis: [
              {
                type: 'category',
                show: false,
                scale: true,
                splitLine: {
                  show: true
                },
                data: imgData.columns, // x軸的數據
                axisLabel: {
                  interval: 0,
                  rotate: 70
                }
              }
            ],
            yAxis: [
              {
                type: 'value',
                scale: true,
                splitLine: {
                  show: true
                },
                axisLabel: {
                  formatter: '{value} s' // y軸數據的格式 xx s
                }
              }
            ],
            series: [
              {
                type: 'scatter',
                symbolSize: 5,
                data: imgData.rows,
                // 設置最大值點和最小值點
                markPoint: {
                  data: [
                    { type: 'max', name: '最大值' },
                    { type: 'min', name: '最小值' }
                  ]
                },
                // 設置平均值線
                markLine: {
                  lineStyle: {
                    normal: {
                      type: 'solid'
                    }
                  },
                  data: [
                    {
                      name: '平均值線',
                      yAxis: imgData.mean // 數值類型,對應y軸坐標
                    }
                  ]
                },
                // 設置陰影區域
                markArea: {
                  silent: true,
                  itemStyle: {
                    normal: {
                      color: '#E8E8E8',
                      borderWidth: 1,
                      borderType: 'dashed'
                    }
                  },
                  data: [[{
                    name: '正常值范圍區間',
                    yAxis: imgData.y_top // 陰影區域上邊界
                  }, {
                    yAxis: imgData.y_bottom // 陰影區域下邊界
                  }]]
                }
              }
            ]
          }
          myChart.setOption(option)
        }
      }
    }
  }
}

談談封裝

有時候封裝的不好不如不封裝,封裝對外的接口如果不是大家需要的功能,反而相當於給被封裝的對象關上了一道門,拒人於封裝之外。

比如eleme和baidu維護的兩版針對vue使用的vchart,我覺得現在的封裝程度就是能用一些echart的基本功能,很多細節都沒有封裝好。

所以,即使vue不推薦直接操作dom元素,但是這次要在散點圖中畫線我還是選擇用原裝的echarts。

更多資料

1. ECharts官網在線調試散點圖

2. Vue項目中如何使用ECharts


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM