Skip to content

Commit 46c36ab

Browse files
authored
IM-164 - ESRI draw tool stops self-intersect on create and dispatches on undo & delete node (#168)
* IM-164 added a source-map config item to the webpack dev build * IM-164 esri draw tool stops self-intersect on create and dispatches on undo & delete node * IM-164 started to cover draw-es * IM-164 added jest-expect-message so expects can be described * IM-164 simplified the tests * IM-164 covered es-draw Done and Cancel clicks * IM-164 added tests to cover reColour * IM-164 added back the ignore draw-es for coverage
1 parent cd9a60d commit 46c36ab

6 files changed

Lines changed: 394 additions & 42 deletions

File tree

jest.config.mjs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default {
99
projects: [{
1010
displayName: 'unit-tests',
1111
testEnvironment: 'jsdom',
12-
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
12+
setupFilesAfterEnv: ['jest-expect-message', '<rootDir>/jest.setup.js'],
1313
testMatch: [
1414
'<rootDir>/src/**/*.test.[jt]s?(x)',
1515
'<rootDir>/plugins/**/*.test.[jt]s?(x)',
@@ -18,9 +18,15 @@ export default {
1818
testPathIgnorePatterns: ['<rootDir>/src/test-utils.js'],
1919
coveragePathIgnorePatterns: [
2020
'<rootDir>/src/test-utils.js',
21-
'<rootDir>/plugins/beta/',
22-
'<rootDir>/providers/beta/'
21+
'<rootDir>/plugins/beta/datasets/',
22+
'<rootDir>/providers/beta/',
23+
'<rootDir>/plugins/beta/draw-es',
24+
'<rootDir>/plugins/beta/draw-ml',
25+
'<rootDir>/plugins/beta/frame',
26+
'<rootDir>/plugins/beta/map-styles',
27+
'<rootDir>/plugins/beta/scale-bar',
28+
'<rootDir>/plugins/beta/use-location'
2329
],
2430
transformIgnorePatterns: []
2531
}]
26-
}
32+
}

package-lock.json

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
"geodesy": "^2.4.0",
157157
"jest": "^29.7.0",
158158
"jest-environment-jsdom": "^30.0.4",
159+
"jest-expect-message": "^1.1.3",
159160
"likec4": "^1.50.0",
160161
"mapbox-gl-snap": "^1.1.9",
161162
"mini-css-extract-plugin": "^2.9.2",

plugins/beta/draw-es/src/events.js

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import * as simplifyOperator from "@arcgis/core/geometry/operators/simplifyOperator.js"
1+
import * as simplifyOperator from '@arcgis/core/geometry/operators/simplifyOperator.js'
22
import { createGraphic, createSymbol, graphicToGeoJSON } from './graphic.js'
33

44
const MODE_CHANGE_DELAY = 50
55

6-
export function attachEvents({ pluginState, mapProvider, events, eventBus, buttonConfig, mapColorScheme }) {
6+
export function attachEvents ({ pluginState, mapProvider, events, eventBus, buttonConfig, mapColorScheme }) {
77
const { view, sketchViewModel, sketchLayer, emptySketchLayer } = mapProvider
88

99
if (!sketchViewModel) {
@@ -12,36 +12,36 @@ export function attachEvents({ pluginState, mapProvider, events, eventBus, butto
1212

1313
const { drawDone, drawCancel } = buttonConfig
1414
const { dispatch, mode, feature } = pluginState
15-
15+
1616
// Re-colour graphics when map style changes
1717
const reColour = async () => {
1818
const activeGraphicId = pluginState.feature?.properties?.id
1919
let activeGraphic = null
2020
const isCreating = sketchViewModel.state === 'active' && !activeGraphicId
21-
21+
2222
// Cancel and wait, but only if we're in update mode (not create mode)
2323
if (sketchViewModel.state === 'active' && activeGraphicId) {
2424
sketchViewModel.cancel()
2525
await new Promise(resolve => setTimeout(resolve, MODE_CHANGE_DELAY))
2626
}
27-
27+
2828
// Update the default symbol for new polygons
2929
sketchViewModel.polygonSymbol = createSymbol(mapColorScheme)
30-
30+
3131
// Update existing graphics
3232
sketchLayer?.graphics.items.forEach(graphic => {
3333
const newGraphic = createGraphic(
34-
graphic.attributes.id,
35-
graphic.geometry.rings,
34+
graphic.attributes.id,
35+
graphic.geometry.rings,
3636
mapColorScheme
3737
)
3838
graphic.symbol = newGraphic.symbol
39-
39+
4040
if (activeGraphicId === graphic.attributes.id) {
4141
activeGraphic = graphic
4242
}
4343
})
44-
44+
4545
// Re-enter update mode only if we were editing (not creating)
4646
if (activeGraphic && !isCreating && sketchViewModel.layer === sketchLayer) {
4747
try {
@@ -68,10 +68,19 @@ export function attachEvents({ pluginState, mapProvider, events, eventBus, butto
6868
// Event handlers
6969
const handleMapStyleChange = () => reColour()
7070

71+
const onGraphicChanged = (graphic) => {
72+
if (!graphic) {
73+
return
74+
}
75+
const tempFeature = graphicToGeoJSON(graphic)
76+
eventBus.emit('draw:updated', tempFeature)
77+
dispatch({ type: 'SET_FEATURE', payload: { tempFeature } })
78+
}
79+
7180
const handleSketchUpdate = (e) => {
7281
const toolInfoType = e.toolEventInfo?.type
7382
const graphic = e.graphics[0]
74-
83+
7584
// Prevent polygon move
7685
if (toolInfoType === 'move-start') {
7786
sketchViewModel.cancel()
@@ -87,10 +96,8 @@ export function attachEvents({ pluginState, mapProvider, events, eventBus, butto
8796
}
8897

8998
// Emit event on update
90-
if (toolInfoType === 'reshape-stop') {
91-
const tempFeature = graphicToGeoJSON(graphic)
92-
eventBus.emit('draw:updated', tempFeature)
93-
dispatch({ type: 'SET_FEATURE', payload: { tempFeature }})
99+
if (toolInfoType === 'reshape-stop' || toolInfoType === 'vertex-remove') {
100+
onGraphicChanged(graphic)
94101
}
95102
}
96103

@@ -108,17 +115,38 @@ export function attachEvents({ pluginState, mapProvider, events, eventBus, butto
108115
updateGraphic()
109116
}
110117

118+
const handleCreate = async (event) => {
119+
const { toolEventInfo } = event
120+
const graphic = event?.graphic
121+
if (graphic && toolEventInfo?.type === 'vertex-add') {
122+
const rings = graphic.geometry?.rings
123+
// rings.length is > 1 occurs when the shape becomes complex (ie self intersects)
124+
// setTimeout is required to cause the undo to be called after handleCreate completes
125+
// otherwise the previous change, rather than this one, is undone
126+
if (rings?.length > 1) {
127+
setTimeout(() => sketchViewModel.undo(), 0)
128+
} else if (rings?.[0]?.length > 3) {
129+
onGraphicChanged(graphic) // emit a graphic update on draw, once the graphic is 2D
130+
}
131+
}
132+
}
133+
134+
const handleUndo = async (event) => {
135+
const graphic = event?.graphics?.[0]
136+
onGraphicChanged(graphic)
137+
}
138+
111139
const handleDone = () => {
112140
sketchViewModel.cancel()
113141
sketchViewModel.layer = emptySketchLayer
114142
dispatch({ type: 'SET_MODE', payload: null })
115-
dispatch({ type: 'SET_FEATURE', payload: { feature: null, tempFeature: null }})
143+
dispatch({ type: 'SET_FEATURE', payload: { feature: null, tempFeature: null } })
116144
eventBus.emit('draw:done', { newFeature: pluginState.tempFeature })
117145
}
118146

119147
const handleCancel = () => {
120148
sketchViewModel.cancel()
121-
149+
122150
// Clear all graphics
123151
sketchLayer.removeAll()
124152

@@ -143,10 +171,12 @@ export function attachEvents({ pluginState, mapProvider, events, eventBus, butto
143171
eventBus.on(events.MAP_STYLE_CHANGE, handleMapStyleChange)
144172
const sketchUpdateHandler = sketchViewModel.on('update', handleSketchUpdate)
145173
const viewClickHandler = view.on('click', handleViewClick)
146-
174+
const createHandler = sketchViewModel.on('create', handleCreate)
175+
const undoHandler = sketchViewModel.on('undo', handleUndo)
176+
147177
const prevDoneClick = drawDone.onClick
148178
const prevCancelClick = drawCancel.onClick
149-
179+
150180
drawDone.onClick = handleDone
151181
drawCancel.onClick = handleCancel
152182

@@ -155,7 +185,9 @@ export function attachEvents({ pluginState, mapProvider, events, eventBus, butto
155185
eventBus.off(events.MAP_STYLE_CHANGE, handleMapStyleChange)
156186
sketchUpdateHandler.remove()
157187
viewClickHandler.remove()
188+
createHandler.remove()
189+
undoHandler.remove()
158190
drawDone.onClick = prevDoneClick
159191
drawCancel.onClick = prevCancelClick
160192
}
161-
}
193+
}

0 commit comments

Comments
 (0)