import { Feature, ViewEventType } from '../../base'
import { Point, Extent } from '../../base/geometry'
import { defaultValue } from '../../util'
import SketchStage from './SketchStage'
import SketchBaseDrawTool from './SketchBaseDrawTool'
import SketchPointDrawTool from './SketchPointDrawTool'
import SketchPolygonDrawTool from './SketchPolygonDrawTool'
import SketchStyle from './SketchStyle'
/**
* 面绘图工具类
* @class SketchExtentDrawTool
* @moduleEX SketchEditorModule
* @extends SketchBaseDrawTool
* @param {Object} options 构造参数
* @param {MapView} [options.mapView] 地图视图对象
* @param {GraphicsLayer} [options.layer] 草图图层管对象
* @param {SketchStyle} [options.sketchStyle] 草图符号
*/
class SketchExtentDrawTool extends SketchBaseDrawTool {
constructor(options) {
super(options)
/**
* 地图视图
* @member {MapView|SecenView} SketchEditor.prototype._mapView
*/
this._mapView = options.mapView
/**
* 草图图层
* @member {GraphicsLayer} SketchEditor.prototype._layer
*/
this._layer = defaultValue(options.layer, undefined)
/**
* 草图绘图形集合
* @member {SketchStage} SketchEditor.prototype._sketchStage
*/
this._sketchStage = new SketchStage()
/**
* 草图符号
* @member {SketchStyle} SketchEditor.prototype._sketchStyle
*/
this._sketchStyle = defaultValue(options.sketchStyle, new SketchStyle())
// this._mouseEventHandlers = null
this._currentVertexIndexOnMultiPoint = null
/**
* 草图编辑状态
* 0:没有画图或编辑状态
* 1:图形编辑
* 2:节点编辑
* 3:画图中
* @member {MapView|SecenView} SketchEditor.prototype._editMode
*/
this._editMode = 0
/**
* 草图捕获配置项
* @member {Object} SketchEditor.prototype.snappingOption
* @param {Object} [snappingOption.showSelectBox = {}] 捕捉时是否展示选中编辑框
* @param {Object} [snappingOption.showSelectVertex = {}] 捕捉时是否展示顶点可编辑图形
* @param {Object} [snappingOption._hitTestMode = {}] 捕捉拾取方式,0:click鼠标拾取。1:pointerDown鼠标按下拾取
*/
const snappingOption = {
showSelectBox: true,
showSelectVertex: false,
canEditFeature: false,
canEditVertex: false,
_hitTestMode: 0
}
this.snappingOption = defaultValue(options.snappingOption, snappingOption)
/**
* 所属父级绘图工具
* @member {GraphicsLayer} SketchEditor.prototype._layer
*/
this._parent = defaultValue(options._parent, undefined)
// 所属sketchEditor对象
this._sketchEditor = defaultValue(options._sketchEditor, undefined)
// this.sketchSnappingTool = new SketchSnappingTool(this.snappingOption)
// 初始化事件
this._initEvent()
this.undoRedoManager = defaultValue(options.undoRedoManager, undefined)
this._drawTools = [this]
this._otherDrawTools = []
}
/**
* @description 初始化事件
* @private
*/
_initEvent() {
this._processEvent = this._processEvent.bind(this)
this.on('pan', this._processEvent)
this.on('vertexScale', this._processEvent)
this.on('midVertexScale', this._processEvent)
this.on('vertexMove', this._processEvent)
this.on('midVertexAdd', this._processEvent)
}
/**
* @description 鼠标绘制图形:鼠标单击绘制区的一个顶点;鼠标移动,区图形随鼠标位置变动;鼠标双击,完成区图形绘制。
*/
drawFeature() {
// 屏蔽地图默认拖拽事件
this._mapView._mapActionControl('drag-pan', false)
// 控制鼠标移动事件频率
const timer = null
/// /////////////////////////
// 当前正在绘制的图形对象
let feature = null
let originCoord = null
// 处理鼠标点击事件。点击后渲染端点图形,渲染区图形
const handlerDrag = (options) => {
clearTimeout(timer)
if (options.button === 0) {
if (options.action === 'start') {
originCoord = originCoord || this._mapView.toMap(options.origin)
} else if (options.action === 'update') {
const curCoord = this._mapView.toMap({ x: options.x, y: options.y })
const xmin = Math.min(
originCoord.coordinates[0],
curCoord.coordinates[0]
)
const ymin = Math.min(
originCoord.coordinates[1],
curCoord.coordinates[1]
)
const xmax = Math.max(
originCoord.coordinates[0],
curCoord.coordinates[0]
)
const ymax = Math.max(
originCoord.coordinates[1],
curCoord.coordinates[1]
)
if (!feature) {
feature = this._getFeature(xmin, ymin, xmax, ymax)
this._addFeaturesToMap(feature)
this._sketchStage.entityGraphic = feature
} else {
feature.geometry.xmin = xmin
feature.geometry.ymin = ymin
feature.geometry.xmax = xmax
feature.geometry.ymax = ymax
}
} else if (options.action === 'end') {
// 停止绘制
this.stop()
// 清除捕获效果
if (this._sketchStage.snapGraphics.length > 0) {
this._sketchStage.snapGraphics.forEach((feature) => {
this._removeFeatureFromMap(feature)
})
this._sketchStage.snapGraphics = []
}
this._editMode = 0
// 发送绘制完成事件
this.fire('drawn', { geometry: feature.geometry }, self)
// 恢复地图默认拖拽事件
this._mapView._mapActionControl('drag-pan', true)
}
}
}
this._mouseEventHandlers = this._mouseEventHandlers
? this._mouseEventHandlers
: []
// 移除绘制事件
this._mouseEventHandlers.push(handlerDrag)
this._mapView.on(ViewEventType.drag, handlerDrag)
}
/**
* @description 添加图形
* @param {Array} points 生成面的点地理坐标集
* @param {SketchStyle} sketchStyle 面的符号样式
*/
addFeature(points, sketchStyle, attributes) {
let lineStyle = null
if (!sketchStyle || !sketchStyle.lineStyle) {
lineStyle = this._sketchStyle.lineStyle
} else {
lineStyle = sketchStyle.lineStyle
}
const feature = this._getFeature(points, lineStyle)
if (attributes) {
feature.attributes = attributes
}
this._sketchStage.entityGraphic = feature
// 更新图层图形
this._addFeaturesToMap(feature)
}
addFeatureByGeometry(geometry, sketchStyle, attributes) {
let symbol = null
if (!sketchStyle || !sketchStyle.lineStyle) {
symbol = this._sketchStyle.lineStyle
} else {
symbol = sketchStyle.lineStyle
}
const feature = new Feature({
geometry,
symbol
})
if (attributes) {
feature.attributes = attributes
}
this._sketchStage.entityGraphic = feature
// 更新图层图形
this._addFeaturesToMap(feature)
}
/**
* @description 获取feature实例
* @private
* @param {Point} point 生成面的点地理坐标集
* @param {Symbol} symbol 点的符号样式
*/
_getFeature(xmin, ymin, xmax, ymax) {
xmin = xmin !== undefined ? xmin : 0
ymin = ymin !== undefined ? ymin : 0
xmax = xmax !== undefined ? xmax : 0
ymax = ymax !== undefined ? ymax : 0
const geometry = new Extent({
xmin,
ymin,
xmax,
ymax,
spatialReference: this._spatialReference
})
const symbol = this._sketchStyle.fillStyle
const circleGeometry = new Feature({
geometry,
symbol
})
return circleGeometry
}
/**
* @description 捕获草图
* @private
* @param {Feature} feature 被选中feature对象
*/
_hitTestFeature(feature, event) {
if (!this._parent && this.snappingOption.showSelectBox) {
if (this._editMode === 0) {
this._editMode = 1
} else if (this._editMode === 2) {
// 临时,把clickMap的事件删掉,否则在图形都被删掉时会被触发
this._mapView.off(ViewEventType.immediateClick, this._mapClickEvent)
this._mapClickEvent = null
this._editMode = 1
}
// 进入图形编辑状态,高亮点元素,用新图形代替高亮,展示选中图形时的辅助图形
this.selectFeature(feature)
}
}
/**
* @description 选中草图feature
* @param {Feature} feature 被选中草图feature对象
*/
selectFeature(feature) {
if (!this.snappingOption.showSelectBox) return
// 1.删除当前编辑图形状态的辅助图形
// 2.添加顶点编辑状态的辅助图形
this._clearEditGraphics(2)
// 加载选时的辅助图形,外包盒
const extent = feature.geometry
const polygonDrawTool = new SketchPolygonDrawTool({
mapView: this._mapView,
layer: this._layer,
sketchStyle: new SketchStyle({
fillStyle: this._sketchStyle._selectBoxStyle,
isShowSegmentLength: true,
isShowArea: true
}),
snappingOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
// 注册hitTest事件移动图形
this._drawTools.push(polygonDrawTool)
polygonDrawTool.addFeature([
[extent.xmax, extent.ymax],
[extent.xmax, extent.ymin],
[extent.xmin, extent.ymin],
[extent.xmin, extent.ymax],
[extent.xmax, extent.ymax]
])
this._sketchStage.selectBoxGraphics = [
polygonDrawTool._sketchStage.entityGraphic
]
// 外包盒顶点和终点
let boxVertexPoints = []
boxVertexPoints = [
{
point: new Point({
coordinates: [extent.xmax, extent.ymax],
spatialReference: this._spatialReference
}),
direction: 'ne'
},
{
point: new Point({
coordinates: [extent.xmax, extent.ymin],
spatialReference: this._spatialReference
}),
direction: 'se'
},
{
point: new Point({
coordinates: [extent.xmin, extent.ymin],
spatialReference: this._spatialReference
}),
direction: 'sw'
},
{
point: new Point({
coordinates: [extent.xmin, extent.ymax],
spatialReference: this._spatialReference
}),
direction: 'nw'
}
]
if (this._sketchEditor && this._sketchEditor.getCenterCoordinate) {
const midVertexPoints = [
// midPoint
{
point: new Point({
coordinates: this._sketchEditor.getCenterCoordinate(
[extent.xmax, extent.ymax],
[extent.xmax, extent.ymin]
),
spatialReference: this._spatialReference
}),
direction: 'e',
type: 'midVertex'
},
{
point: new Point({
coordinates: this._sketchEditor.getCenterCoordinate(
[extent.xmax, extent.ymin],
[extent.xmin, extent.ymin]
),
spatialReference: this._spatialReference
}),
direction: 's',
type: 'midVertex'
},
{
point: new Point({
coordinates: this._sketchEditor.getCenterCoordinate(
[extent.xmin, extent.ymin],
[extent.xmin, extent.ymax]
),
spatialReference: this._spatialReference
}),
direction: 'w',
type: 'midVertex'
},
{
point: new Point({
coordinates: this._sketchEditor.getCenterCoordinate(
[extent.xmin, extent.ymax],
[extent.xmax, extent.ymax]
),
spatialReference: this._spatialReference
}),
direction: 'n',
type: 'midVertex'
}
]
boxVertexPoints = boxVertexPoints.concat(midVertexPoints)
}
const pointDrawTools = []
const boxVertexGraphics = []
boxVertexPoints.forEach((item) => {
const pointDrawTool = new SketchPointDrawTool({
mapView: this._mapView,
layer: this._layer,
sketchStyle: new SketchStyle({
vertexStyle: this._sketchStyle._selectBoxVertexStyle
}),
snappingOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
// 注册hitTest事件移动图形
// this._hitTestDrawToolStack.push(pointDrawTool)
this._drawTools.push(pointDrawTool)
pointDrawTool.addFeature(item.point, this._sketchStage, {
direction: item.direction,
type: item.type
})
pointDrawTools.push(pointDrawTool)
boxVertexGraphics.push(pointDrawTool._sketchStage.entityGraphic)
})
this._sketchStage.selectBoxVertexGraphics = boxVertexGraphics
if (this._otherDrawTools) {
this._otherDrawTools.push(polygonDrawTool)
} else {
this._otherDrawTools = [polygonDrawTool]
}
this._otherDrawTools = this._otherDrawTools.concat(pointDrawTools)
// 添加到undoRedoManager中
if (this.undoRedoManager) {
this.undoRedoManager.addProcess('add', this._sketchStage)
}
// 点击到地图没有feature图形区域,退出编辑
if (
!this._mapClickEvent &&
(!this._parent || (this._parent && !this._parent._mapClickEvent))
) {
this._mapClickEvent = () => {
const removedFeatures = this._sketchStage.selectBoxGraphics
.concat(this._sketchStage.selectBoxVertexGraphics)
.concat(this._sketchStage.vertexGraphics)
.concat(this._sketchStage.midVertexGraphics)
removedFeatures.forEach((feature) => {
this._removeFeatureFromMap(feature)
})
this._mapView.off(ViewEventType.immediateClick, this._mapClickEvent)
this._mapView._mapActionControl('drag-pan', true)
this._mapClickEvent = null
// 发送草图没有被选中状态
this.fire('selected', { isSelected: false }, self)
this._sketchStage.selectBoxGraphics = []
this._sketchStage.selectBoxVertexGraphics = []
this._sketchStage.vertexGraphics = []
this._sketchStage.midVertexGraphics = []
}
setTimeout(() => {
this._hitTestEventHandlers.push(this._mapClickEvent)
this._mapView.on(ViewEventType.immediateClick, this._mapClickEvent)
}, 200)
}
}
/**
* @description 响应图形平移事件
* @private
* @param {Object} event 拾取事件参数
*/
_processEvent(event) {
if (event.type === 'pan') {
// 处理平移逻辑
this._handlerPanEvent(event)
} else if (event.type === 'vertexScale') {
// 处理顶点缩放逻辑
this._handlerVertexScaleEvent(event)
} else if (event.type === 'midVertexScale') {
// 处理中点缩放逻辑
this._handlerMidVertexScaleEvent(event)
}
}
/**
* @description 响应平移事件
* @private
* @param {Object} event 拾取事件参数
*/
_handlerPanEvent(event) {
// 更新当前草图的图形位置
const extent = this._sketchStage.entityGraphic.geometry
extent.xmin += event.deltaPosition.x
extent.ymin += event.deltaPosition.y
extent.xmax += event.deltaPosition.x
extent.ymax += event.deltaPosition.y
// 更新同级的辅助草图的图形位置
if (this._otherDrawTools) {
this._otherDrawTools.forEach((drawTool) => {
drawTool._processEvent(event)
})
}
}
/**
* @description 响应顶点缩放事件
* @private
* @param {Object} event 传入事件参数
*/
_handlerVertexScaleEvent(event) {
if (event.action === 'scale') {
const geometry = this._sketchStage.entityGraphic.geometry
// 更新当前草图的图形位置
if (!this._sketchStage.entityGraphic.attributes.lastCoordinates) {
const oriCoordinates = [
[geometry.xmin, geometry.ymin],
[geometry.xmax, geometry.ymax]
]
this._sketchStage.entityGraphic.attributes.lastCoordinates =
oriCoordinates
}
this._sketchStage.entityGraphic.attributes = this._sketchStage
.entityGraphic.attributes
? this._sketchStage.entityGraphic.attributes
: {}
const newCoordinates = this.getScaleCoordinates(
[
[geometry.xmin, geometry.ymin],
[geometry.xmax, geometry.ymax]
],
event.direction,
event.extent,
event.startPoint,
event.movePoint,
this._sketchStage.entityGraphic.attributes.lastCoordinates
)
geometry.xmin = newCoordinates[0][0]
geometry.ymin = newCoordinates[0][1]
geometry.xmax = newCoordinates[1][0]
geometry.ymax = newCoordinates[1][1]
// 更新同级的辅助草图的图形位置
if (this._otherDrawTools) {
this._otherDrawTools.forEach((drawTool) => {
// 传给子草图的extent应该是草图改变前的,不是草图改变后的extent
// event.extent = extent
drawTool._processEvent(event)
})
}
} else if (event.action === 'stop') {
if (this._sketchStage.entityGraphic.attributes.lastCoordinates) {
this._sketchStage.entityGraphic.attributes.lastCoordinates = undefined
}
if (this._otherDrawTools) {
this._otherDrawTools.forEach((drawTool) => {
// if (drawTool._sketchStage.entityGraphic.id !== event.feature.id) {
drawTool._processEvent(event)
// }
})
}
}
}
/**
* @description 响应中点缩放事件
* @private
* @param {Object} event 传入事件参数
*/
_handlerMidVertexScaleEvent(event) {
if (event.action === 'scale') {
// 更新当前草图的图形位置
const geometry = this._sketchStage.entityGraphic.geometry
if (!this._sketchStage.entityGraphic.attributes.lastCoordinates) {
const oriCoordinates = [
[geometry.xmin, geometry.ymin],
[geometry.xmax, geometry.ymax]
]
this._sketchStage.entityGraphic.attributes.lastCoordinates =
oriCoordinates
}
const newCoordinates = this.getMidScaleCoordinates(
[
[geometry.xmin, geometry.ymin],
[geometry.xmax, geometry.ymax]
],
event.direction,
event.extent,
event.startPoint,
event.movePoint,
this._sketchStage.entityGraphic.attributes.lastCoordinates
)
geometry.xmin = newCoordinates[0][0]
geometry.ymin = newCoordinates[0][1]
geometry.xmax = newCoordinates[1][0]
geometry.ymax = newCoordinates[1][1]
// 更新同级的辅助草图的图形位置
if (this._otherDrawTools) {
this._otherDrawTools.forEach((drawTool) => {
// 传给子草图的extent应该是草图改变前的,不是草图改变后的extent
// event.extent = extent
drawTool._processEvent(event)
})
}
} else if (event.action === 'stop') {
if (this._sketchStage.entityGraphic.attributes.lastCoordinates) {
this._sketchStage.entityGraphic.attributes.lastCoordinates = undefined
}
if (this._otherDrawTools) {
this._otherDrawTools.forEach((drawTool) => {
// if (drawTool._sketchStage.entityGraphic.id !== event.feature.id) {
drawTool._processEvent(event)
// }
})
}
}
}
/**
* 图形捕获,捕获重合点、点在线上、平行线、垂直线
* @private
*/
getSnapGraphics() {}
/**
* @description 选中图形顶点
* @private
*/
selectVertex() {}
}
export default SketchExtentDrawTool