切換語言為:簡體
為 echarts 圖表空白區域新增點選事件

為 echarts 圖表空白區域新增點選事件

  • 爱糖宝
  • 2024-08-16
  • 2060
  • 0
  • 0

客戶的需求

客戶是上帝,現在客戶說這個圖表上的點選事件不好操作,特別是在折線上點選時,我無法點中!這時專案經理說,像這樣在空白處有圖例顯示時就能點中可不可以?客戶說,中,我要的就是這個效果!

為 echarts 圖表空白區域新增點選事件

現實情況

你翻遍了echarts的官方文件,在echarts官方文件的事件欄目中有這樣一段話:在 ECharts 中事件分為兩種型別,一種是使用者滑鼠操作點選,或者 hover 圖表的圖形時觸發的事件,還有一種是使用者在使用可以互動的元件後觸發的行為事件,例如在切換圖例開關時觸發的 legendselectchanged 事件(這裏需要注意切換圖例開關是不會觸發 legendselected 事件的),資料區域縮放時觸發的 datazoom 事件等等。也就是說現實情況其實就是巧婦無米,在事件那塊的api中,所有的事件裡都沒有點選圖表空白地方觸發的,比如click事件,這個只能在點選到圖表要素上時才能觸發;

困局破解

到目前這地步,只看官方文件已經不解渴了,如果你還沒放棄,試著問下AI,它可能會給你提供一些思路,它能幫你省去看原始碼的功夫。在 ECharts 中,點選空白區域(即未繫結資料的區域)預設並不會觸發 click 事件,但是,ECharts 使用 ZRender 作為其渲染引擎,提供了對整個畫布進行事件監聽的能力。你可以透過監聽底層的渲染引擎(ZRender)的 click 事件來捕獲整個畫布上的點選事件,包括空白區域。

這就是說,我可以透過 myChart.getZr() 返回 ZRender 例項,然後監聽它上面的 click 事件,透過這種方式,就可以捕獲到整個圖表區域內的所有點選事件,無論你是否在資料點或圖形上。

我將信將疑地試了下:

this.$refs.flowChat.chart.getZr().on('click', (e) => {
        debugger
      })

為 echarts 圖表空白區域新增點選事件

除錯後發現果然進入了斷點,心裏驚喜萬分,程式設計師的快樂暴擊了。

抓住線索

前面已經找到了這個事件,這還不夠,我得透過這個事件回撥找到對我有用的引數,透過斷點監聽發現回撥包含了這些引數:

為 echarts 圖表空白區域新增點選事件 

有用的引數就是offsetX和offsetY,這兩個是當前滑鼠位置相對整個echart邊框的水平和垂直方向上的偏移量。根據這兩個引數,我就確定了滑鼠的位置,然後在滑鼠所有位置的垂直線上,肯定相交了一條資料,這條資料的x軸就可以拿到了,而我可以寫一個演算法,透過這個x軸的關係找到折線上的真實資料;

還需要一個api

這裏還有一個關鍵的api:convertFromPixel,在對應官方文件上有說明:轉換畫素座標值到邏輯座標系上的點。也就是說,雖然當前點選位置沒有折線經過,但我也可以透過前面點選獲取的偏移值offsetX和offsetY計算出當前點在座標軸上的真實x、y值,這個x值就是我要的,透過這個x值我可以遍歷y軸對應的series中的值,找到y值。還有一個api要用到,透過echart物件的getOption方法可以獲取到當前例項的所有option物件,這裏有你想要的series及其data。

// todo
this.$refs.flowChat.chart.getZr().on('click', (e) => {
        debugger
        getRealData(e.offsetX, e.offsetY)
})
getRealData() {
  const option = myChart.getOption()
  const series = option.series
  // todo
  // 透過e.offsetX和e.offsetY找到series中與點選點相交的那條資料。
}

還需要一個演算法

基本上到這一步,聰明的程式就不需要往下看了,自己動手啪啪啪寫完剩下的了。我這裏還是幫人幫到底,把我的演算法貼出來,即是記錄也可以幫到需要的人。

function getRealData(myChart, x, y) {
        const option = myChart.getOption()
        const series = option.series
        let nearestData = null
        let minDistance = Infinity

        series.forEach((s) => {
          if (s.type === 'line') {
            const data = s.data
            data.forEach((item) => {
              const coord = myChart.convertFromPixel({ seriesIndex: 0 }, [x, y])
              const distance = Math.abs(coord[0] - item[0])
              if (distance < minDistance) {
                minDistance = distance
                nearestData = {
                  seriesName: s.name,
                  data: item,
                  dataIndex: data.indexOf(item)
                }
              }
            })
          }
        })

        return nearestData
      }

透過getOption獲取到data物件之後,遍歷,然後透過convertFromPixel逆運算得到我想要的一個座標值(x,y),然後再遍歷data物件,將點選點的x值與data中存的x值相減並求絕對值,透過冒泡演算法尋找,差值最小的就是我要的資料。

還有小技能包喲

這裏要注意一點可能你會有疑問,就是data是一個數組,一般只會存有用的x或者y要素,但其實你在初始化series時,可以在新增了x、y要素之後再push一個完整的包含x、y的物件,這樣我的這個整個流程就成了一個閉環了,因為data是一個數組,透過上面的演算法找到了點選點與折線相交的x座標值就找到了索引然後就能找到對應的完整的x、y了。

ok,到這裏就結束了,盡情的在echart上點選吧,哪怕你瞄不準折線上的點也無所謂,儘管肓點,一定能選中!

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.