import { Feature, ViewEventType } from '../../base'
import { Polygon, Point, LineString } from '../../base/geometry'
import SketchBaseDrawTool from './SketchBaseDrawTool'
import Color from '../../base/Color'
import SketchPointDrawTool from './SketchPointDrawTool'
import SketchPolylineDrawTool from './SketchPolylineDrawTool'
import SketchStyle from './SketchStyle'
import { SimpleLineSymbol } from '../../base/symbol'
/**
* 面绘图工具类
* @class SketchPolygonDrawTool
* @moduleEX SketchEditorModule
* @extends SketchBaseDrawTool
* @param {Object} options 构造参数
* @param {MapView|SceneView} [options.view] 地图视图对象
* @param {GraphicsLayer} [options.layer] 草图图层管对象
* @param {SketchStyle} [options.sketchStyle] 草图符号
*/
class SketchPolygonDrawTool extends SketchBaseDrawTool {
constructor(options) {
super(options)
// 初始化事件
this._initEvent()
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.view._mapActionControl('double-click-zoom', false)
// 控制鼠标移动事件频率
const timer = null
// 鼠标点击两次以上,即有两个以上的点构成区时,触发鼠标移动时逻辑
let isStartDrawing = false
// 鼠标移动过程中,控制鼠标移动逻辑触发次数
let moving = false
// 当前正在绘制的图形对象
let feature = null
let pixelCoords = []
// 绘制过程中所有的端点
let polygonSpots = []
// 绘制过程中所有所有线段的斜率
const polygonSpotSlopes = []
// timer判断是单击事件、双击事件
const clickTimer = null
// 区分单击、双击事件,若为双击事件,则阻止单击事件逻辑触发
// let preventClick = false
// 获取两点斜率
const getSlope = function (point1, point2) {
return (point1[1] - point2[1]) / (point1[0] - point2[0])
}
let lastMouseEvent = null
// 捕获到的坐标点
let snapPoint = null
// 处理鼠标点击事件。点击后渲染端点图形,渲染区图形
const handlerClick = (options) => {
// clickTimer = setTimeout(() => {
// preventClick = false
// }, 300)
// // 判断是否为单击事件
// if (preventClick) return
if (!options || !options.x || !options.y) return
clearTimeout(timer)
this._editMode = 3
const pixelCoord = { x: options.x, y: options.y }
let geoCoord = null
if (!snapPoint) {
// 如果没有捕获结果,则此时坐标点为屏幕地理坐标
geoCoord = this.view.toMap({ x: pixelCoord.x, y: pixelCoord.y })
// if (this._hight) {
// geoCoord = new Point({
// coordinates: [
// geoCoord.coordinates[0],
// geoCoord.coordinates[1],
// this._hight
// ],
// spatialReference: this._spatialReference
// })
// } else {
// geoCoord = new Point({
// coordinates: [geoCoord.coordinates[0], geoCoord.coordinates[1]],
// spatialReference: this._spatialReference
// })
// }
} else {
// 如果有捕获结果,则纠正此时鼠标坐标为捕获坐标点
geoCoord = snapPoint
}
pixelCoords.push(pixelCoord)
polygonSpots.push(geoCoord.coordinates)
if (!feature) {
if (polygonSpots.length > 2) {
feature = this._getFeature()
feature.geometry._pixelCoords = [...pixelCoords, pixelCoords[0]]
feature.geometry.coordinates = [[...polygonSpots, polygonSpots[0]]]
// 保存当前编辑中的geometry
this._polygonGeometry = feature
} else if (polygonSpots.length === 2) {
pixelCoords.push(pixelCoords[0])
polygonSpots.push(polygonSpots[0])
feature = this._getFeature()
feature.geometry._pixelCoords = [...pixelCoords, pixelCoords[0]]
feature.geometry.coordinates = [[...polygonSpots, polygonSpots[0]]]
} else {
isStartDrawing = false
}
}
const pointDrawTool = new SketchPointDrawTool({
view: this.view,
layer: this.layer,
_parent: this,
sketchStyle: this.sketchStyle
})
pointDrawTool.addFeature(geoCoord)
const vertexGraphic = pointDrawTool.sketchStage.entityGraphic
this.sketchStage.entityGraphic = feature
this.sketchStage.vertexGraphics.push(vertexGraphic)
if (feature) {
isStartDrawing = true
}
// preventClick = true
// 计算线段斜率
if (polygonSpots.length > 3) {
polygonSpotSlopes.push(
getSlope(
polygonSpots[polygonSpots.length - 2],
polygonSpots[polygonSpots.length - 3]
)
)
} else if (polygonSpots.length > 2) {
polygonSpotSlopes.push(getSlope(polygonSpots[0], polygonSpots[1]))
}
lastMouseEvent = 'click'
// 发送绘制一个顶点完成事件
this.fire(
'drawn-vertex',
{ geometry: pointDrawTool.sketchStage.entityGraphic },
self
)
}
let isFirstAdd = true
// 处理平移时,鼠标移动时逻辑。鼠标移动时根据鼠标坐标实时更新区图形。
const handlerMove = (options) => {
if (!options || !options.x || !options.y) return
if (!isStartDrawing || moving) return
clearTimeout(timer)
moving = true
// 清除捕获效果(上一次)
if (this.sketchStage.snapGraphics.length > 0) {
this.sketchStage.snapGraphics.forEach((feature) => {
this._removeFeatureFromMap(feature)
})
this.sketchStage.snapGraphics = []
}
const pixelCoord = { x: options.x, y: options.y }
pixelCoords[pixelCoords.length - 1] = pixelCoord
const geoCoord = this.view.toMap({ x: pixelCoord.x, y: pixelCoord.y })
// if (this._hight) {
// geoCoord = new Point({
// coordinates: [
// geoCoord.coordinates[0],
// geoCoord.coordinates[1],
// this._hight
// ],
// spatialReference: this._spatialReference
// })
// }
polygonSpots[polygonSpots.length - 1] = geoCoord.coordinates
this.sketchStage.entityGraphic = feature
// 鼠标移动时,去捕获重合点、点在线上、平行线、垂直线
snapPoint = this.getSnapGraphics(
geoCoord,
polygonSpots,
polygonSpotSlopes
)
if (snapPoint) {
polygonSpots[polygonSpots.length - 1] = snapPoint.coordinates // geoCoord.coordinates
}
// 更新草图图层
feature.geometry._pixelCoords = JSON.parse(JSON.stringify(pixelCoords))
feature.geometry._pixelCoords.push(pixelCoords[0])
const newCoor = JSON.parse(JSON.stringify(polygonSpots))
newCoor.push(polygonSpots[0])
feature.geometry.coordinates = [newCoor]
if (isFirstAdd) {
this._addFeaturesToMap(feature)
isFirstAdd = false
}
moving = false
lastMouseEvent = 'move'
}
// 处理鼠标双击时,处理逻辑
const handlerDoubleClick = () => {
clearTimeout(clickTimer)
clearTimeout(timer)
// preventClick = true
if (!isStartDrawing) {
feature = null
polygonSpots = []
pixelCoords = []
return
}
// 最后一次双击触发两次点击事件,去掉最后一个重复点
pixelCoords.splice(-2, 1)
polygonSpots.splice(-2, 1)
// 临时解决,move事件有可能发生在两个click事件之间,导致多绘制一个点
if (
lastMouseEvent === 'move' &&
polygonSpots.length > 2 &&
polygonSpots[polygonSpots.length - 2][0] ===
polygonSpots[polygonSpots.length - 3][0] &&
polygonSpots[polygonSpots.length - 2][1] ===
polygonSpots[polygonSpots.length - 3][1]
) {
pixelCoords.splice(-2, 1)
polygonSpots.splice(-2, 1)
feature.geometry._pixelCoords.splice(-2, 1)
feature.geometry.coordinates[0].splice(-2, 1)
}
polygonSpots = []
pixelCoords = []
isStartDrawing = false
// 停止绘制
this.stop()
// 清除捕获效果
if (this.sketchStage.snapGraphics.length > 0) {
this.sketchStage.snapGraphics.forEach((feature) => {
this._removeFeatureFromMap(feature)
})
this.sketchStage.snapGraphics = []
}
this._editMode = 0
lastMouseEvent = 'doubleClick'
// 发送绘制完成事件
this.fire('drawn', { geometry: feature.geometry }, self)
// 绘制完成后,移除顶点
this.sketchStage.vertexGraphics.forEach((feature) => {
this._removeFeatureFromMap(feature)
})
this.sketchStage.vertexGraphics = []
// this.sketchStage.editMode = this._editMode
// 恢复地图默认双击事件
this.view._mapActionControl('double-click-zoom', true)
}
// 注册绘制事件
this._drawEventHandlers.push(handlerClick, handlerMove, handlerDoubleClick)
this.view.on(ViewEventType.immediateClick, handlerClick)
this.view.on(ViewEventType.pointerMove, handlerMove)
this.view.on(ViewEventType.doubleClick, handlerDoubleClick)
}
/**
* @description 添加图形
* @param {Array} points 生成面的点地理坐标集
* @param {SketchStyle} sketchStyle 面的符号样式
*/
addFeature(points, sketchStyle, attributes) {
let fillStyle = null
if (!sketchStyle || !sketchStyle.fillStyle) {
fillStyle = this.sketchStyle._fillStyle
} else {
fillStyle = sketchStyle.fillStyle
}
const feature = this._getFeature(points, fillStyle)
if (attributes) {
feature.attributes = attributes
}
this.sketchStage.entityGraphic = feature
// 更新图层图形
this._addFeaturesToMap(feature)
}
addFeatureByGeometry(geometry, sketchStyle, attributes) {
let symbol = null
if (!sketchStyle || !sketchStyle.fillStyle) {
symbol = this.sketchStyle._fillStyle
} else {
symbol = sketchStyle.fillStyle
}
const feature = new Feature({
geometry,
symbol
})
if (attributes) {
feature.attributes = attributes
}
this.sketchStage.entityGraphic = feature
// 更新图层图形
this._addFeaturesToMap(feature)
}
/**
* @description 获取feature实例
* @private
* @param {Array} points 生成面的点地理坐标集
* @param {Symbol} symbol 点的符号样式
*/
_getFeature(points) {
if (!points) {
points = [
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
}
const geometry = new Polygon({
coordinates: [points],
spatialReference: this._spatialReference
})
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
}
/**
* @description 捕获草图
* @private
* @param {Feature} feature 被选中feature对象
*/
hitTestFeature(feature, event) {
// this._sketchEditor._drawTool = this
if (!this._parent && this.editOption.showSelectBox) {
if (this._editMode === 0) {
this._editMode = 1
} else if (this._editMode === 2) {
// 临时,把clickMap的事件删掉,否则在图形都被删掉时会被触发
this.view.off(ViewEventType.immediateClick, this._mapClickEvent)
this._mapClickEvent = null
this._editMode = 1
}
// 进入图形编辑状态,高亮点元素,用新图形代替高亮,展示选中图形时的辅助图形
this.selectFeature(feature)
}
if (this._parent && this._parent._editMode === 1) {
// 注册图形编辑时的事件,平移图形
this.startPanGraphics(feature, event)
} else if (this._parent && this._parent._editMode === 2) {
// 进入顶点编辑状态,添加顶点+中点辅助图形
// 调用辅助图形的父级图形的selectFeatureVertex,
// 1.添加顶点编辑状态的辅助图形
// 2.删除当前编辑图形状态的辅助图形
// this._parent.selectFeatureVertex(this._parent.entityGraphic)
}
}
/**
* @description 选中草图feature
* @param {Feature} feature 被选中草图feature对象
*/
selectFeature(feature) {
if (!this.editOption.showSelectBox) return
// 1.删除当前编辑图形状态的辅助图形
// 2.添加顶点编辑状态的辅助图形
this._clearEditGraphics(2)
// 加载选时的辅助图形,外包盒
const extent = feature.geometry.extent
const polygonDrawTool = new SketchPolygonDrawTool({
view: this.view,
layer: this.layer,
sketchStyle: new SketchStyle({
fillStyle: this.sketchStyle._selectBoxStyle,
isShowSegmentLength: true,
isShowArea: true
}),
editOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
// 注册hitTest事件移动图形
// this._hitTestDrawToolStack.push(polygonDrawTool)
this._drawTools.push(polygonDrawTool)
// if (this._hight) {
// polygonDrawTool.addFeature([
// [extent.xmax, extent.ymax, this._hight],
// [extent.xmax, extent.ymin, this._hight],
// [extent.xmin, extent.ymin, this._hight],
// [extent.xmin, extent.ymax, this._hight],
// [extent.xmax, extent.ymax, this._hight]
// ])
// } else {
// polygonDrawTool.addFeature([
// [extent.xmax, extent.ymax],
// [extent.xmax, extent.ymin],
// [extent.xmin, extent.ymin],
// [extent.xmin, extent.ymax],
// [extent.xmax, extent.ymax]
// ])
// }
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({
view: this.view,
layer: this.layer,
sketchStyle: new SketchStyle({
vertexStyle: this.sketchStyle._selectBoxVertexStyle
}),
editOption: {
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)
// this.sketchStage.editMode = this._editMode
// 添加到undoRedoManager中
if (this.undoRedoManager) {
this.undoRedoManager.addProcess('add', this.sketchStage)
}
// 点击到地图没有feature图形区域,退出编辑
if (
!this._mapClickEvent &&
(!this._parent || (this._parent && !this._parent._mapClickEvent))
) {
this._mapClickEvent = () => {
if (this._preventFirstCall) {
this._preventFirstCall = undefined
return
}
const removedFeatures = this.sketchStage.selectBoxGraphics
.concat(this.sketchStage.selectBoxVertexGraphics)
.concat(this.sketchStage.vertexGraphics)
.concat(this.sketchStage.midVertexGraphics)
removedFeatures.forEach((feature) => {
this._removeFeatureFromMap(feature)
})
this.view.off(ViewEventType.immediateClick, this._mapClickEvent)
this.view._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 = []
}
this._hitTestEventHandlers.push(this._mapClickEvent)
this._preventFirstCall = true
this.view.on(ViewEventType.immediateClick, this._mapClickEvent)
}
}
/**
* @description 选中feature图形顶点
* @param {Feature} feature 被选中feature对象
*/
selectFeatureVertex(feature) {
// 1.删除当前编辑图形状态的辅助图形
// 2.添加顶点编辑状态的辅助图形
this._clearEditGraphics(1)
const pointDrawTools = []
const midPointDrawTools = []
feature.geometry.coordinates[0].forEach((coordinate, i) => {
// 区集合坐标集比区顶点多(最后)一个坐标,添加顶点时读取到倒数第二个坐标
if (i < feature.geometry.coordinates[0].length - 1) {
// 渲染区的每一个顶点
const pointDrawTool = new SketchPointDrawTool({
view: this.view,
layer: this.layer,
sketchStyle: new SketchStyle({
vertexStyle: this.sketchStyle._selectVertexStyle
}),
editOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
const point = new Point({
coordinates: coordinate,
spatialReference: this._spatialReference
})
// 注册hitTest事件移动图形
// this._hitTestDrawToolStack.push(pointDrawTool)
this._drawTools.push(pointDrawTool)
pointDrawTool.addFeature(point, undefined, {
vertexIndex: i
})
pointDrawTools.push(pointDrawTool)
this.sketchStage.vertexGraphics.push(
pointDrawTool.sketchStage.entityGraphic
)
}
// 渲染顶点之间的每一个中点
if (i > 0) {
const midPointDrawTool = new SketchPointDrawTool({
view: this.view,
layer: this.layer,
sketchStyle: new SketchStyle({
vertexStyle: this.sketchStyle._selectMidVertexStyle
}),
editOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
midPointDrawTools.push(midPointDrawTool)
const lastCoordinate = feature.geometry.coordinates[0][i - 1]
let point = null
if (coordinate.length > 2) {
point = new Point({
coordinates: [
(coordinate[0] + lastCoordinate[0]) / 2,
(coordinate[1] + lastCoordinate[1]) / 2,
(coordinate[2] + lastCoordinate[2]) / 2
],
spatialReference: this._spatialReference
})
} else {
point = new Point({
coordinates: [
(coordinate[0] + lastCoordinate[0]) / 2,
(coordinate[1] + lastCoordinate[1]) / 2
],
spatialReference: this._spatialReference
})
}
this._drawTools.push(midPointDrawTool)
midPointDrawTool.addFeature(point, undefined, {
vertexIndex: i - 1,
type: 'midVertex'
})
this.sketchStage.midVertexGraphics.push(
midPointDrawTool.sketchStage.entityGraphic
)
}
})
const drawTools = pointDrawTools.concat(midPointDrawTools)
this._otherDrawTools = this._otherDrawTools
? this._otherDrawTools.concat(drawTools)
: drawTools
// this.sketchStage.editMode = this._editMode
// 添加到undoRedoManager中
if (this.undoRedoManager) {
this.undoRedoManager.addProcess('add', this.sketchStage)
}
}
/**
* @description 平移图形
* @param {Feature} feature 被选中feature对象
* @param {Object} event 拾取事件
*/
startPanGraphics(feature, event) {
this.view._mapActionControl('drag-pan', false)
const timer = null
let moving = false
this._startPan = true
let startPoint = null
// if (this._hight) {
// startPoint = new Point({
// coordinates: [
// event.mapPoint.coordinates[0],
// event.mapPoint.coordinates[1],
// this._hight
// ],
// spatialReference: this._spatialReference
// })
// } else {
// startPoint = event.mapPoint
// }
startPoint = event.mapPoint
// 区分点击事件和鼠标按下(并保持)事件。
// 如果是点击事件,则进入顶点编辑状态。如果是鼠标按下(并保持)事件,则平移图形
let isClickEvent = true
const isClickTimer = setTimeout(() => {
isClickEvent = false
}, 200)
// 移除父级草图地图点击事件。点图形仍然会触发mapClick事件。
if (this._parent && this._parent._mapClickEvent) {
this.view.off(ViewEventType.immediateClick, this._parent._mapClickEvent)
}
// 处理平移时,鼠标移动时逻辑。
const handlerMove = (options) => {
if (!options || !options.x || !options.y) return
if (moving || !this._startPan || !this._editMode === 1) return
if (isClickEvent) return
clearTimeout(timer)
moving = true
const pixelCoord = { x: options.x, y: options.y }
const movePoint = this.view.toMap({
x: pixelCoord.x,
y: pixelCoord.y
})
// if (this._hight) {
// movePoint = new Point({
// coordinates: [
// movePoint.coordinates[0],
// movePoint.coordinates[1],
// this._hight
// ],
// spatialReference: this._spatialReference
// })
// }
const deltaX = movePoint.coordinates[0] - startPoint.coordinates[0]
const deltaY = movePoint.coordinates[1] - startPoint.coordinates[1]
if (deltaX === 0 && deltaY === 0) {
moving = false
return
}
const coordinates = []
feature.geometry.coordinates[0].forEach((coordinate) => {
coordinates.push(this.getPanCoordinates(coordinate, deltaX, deltaY))
})
// 临时,三维geometry extent有bug,暂时用先创建二维geometry,再赋值三维坐标
// const newGeometry = new Polygon({
// coordinates: [coordinates],
// spatialReference: this._spatialReference
// })
const newGeometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
newGeometry.coordinates = [coordinates]
startPoint = movePoint
// 发送平移事件给父级草图
this._dispatchEvent(
'pan',
{ deltaPosition: { x: deltaX, y: deltaY } },
this
)
this.updateFeature(newGeometry, feature)
moving = false
}
// 处理平移时,鼠标按下后抬起逻辑。
const handlerUp = () => {
if (!this._editMode === 1) {
return
}
if (!this._startPan) {
return
}
if (
isClickEvent &&
this._parent &&
this._parent._editMode === 1 &&
(this._parent instanceof SketchPolygonDrawTool ||
this._parent instanceof SketchPolylineDrawTool)
) {
this._parent._editMode = 2
clearTimeout(isClickTimer)
// 在图形编辑状态时,当鼠标单击时,进入顶点编辑状态,添加顶点+中点辅助图形,调用辅助图形的父级图形的selectFeatureVertex。
// 当鼠标移动时,则是平移事件
this._parent.selectFeatureVertex(this._parent.sketchStage.entityGraphic)
if (this._parent && this._parent._mapClickEvent) {
this.view.on(
ViewEventType.immediateClick,
this._parent._mapClickEvent
)
}
this._startPan = false
// pan事件移除
this.view.off(ViewEventType.pointerMove, handlerMove)
this.view.off(ViewEventType.pointerUp, handlerUp)
return
}
// this._stopHitTest()
this._editMode = 0
this._startPan = false
this.view.off(ViewEventType.pointerMove, handlerMove)
this.view.off(ViewEventType.pointerUp, handlerUp)
// 添加到undoRedoManager中
if (this._parent && this._parent.undoRedoManager) {
this._parent.undoRedoManager.addProcess(
'update',
this._parent.sketchStage
)
}
// 重新注册父级草图地图点击事件
if (this._parent && this._parent._mapClickEvent) {
this._parent._preventFirstCall = true
this.view.on(ViewEventType.immediateClick, this._parent._mapClickEvent)
}
this.view._mapActionControl('drag-pan', true)
}
// 注册平移时鼠标相关事件
this._hitTestEventHandlers.push(handlerMove)
this._hitTestEventHandlers.push(handlerUp)
this.view.on(ViewEventType.pointerUp, handlerUp)
this.view.on(ViewEventType.pointerMove, handlerMove)
}
/**
* @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)
} else if (event.type === 'circleVertexScale') {
// 处理顶点缩放逻辑
this._handlerCircleVertexScaleEvent(event)
} else if (event.type === 'vertexMove') {
// 处理移动顶点逻辑
this._handlerVertexMoveEvent(event)
} else if (event.type === 'midVertexAdd') {
// 处理中点位置增加顶点逻辑
this._handlerMidVertexAddEvent(event)
}
}
/**
* @description 响应平移事件
* @private
* @param {Object} event 拾取事件参数
*/
_handlerPanEvent(event) {
// 更新当前草图的图形位置
const newCoordinates = []
this.sketchStage.entityGraphic.geometry.coordinates[0].forEach(
(coordinate) => {
newCoordinates.push(
this.getPanCoordinates(
coordinate,
event.deltaPosition.x,
event.deltaPosition.y
)
)
}
)
// 临时,三维geometry extent有bug,暂时用先创建二维geometry,再赋值三维坐标
// const newGeometry = new Polygon({
// coordinates: [newCoordinates],
// spatialReference: this._spatialReference
// })
const newGeometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
newGeometry.coordinates = [newCoordinates]
this.sketchStage.entityGraphic.geometry = newGeometry
// 更新同级的辅助草图的图形位置
if (this._otherDrawTools) {
this._otherDrawTools.forEach((drawTool) => {
drawTool._processEvent(event)
})
}
}
/**
* @description 响应顶点缩放事件
* @private
* @param {Object} event 传入事件参数
*/
_handlerVertexScaleEvent(event) {
if (event.action === 'scale') {
// 更新当前草图的图形位置
let newGeometry = null
if (!this.sketchStage.entityGraphic.attributes.lastCoordinates) {
const oriCoordinates = JSON.parse(
JSON.stringify(this.sketchStage.entityGraphic.geometry.coordinates[0])
)
this.sketchStage.entityGraphic.attributes.lastCoordinates =
oriCoordinates
}
const newCoordinates = this.getScaleCoordinates(
this.sketchStage.entityGraphic.geometry.coordinates[0],
event.direction,
event.extent,
// this.sketchStage.entityGraphic.geometry.extent,
event.startPoint,
event.movePoint,
this.sketchStage.entityGraphic.attributes.lastCoordinates
)
// 临时,三维geometry extent有bug,暂时用先创建二维geometry,再赋值三维坐标
// newGeometry = new Polygon({
// coordinates: [newCoordinates],
// spatialReference: this._spatialReference
// })
newGeometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
newGeometry.coordinates = [newCoordinates]
this.sketchStage.entityGraphic.geometry = newGeometry
// extent = item.geometry.extent
// 更新同级的辅助草图的图形位置
if (this._otherDrawTools) {
this._otherDrawTools.forEach((drawTool) => {
// 传给子草图的extent应该是草图改变前的,不是草图改变后的extent
// event.extent = extent
// if (drawTool.sketchStage.entityGraphic.id !== event.feature.id) {
drawTool._processEvent(event)
// }
})
}
}
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) {
// 更新当前草图的图形位置
let newGeometry = null
if (!this.sketchStage.entityGraphic.attributes.lastCoordinates) {
const oriCoordinates = JSON.parse(
JSON.stringify(this.sketchStage.entityGraphic.geometry.coordinates[0])
)
this.sketchStage.entityGraphic.attributes.lastCoordinates = oriCoordinates
}
const newCoordinates = this.getMidScaleCoordinates(
this.sketchStage.entityGraphic.geometry.coordinates[0],
event.direction,
event.extent,
// item.geometry.extent,
event.startPoint,
event.movePoint,
this.sketchStage.entityGraphic.attributes.lastCoordinates
)
// 临时,三维geometry extent有bug,暂时用先创建二维geometry,再赋值三维坐标
// newGeometry = new Polygon({
// coordinates: [newCoordinates],
// spatialReference: this._spatialReference
// })
newGeometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
newGeometry.coordinates = [newCoordinates]
this.sketchStage.entityGraphic.geometry = newGeometry
// extent = item.geometry.extent
// newEntityGraphic = this.sketchStage.entityGraphic
// this.sketchStage.entityGraphic = newEntityGraphic
// 更新同级的辅助草图的图形位置
if (this._otherDrawTools) {
this._otherDrawTools.forEach((drawTool) => {
// 传给子草图的extent应该是草图改变前的,不是草图改变后的extent
// event.extent = extent
drawTool._processEvent(event)
})
}
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)
// }
})
}
}
}
_handlerCircleVertexScaleEvent(event) {
if (!this._parent || !this._parent.sketchStage.entityGraphic) return
// 更新当前草图的图形位置
let newGeometry = null
const extent = this._parent.sketchStage.entityGraphic.geometry.extent
const newCoordinates = [
[extent.xmax, extent.ymax],
[extent.xmax, extent.ymin],
[extent.xmin, extent.ymin],
[extent.xmin, extent.ymax],
[extent.xmax, extent.ymax]
]
newGeometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
newGeometry.coordinates = [newCoordinates]
this.sketchStage.entityGraphic.geometry = newGeometry
// 更新同级的辅助草图的图形位置
if (this._otherDrawTools) {
this._otherDrawTools.forEach((drawTool) => {
// 传给子草图的extent应该是草图改变前的,不是草图改变后的extent
// event.extent = extent
drawTool._processEvent(event)
})
}
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 传入事件参数
*/
_handlerVertexMoveEvent(event) {
// 更新当前草图的图形位置
this.sketchStage.currentVertexIndex = event.vertexIndex
const entityGraphic = this.sketchStage.entityGraphic
const originCoordinates = entityGraphic.geometry.coordinates[0]
entityGraphic.geometry.coordinates[0][event.vertexIndex] =
event.movePoint.coordinates
// 当被移动的顶点是区的最后一个点,则需同步改变区的第一个顶点坐标。
// 当被移动的顶点是区的第一个点,则需同步改变区的最后一个顶点坐标。
if (
entityGraphic.geometry.coordinates[0].length - 1 ===
event.vertexIndex
) {
entityGraphic.geometry.coordinates[0][0] = event.movePoint.coordinates
} else if (event.vertexIndex === 0) {
entityGraphic.geometry.coordinates[0][
entityGraphic.geometry.coordinates[0].length - 1
] = event.movePoint.coordinates
}
// 临时,三维geometry extent有bug,暂时用先创建二维geometry,再赋值三维坐标
// entityGraphic.geometry = new Polygon({
// coordinates: entityGraphic.geometry.coordinates,
// spatialReference: this._spatialReference
// })
const newCoordinates = JSON.parse(
JSON.stringify(entityGraphic.geometry.coordinates)
)
entityGraphic.geometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
entityGraphic.geometry.coordinates = newCoordinates
// 更新同级的辅助草图的图形位置
if (this._otherDrawTools) {
const curIndex = event.vertexIndex
const lastIndex =
curIndex === 0
? curIndex - 1 + this.sketchStage.midVertexGraphics.length
: curIndex - 1
const nextIndex =
curIndex === this.sketchStage.midVertexGraphics.length - 1
? 0
: curIndex + 1
const feature = this.sketchStage.midVertexGraphics[curIndex]
const featureLast = this.sketchStage.midVertexGraphics[lastIndex]
const pLast = originCoordinates[lastIndex]
const p = originCoordinates[curIndex]
const pNext = originCoordinates[nextIndex]
feature.geometry.coordinates = [
(pNext[0] + p[0]) / 2,
(pNext[1] + p[1]) / 2
]
feature.geometry = new Point({
coordinates: feature.geometry.coordinates,
spatialReference: this._spatialReference
})
featureLast.geometry.coordinates = [
(pLast[0] + p[0]) / 2,
(pLast[1] + p[1]) / 2
]
featureLast.geometry = new Point({
coordinates: featureLast.geometry.coordinates,
spatialReference: this._spatialReference
})
}
}
/**
* @description 响应中点位置增加顶点事件
* @private
* @param {Object} event 传入事件参数
*/
_handlerMidVertexAddEvent(event) {
if (event.action === 'changeFeature') {
// 向当前草图几何对象中插入一个顶点
this.sketchStage.entityGraphic.geometry.coordinates[0].splice(
event.vertexIndex + 1,
0,
event.point.coordinates
)
// 临时,三维geometry extent有bug,暂时用先创建二维geometry,再赋值三维坐标
// this.sketchStage.entityGraphic.geometry = new Polygon({
// coordinates: [this.sketchStage.entityGraphic.geometry.coordinates[0]],
// spatialReference: this._spatialReference
// })
const newCoordinates = JSON.parse(
JSON.stringify([this.sketchStage.entityGraphic.geometry.coordinates[0]])
)
this.sketchStage.entityGraphic.geometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
this.sketchStage.entityGraphic.geometry.coordinates = newCoordinates
}
if (event.action === 'moveMidVertex') {
// 根据移动的顶点实时位置,更新当前草图图形顶点坐标
this.sketchStage.currentVertexIndex = event.vertexIndex
this.sketchStage.entityGraphic.geometry.coordinates[0][
event.vertexIndex + 1
] = event.movePoint.coordinates
// 临时,三维geometry extent有bug,暂时用先创建二维geometry,再赋值三维坐标
// this.sketchStage.entityGraphic.geometry = new Polygon({
// coordinates: this.sketchStage.entityGraphic.geometry.coordinates,
// spatialReference: this._spatialReference
// })
const newCoordinates = JSON.parse(
JSON.stringify(this.sketchStage.entityGraphic.geometry.coordinates)
)
this.sketchStage.entityGraphic.geometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
this.sketchStage.entityGraphic.geometry.coordinates = newCoordinates
}
if (event.action === 'addVertex') {
// 更新同级的辅助草图的图形顶点
// 增加一个新的顶点和两个中点图形
const oldMidId =
this.sketchStage.midVertexGraphics[event.vertexIndex].id.toString()
const pointDrawTool = new SketchPointDrawTool({
view: this.view,
layer: this.layer,
sketchStyle: new SketchStyle({
vertexStyle: this.sketchStyle._selectVertexStyle
}),
editOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
// this._hitTestDrawToolStack.push(pointDrawTool)
this._drawTools.push(pointDrawTool)
pointDrawTool.addFeature(event.point)
this.sketchStage.vertexGraphics.splice(
event.vertexIndex + 1,
0,
pointDrawTool.sketchStage.entityGraphic
)
// 添加第一个中点
const p =
this.sketchStage.entityGraphic.geometry.coordinates[0][
event.vertexIndex
]
let newMidPoint1 = null
// if (this._hight) {
// newMidPoint1 = new Point({
// coordinates: [
// (p[0] + event.point.coordinates[0]) / 2,
// (p[1] + event.point.coordinates[1]) / 2,
// this._hight
// ],
// spatialReference: this._spatialReference
// })
// } else {
// newMidPoint1 = new Point({
// coordinates: [
// (p[0] + event.point.coordinates[0]) / 2,
// (p[1] + event.point.coordinates[1]) / 2
// ],
// spatialReference: this._spatialReference
// })
// }
// if (this._getHight) {
// this._getHight.then(() => {})
// }
let hight1 = null
if (this._getHight) {
hight1 = 0
}
if (hight1) {
newMidPoint1 = new Point({
coordinates: [
(p[0] + event.point.coordinates[0]) / 2,
(p[1] + event.point.coordinates[1]) / 2,
hight1
],
spatialReference: this._spatialReference
})
} else {
newMidPoint1 = new Point({
coordinates: [
(p[0] + event.point.coordinates[0]) / 2,
(p[1] + event.point.coordinates[1]) / 2
],
spatialReference: this._spatialReference
})
}
const midPointDrawTool1 = new SketchPointDrawTool({
view: this.view,
layer: this.layer,
sketchStyle: new SketchStyle({
vertexStyle: this.sketchStyle._selectMidVertexStyle
}),
editOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
// this._hitTestDrawToolStack.push(midPointDrawTool1)
this._drawTools.push(midPointDrawTool1)
midPointDrawTool1.addFeature(newMidPoint1, undefined, {
type: 'midVertex'
})
// 下标为vertexIndex的元素被替换掉
this.sketchStage.midVertexGraphics.splice(
event.vertexIndex,
1,
midPointDrawTool1.sketchStage.entityGraphic
)
// 添加第二个中点
const pNext =
this.sketchStage.entityGraphic.geometry.coordinates[0][
event.vertexIndex + 2
]
let newMidPoint2 = null
// if (this._hight) {
// newMidPoint2 = new Point({
// coordinates: [
// (pNext[0] + event.point.coordinates[0]) / 2,
// (pNext[1] + event.point.coordinates[1]) / 2,
// this._hight
// ],
// spatialReference: this._spatialReference
// })
// } else {
// newMidPoint2 = new Point({
// coordinates: [
// (pNext[0] + event.point.coordinates[0]) / 2,
// (pNext[1] + event.point.coordinates[1]) / 2
// ],
// spatialReference: this._spatialReference
// })
// }
let hight2 = null
if (this._getHight) {
hight2 = 0
}
if (hight2) {
newMidPoint2 = new Point({
coordinates: [
(pNext[0] + event.point.coordinates[0]) / 2,
(pNext[1] + event.point.coordinates[1]) / 2,
hight2
],
spatialReference: this._spatialReference
})
} else {
newMidPoint2 = new Point({
coordinates: [
(pNext[0] + event.point.coordinates[0]) / 2,
(pNext[1] + event.point.coordinates[1]) / 2
],
spatialReference: this._spatialReference
})
}
const midPointDrawTool2 = new SketchPointDrawTool({
view: this.view,
layer: this.layer,
sketchStyle: new SketchStyle({
vertexStyle: this.sketchStyle._selectMidVertexStyle
}),
editOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
// this._hitTestDrawToolStack.push(midPointDrawTool2)
this._drawTools.push(midPointDrawTool2)
midPointDrawTool2.addFeature(newMidPoint2, undefined, {
type: 'midVertex'
})
// 下标为vertexIndex的元素后面添加一个新元素
this.sketchStage.midVertexGraphics.splice(
event.vertexIndex + 1,
0,
midPointDrawTool2.sketchStage.entityGraphic
)
// 更新每个feature的VertexIndex
this.sketchStage.vertexGraphics.forEach((feature, i) => {
if (feature.attributes) {
feature.attributes.vertexIndex = i
} else {
feature.attributes = {
vertexIndex: i
}
}
})
this.sketchStage.midVertexGraphics.forEach((feature, i) => {
if (feature.attributes) {
feature.attributes.vertexIndex = i
} else {
feature.attributes = {
vertexIndex: i
}
}
})
// 移除被选中的中点(中点被新增的顶点替代)
// let existIndex = -1
this._otherDrawTools.forEach((drawTool, i) => {
if (drawTool.sketchStage.entityGraphic.id === oldMidId) {
// existIndex = i
this._removeFeatureFromMap(drawTool.sketchStage.entityGraphic)
}
})
// if (existIndex > -1) {
// this._otherDrawTools.splice(existIndex, 1)
// }
this._otherDrawTools.push(pointDrawTool)
this._otherDrawTools.push(midPointDrawTool1)
this._otherDrawTools.push(midPointDrawTool2)
}
}
/**
* 图形捕获,捕获重合点、点在线上、平行线、垂直线
* @private
* @param {Point} geoCoord 当前坐标点
* @param {Array} polygonSpots 被捕获的顶点数据组
* @param {Array} polygonSpotSlopes 被捕获的直线斜率数据组
*/
getSnapGraphics(targetPoint, polygonSpots) {
let realPoint = null
const tolerance = this.getDistanceByPixel
? this.getDistanceByPixel(this.sketchSnappingTool.pixelTolerance)
: 200
const moveLine = new LineString({
coordinates: polygonSpots.slice(polygonSpots.length - 2),
spatialReference: this._spatialReference
})
let geometries
if (this.sketchSnappingTool.snapSketchGeometry && polygonSpots.length > 3) {
const entityPolyline = new LineString({
coordinates: polygonSpots.slice(0, polygonSpots.length - 2),
spatialReference: this._spatialReference
})
geometries = this.snapAndReferGeometries.concat([entityPolyline])
} else {
geometries = this.snapAndReferGeometries
}
// 获取捕获结果
const snapResult = this.sketchSnappingTool.snapGeometries(
targetPoint,
moveLine,
geometries,
tolerance
)
if (snapResult.coincidentPoint) {
// 端点重合
const pointFeature = new Feature({
geometry: snapResult.coincidentPoint.realPoint,
symbol: this.sketchStyle._coincidentPointStyle
})
this.sketchStage.snapGraphics.push(pointFeature)
realPoint = snapResult.coincidentPoint.realPoint
} else if (snapResult.inLineAndParallel) {
snapResult.inLineAndParallel.lines.forEach((line) => {
const lineFeature = new Feature({
geometry: line,
symbol: new SimpleLineSymbol({
color: new Color(255, 255, 0, 1),
width: 3
})
})
this.sketchStage.snapGraphics.push(lineFeature)
})
const pointFeature = new Feature({
geometry: snapResult.inLineAndParallel.realPoint,
symbol: this.sketchStyle._selectVertexStyle
})
this.sketchStage.snapGraphics.push(pointFeature)
if (snapResult.inLineAndParallel.symbolGeometry) {
const symbolFeature = new Feature({
geometry: snapResult.inLineAndParallel.symbolGeometry,
symbol: new SimpleLineSymbol({
color: new Color(255, 255, 0, 1),
width: 3
})
})
this.sketchStage.snapGraphics.push(symbolFeature)
}
realPoint = snapResult.inLineAndParallel.realPoint
} else if (snapResult.inLineAndPerpendicular) {
snapResult.inLineAndPerpendicular.lines.forEach((line) => {
const lineFeature = new Feature({
geometry: line,
symbol: new SimpleLineSymbol({
color: new Color(255, 255, 0, 1),
width: 3
})
})
this.sketchStage.snapGraphics.push(lineFeature)
})
const pointFeature = new Feature({
geometry: snapResult.inLineAndPerpendicular.realPoint,
symbol: this.sketchStyle._selectVertexStyle
})
this.sketchStage.snapGraphics.push(pointFeature)
if (snapResult.inLineAndPerpendicular.symbolGeometry) {
const symbolFeature = new Feature({
geometry: snapResult.inLineAndPerpendicular.symbolGeometry,
symbol: new SimpleLineSymbol({
color: new Color(255, 255, 0, 1),
width: 3
})
})
this.sketchStage.snapGraphics.push(symbolFeature)
}
realPoint = snapResult.inLineAndPerpendicular.realPoint
} else if (snapResult.pointInLine) {
// 点在线上捕获上图
const lineFeature = new Feature({
geometry: snapResult.pointInLine.line,
symbol: new SimpleLineSymbol({
color: new Color(255, 255, 0, 1),
width: 3
})
})
this.sketchStage.snapGraphics.push(lineFeature)
const pointFeature = new Feature({
geometry: snapResult.pointInLine.realPoint,
symbol: this.sketchStyle._selectVertexStyle
})
this.sketchStage.snapGraphics.push(pointFeature)
realPoint = snapResult.pointInLine.realPoint
} else if (snapResult.parallelLine) {
// 平行捕获结果上图
const lineFeature = new Feature({
geometry: snapResult.parallelLine.line,
symbol: new SimpleLineSymbol({
color: new Color(255, 255, 0, 1),
width: 3
})
})
this.sketchStage.snapGraphics.push(lineFeature)
const pointFeature = new Feature({
geometry: snapResult.parallelLine.realPoint,
symbol: this.sketchStyle._selectVertexStyle
})
this.sketchStage.snapGraphics.push(pointFeature)
// 渲染高亮平行
if (snapResult.parallelLine.symbolGeometry) {
const symbolFeature = new Feature({
geometry: snapResult.parallelLine.symbolGeometry,
symbol: new SimpleLineSymbol({
color: new Color(255, 255, 0, 1),
width: 3
})
})
this.sketchStage.snapGraphics.push(symbolFeature)
}
realPoint = snapResult.parallelLine.realPoint
} else if (snapResult.perpendicularLine) {
// 渲染高亮垂直,坐标点
const lineFeature = new Feature({
geometry: snapResult.perpendicularLine.line,
symbol: new SimpleLineSymbol({
color: new Color(255, 255, 0, 1),
width: 3
})
})
this.sketchStage.snapGraphics.push(lineFeature)
const pointFeature = new Feature({
geometry: snapResult.perpendicularLine.realPoint,
symbol: this.sketchStyle._selectVertexStyle
})
this.sketchStage.snapGraphics.push(pointFeature)
// 渲染高亮垂足
if (snapResult.perpendicularLine.symbolGeometry) {
const symbolFeature = new Feature({
geometry: snapResult.perpendicularLine.symbolGeometry,
symbol: new SimpleLineSymbol({
color: new Color(255, 255, 0, 1),
width: 3
})
})
this.sketchStage.snapGraphics.push(symbolFeature)
}
realPoint = snapResult.perpendicularLine.realPoint
}
this.sketchStage.snapGraphics.forEach((feature) => {
this._addFeaturesToMap(feature)
})
return realPoint
}
/**
* @description 选中图形顶点
* @private
*/
selectVertex() {}
/**
* @description 选中图形中点点
*/
addMidVertex(index, point) {
const midPointDrawTool = new SketchPointDrawTool()
midPointDrawTool.addPoint(point)
this.sketchStage.midVertexGraphics = midPointDrawTool
}
/**
* 当前草图图形中插入新的顶点
* @private
* @param {Point} point 新增/插入顶点
* @param {Number} index 新增/新增点的序号,从1开始
*/
addVertex(point, index) {
index--
let newGeometry = null
if (index > -1) {
let vertexCount = 0
let newCoordinates = []
vertexCount =
this.sketchStage.entityGraphic.geometry.coordinates[0].length - 1
if (index < vertexCount) {
// 向当前草图几何对象中插入一个顶点
newCoordinates = this.sketchStage.entityGraphic.geometry.coordinates[0]
newCoordinates.splice(index, 0, point.coordinates)
if (index === 0) {
newCoordinates[newCoordinates.length - 1] = point.coordinates
} else if (index === newCoordinates.length - 1) {
newCoordinates.splice(0, 0, point.coordinates)
}
this.sketchStage.entityGraphic.geometry.coordinates = [newCoordinates]
newGeometry = this.sketchStage.entityGraphic.geometry
// 更新同级的辅助草图的图形顶点
let pointDrawTool = undefined
let midPointDrawTool2 = undefined
const extent = this.sketchStage.entityGraphic.geometry.extent
if (this.sketchStage.selectBoxGraphics.length > 0) {
this.sketchStage.selectBoxGraphics.forEach((feature) => {
feature.geometry.coordinates = [
[
[extent.xmax, extent.ymax],
[extent.xmax, extent.ymin],
[extent.xmin, extent.ymin],
[extent.xmin, extent.ymax],
[extent.xmax, extent.ymax]
]
]
})
}
if (this.sketchStage.selectBoxVertexGraphics.length > 0) {
const points = [
[extent.xmax, extent.ymax],
[extent.xmax, extent.ymin],
[extent.xmin, extent.ymin],
[extent.xmin, extent.ymax],
[(extent.xmax + extent.xmin) / 2, extent.ymax],
[(extent.xmax + extent.xmin) / 2, extent.ymin],
[extent.xmax, (extent.ymax + extent.ymin) / 2],
[extent.xmin, (extent.ymax + extent.ymin) / 2]
]
this.sketchStage.selectBoxVertexGraphics.forEach((feature, i) => {
feature.geometry.coordinates = points[i]
})
}
// 增加一个新的顶点
if (this.sketchStage.vertexGraphics.length > 0) {
pointDrawTool = new SketchPointDrawTool({
view: this.view,
layer: this.layer,
sketchStyle: new SketchStyle({
vertexStyle: this.sketchStyle._selectVertexStyle
}),
editOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
// this._hitTestDrawToolStack.push(pointDrawTool)
this._drawTools.push(pointDrawTool)
pointDrawTool.addFeatureByGeometry(point)
this.sketchStage.vertexGraphics.splice(
index,
0,
pointDrawTool.sketchStage.entityGraphic
)
// 更新每个feature的VertexIndex
this.sketchStage.vertexGraphics.forEach((feature, i) => {
if (feature.attributes) {
feature.attributes.vertexIndex = i
} else {
feature.attributes = {
vertexIndex: i
}
}
})
}
// 修改第一个中点坐标,增加第二个新的中点
if (this.sketchStage.midVertexGraphics.length > 0) {
let replaceIndex = -1
let addIndex = -1
let pLast = null
let pNext = null
if (index === 0) {
addIndex = 0
replaceIndex = this.sketchStage.midVertexGraphics.length - 1
pLast =
this.sketchStage.entityGraphic.geometry.coordinates[0][
this.sketchStage.entityGraphic.geometry.coordinates[0].length -
2
]
pNext = this.sketchStage.entityGraphic.geometry.coordinates[0][1]
}
// else if (index === this.sketchStage.midVertexGraphics.length - 2) {
// nextIndex = 0
// }
else {
replaceIndex = index - 1
addIndex = index + 1
pLast =
this.sketchStage.entityGraphic.geometry.coordinates[0][
replaceIndex
]
pNext =
this.sketchStage.entityGraphic.geometry.coordinates[0][addIndex]
}
// 修改第一个中点
const newMidPoint1 = new Point({
coordinates: [
(pLast[0] + point.coordinates[0]) / 2,
(pLast[1] + point.coordinates[1]) / 2
],
spatialReference: this._spatialReference
})
// 下标为Index的上一个点坐标被替换掉新坐标
this.sketchStage.midVertexGraphics[
replaceIndex
].geometry.coordinates = newMidPoint1.coordinates
// 添加第二个中点
const newMidPoint2 = new Point({
coordinates: [
(pNext[0] + point.coordinates[0]) / 2,
(pNext[1] + point.coordinates[1]) / 2
],
spatialReference: this._spatialReference
})
midPointDrawTool2 = new SketchPointDrawTool({
view: this.view,
layer: this.layer,
sketchStyle: new SketchStyle({
vertexStyle: this.sketchStyle._selectMidVertexStyle
}),
editOption: {
showSelectBox: false,
_hitTestMode: 1
},
_parent: this // 或者只传父级相应pan的事件
})
// this._hitTestDrawToolStack.push(midPointDrawTool2)
this._drawTools.push(midPointDrawTool2)
midPointDrawTool2.addFeatureByGeometry(newMidPoint2, undefined, {
type: 'midVertex'
})
// 下标为Index的元素后面添加一个新元素
this.sketchStage.midVertexGraphics.splice(
index,
0,
midPointDrawTool2.sketchStage.entityGraphic
)
this.sketchStage.midVertexGraphics.forEach((feature, i) => {
if (feature.attributes) {
feature.attributes.vertexIndex = i
} else {
feature.attributes = {
vertexIndex: i
}
}
})
}
// 修改drawTool集合中增加一个顶点两个中点
if (pointDrawTool) {
this._otherDrawTools.push(pointDrawTool)
}
if (midPointDrawTool2) {
this._otherDrawTools.push(midPointDrawTool2)
}
this.undoRedoManager.addProcess('update', this.sketchStage)
}
return newGeometry
}
}
/**
* 更新当前草图图形的某个顶点
* @param {Point} point 新的顶点
* @param {Number} index 需更新的顶点的序号
*/
updateVertex(point, index) {
index--
let newGeometry = null
if (index > -1) {
const vertexCount =
this.sketchStage.entityGraphic.geometry.coordinates[0].length - 1
if (index < vertexCount) {
// 当前草图几何对象中更新顶点,更新草图实体图形
const entityGraphic = this.sketchStage.entityGraphic
const newCoordinates = entityGraphic.geometry.coordinates[0]
entityGraphic.geometry.coordinates = [newCoordinates]
this.currentVertexIndex = index
newCoordinates[index] = point.coordinates
if (newCoordinates.length - 1 === index) {
newCoordinates[0] = point.coordinates
} else if (index === 0) {
newCoordinates[newCoordinates.length - 1] = point.coordinates
}
// 临时,三维geometry extent有bug,暂时用先创建二维geometry,再赋值三维坐标
// entityGraphic.geometry = new Polygon({
// coordinates: entityGraphic.geometry.coordinates,
// spatialReference: this._spatialReference
// })
const newGeometryCoordinates = JSON.parse(
JSON.stringify(entityGraphic.geometry.coordinates)
)
entityGraphic.geometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
entityGraphic.geometry.coordinates = newGeometryCoordinates
newGeometry = entityGraphic.geometry
const extent = entityGraphic.geometry.extent
if (this.sketchStage.selectBoxGraphics.length > 0) {
this.sketchStage.selectBoxGraphics.forEach((feature) => {
feature.geometry.coordinates = [
[
[extent.xmax, extent.ymax],
[extent.xmax, extent.ymin],
[extent.xmin, extent.ymin],
[extent.xmin, extent.ymax],
[extent.xmax, extent.ymax]
]
]
})
}
if (this.sketchStage.selectBoxVertexGraphics.length > 0) {
const points = [
[extent.xmax, extent.ymax],
[extent.xmax, extent.ymin],
[extent.xmin, extent.ymin],
[extent.xmin, extent.ymax],
[(extent.xmax + extent.xmin) / 2, extent.ymax],
[(extent.xmax + extent.xmin) / 2, extent.ymin],
[extent.xmax, (extent.ymax + extent.ymin) / 2],
[extent.xmin, (extent.ymax + extent.ymin) / 2]
]
this.sketchStage.selectBoxVertexGraphics.forEach((feature, i) => {
feature.geometry.coordinates = points[i]
})
}
// 更新顶点图形
if (this.sketchStage.vertexGraphics.length > 0) {
this.sketchStage.vertexGraphics[index].geometry.coordinates =
point.coordinates
}
// 更新中点图形
if (this.sketchStage.midVertexGraphics.length > 0) {
const curIndex = index
const lastIndex =
curIndex === 0
? curIndex - 1 + this.sketchStage.midVertexGraphics.length
: curIndex - 1
const nextIndex =
curIndex === this.sketchStage.midVertexGraphics.length - 1
? 0
: curIndex + 1
const feature = this.sketchStage.midVertexGraphics[curIndex]
const featureLast = this.sketchStage.midVertexGraphics[lastIndex]
const pLast = newCoordinates[lastIndex]
const p = newCoordinates[curIndex]
const pNext = newCoordinates[nextIndex]
feature.geometry.coordinates = [
(pNext[0] + p[0]) / 2,
(pNext[1] + p[1]) / 2
]
feature.geometry = new Point({
coordinates: feature.geometry.coordinates,
spatialReference: this._spatialReference
})
featureLast.geometry.coordinates = [
(pLast[0] + p[0]) / 2,
(pLast[1] + p[1]) / 2
]
featureLast.geometry = new Point({
coordinates: featureLast.geometry.coordinates,
spatialReference: this._spatialReference
})
}
}
this.undoRedoManager.addProcess('update', this.sketchStage)
}
return newGeometry
}
/**
* 移除草图图形的某个顶点
* @param {Number} index 需更新的顶点的序号
*/
removeVertex(index) {
index--
let newGeometry = null
if (index > -1) {
const vertexCount =
this.sketchStage.entityGraphic.geometry.coordinates[0].length - 1
if (vertexCount > 3 && index < vertexCount) {
const newCoordinates =
this.sketchStage.entityGraphic.geometry.coordinates[0]
// 更新草图实体图形
newCoordinates.splice(index, 1)
if (index === 0) {
newCoordinates.splice(newCoordinates.length - 1, 1, newCoordinates[0])
}
// else if (index === vertexCount - 1) {
// newCoordinates.splice(index - 1, 1)
// newCoordinates.splice(0, 1)
// }
// 临时,三维geometry extent有bug,暂时用先创建二维geometry,再赋值三维坐标
// newGeometry = new Polygon({
// coordinates: [newCoordinates],
// spatialReference: this._spatialReference
// })
newGeometry = new Polygon({
coordinates: [
[
[0, 0],
[0, 0],
[0, 0],
[0, 0]
]
],
spatialReference: this._spatialReference
})
newGeometry.coordinates = [newCoordinates]
this.sketchStage.entityGraphic.geometry = newGeometry
// 更新草图辅助图形
const extent = this.sketchStage.entityGraphic.geometry.extent
if (this.sketchStage.selectBoxGraphics.length > 0) {
this.sketchStage.selectBoxGraphics.forEach((feature) => {
feature.geometry.coordinates = [
[
[extent.xmax, extent.ymax],
[extent.xmax, extent.ymin],
[extent.xmin, extent.ymin],
[extent.xmin, extent.ymax],
[extent.xmax, extent.ymax]
]
]
})
}
if (this.sketchStage.selectBoxVertexGraphics.length > 0) {
const points = [
[extent.xmax, extent.ymax],
[extent.xmax, extent.ymin],
[extent.xmin, extent.ymin],
[extent.xmin, extent.ymax],
[(extent.xmax + extent.xmin) / 2, extent.ymax],
[(extent.xmax + extent.xmin) / 2, extent.ymin],
[extent.xmax, (extent.ymax + extent.ymin) / 2],
[extent.xmin, (extent.ymax + extent.ymin) / 2]
]
this.sketchStage.selectBoxVertexGraphics.forEach((feature, i) => {
feature.geometry.coordinates = points[i]
})
}
if (this.sketchStage.vertexGraphics.length > 0) {
const oriFeatureId =
this.sketchStage.vertexGraphics[index].id.toString()
this._removeFeatureFromMap(this.sketchStage.vertexGraphics[index])
this.sketchStage.vertexGraphics.splice(index, 1)
this.sketchStage.vertexGraphics.forEach((feature, i) => {
if (feature.attributes) {
feature.attributes.vertexIndex = i
} else {
feature.attributes = {
vertexIndex: i
}
}
})
this._otherDrawTools = this._otherDrawTools.filter((drawTool) => {
if (drawTool.sketchStage.entityGraphic.id !== oriFeatureId) {
return drawTool
}
})
}
if (this.sketchStage.midVertexGraphics.length > 0) {
let newMidCoordinates = []
let updateIndex = -1
if (index === 0) {
// newMidCoordinates = [
// (newGeometry[newGeometry.length - 1][0] + newGeometry[index][0]) /
// 2,
// (newGeometry[newGeometry.length - 1 - 1][1] +
// newGeometry[index][1]) /
// 2
// ]
newMidCoordinates = [
(newGeometry.coordinates[0][
newGeometry.coordinates[0].length - 2
][0] +
newGeometry.coordinates[0][index][0]) /
2,
(newGeometry.coordinates[0][
newGeometry.coordinates[0].length - 2
][1] +
newGeometry.coordinates[0][index][1]) /
2
]
updateIndex = this.sketchStage.midVertexGraphics.length - 1
}
// else if (index === vertexCount - 1) {
// newMidCoordinates = [
// (newGeometry[newGeometry.length - 1][0] + newGeometry[index][0]) /
// 2,
// (newGeometry[newGeometry.length - 1 - 1][1] +
// newGeometry[index][1]) /
// 2
// ]
// }
else {
newMidCoordinates = [
(newGeometry.coordinates[0][index - 1][0] +
newGeometry.coordinates[0][index][0]) /
2,
(newGeometry.coordinates[0][index - 1][1] +
newGeometry.coordinates[0][index][1]) /
2
]
updateIndex = index - 1
}
this.sketchStage.midVertexGraphics[updateIndex].geometry = new Point({
coordinates: newMidCoordinates,
spatialReference: this._spatialReference
})
const oriFeatureId =
this.sketchStage.vertexGraphics[index].id.toString()
this._removeFeatureFromMap(this.sketchStage.midVertexGraphics[index])
this.sketchStage.midVertexGraphics.splice(index, 1)
// this._otherDrawTools.filter(drawTool => drawTool.sketchStage.entityGraphic.id!= )
this.sketchStage.midVertexGraphics.forEach((feature, i) => {
if (feature.attributes) {
feature.attributes.vertexIndex = i
} else {
feature.attributes = {
vertexIndex: i
}
}
})
this._otherDrawTools = this._otherDrawTools.filter((drawTool) => {
if (drawTool.sketchStage.entityGraphic.id !== oriFeatureId) {
return drawTool
}
})
}
}
this.undoRedoManager.addProcess('update', this.sketchStage)
}
return newGeometry
}
}
export default SketchPolygonDrawTool