1- import * as simplifyOperator from " @arcgis/core/geometry/operators/simplifyOperator.js"
1+ import * as simplifyOperator from ' @arcgis/core/geometry/operators/simplifyOperator.js'
22import { createGraphic , createSymbol , graphicToGeoJSON } from './graphic.js'
33
44const 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