使用echarts折線圖拖拽點及加點功能實現

最近在實現一個需求,需要改造echarts的折線圖,在其基礎上實現點的拖拽及點擊操作,效果如下:

實現方案

拖拽點

這個方法網上有說,原理:就是在折線的點位置上新增對應的拖拽點,並把拖拽點覆蓋在原點上面,設置其visible爲false,做到以假亂真的效果。

      // 初始化echarts
      let sideView = this.$refs.sideView;
      if (!this.chart) {
        this.chart = echarts.init(sideView);
        this.chart.setOption(this.option);

        this.chart.getZr().on('click', (params) => {
          this.lineClickHandler(params)
        })

        this.chart.on('dataZoom', (params) => {
          this.getDragedPointer()
        })
      }
 // 新增圖形:透明的可操作的點
            self.chart.setOption({
              graphic: data.map((item, dataIndex) => {
                // 獲取對應的物理像素點
                let positionPoint = self.chart.convertToPixel({ seriesIndex: 0 }, item);
                // 記錄原始的點信息 相對的點信息
                self.lastCircleInfo[dataIndex] = positionPoint;
                return {
                  type: 'circle',
                  position: positionPoint,
                  shape: {
                    cx: 0,
                    cy: 0,
                    r: self.symbolSize
                  },
                  invisible: true, // 設置隱藏
                  draggable: true,
                  z: 1000,
                  ondrag: function () {
                    let [lastX, lastY] = self.lastCircleInfo[dataIndex];
                    // Y不變 更改
                    data[dataIndex] = self.chart.convertFromPixel({ seriesIndex: 0 }, [this.x, lastY]);
                    self.chart.setOption({
                      series: [{
                        id: 'line',
                        data: data
                      }]
                    });

                    // 修改了Z需要放到數據中 ...業務處理
                    
                    self.lastCircleInfo[dataIndex] = [this.x, lastY];
                  },
                  onmousedown: function () {
                    self.mouseDownFlag = true;
                  },
                  onmouseup: function () {
                    self.chartMouseUp();
                  },
                  onmousemove: function () {
                    self.chart.dispatchAction({
                      type: 'showTip',
                      seriesIndex: 0,
                      dataIndex: dataIndex
                    });
                  },
                  onmouseout: function () {
                    self.chart.dispatchAction({
                      type: 'hideTip'
                    });
                  }
                };
              })
            })

新增點

原理:從點擊位置找到它的前後點,根據前後點把新增點放到對應的點index座標中。由於我的業務場景更復雜,還需要通過獲取到的點信息,轉換出其他的點信息

 // 點擊折線新增點信息
    lineClickHandler (params) {
      let self = this;
      const { target, topTarget } = params;
      // 判斷必須是點擊在線上
      if (self.addPoint && (target?.type === 'ec-polyline' || topTarget?.type === 'ec-polyline')) {
        // 獲取在chart上的像素座標點
        const pointInPixel = [params.offsetX, params.offsetY];

        // 獲取點擊的點的前後點
        let { points3d, points } = this.vm.currentDrawData;

        // 獲取當前折線上有的點信息 lastCircleInfo 是在繪製點的時候記錄的點信息
        let circleInfo = []
        for (let i in this.lastCircleInfo) {
          let circle = this.lastCircleInfo[i];
          let [cicleX, circleY] = circle;
          circleInfo.push([cicleX, circleY, Number(i)]);
        }

        // 獲取點擊的點到折線點的最短距離,距離最短的可以理解爲是點在線上
        let prePoint = null;
        let nextPoint = null;
        circleInfo.find((item, itemIndex) => {
          let flag = false;
          circleInfo.find((unit, unitIndex) => {
            // 相鄰的點纔有線  距離短纔是在線上的
            if (itemIndex !== unitIndex && Math.abs(itemIndex - unitIndex) === 1) {
              let dis = this.getShortestDistance([params.offsetX, params.offsetY], [unit[0], unit[1]], [item[0], item[1]]);
              if (dis === 0) {
                flag = true;
                prePoint = item;
                nextPoint = unit;
                return true;
              }
            }
          })
          if (flag) {
            return true;
          }
        })
        
        // 獲取前後點後 將新增的點放到對應的位置上
        if (prePoint && nextPoint) {
          let prePointIndex = prePoint[2];
          let nextPointIndex = nextPoint[2];

          // 根據像素點獲取折線上的的點 注意折線上的點記錄的是3D的z 和 2D的y 
          prePoint = points3d[prePointIndex];
          nextPoint = points3d[nextPointIndex];
          let [z, yy] = this.chart.convertFromPixel({ seriesIndex: 0 }, pointInPixel);

          // 需要獲取到3D的xy,這裏根據 【插值法】通過z 計算出x 和 y 的值
          const prez1 = Math.abs(prePoint[2]);
          const nextz1 = Math.abs(nextPoint[2]);
          const startPrecent = Math.abs((z - prez1) / (nextz1 - prez1));

          const x = prePoint[0] * (1 - startPrecent) + nextPoint[0] * startPrecent;
          const y = prePoint[1] * (1 - startPrecent) + nextPoint[1] * startPrecent;

          // 插入3D點
          points3d.splice(prePointIndex + 1, 0, [x, y, z]);

          // 獲取2D的點         
          let prePoint2D = points[prePointIndex];
          let nextPoint2D = points[nextPointIndex];

          const x2d = prePoint2D[0] * (1 - startPrecent) + nextPoint2D[0] * startPrecent;
          const y2d = prePoint2D[1] * (1 - startPrecent) + nextPoint2D[1] * startPrecent;
          // 插入2D
          points.splice(prePointIndex + 1, 0, [x2d, y2d]);

          // 更新視圖
          this.updateCurrentDrawData();
        }
      }
    },

關於插值法的說明

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章