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