Turf.js 的使用(一)


Turf.js 是一個開源的空間分析庫,由 Mapbox 提供。源碼地址,在其官網中都有 Mapbox 作為底圖的示例。

並且在 Mapbox 官網也推薦使用 Turf.js 作為空間分析庫。

用 Turf.js 是因為最近一個項目中要用到線的分隔等功能,因為使用的是高德地圖,對這一項空間分析、拓撲的功能不足,所以找到了這個庫。

一、功能

主要使用的功能:

1、線的交點--lineIntersect

給定兩條線,返回兩條線的交點,交點個數可以是:0、1、2……n個

從源碼中可知,就是遍歷兩條線的線段(每兩個點位一個線段),根據其坐標范圍得到是否有交點,有交點再計算交點位置。

下面是高德地圖的示例(用 MouseTool 畫線)

    sliceLine() {
      if (this.gaodeMap) {
        if (this.aMapSliceLine) {
          this.gaodeMap.baseMap.remove(this.aMapSliceLine)
          this.aMapSliceLine = null
          this.gaodeMap.baseMap.remove(this.intersectPointMarker)
          this.intersectPointMarker = []
        }
        this.gaodeMap.baseMap.setDefaultCursor('crosshair')
        this.gaodeMap.drawPolyline({ strokeColor: '#33FF66', strokeWeight: 4 })

        this.mouseToolEvent &&
          this.gaodeMap.amapApi.event.removeListener(this.mouseToolEvent)
        this.mouseToolEvent = this.gaodeMap.amapApi.event.addListener(
          this.gaodeMap.mouseTool,
          'draw',
          event => {
            this.aMapSliceLine = event.obj
            this.gaodeMap.baseMap.setDefaultCursor('pointer')
            this.gaodeMap.mouseTool.close()

            // 進行交點計算
            if (this.aMapLine) {
              let line1 = [],
                line2 = []
              this.aMapLine.getPath().map(item => {
                line1.push([item.lng, item.lat])
              })
              this.aMapSliceLine.getPath().map(item => {
                line2.push([item.lng, item.lat])
              })

              let intersectPoint = lineIntersect(
                lineString(line1),
                lineString(line2)
              )
              intersectPoint.features &&
                intersectPoint.features.map(item => {
                  this.intersectPointMarker.push(
                    this.gaodeMap.addMarker({
                      position: item.geometry.coordinates
                    })
                  )
                })
            }
            this.mouseToolEvent &&
              this.gaodeMap.amapApi.event.removeListener(this.mouseToolEvent)
          }
        )
      }
    }

2、線上的點分隔線--lineSlice

根據給定起始點和結束點,返回兩點間的線,不在要分隔的線上面,就找這兩點離線最近的點,作為分隔點。

3、分隔線--lineSplit

這個分隔線,用來分隔的可以是點、多點、線、多線、面等,對於非點的,第一步會找出和被分割線的交點,再根據這些點分隔線。(即最終都是用電分隔)

下面是切割線的高德地圖示例(MouseTool 畫線)

    // 切割線
    splitLine() {
      if (this.gaodeMap) {
        if (this.aMapSplitLine) {
          this.gaodeMap.baseMap.remove(this.aMapSplitLine)
          this.aMapSplitLine = null
          this.gaodeMap.baseMap.remove(this.splitLines)
          this.splitLines = []
        }
        this.gaodeMap.baseMap.setDefaultCursor('crosshair')
        this.gaodeMap.drawPolyline({ strokeColor: '#dd3333', strokeWeight: 4 })

        this.mouseToolEvent &&
          this.gaodeMap.amapApi.event.removeListener(this.mouseToolEvent)
        this.mouseToolEvent = this.gaodeMap.amapApi.event.addListener(
          this.gaodeMap.mouseTool,
          'draw',
          event => {
            this.aMapSplitLine = event.obj
            this.gaodeMap.baseMap.setDefaultCursor('pointer')
            this.gaodeMap.mouseTool.close()

            // 進行切割
            if (this.aMapLine) {
              let line1 = [], line2 = []
              this.aMapLine.getPath().map(item => {
                line1.push([item.lng, item.lat])
              })
              this.aMapSplitLine.getPath().map(item => {
                line2.push([item.lng, item.lat])
              })

              let split = lineSplit(
                lineString(line1),
                lineString(line2)
              )
              split.features &&
                split.features.map(item => {
                  this.splitLines.push(
                    this.gaodeMap.drawLine({
                      path: item.geometry.coordinates,
                      strokeColor: randomColor2(),
                      strokeWeight: 3,
                    })
                  )
                })
            }
            this.mouseToolEvent &&
              this.gaodeMap.amapApi.event.removeListener(this.mouseToolEvent)
          }
        )
      }
    }

二、線的差集

在實現了線的分隔、高亮等。在編輯的時候需要回顯,那么一條父級線以及有了分隔線,要對剩下的線進行分隔,那么久要對父級線和子級線進行差集計算。

查找了 Truf.js 和別的庫,沒有發現這樣的功能,看來只能自己根據自己的實際業務需求寫了。

具體業務下的思路

線的差集(子線一定是父線的子集,那么可以特殊考慮下面幾種情況)

1、子線和父線一致,差集為空;

2、子線的開始點是父線開始點:父線切除子線中共同的部分,子線終點作為父線的起點;

3、子線的結束點是父線結束點:父線切除子線中共同的部分,子線起點作為父線的終點;

4、子線是父線中間部分:父線切除子線中共同的部分,子線起點為切割線段1的終點,子線終點為切割線2的起點點;

對於4中,可能子線的兩端是父線中的節點,對於畫線分隔這樣的概率很小,所以在這里沒有考慮(視情況是否考慮)。

下面是代碼實現(線的坐標轉為字符串)

    // 子級線和父級線的差集計算
    getLineDifference(parentPointStrList, sonPointStr) {
      const newParentPointStrList = []
      parentPointStrList.map(parentPointStr => {
        const temp = sonPointStr.slice(1, -1).split('],')
        const startPoint = temp[0] + ']'
        const startPoints = temp.slice(0, -1).join('],') + ']'
        const endPoint = temp[temp.length - 1]
        const endPoints = temp.slice(1).join('],')
        const centerPoints = temp.slice(1, -1).join('],') + ']'

        if (parentPointStr.indexOf(sonPointStr) > -1) {
          console.log('相同')
        } else if (parentPointStr.indexOf(startPoints) > -1) {
          newParentPointStrList.push(parentPointStr.replace(startPoints, endPoint))
        } else if (parentPointStr.indexOf(endPoints) > -1) {
          newParentPointStrList.push(parentPointStr.replace(endPoints, startPoint))
        } else if (parentPointStr.indexOf(centerPoints) > -1) {
          newParentPointStrList.push(parentPointStr.split(centerPoints)[0] + startPoint + ']')
          newParentPointStrList.push('[' + endPoint + parentPointStr.split(centerPoints)[1])
        } else {
          newParentPointStrList.push(parentPointStr)
        }
      })

      return newParentPointStrList
    }

 


免責聲明!

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



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