类名 common/sketchEditor/base/SketchEditorVideoBase.js
import { Evented, Feature, SketchDataType, ViewEventType } from '../../base'
import { Point, LineString, Polygon } from '../../base/geometry'
import { defaultValue, Log } from '../../util'
import SketchStyle from './SketchStyle'

/**
 * 草图编辑基类
 * @classdesc 草图编辑基类
 * @moduleEX SketchEditorModule
 * @extends Evented
 * @param {Object} options 构造参数
 * @param {VideoMapView} [options.mapView] 视图
 * @param {SketchStyle} [options.sketchStyle] 草图样式
 * @example
 * // ES5引入方式
 * const { SketchEditorVideo } = Zondy
 * // ES6引入方式
 * import { SketchEditorVideo } from "@mapgis/webclient-common"
 * // 新建一个草图编辑器,传入视频地图mapview
 * sketchEditorVideo = new SketchEditorVideo({
 *   mapView: videoMapView
 * })
 */
class SketchEditorVideoBase extends Evented {
  /**
   * @param {Object} options
   * @param {VideoMapView} options.mapView 视图
   * @param {SketchStyle} [options.sketchStyle] 草图样式
   */
  constructor(options) {
    super()
    options = defaultValue(options, {})
    if (!options.mapView) {
      Log.error('options.mapView is null!', options)
    }

    this._mapView = options.mapView

    this._coordTransfomrs = defaultValue(
      this._mapView.videoPixelCoordTransforms,
      undefined
    )

    this._mouseEventHandlers = null

    this.sketchStyle = defaultValue(options.sketchStyle, new SketchStyle())

    this._sketchDataType = null

    this._pointGeomtry = null
    this._lineGeomtry = null
    this._polygonGeomtry = null
    this._textGeomtry = null
  }

  /**
   * 像素坐标与地理坐标转换矩阵
   * @readonly
   * @type {VideoPixelCoordTransforms}
   */
  get coorTransfomrs() {
    return this._coordTransfomrs
  }

  /**
   * 开始草图编辑
   * @function SketchEditorVideoBase.prototype.start
   * @param {SketchDataType} dataType 草图编辑类型
   */
  start(dataType) {
    this._stopCurrentGraphicDrawing()
    this.clearGeometry()
    this._mapView._enabledMouseEvent('auto')
    switch (dataType) {
      case SketchDataType.POINT:
        this._sketchDataType = SketchDataType.POINT
        this._drawPoint()
        break
      case SketchDataType.POLYLINE:
        this._sketchDataType = SketchDataType.POLYLINE
        this._drawLine()
        break
      case SketchDataType.POLYGON:
        this._sketchDataType = SketchDataType.POLYGON
        this._drawPolygon()
        break
    }
  }

  /**
   * 结束草图编辑
   * @function SketchEditorVideoBase.prototype.stop
   */
  stop() {
    this._stopCurrentGraphicDrawing()

    this.clearGeometry()

    this._mapView._enabledMouseEvent('none')
  }

  /**
   * 获取当前草图数据类型
   * @function SketchEditorVideoBase.prototype.getSketchDataType
   * @returns {SketchDataType}
   */
  getSketchDataType() {
    return this._sketchDataType
  }

  /**
   * 获取几何
   * @function SketchEditorVideoBase.prototype.getGeometry
   * @returns {Geometry}
   */
  getGeometry() {
    if (this._sketchDataType === SketchDataType.POINT) {
      if (this._pointGeomtry) {
        const geometry = new Point({
          coordinates: this._pointGeomtry.geometry.coordinates
        })
        geometry._pixelCoords = this._pointGeomtry.geometry._pixelCoords
        return geometry
      }
    } else if (this._sketchDataType === SketchDataType.POLYLINE) {
      if (this._lineGeomtry) {
        const geometry = new LineString({
          coordinates: this._lineGeomtry.geometry.coordinates
        })
        geometry._pixelCoords = this._lineGeomtry.geometry._pixelCoords
        return geometry
      }
    } else if (this._sketchDataType === SketchDataType.POLYGON) {
      if (this._polygonGeomtry) {
        const geometry = new Polygon({
          coordinates: this._polygonGeomtry.geometry.coordinates
        })
        geometry._pixelCoords = this._polygonGeomtry.geometry._pixelCoords
        return geometry
      }
    }
  }

  /**
   * 删除编辑中的几何
   * @function SketchEditorVideoBase.prototype.clearGeometry
   */
  clearGeometry() {
    if (this._pointGeomtry) {
      this._mapView.graphics.remove(this._pointGeomtry)
    }
    if (this._lineGeomtry) {
      this._mapView.graphics.remove(this._lineGeomtry)
    }
    if (this._polygonGeomtry) {
      this._mapView.graphics.remove(this._polygonGeomtry)
    }
    if (this._textGeomtry) {
      this._mapView.graphics.remove(this._textGeomtry)
    }
    this._pointGeomtry = null
    this._lineGeomtry = null
    this._polygonGeomtry = null
    this._textGeomtry = null
  }

  isSketchValid() {}

  /**
   * 设置草图样式
   * @function SketchEditorVideoBase.prototype.setSketchStyle
   * @param {SketchStyle} sketchStyle
   * @example
   * // ES5引入方式
   * const { SimpleFillSymbol, SimpleLineSymbol } = Zondy.Symbol
   * const { Color, SketchStyle } = Zondy
   * // ES6引入方式
   * import { SimpleFillSymbol, SimpleLineSymbol, Color, SketchStyle } from "@mapgis/webclient-common"
   * // 新建一个填充样式
   * const fillStyle = new SimpleFillSymbol({
   *   color: new Color(0, 255, 255, 1),
   *   outline: new SimpleLineSymbol({
   *     color: new Color(255, 0, 0, 1),
   *     width: 2
   *   })
   * })
   * // 新建一个草图样式
   * const sketchStyle = new SketchStyle({
   *   // 传入填充样式给区注记使用
   *   fillStyle: fillStyle,
   *   // 绘制线注记时显示分段长度
   *   isShowSegmentLength: true,
   *   // 绘制区注记时显示面积
   *   isShowArea: true
   * })
   * sketchEditorVideo.setSketchStyle(sketchStyle)
   */
  setSketchStyle(sketchStyle) {
    this.sketchStyle = sketchStyle
  }

  /**
   * 获取草图样式
   * @function SketchEditorVideoBase.prototype.getSketchStyle
   * @returns {SketchStyle}
   */
  getSketchStyle() {
    return this.sketchStyle
  }

  _stopCurrentGraphicDrawing() {
    if (this._mouseEventHandlers) {
      this._mouseEventHandlers.forEach((handler) => {
        this._mapView.off(ViewEventType.mouseDown, handler)
        this._mapView.off(ViewEventType.mouseUp, handler)
        this._mapView.off(ViewEventType.mouseMove, handler)
        this._mapView.off(ViewEventType.doubleClick, handler)
      })
      this._mouseEventHandlers = null
    }
  }

  /**
   * @private
   */
  _getGraphic() {
    if (this._sketchDataType === SketchDataType.POINT) {
      const geometry = new Point({
        coordinates: [0, 0, 0]
      })
      const symbol = this.sketchStyle.vertexStyle
      const pointGeometry = new Feature({
        geometry,
        symbol
      })

      return pointGeometry
    } else if (this._sketchDataType === SketchDataType.POLYLINE) {
      const geometry = new LineString({
        coordinates: [
          [0, 0],
          [1, 1]
        ]
      })
      const symbol = this.sketchStyle.lineStyle
      const lineGeometry = new Feature({
        geometry,
        symbol
      })
      lineGeometry.isShowSegmentLength = this.sketchStyle.isShowSegmentLength
      if (lineGeometry.isShowSegmentLength) {
        lineGeometry._textStyle = this.sketchStyle.textStyle
      }
      return lineGeometry
    } else if (this._sketchDataType === SketchDataType.POLYGON) {
      const geometry = new Polygon({
        coordinates: [
          [
            [0, 0],
            [0, 0],
            [0, 0],
            [0, 0]
          ]
        ]
      })
      const symbol = this.sketchStyle.fillStyle
      const polygonGeometry = new Feature({
        geometry,
        symbol
      })
      polygonGeometry.isShowArea = this.sketchStyle.isShowArea
      if (polygonGeometry.isShowArea) {
        polygonGeometry._textStyle = this.sketchStyle.textStyle
      }
      return polygonGeometry
    }
  }

  /**
   * @private
   */
  _drawPoint() {
    const handler = (options) => {
      // 这个判断需要优化
      if (options.target && options.target.type === 'circle') {
        return
      }
      const position = options.pointer
      const pixelCoord = { x: position.x, y: position.y }
      const graphic = this._getGraphic()
      const geoCoord = this._mapView.pixelCoordToGeoCoord(
        new Point({ coordinates: [pixelCoord.x, pixelCoord.y] })
      )
      graphic.geometry.coordinates = geoCoord.coordinates
      graphic.geometry._pixelCoords = pixelCoord
      this._mapView.graphics.add(graphic)
      // 保存point的点坐标
      this._pointGeomtry = graphic

      this._stopCurrentGraphicDrawing()
    }
    this._mouseEventHandlers = this._mouseEventHandlers
      ? this._mouseEventHandlers
      : []
    this._mouseEventHandlers.push(handler)
    this._mapView.on(ViewEventType.mouseUp, handler)
  }

  _drawLine() {
    let movePosition
    let timer = null
    let isStartDrawing = false
    let isDrawing = false
    /** @type {Feature} */
    let graphic = null
    let pixelCoords = []
    let lineSpots = []

    const handlerUp = (options) => {
      clearTimeout(timer)
      const position = options.pointer

      // 保存编辑的折线点
      const pixelCoord = { x: position.x, y: position.y }
      const geoCoord = this._mapView.pixelCoordToGeoCoord(
        new Point({ coordinates: [pixelCoord.x, pixelCoord.y] })
      )
      if (!graphic) {
        pixelCoords.push(pixelCoord, pixelCoord)
        lineSpots.push(geoCoord.coordinates, geoCoord.coordinates)
        graphic = this._getGraphic()
        graphic.geometry.coordinates = lineSpots
        graphic.geometry._pixelCoords = pixelCoords
        this._mapView.graphics.add(graphic)

        // 保存当前编辑中的geometry
        this._lineGeomtry = graphic
      } else {
        pixelCoords.push(pixelCoord)
        lineSpots.push(geoCoord.coordinates)
        graphic.geometry._pixelCoords = pixelCoords
        graphic.geometry.coordinates = lineSpots
      }

      // 判断是否是双击
      timer = setTimeout(() => {
        isStartDrawing = true
      }, 500)
    }

    const handlerMove = (options) => {
      movePosition = options.pointer
      if (!isStartDrawing) {
        return
      }
      isDrawing = true

      const pixelCoord = { x: movePosition.x, y: movePosition.y }
      pixelCoords[pixelCoords.length - 1] = pixelCoord

      const geoCoord = this._mapView.pixelCoordToGeoCoord(
        new Point({ coordinates: [pixelCoord.x, pixelCoord.y] })
      )
      lineSpots[lineSpots.length - 1] = geoCoord.coordinates

      graphic.geometry._pixelCoords = pixelCoords
      graphic.geometry.coordinates = lineSpots
    }

    const handlerDoubleClick = (options) => {
      clearTimeout(timer)
      // 清除双击时单击事件添加的多余点
      lineSpots.pop()
      pixelCoords.pop()

      lineSpots.pop()
      pixelCoords.pop()
      // 清除最后一个点
      lineSpots.pop()
      pixelCoords.pop()
      graphic.geometry._pixelCoords = pixelCoords
      graphic.geometry.coordinates = lineSpots

      if (!isDrawing) {
        graphic = null
        lineSpots = []
        pixelCoords = []
        return
      }
      const position = options.pointer
      const pixelCoord = { x: position.x, y: position.y }
      const geoCoord = this._mapView.pixelCoordToGeoCoord(
        new Point({ coordinates: [pixelCoord.x, pixelCoord.y] })
      )
      pixelCoords.push(pixelCoord)
      lineSpots.push(geoCoord.coordinates)
      graphic.geometry._pixelCoords = pixelCoords
      graphic.geometry.coordinates = lineSpots

      graphic = null
      lineSpots = []
      pixelCoords = []
      isDrawing = false
      isStartDrawing = false

      this._stopCurrentGraphicDrawing()
    }
    this._mouseEventHandlers = this._mouseEventHandlers
      ? this._mouseEventHandlers
      : []

    this._mouseEventHandlers.push(handlerUp, handlerMove, handlerDoubleClick)
    this._mapView.on(ViewEventType.mouseUp, handlerUp)
    this._mapView.on(ViewEventType.mouseMove, handlerMove)
    this._mapView.on(ViewEventType.doubleClick, handlerDoubleClick)
  }

  _drawPolygon() {
    let movePosition
    let timer = null
    let isStartDrawing = false
    let isDrawing = false
    /** @type {Feature} */
    let graphic = null
    let pixelCoords = []
    let polygonSpots = []

    const handlerUp = (options) => {
      clearTimeout(timer)
      const position = options.pointer
      const pixelCoord = { x: position.x, y: position.y }
      const geoCoord = this._mapView.pixelCoordToGeoCoord(
        new Point({ coordinates: [pixelCoord.x, pixelCoord.y] })
      )

      if (!graphic) {
        pixelCoords.push(pixelCoord, pixelCoord)
        polygonSpots.push(geoCoord.coordinates, geoCoord.coordinates)
        graphic = this._getGraphic()
        graphic.geometry._pixelCoords = [...pixelCoords, pixelCoords[0]]
        graphic.geometry.coordinates = [[...polygonSpots, polygonSpots[0]]]
        this._mapView.graphics.add(graphic)

        // 保存当前编辑中的geometr
        this._polygonGeomtry = graphic
      } else {
        pixelCoords.push(pixelCoord)
        polygonSpots.push(geoCoord.coordinates)
        graphic.geometry._pixelCoords = [...pixelCoords, pixelCoords[0]]
        graphic.geometry.coordinates = [[...polygonSpots, polygonSpots[0]]]
      }

      timer = setTimeout(() => {
        isStartDrawing = true
      }, 500)
    }
    const handlerMove = (options) => {
      if (!isStartDrawing) {
        return
      }
      isDrawing = true
      movePosition = options.pointer

      const pixelCoord = { x: movePosition.x, y: movePosition.y }
      pixelCoords[pixelCoords.length - 1] = pixelCoord
      const geoCoord = this._mapView.pixelCoordToGeoCoord(
        new Point({ coordinates: [pixelCoord.x, pixelCoord.y] })
      )
      polygonSpots[polygonSpots.length - 1] = geoCoord.coordinates

      graphic.geometry._pixelCoords = [...pixelCoords, pixelCoords[0]]
      graphic.geometry.coordinates = [[...polygonSpots, polygonSpots[0]]]
    }
    const handlerDoubleClick = (options) => {
      clearTimeout(timer)

      // 清除双击时单击事件添加的多余点
      polygonSpots.pop()
      pixelCoords.pop()

      polygonSpots.pop()
      pixelCoords.pop()

      // 清除最后一个点
      polygonSpots.pop()
      pixelCoords.pop()
      graphic.geometry._pixelCoords = [...pixelCoords, pixelCoords[0]]
      graphic.geometry.coordinates = [[...polygonSpots, polygonSpots[0]]]

      if (!isDrawing) {
        graphic = null
        polygonSpots = []
        pixelCoords = []
        return
      }
      const position = options.pointer
      const pixelCoord = { x: position.x, y: position.y }
      const geoCoord = this._mapView.pixelCoordToGeoCoord(
        new Point({ coordinates: [pixelCoord.x, pixelCoord.y] })
      )
      pixelCoords.push(pixelCoord)
      polygonSpots.push(geoCoord.coordinates)
      graphic.geometry._pixelCoords = [...pixelCoords, pixelCoords[0]]
      graphic.geometry.coordinates = [[...polygonSpots, polygonSpots[0]]]

      graphic = null
      polygonSpots = []
      pixelCoords = []
      isDrawing = false
      isStartDrawing = false

      this._stopCurrentGraphicDrawing()
    }

    this._mouseEventHandlers = this._mouseEventHandlers
      ? this._mouseEventHandlers
      : []

    this._mouseEventHandlers.push(handlerUp, handlerMove, handlerDoubleClick)
    this._mapView.on(ViewEventType.mouseUp, handlerUp)
    this._mapView.on(ViewEventType.mouseMove, handlerMove)
    this._mapView.on(ViewEventType.doubleClick, handlerDoubleClick)
  }
}
export default SketchEditorVideoBase
构造函数
成员变量
方法
事件