@defra/interactive-map 0.0.31-alpha → 0.0.33-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/assets/images/bright-ofm-thumb.jpg +0 -0
- package/assets/images/dark-ofm-thumb.jpg +0 -0
- package/assets/images/road-ofm-thumb.jpg +0 -0
- package/assets/templates/add-polygons.njk +143 -0
- package/assets/templates/add-symbols.njk +119 -0
- package/assets/templates/{map.njk → basic-map.njk} +9 -17
- package/assets/templates/button-map.njk +56 -0
- package/assets/templates/draw-tools.njk +161 -0
- package/assets/templates/marker-panel.njk +91 -0
- package/assets/templates/place-marker.njk +104 -0
- package/assets/templates/search-control.njk +98 -0
- package/assets/templates/select-feature.njk +101 -0
- package/assets/templates/style-switcher.njk +87 -0
- package/assets/templates/toggle-marker-label.njk +74 -0
- package/dist/css/index.css +1 -1
- package/dist/esm/im-core.js +1 -1
- package/dist/esm/im-shell.js +1 -1
- package/dist/umd/im-core.js +1 -1
- package/dist/umd/index.js +1 -1
- package/docs/api/map-style-config.md +27 -3
- package/docs/api.md +55 -0
- package/docs/assets/css/docusaurus.scss +22 -6
- package/docs/assets/images/add-polygons.jpg +0 -0
- package/docs/assets/images/add-symbols.jpg +0 -0
- package/docs/assets/images/hero.png +0 -0
- package/docs/assets/images/place-marker.jpg +0 -0
- package/docs/assets/images/screenshot.jpg +0 -0
- package/docs/examples/add-marker-with-panel.mdx +1 -1
- package/docs/examples/add-polygons.mdx +225 -0
- package/docs/examples/add-symbols.mdx +177 -0
- package/docs/examples/{draw.mdx → draw-tools.mdx} +2 -2
- package/docs/examples/index.mdx +38 -2
- package/docs/examples/place-marker.mdx +151 -0
- package/docs/plugins/datasets.md +144 -96
- package/docs/plugins/interact.md +1 -4
- package/docusaurus.config.cjs +5 -2
- package/govuk-prototype-kit.config.json +52 -2
- package/package.json +1 -1
- package/plugins/beta/datasets/dist/css/index.css +1 -2
- package/plugins/beta/datasets/dist/esm/im-datasets-ml-adapter.js +1 -1
- package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -1
- package/plugins/beta/datasets/dist/umd/im-datasets-ml-adapter.js +1 -1
- package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +1 -1
- package/plugins/beta/datasets/dist/umd/index.js +1 -1
- package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.js +27 -9
- package/plugins/beta/datasets/src/adapters/maplibre/registry/mapLibreDataset.test.js +46 -4
- package/plugins/beta/datasets/src/api/setFeatureVisibility.js +10 -1
- package/plugins/beta/datasets/src/api/setFeatureVisibility.test.js +48 -6
- package/plugins/beta/datasets/src/components/LayersMenu/Layers.module.scss +12 -12
- package/plugins/beta/datasets/src/reducers/datasetsToMenu.js +11 -6
- package/plugins/beta/datasets/src/reducers/datasetsToMenu.test.js +49 -0
- package/plugins/beta/datasets/src/reducers/mappedDatasetsReducer.js +8 -1
- package/plugins/beta/datasets/src/reducers/pluginState.js +1 -1
- package/plugins/beta/datasets/src/registry/dataset.js +7 -3
- package/plugins/beta/datasets/src/registry/dataset.test.js +14 -0
- package/plugins/beta/datasets/src/registry/dynamicGeoJson.js +1 -1
- package/plugins/beta/draw-es/dist/esm/im-draw-es-plugin.js +1 -1
- package/plugins/beta/draw-es/src/api/addFeature.js +12 -3
- package/plugins/beta/draw-es/src/events.js +8 -3
- package/plugins/beta/draw-es/src/events.test.js +2 -0
- package/plugins/beta/draw-es/src/graphic.js +26 -2
- package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -1
- package/plugins/beta/draw-ml/src/DrawInit.jsx +19 -0
- package/plugins/beta/draw-ml/src/api/newLine.js +1 -0
- package/plugins/beta/draw-ml/src/api/newPolygon.js +1 -0
- package/plugins/beta/draw-ml/src/modes/createDrawMode.js +52 -37
- package/plugins/beta/draw-ml/src/modes/editVertex/touchHandlers.js +1 -1
- package/plugins/beta/draw-ml/src/modes/editVertex/vertexOperations.js +5 -4
- package/plugins/beta/draw-ml/src/modes/editVertexMode.js +53 -21
- package/plugins/beta/draw-ol/dist/esm/DrawMode.js +1 -1
- package/plugins/beta/draw-ol/dist/esm/EditMode.js +1 -1
- package/plugins/beta/draw-ol/dist/esm/im-draw-ol-plugin.js +1 -1
- package/plugins/beta/draw-ol/src/core/OLDrawManager.js +3 -0
- package/plugins/beta/draw-ol/src/draw/DrawMode.js +57 -49
- package/plugins/beta/draw-ol/src/draw/drawInput.js +76 -32
- package/plugins/beta/draw-ol/src/edit/EditMode.js +4 -4
- package/plugins/beta/draw-ol/src/edit/keyboardHandler.js +4 -2
- package/plugins/beta/draw-ol/src/manifest.js +5 -1
- package/plugins/beta/draw-ol/src/reducer.js +1 -1
- package/plugins/beta/draw-ol/src/snap/snapEngine.js +75 -31
- package/plugins/beta/draw-ol/src/snap/snapGeometry.js +23 -46
- package/plugins/beta/draw-ol/src/snap/snapInteraction.js +30 -29
- package/plugins/beta/draw-ol/src/snap/snapManager.js +10 -1
- package/plugins/beta/draw-ol/src/utils/geometryHelpers.js +9 -3
- package/plugins/beta/draw-ol/src/utils/olCoords.js +2 -2
- package/plugins/beta/draw-ol/src/utils/spatial.js +4 -8
- package/plugins/beta/map-styles/src/mapStyles.scss +41 -41
- package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
- package/plugins/interact/dist/umd/index.js +1 -1
- package/plugins/interact/src/InteractInit.jsx +1 -3
- package/plugins/interact/src/InteractInit.test.js +0 -2
- package/plugins/interact/src/events.test.js +1 -1
- package/plugins/interact/src/hooks/useCrossHairVisibility.js +4 -10
- package/plugins/interact/src/hooks/useCrossHairVisibility.test.js +5 -10
- package/plugins/interact/src/hooks/useHighlightSync.js +1 -10
- package/plugins/interact/src/hooks/useHighlightSync.test.js +2 -21
- package/plugins/interact/src/hooks/useInteractionHandlers.js +5 -11
- package/plugins/interact/src/hooks/useInteractionHandlers.test.js +5 -25
- package/plugins/interact/src/reducer.js +4 -22
- package/plugins/interact/src/reducer.test.js +11 -39
- package/plugins/search/dist/css/index.css +5 -2
- package/plugins/search/src/components/Form/Form.module.scss +5 -2
- package/plugins/search/src/search.scss +4 -4
- package/providers/beta/openlayers/dist/esm/im-openlayers-provider.js +1 -1
- package/providers/beta/openlayers/dist/umd/im-openlayers-provider.js +1 -1
- package/providers/beta/openlayers/dist/umd/index.js +1 -1
- package/providers/beta/openlayers/src/utils/tileLayers.js +29 -2
- package/providers/beta/openlayers/src/utils/tileLayers.test.js +53 -1
- package/src/App/components/CrossHair/CrossHair.module.scss +8 -8
- package/src/App/components/MapButton/MapButton.jsx +14 -10
- package/src/App/components/MapButton/MapButton.module.scss +1 -1
- package/src/App/components/MapButton/MapButton.test.jsx +1 -1
- package/src/App/components/PopupMenu/PopupMenu.test.jsx +79 -0
- package/src/App/components/PopupMenu/usePopupMenu.js +61 -12
- package/src/App/hooks/useLayoutMeasurements.js +10 -2
- package/src/App/hooks/useResizeObserver.js +4 -2
- package/src/InteractiveMap/InteractiveMap.js +4 -4
- package/src/InteractiveMap/InteractiveMap.test.js +3 -3
- package/src/InteractiveMap/behaviourController.js +3 -1
- package/src/InteractiveMap/behaviourController.test.js +6 -3
- package/src/InteractiveMap/domStateManager.js +2 -0
- package/src/config/events.js +21 -3
- package/src/types.js +12 -3
- package/src/utils/findNextTabStop.js +3 -3
- package/src/utils/findNextTabStop.test.js +25 -1
- package/webpack.dev.mjs +1 -0
- package/docs/assets/images/screens-blue.jpg +0 -0
- package/docs/assets/images/screens-white.jpg +0 -0
|
@@ -35,6 +35,14 @@ export const DrawInit = ({ appState, appConfig, mapState, pluginConfig, pluginSt
|
|
|
35
35
|
return () => remove()
|
|
36
36
|
}, [mapState.isMapReady, appState.mode])
|
|
37
37
|
|
|
38
|
+
// Keep draw instance aware of the crossHair API so draw modes can use show/hide
|
|
39
|
+
// (rather than direct DOM manipulation which conflicts with React's controlled display style)
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (mapProvider.draw) {
|
|
42
|
+
mapProvider.draw._crossHair = crossHair
|
|
43
|
+
}
|
|
44
|
+
}, [mapProvider.draw, crossHair])
|
|
45
|
+
|
|
38
46
|
// Show crosshair immediately on touch/keyboard when entering draw mode
|
|
39
47
|
useEffect(() => {
|
|
40
48
|
if (['draw_polygon', 'draw_line'].includes(pluginState.mode) && isTouchOrKeyboard) {
|
|
@@ -48,6 +56,17 @@ export const DrawInit = ({ appState, appConfig, mapState, pluginConfig, pluginSt
|
|
|
48
56
|
}
|
|
49
57
|
}, [pluginState.mode, appState.interfaceType])
|
|
50
58
|
|
|
59
|
+
// Keep edit mode in sync with the global interface type so the touch
|
|
60
|
+
// offset target shows/hides immediately when the input device changes
|
|
61
|
+
// (e.g. switching between stylus/touch and mouse on a Surface tablet).
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (pluginState.mode !== 'edit_vertex' || !mapProvider.map) {
|
|
64
|
+
return undefined
|
|
65
|
+
}
|
|
66
|
+
mapProvider.map.fire('draw.interfacetypechange', { interfaceType: appState.interfaceType })
|
|
67
|
+
return undefined
|
|
68
|
+
}, [appState.interfaceType, pluginState.mode])
|
|
69
|
+
|
|
51
70
|
// Attach events when plgin state changes
|
|
52
71
|
useEffect(() => {
|
|
53
72
|
if (!mapProvider.draw) {
|
|
@@ -56,6 +56,7 @@ export const newLine = ({ appState, appConfig, pluginConfig, pluginState, mapPro
|
|
|
56
56
|
vertexMarkerId: `${appConfig.id}-cross-hair`,
|
|
57
57
|
addVertexButtonId: `${appConfig.id}-draw-add-point`,
|
|
58
58
|
interfaceType: appState.interfaceType,
|
|
59
|
+
crossHair: draw._crossHair,
|
|
59
60
|
getSnapEnabled: () => mapProvider.snapEnabled === true,
|
|
60
61
|
featureId,
|
|
61
62
|
...modeOptions,
|
|
@@ -56,6 +56,7 @@ export const newPolygon = ({ appState, appConfig, pluginConfig, pluginState, map
|
|
|
56
56
|
vertexMarkerId: `${appConfig.id}-cross-hair`,
|
|
57
57
|
addVertexButtonId: `${appConfig.id}-draw-add-point`,
|
|
58
58
|
interfaceType: appState.interfaceType,
|
|
59
|
+
crossHair: draw._crossHair,
|
|
59
60
|
getSnapEnabled: () => mapProvider.snapEnabled === true,
|
|
60
61
|
featureId,
|
|
61
62
|
...modeOptions,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import createVertex from '../../../../../node_modules/@mapbox/mapbox-gl-draw/src/lib/create_vertex.js'
|
|
1
|
+
import createVertex from '../../../../../node_modules/@mapbox/mapbox-gl-draw/src/lib/create_vertex.js' // NOSONAR
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
getSnapInstance,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
* @param {Function} config.validateClick - Validation function for clicks
|
|
24
24
|
* @param {Function} config.createVertices - Function to create vertex display features
|
|
25
25
|
*/
|
|
26
|
-
export const createDrawMode = (ParentMode, config) => {
|
|
26
|
+
export const createDrawMode = (ParentMode, config) => { // NOSONAR — factory returns a single cohesive mode object; splitting across files would obscure the event flow
|
|
27
27
|
const {
|
|
28
28
|
featureProp,
|
|
29
29
|
geometryType,
|
|
@@ -35,6 +35,7 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
35
35
|
} = config
|
|
36
36
|
|
|
37
37
|
const getFeature = (state) => state[featureProp]
|
|
38
|
+
const RUBBER_BAND_OFFSET = 2 // ring is [...placed, last_placed, rubber_band]; splice(-2,1) removes last_placed
|
|
38
39
|
|
|
39
40
|
return {
|
|
40
41
|
...ParentMode,
|
|
@@ -45,7 +46,7 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
45
46
|
// Some parent modes (DrawLineString) interpret featureId as "continue existing"
|
|
46
47
|
// rather than "use this ID for new feature"
|
|
47
48
|
const parentOptions = excludeFeatureIdFromSetup
|
|
48
|
-
? { ...options, featureId:
|
|
49
|
+
? { ...options, featureId: null }
|
|
49
50
|
: options
|
|
50
51
|
|
|
51
52
|
const state = {
|
|
@@ -56,17 +57,22 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
56
57
|
// Add initial props
|
|
57
58
|
state[featureProp].properties = options.properties
|
|
58
59
|
|
|
59
|
-
const { container,
|
|
60
|
+
const { container, vertexMarkerId, getInterfaceType } = state
|
|
61
|
+
const currentInterfaceType = getInterfaceType ? getInterfaceType() : state.interfaceType
|
|
62
|
+
state.interfaceType = currentInterfaceType
|
|
60
63
|
const vertexMarker = container.querySelector(`#${vertexMarkerId}`)
|
|
61
|
-
vertexMarker.style.display = ['touch', 'keyboard'].includes(interfaceType) ? 'block' : 'none'
|
|
62
64
|
state.vertexMarker = vertexMarker
|
|
65
|
+
if (['touch', 'keyboard'].includes(currentInterfaceType)) {
|
|
66
|
+
this._showCrossHair(state)
|
|
67
|
+
} else {
|
|
68
|
+
this._hideCrossHair(state)
|
|
69
|
+
}
|
|
63
70
|
|
|
64
71
|
// Bind all handlers once
|
|
65
72
|
const bind = (name, fn) => (this[name] = fn.bind(this, state))
|
|
66
73
|
const handlers = {
|
|
67
74
|
keydownHandler: this.onKeydown,
|
|
68
75
|
keyupHandler: this.onKeyup,
|
|
69
|
-
focusHandler: this.onFocus,
|
|
70
76
|
blurHandler: this.onBlur,
|
|
71
77
|
createHandler: this.onCreate,
|
|
72
78
|
moveHandler: this.onMove,
|
|
@@ -83,7 +89,6 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
83
89
|
[window, 'keydown', this.keydownHandler],
|
|
84
90
|
[window, 'keyup', this.keyupHandler],
|
|
85
91
|
[window, 'click', this.vertexButtonClickHandler],
|
|
86
|
-
[container, 'focus', this.focusHandler],
|
|
87
92
|
[container, 'blur', this.blurHandler],
|
|
88
93
|
[container, 'pointermove', this.pointermoveHandler],
|
|
89
94
|
[container, 'pointerup', this.pointerupHandler],
|
|
@@ -118,9 +123,10 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
118
123
|
}
|
|
119
124
|
const coordsBefore = getCoords(getFeature(state)).length
|
|
120
125
|
ParentMode.onClick.call(this, state, e)
|
|
121
|
-
// Push undo if a vertex was added
|
|
126
|
+
// Push undo and update count if a vertex was added
|
|
122
127
|
if (getCoords(getFeature(state)).length > coordsBefore) {
|
|
123
128
|
this.pushDrawUndo(state)
|
|
129
|
+
this.dispatchVertexChange(getCoords(getFeature(state)))
|
|
124
130
|
}
|
|
125
131
|
},
|
|
126
132
|
|
|
@@ -168,7 +174,7 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
168
174
|
},
|
|
169
175
|
|
|
170
176
|
dispatchVertexChange (coords) {
|
|
171
|
-
//
|
|
177
|
+
// Both polygon ring and LineString store [v0...vN, rubber_band] during drawing — subtract 1 to get placed vertex count
|
|
172
178
|
this.map.fire('draw.vertexchange', {
|
|
173
179
|
numVertecies: Math.max(0, coords.length - 1)
|
|
174
180
|
})
|
|
@@ -230,6 +236,7 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
230
236
|
featureId,
|
|
231
237
|
container: state.container,
|
|
232
238
|
interfaceType: state.interfaceType,
|
|
239
|
+
crossHair: state.crossHair,
|
|
233
240
|
vertexMarkerId: state.vertexMarkerId,
|
|
234
241
|
addVertexButtonId: state.addVertexButtonId,
|
|
235
242
|
getSnapEnabled: state.getSnapEnabled,
|
|
@@ -269,7 +276,7 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
269
276
|
_removeLastVertex (state, feature, coords) {
|
|
270
277
|
// Structure during drawing: [v1, v2, ..., vN, rubber_band]
|
|
271
278
|
const ring = geometryType === 'Polygon' ? feature.coordinates[0] : coords
|
|
272
|
-
ring.splice(
|
|
279
|
+
ring.splice(-RUBBER_BAND_OFFSET, 1)
|
|
273
280
|
|
|
274
281
|
// Snap rubber band to new last vertex position
|
|
275
282
|
const newLastVertex = ring[ring.length - 2]
|
|
@@ -338,10 +345,18 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
338
345
|
this.map.fire('draw.geometrychange', state.polygon || state.line)
|
|
339
346
|
},
|
|
340
347
|
|
|
348
|
+
_showCrossHair (state) {
|
|
349
|
+
if (state.crossHair) { state.crossHair.show() } else { state.vertexMarker.style.display = 'block' }
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
_hideCrossHair (state) {
|
|
353
|
+
if (state.crossHair) { state.crossHair.hide() } else { state.vertexMarker.style.display = 'none' }
|
|
354
|
+
},
|
|
355
|
+
|
|
341
356
|
_setInterface (state, type, show = true) {
|
|
342
357
|
state.interfaceType = type
|
|
343
358
|
if (show) {
|
|
344
|
-
state
|
|
359
|
+
this._showCrossHair(state)
|
|
345
360
|
}
|
|
346
361
|
},
|
|
347
362
|
|
|
@@ -370,32 +385,36 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
370
385
|
this.onMove(state, e)
|
|
371
386
|
},
|
|
372
387
|
|
|
388
|
+
_handleUndoKeydown (state, e) {
|
|
389
|
+
const tag = document.activeElement?.tagName
|
|
390
|
+
if (tag === 'INPUT' || tag === 'TEXTAREA') {
|
|
391
|
+
return
|
|
392
|
+
}
|
|
393
|
+
e.preventDefault()
|
|
394
|
+
e.stopPropagation()
|
|
395
|
+
const undoStack = this.map._undoStack
|
|
396
|
+
if (undoStack && undoStack.length > 0) {
|
|
397
|
+
const operation = undoStack.pop()
|
|
398
|
+
if (operation?.type === 'draw_vertex') {
|
|
399
|
+
// Set flag to prevent click interference during undo
|
|
400
|
+
this.map._undoInProgress = true
|
|
401
|
+
setTimeout(() => { this.map._undoInProgress = false }, 100)
|
|
402
|
+
this.undoVertex(state)
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
|
|
373
407
|
onKeydown (state, e) {
|
|
374
|
-
// Undo with Cmd/Ctrl+Z (works without viewport focus, but not in input fields)
|
|
375
408
|
if (e.key === 'z' && (e.metaKey || e.ctrlKey) && !e.shiftKey) {
|
|
376
|
-
|
|
377
|
-
if (tag === 'INPUT' || tag === 'TEXTAREA') {
|
|
378
|
-
return
|
|
379
|
-
}
|
|
380
|
-
e.preventDefault()
|
|
381
|
-
e.stopPropagation()
|
|
382
|
-
const undoStack = this.map._undoStack
|
|
383
|
-
if (undoStack && undoStack.length > 0) {
|
|
384
|
-
const operation = undoStack.pop()
|
|
385
|
-
if (operation?.type === 'draw_vertex') {
|
|
386
|
-
// Set flag to prevent click interference during undo
|
|
387
|
-
this.map._undoInProgress = true
|
|
388
|
-
setTimeout(() => { this.map._undoInProgress = false }, 100)
|
|
389
|
-
this.undoVertex(state)
|
|
390
|
-
}
|
|
391
|
-
}
|
|
409
|
+
this._handleUndoKeydown(state, e)
|
|
392
410
|
return
|
|
393
411
|
}
|
|
394
412
|
if (document.activeElement !== state.container) {
|
|
395
413
|
return
|
|
396
414
|
}
|
|
397
415
|
if (e.key === 'Escape') {
|
|
398
|
-
|
|
416
|
+
e.preventDefault()
|
|
417
|
+
return
|
|
399
418
|
}
|
|
400
419
|
if (e.key === 'Enter') {
|
|
401
420
|
state.isActive = true
|
|
@@ -449,13 +468,9 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
449
468
|
}
|
|
450
469
|
},
|
|
451
470
|
|
|
452
|
-
onFocus (state) {
|
|
453
|
-
state.vertexMarker.style.display = ['touch', 'keyboard'].includes(state.interfaceType) ? 'block' : 'none'
|
|
454
|
-
},
|
|
455
|
-
|
|
456
471
|
onBlur (state, e) {
|
|
457
472
|
if (e.target !== state.container) {
|
|
458
|
-
state
|
|
473
|
+
this._hideCrossHair(state)
|
|
459
474
|
}
|
|
460
475
|
},
|
|
461
476
|
|
|
@@ -505,13 +520,13 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
505
520
|
|
|
506
521
|
onPointerdown (state, e) {
|
|
507
522
|
if (e.pointerType !== 'touch') {
|
|
508
|
-
this._setInterface(state, '
|
|
523
|
+
this._setInterface(state, 'mouse', false)
|
|
509
524
|
}
|
|
510
525
|
},
|
|
511
526
|
|
|
512
527
|
onPointermove (state, e) {
|
|
513
528
|
if (e.pointerType !== 'touch') {
|
|
514
|
-
state
|
|
529
|
+
this._hideCrossHair(state)
|
|
515
530
|
}
|
|
516
531
|
},
|
|
517
532
|
|
|
@@ -531,7 +546,7 @@ export const createDrawMode = (ParentMode, config) => {
|
|
|
531
546
|
onStop (state) {
|
|
532
547
|
ParentMode.onStop.call(this, state)
|
|
533
548
|
this._listeners.forEach(([t, e, h]) => t.removeEventListener ? t.removeEventListener(e, h) : t.off(e, h))
|
|
534
|
-
state
|
|
549
|
+
this._hideCrossHair(state)
|
|
535
550
|
}
|
|
536
551
|
}
|
|
537
552
|
}
|
|
@@ -43,7 +43,7 @@ export const touchHandlers = {
|
|
|
43
43
|
},
|
|
44
44
|
|
|
45
45
|
onPointerevent (state, e) {
|
|
46
|
-
state.interfaceType = e.pointerType === 'touch' ? 'touch' : '
|
|
46
|
+
state.interfaceType = e.pointerType === 'touch' ? 'touch' : 'mouse'
|
|
47
47
|
state.isPanEnabled = true
|
|
48
48
|
if (e.pointerType === 'touch' && e.type === 'pointermove' && !isOnSVG(e.target.parentNode) && !state._ignorePointermoveDeselect) {
|
|
49
49
|
this.changeMode(state, { selectedVertexIndex: -1, selectedVertexType: null, coordPath: null })
|
|
@@ -119,11 +119,12 @@ export const vertexOperations = {
|
|
|
119
119
|
const deletedPosition = [...state.vertecies[state.selectedVertexIndex]]
|
|
120
120
|
const deletedIndex = state.selectedVertexIndex
|
|
121
121
|
|
|
122
|
-
this._ctx.api.trash()
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
// Remove the coordinate directly rather than via this._ctx.api.trash(), which routes through
|
|
123
|
+
// DirectSelect.trash() and calls onSetup({ featureId }) with incomplete options, crashing event registration.
|
|
124
|
+
const coordPath = [...result.segment.path, result.localIdx].join('.')
|
|
125
|
+
feature.removeCoordinate(coordPath)
|
|
126
|
+
this.fireUpdate()
|
|
125
127
|
this.clearSelectedCoordinates()
|
|
126
|
-
// Force feature re-render to clear vertex highlights
|
|
127
128
|
feature.changed()
|
|
128
129
|
this._ctx.store.render()
|
|
129
130
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import DirectSelect from '../../../../../node_modules/@mapbox/mapbox-gl-draw/src/modes/direct_select.js'
|
|
1
|
+
import DirectSelect from '../../../../../node_modules/@mapbox/mapbox-gl-draw/src/modes/direct_select.js' // NOSONAR
|
|
2
2
|
import {
|
|
3
3
|
getSnapInstance, isSnapActive, isSnapEnabled, getSnapLngLat,
|
|
4
4
|
getSnapRadius, triggerSnapAtPoint, clearSnapIndicator, clearSnapState
|
|
@@ -44,25 +44,7 @@ export const EditVertexMode = {
|
|
|
44
44
|
state.midpoints = this.getMidpoints(state.featureId)
|
|
45
45
|
this.setupEventListeners(state)
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
// Clear any vertex selection when switching to midpoint
|
|
49
|
-
state.selectedCoordPaths = []
|
|
50
|
-
this.clearSelectedCoordinates()
|
|
51
|
-
// Force feature re-render to clear vertex highlights
|
|
52
|
-
if (state.feature) {
|
|
53
|
-
state.feature.changed()
|
|
54
|
-
}
|
|
55
|
-
this._ctx.store.render()
|
|
56
|
-
this.updateMidpoint(state.midpoints[options.selectedVertexIndex - state.vertecies.length])
|
|
57
|
-
} else if (options.selectedVertexIndex === -1) {
|
|
58
|
-
// Explicitly clear selection when re-entering with no vertex selected
|
|
59
|
-
state.selectedCoordPaths = []
|
|
60
|
-
this.clearSelectedCoordinates()
|
|
61
|
-
if (state.feature) {
|
|
62
|
-
state.feature.changed()
|
|
63
|
-
}
|
|
64
|
-
this._ctx.store.render()
|
|
65
|
-
}
|
|
47
|
+
this.applyVertexSelection(state, options)
|
|
66
48
|
this.map._drawEditContainer = options.container
|
|
67
49
|
this.addTouchVertexTarget(state)
|
|
68
50
|
|
|
@@ -104,7 +86,8 @@ export const EditVertexMode = {
|
|
|
104
86
|
selectionchange: bind(this.onSelectionChange),
|
|
105
87
|
scalechange: bind(this.onScaleChange),
|
|
106
88
|
update: bind(this.onUpdate),
|
|
107
|
-
move: bind(this.onMove)
|
|
89
|
+
move: bind(this.onMove),
|
|
90
|
+
interfacetypechange: bind(this.onInterfaceTypeChange)
|
|
108
91
|
}
|
|
109
92
|
|
|
110
93
|
window.addEventListener('keydown', h.keydown, { capture: true })
|
|
@@ -120,9 +103,30 @@ export const EditVertexMode = {
|
|
|
120
103
|
this.map.on('draw.scalechange', h.scalechange)
|
|
121
104
|
this.map.on('draw.update', h.update)
|
|
122
105
|
this.map.on('move', h.move)
|
|
106
|
+
this.map.on('draw.interfacetypechange', h.interfacetypechange)
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
applyVertexSelection (state, options) {
|
|
110
|
+
if (options.selectedVertexType === 'midpoint') {
|
|
111
|
+
state.selectedCoordPaths = []
|
|
112
|
+
this.clearSelectedCoordinates()
|
|
113
|
+
if (state.feature) { state.feature.changed() }
|
|
114
|
+
this._ctx.store.render()
|
|
115
|
+
this.updateMidpoint(state.midpoints[options.selectedVertexIndex - state.vertecies.length])
|
|
116
|
+
return
|
|
117
|
+
}
|
|
118
|
+
if (options.selectedVertexIndex === -1) {
|
|
119
|
+
state.selectedCoordPaths = []
|
|
120
|
+
this.clearSelectedCoordinates()
|
|
121
|
+
if (state.feature) { state.feature.changed() }
|
|
122
|
+
this._ctx.store.render()
|
|
123
|
+
}
|
|
123
124
|
},
|
|
124
125
|
|
|
125
126
|
onSelectionChange (state, e) {
|
|
127
|
+
// Refresh vertex list so numVertecies reflects the latest geometry (e.g. after midpoint insertion)
|
|
128
|
+
this.syncVertices(state)
|
|
129
|
+
|
|
126
130
|
const vertexCoord = e.points[e.points.length - 1]?.geometry.coordinates
|
|
127
131
|
|
|
128
132
|
// Only update selectedVertexIndex from event if not keyboard mode AND event has valid vertex
|
|
@@ -151,6 +155,12 @@ export const EditVertexMode = {
|
|
|
151
155
|
state.scale = e.scale
|
|
152
156
|
},
|
|
153
157
|
|
|
158
|
+
onInterfaceTypeChange (state, e) {
|
|
159
|
+
state.interfaceType = e.interfaceType
|
|
160
|
+
const vertex = state.selectedVertexIndex >= 0 ? state.vertecies[state.selectedVertexIndex] : null
|
|
161
|
+
this.updateTouchVertexTarget(state, vertex ? scalePoint(this.map.project(vertex), state.scale) : null)
|
|
162
|
+
},
|
|
163
|
+
|
|
154
164
|
onUpdate (state) {
|
|
155
165
|
const prev = new Set(state.vertecies.map(c => JSON.stringify(c)))
|
|
156
166
|
if (prev.size === state.vertecies.length) {
|
|
@@ -168,6 +178,10 @@ export const EditVertexMode = {
|
|
|
168
178
|
state.interfaceType = 'keyboard'
|
|
169
179
|
this.hideTouchVertexIndicator(state)
|
|
170
180
|
|
|
181
|
+
if (e.key === ' ') {
|
|
182
|
+
e.preventDefault()
|
|
183
|
+
}
|
|
184
|
+
|
|
171
185
|
if (e.key === ' ' && state.selectedVertexIndex < 0) {
|
|
172
186
|
// Clear snap indicator when starting keyboard selection
|
|
173
187
|
const snap = getSnapInstance(this.map)
|
|
@@ -321,6 +335,21 @@ export const EditVertexMode = {
|
|
|
321
335
|
}
|
|
322
336
|
},
|
|
323
337
|
|
|
338
|
+
onClick (state, e) { // NOSONAR — complexity accumulated from object-level context; single guard clause, see feedback_mgl_click_vs_mouseup.md
|
|
339
|
+
if (state._isInsertingVertex && state._insertedVertexIndex !== undefined) {
|
|
340
|
+
const insertedIndex = state._insertedVertexIndex
|
|
341
|
+
this.syncVertices(state)
|
|
342
|
+
this.pushUndo({ type: 'insert_vertex', featureId: state.featureId, vertexIndex: insertedIndex })
|
|
343
|
+
state.selectedVertexIndex = insertedIndex
|
|
344
|
+
state.selectedVertexType = 'vertex'
|
|
345
|
+
state._isInsertingVertex = false
|
|
346
|
+
state._insertedVertexIndex = undefined
|
|
347
|
+
this.map.fire('draw.vertexselection', { index: insertedIndex, numVertecies: state.vertecies.length })
|
|
348
|
+
return
|
|
349
|
+
}
|
|
350
|
+
DirectSelect.onClick.call(this, state, e)
|
|
351
|
+
},
|
|
352
|
+
|
|
324
353
|
onMouseUp (state, e) {
|
|
325
354
|
clearSnapState(getSnapInstance(this.map))
|
|
326
355
|
|
|
@@ -372,6 +401,8 @@ export const EditVertexMode = {
|
|
|
372
401
|
vertexIndex: state._moveStartIndex,
|
|
373
402
|
previousPosition: state._moveStartPosition
|
|
374
403
|
})
|
|
404
|
+
} else {
|
|
405
|
+
// No action
|
|
375
406
|
}
|
|
376
407
|
}
|
|
377
408
|
|
|
@@ -454,6 +485,7 @@ export const EditVertexMode = {
|
|
|
454
485
|
this.map.off('draw.scalechange', h.scalechange)
|
|
455
486
|
this.map.off('draw.update', h.update)
|
|
456
487
|
this.map.off('move', h.move)
|
|
488
|
+
this.map.off('draw.interfacetypechange', h.interfacetypechange)
|
|
457
489
|
this.map.dragPan.enable()
|
|
458
490
|
window.removeEventListener('click', h.click)
|
|
459
491
|
window.removeEventListener('keydown', h.keydown, { capture: true })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"ol/interaction/Draw.js";import{c as
|
|
1
|
+
import e from"ol/interaction/Draw.js";import{noModifierKeys as t}from"ol/events/condition.js";import{c as r,p as n,g as o}from"./geometryHelpers.js";var a=4,i=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"]),l=e=>{var t,{drawInteraction:o,options:l}=e,{container:d,addVertexButtonId:s,mapProvider:u,snap:g,onUndo:p,canFinish:c}=l,v=null!==(t=l.interfaceType)&&void 0!==t?t:"mouse",y=null,m=null;o.on("drawstart",e=>{y=e.feature,m=null}),o.on("drawend",()=>{y=null,m=null}),o.on("drawabort",()=>{y=null,m=null});var f=()=>{if(y){var e=y.getGeometry();if(e.getCoordinates().length){var t=u.getCenter();((e,t)=>{if("LineString"===e.getType()){var r=[...e.getCoordinates()];r[r.length-1]=t,e.setCoordinates(r)}else if("Polygon"===e.getType()){var n=e.getCoordinates().map((e,r)=>{if(0!==r)return e;var n=[...e];return n[n.length-1]=t,n});e.setCoordinates(n)}})(e,"mouse"!==v&&g?g.apply(t):t)}}else"mouse"!==v&&g&&g.apply(u.getCenter())},h=(e,t,i)=>{if(m&&m[0]===i[0]&&m[1]===i[1])return null!=c&&c()&&o.finishDrawing(),m=null,!0;if(((e,t,o,i)=>{if("Polygon"!==i||o.length<a)return!1;var l=o[0],d=r(e,t),s=r(e,l);return!(!d||!s)&&n(d,s)<12})(o.getMap(),i,t,e.getType()))return o.finishDrawing(),!0;var l=o.getMap(),d=(e=>{if("Polygon"===e.getType()){var t=e.getCoordinates()[0]||[];return t.length>=3?t[t.length-3]:null}var r=e.getCoordinates();return r.length>=2?r[r.length-2]:null})(e);if(d){var s=l.getPixelFromCoordinate(d),u=l.getPixelFromCoordinate(i);if(s&&u){var g=s[0]-u[0],p=s[1]-u[1];if(g*g+p*p<4)return m=i,!0}}return!1},w=o.getMap(),C=null==w?void 0:w.getView(),T=(e=>{var{container:t,addVertexButtonId:r,olView:n,onUndo:o,getInterfaceType:a,setInterfaceType:l,clearLastCoord:d,updateRubberbanding:s,placeVertex:u}=e,g=()=>{"mouse"!==a()&&s()};null==n||n.on("change:center",g);var p=e=>{t.contains(document.activeElement)&&(i.has(e.key)?l("keyboard"):("Enter"===e.key&&(e.preventDefault(),l("keyboard"),u()),"z"===e.key&&(e.metaKey||e.ctrlKey)&&(e.preventDefault(),null==o||o())))},c=e=>{r&&e.target.closest("#".concat(r))&&u()},v=e=>{"touch"!==e.pointerType&&(l("mouse"),d())},y=()=>{l("touch")},m=()=>{"mouse"!==a()&&s()};return globalThis.addEventListener("keydown",p),globalThis.addEventListener("click",c),t.addEventListener("pointerdown",v),t.addEventListener("touchstart",y,{passive:!0}),t.addEventListener("pointermove",m),{destroy(){null==n||n.un("change:center",g),globalThis.removeEventListener("keydown",p),globalThis.removeEventListener("click",c),t.removeEventListener("pointerdown",v),t.removeEventListener("touchstart",y),t.removeEventListener("pointermove",m)}}})({container:d,addVertexButtonId:s,olView:C,onUndo:p,getInterfaceType:()=>v,setInterfaceType:e=>{v=e},clearLastCoord:()=>{m=null},updateRubberbanding:f,placeVertex:()=>{var e=u.getCenter(),t="mouse"!==v&&g?g.apply(e):e;if(null==g||g.hideIndicator(),y){var r=y.getGeometry(),n=r.getCoordinates(),a="Polygon"===r.getType()?n[0]||[]:n;if(h(r,a,t))return}o.appendCoordinates([t]),m=t}}),I=()=>{"mouse"!==v&&null!=C&&C.getAnimating()&&f()};return null==w||w.on("postrender",I),{getInterfaceType:()=>v,destroy(){T.destroy(),null==w||w.un("postrender",I)}}},d={Polygon:3,LineString:2},s=(e,t)=>{if(!t)return!1;var r=t.getGeometry();return o({type:e,coordinates:r.getCoordinates()}).length-1>=d[e]},u=(e,r,n)=>o=>{if(!t(o))return!1;var a=n();if(!a||s(r,a))return!0;var i=(e=>{if("Polygon"===e.getType()){var t=e.getCoordinates()[0]||[];return t.length>=3?t[t.length-3]:null}var r=e.getCoordinates();return r.length>=2?r[r.length-2]:null})(a.getGeometry());if(!i)return!0;var l=e.getPixelFromCoordinate(i);if(!l)return!0;var d=o.pixel[0]-l[0],u=o.pixel[1]-l[1];return d*d+u*u>4},g=t=>{var{map:r,manager:n,options:a}=t,{geometryType:i,featureId:d,properties:g={},container:p,interfaceType:c,addVertexButtonId:v,mapProvider:y,snap:m}=a,f=null,h=new e({type:i,style:n.styles.createSketchStyle(),stopClick:!0,snapTolerance:12,condition:u(r,i,()=>f)});r.addInteraction(h),h.overlay_.updateWhileAnimating_=!0;var w=()=>{if(f){var e=f.getGeometry(),t=o({type:i,coordinates:e.getCoordinates()});n.emit("vertexchange",{numVertices:Math.max(0,t.length-1)})}};h.on("drawstart",e=>{(f=e.feature).getGeometry().on("change",w)}),h.on("drawend",e=>{var t=e.feature;t.setId(String(d)),t.setProperties(g),n.store.source.addFeature(t),n.emit("create",n.store.toGeoJSON(t))}),h.on("drawabort",()=>{n.emit("cancel")});var C=l({drawInteraction:h,options:{container:p,interfaceType:c,addVertexButtonId:v,mapProvider:y,snap:m,onUndo:()=>{h.removeLastPoint(),w()},canFinish:()=>s(i,f)}});return{done(){s(i,f)&&h.finishDrawing()},cancel(){h.abortDrawing()},undo(){h.removeLastPoint(),w()},destroy(){C.destroy(),r.removeInteraction(h),f=null}}};export{g as createDrawMode};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"ol/interaction/Modify.js";import t from"ol/Collection.js";import r from"ol/source/Vector.js";import n from"ol/layer/Vector.js";import o from"ol/Feature.js";import a from"ol/geom/Point.js";import{a as i,g as d,b as l,d as s,e as c,c as v,p,f as x,n as u}from"./geometryHelpers.js";var y=(e,t)=>{e&&(e.style.setProperty("--draw-halo",t.editActive),e.style.setProperty("--draw-bg",t.editHalo),e.style.setProperty("--draw-primary",t.editVertex))},g=(e,t)=>{t&&e&&(e.style.left="".concat(t.x,"px"),e.style.top="".concat(t.y,"px"),e.style.display="block")},f=e=>{e&&(e.style.display="none")},m=e=>{if(!e)return!1;var t=e.parentNode;return t instanceof globalThis.SVGElement||null!=(null==t?void 0:t.ownerSVGElement)},h=(e,t,r,n)=>{var o=r-n,a=t[o];if(!a)return null;var i=e.getGeometry(),d={type:i.getType(),coordinates:i.getCoordinates()},s=l(d),v=0;for(var p of s){var x=p.closed?p.length:p.length-1;if(o<v+x){var u=o-v+1,y=p.start+u;return c(d,p.path).splice(u,0,[...a]),i.setCoordinates(d.coordinates),{insertedIndex:y}}v+=x}return null},I=(e,t,r)=>{var n=e.getGeometry(),o={type:n.getType(),coordinates:n.getCoordinates()},a=l(o),i=s(a,t);if(i){var d=c(o,i.segment.path);d[i.localIdx]=[...r],i.segment.closed&&0===i.localIdx&&(d[d.length-1]=[...r]),n.setCoordinates(o.coordinates)}},T=function(e,t,r,n){var o,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:12;return null!==(o=function(e,t,r){var n=-1,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:12;return t.forEach((t,a)=>{var i=v(e,t);if(i){var d=p(i,r);d<o&&(o=d,n=a)}}),n>=0?{index:n,type:"vertex"}:null}(e,t,n,a))&&void 0!==o?o:function(e,t,r,n){var o=-1,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:12;return t.forEach((t,n)=>{var i=v(e,t);if(i){var d=p(i,r);d<a&&(a=d,o=n)}}),o>=0?{index:n+o,type:"midpoint"}:null}(e,r,n,t.length,a)},V=e=>{var{map:t,container:r,getState:n,setState:o,onVertexMoved:a,onTap:i,colors:d,snap:l}=e,s=(e=>{var t=e.querySelector("[data-im-draw-touch-target]");return t||(e.insertAdjacentHTML("beforeend","\n <svg width='48' height='48' viewBox='0 0 48 48' fill-rule='evenodd'\n style='display:none;position:absolute;top:0;left:0;margin:24px 0 0 -24px;cursor:grab'\n class='im-draw-touch-target' data-im-draw-touch-target>\n <circle cx='24' cy='24' r='24' fill='var(--draw-halo, #000)'/>\n <path d=\"M37.543 25H34a1 1 0 1 1 0-2h3.629l-.836-.837a1 1 0 0 1 1.414-1.414l2.5 2.501A1 1 0 0 1 41 24a1 1 0 0 1-.487.858l-2.306 2.306a1 1 0 0 1-1.414-1.414l.75-.75zM23 10.414l-.793.793a1 1 0 0 1-1.414-1.414l2.5-2.5C23.481 7.105 23.734 7 24 7s.519.105.707.293l2.5 2.5a1 1 0 0 1-1.414 1.414L25 10.414V14a1 1 0 1 1-2 0v-3.586zM7 24a1 1 0 0 1 .293-.75l2.5-2.501a1 1 0 0 1 1.414 1.414l-.836.837H14a1 1 0 1 1 0 2h-3.543l.75.75a1 1 0 0 1-1.414 1.414l-2.306-2.306A1 1 0 0 1 7 24zm16.293 16.707l-2.5-2.5a1 1 0 0 1 1.414-1.414l.793.793V34a1 1 0 1 1 2 0v3.586l.793-.793a1 1 0 0 1 1.414 1.414l-2.5 2.5c-.188.188-.441.293-.707.293s-.519-.105-.707-.293zM24 20c2.208 0 4 1.792 4 4s-1.792 4-4 4-4-1.792-4-4 1.792-4 4-4z\" fill='var(--draw-bg, #fff)'/>\n </svg>\n"),t=e.querySelector("[data-im-draw-touch-target]")),t})(r);y(s,d);var c={scale:1,ox:0,oy:0},p=e=>({x:e.x*c.scale+c.ox,y:e.y*c.scale+c.oy}),u=()=>{var e=t.getViewport(),n=e.getBoundingClientRect(),o=r.getBoundingClientRect(),a=e.offsetWidth>0?n.width/e.offsetWidth:1,i=r.offsetWidth>0?o.width/r.offsetWidth:1;Object.assign(c,{scale:a/i,ox:(n.left-o.left)/i,oy:(n.top-o.top)/i})},h=(e=>{var{container:t,map:r,targetEl:n,olToCSS:o,cssToOl:a,getState:i,setState:d,onVertexMoved:l,onTap:s,snap:c}=e,p=null,u=null,y=null,f=null,h=null,V=e=>{var t=e.touches[0],o=m(e.target);if(h={x:t.clientX,y:t.clientY,time:Date.now(),onTarget:o},o){var{selectedVertexIndex:d,vertices:l}=i(),s=l[d];if(s){var c=r.getEventPixel({clientX:t.clientX,clientY:t.clientY}),x=v(r,s),g=getComputedStyle(n),I=a({x:Number.parseFloat(g.left),y:Number.parseFloat(g.top)});p=[...s],u=d,y={x:c[0]-x.x,y:c[1]-x.y},f={x:c[0]-I.x,y:c[1]-I.y},e.preventDefault()}}},w=e=>{if(m(e.target)&&null!=u){e.preventDefault();var t=r.getEventPixel({clientX:e.touches[0].clientX,clientY:e.touches[0].clientY}),a=x(r,{x:t[0]-y.x,y:t[1]-y.y}),l=c?c.apply(a):a;null==c||c.hideIndicator();var{olFeature:s,vertices:v}=i();s&&(I(s,u,l),d({vertices:v.map((e,t)=>t===u?l:e)}),g(n,o({x:t[0]-f.x,y:t[1]-f.y})))}},S=e=>{if(null!=u){h=null;var{vertices:t}=i();t[u]&&p&&l({vertexIndex:u,previousCoord:p}),null==c||c.hideIndicator(),p=null,u=null,y=null,f=null,e.preventDefault()}else{if(h&&!h.onTarget&&e.changedTouches.length>0){var n=e.changedTouches[0],o=Date.now()-h.time;if(Math.hypot(n.clientX-h.x,n.clientY-h.y)<10&&o<400){var a=r.getEventPixel({clientX:n.clientX,clientY:n.clientY}),d=i();null==s||s(T(r,d.vertices,d.midpoints,{x:a[0],y:a[1]},24)),e.preventDefault()}}h=null}};return t.addEventListener("touchstart",V,{passive:!1}),t.addEventListener("touchmove",w,{passive:!1}),t.addEventListener("touchend",S,{passive:!1}),{isDragging:()=>null!=u,destroy(){t.removeEventListener("touchstart",V),t.removeEventListener("touchmove",w),t.removeEventListener("touchend",S)}}})({container:r,map:t,targetEl:s,olToCSS:p,cssToOl:e=>({x:(e.x-c.ox)/c.scale,y:(e.y-c.oy)/c.scale}),getState:n,setState:o,onVertexMoved:a,onTap:i,snap:l}),V=()=>{var{selectedVertexIndex:e,vertices:r,interfaceType:o}=n();if(e<0||!r[e]||"touch"!==o)f(s);else{var a=v(t,r[e]);a?g(s,p(a)):f(s)}},w=()=>{var{selectedVertexIndex:e,interfaceType:t}=n();e>=0&&!h.isDragging()&&"touch"===t&&V()};t.on("postrender",w);var S=()=>{u(),t.once("postrender",V)};return t.on("change:size",S),u(),{updateTargetPosition:V,updateColors(e){y(s,e)},hide(){f(s)},destroy(){t.un("change:size",S),t.un("postrender",w),h.destroy(),f(s)}}},w=(e,t,r)=>{var n=t.filter(t=>{var n=Math.abs(t[0]-e[0]),o=Math.abs(t[1]-e[1]);return("ArrowUp"===r?t[1]<=e[1]&&o>=n:"ArrowDown"===r?t[1]>e[1]&&o>=n:"ArrowLeft"===r?t[0]<=e[0]&&o<n:"ArrowRight"!==r||t[0]>e[0]&&o<n)&&JSON.stringify(t)!==JSON.stringify(e)});n.length||n.push(e);var o=t=>Math.sqrt((e[0]-t[0])**2+(e[1]-t[1])**2),a=n.reduce((e,t)=>o(t)<o(e)?t:e);return t.findIndex(e=>JSON.stringify(e)===JSON.stringify(a))},S=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"]),C=new Set(["INPUT","TEXTAREA","BUTTON","SELECT","A"]),E=e=>{var{map:t,snap:r,getState:n,setState:o,onInserted:a}=e,i={start:null,index:null};return{nudge:e=>{var{selectedVertexIndex:d,selectedVertexType:l,vertices:s,midpoints:c,olFeature:v}=n();if(v){var p=e.shiftKey?1:5,x={ArrowUp:[0,-p],ArrowDown:[0,p],ArrowLeft:[-p,0],ArrowRight:[p,0]},[y,g]=x[e.key];if("midpoint"!==l){if(!(d<0)&&s[d]){var f=s[d];i.start||(i.start=[...f],i.index=d);var m=u(t,f,y,g),T=r?r.apply(m):m;null==r||r.hideIndicator();var V=((e,t,r,n,o,a,i)=>{if(!e)return o;var d=[n[0]-r[0],n[1]-r[1]],l=[o[0]-r[0],o[1]-r[1]],s=d[0]**2+d[1]**2;if(s>0&&(l[0]*d[0]+l[1]*d[1])/s<.5){var c=e.snapRadius+1;return u(t,r,0===a?0:Math.sign(a)*c,0===i?0:Math.sign(i)*c)}return o})(r,t,f,m,T,y,g);I(v,d,V),o({vertices:s.map((e,t)=>t===d?V:e)})}}else((e,d,l,s,c,v)=>{var p=h(e,d,l,s.length);if(p){a({insertedIndex:p.insertedIndex});var x=n().vertices,y=x[p.insertedIndex];if(y){i.start=[...y],i.index=p.insertedIndex;var g=u(t,y,c,v),f=r?r.apply(g):g;I(e,p.insertedIndex,f),o({selectedVertexIndex:p.insertedIndex,selectedVertexType:"vertex",vertices:x.map((e,t)=>t===p.insertedIndex?f:e)})}}})(v,c,d,s,y,g)}},keyMove:i}},L=e=>{var t,{map:r,snap:n,getState:o,setState:a,onVertexMoved:i,onInserted:d,onDeleted:l,onUndo:s,onKeyboardActive:c}=e,{nudge:p,keyMove:x}=E({map:r,snap:n,getState:o,setState:a,onInserted:d}),u=null!==(t=r.getViewport().closest('[role="application"]'))&&void 0!==t?t:r.getViewport(),y=()=>(e=>{var t=document.activeElement;if(!t||t===document.body)return!1;if(e.contains(t))return!1;var r=t.tagName;return C.has(r)||t.isContentEditable||t.hasAttribute("tabindex")})(u),g=e=>{e.altKey?(e.preventDefault(),e.stopPropagation(),((e,t,r,n)=>{var{selectedVertexIndex:o,vertices:a,midpoints:i}=r();if(a.length){var d,l=[...a,...i].map(e=>v(t,e)).filter(Boolean).map(e=>[e.x,e.y]),s=o>=0?l[o]:(d=v(t,t.getView().getCenter()))?[d.x,d.y]:null;if(s){var c=w(s,l,e);n({selectedVertexIndex:c,selectedVertexType:c<a.length?"vertex":"midpoint"})}}})(e.key,r,o,a)):o().selectedVertexIndex>=0&&(e.preventDefault(),e.stopPropagation(),p(e))},f=e=>{if(null==c||c()," "===e.key&&o().selectedVertexIndex<0)e.preventDefault(),((e,t,r)=>{var{vertices:n,midpoints:o}=t();if(n.length){var a=e.getView().getCenter(),i=v(e,a);if(i){var d=[...n.map(t=>v(e,t)),...o.map(t=>v(e,t))].filter(Boolean).map(e=>[e.x,e.y]),l=w([i.x,i.y],d,void 0);r({selectedVertexIndex:l,selectedVertexType:l<n.length?"vertex":"midpoint"})}}})(r,o,a);else if(S.has(e.key))g(e);else if("z"===e.key&&(e.metaKey||e.ctrlKey)){var t,n=null===(t=document.activeElement)||void 0===t?void 0:t.tagName;C.has(n)||(e.preventDefault(),e.stopPropagation(),s())}},m=e=>{y()||("Escape"===e.key&&o().selectedVertexIndex>=0?(e.preventDefault(),x.start=null,x.index=null,a({selectedVertexIndex:-1,selectedVertexType:null})):f(e))},h=e=>{y()||(S.has(e.key)&&x.start&&null!=x.index&&(null==n||n.hideIndicator(),i({vertexIndex:x.index,previousCoord:x.start}),x.start=null,x.index=null),"Delete"===e.key&&l())};return window.addEventListener("keydown",m,{capture:!0}),window.addEventListener("keyup",h,{capture:!0}),{destroy(){window.removeEventListener("keydown",m,{capture:!0}),window.removeEventListener("keyup",h,{capture:!0})}}},b=(e,t)=>{switch(t.type){case"move_vertex":return((e,t)=>{var{vertexIndex:r,previousCoord:n}=t,o=e.getGeometry(),a={type:o.getType(),coordinates:o.getCoordinates()},i=l(a),d=s(i,r);if(!d)return-1;var v=c(a,d.segment.path);return v[d.localIdx]=[...n],d.segment.closed&&0===d.localIdx&&(v[v.length-1]=[...n]),o.setCoordinates(a.coordinates),r})(e,t);case"insert_vertex":return((e,t)=>{var{vertexIndex:r}=t,n=e.getGeometry(),o={type:n.getType(),coordinates:n.getCoordinates()},a=l(o),i=s(a,r);if(!i)return-1;var d=c(o,i.segment.path);return d.splice(i.localIdx,1),i.segment.closed&&(d[d.length-1]=[...d[0]]),n.setCoordinates(o.coordinates),-1})(e,t);case"delete_vertex":return((e,t)=>{var{vertexIndex:r,deletedCoord:n}=t,o=e.getGeometry(),a={type:o.getType(),coordinates:o.getCoordinates()},i=l(a),d=s(i,r);if(!d)for(var v of i)if(r===v.start+v.length){d={segment:v,localIdx:v.length};break}if(!d)return-1;var p=c(a,d.segment.path);return p.splice(d.localIdx,0,[...n]),d.segment.closed&&(p[p.length-1]=[...p[0]]),o.setCoordinates(a.coordinates),r})(e,t);default:return-1}},k=v=>{var{map:p,manager:x,options:u}=v,{featureId:y,container:g,interfaceType:f,deleteVertexButtonId:m,snap:I}=u,{store:w,undoStack:S}=x,C=w.getOL(y);if(!C)return null;var E=C.getStyle();C.setStyle(x.styles.editFeatureStyle);var k={olFeature:C,selectedVertexIndex:-1,selectedVertexType:null,vertices:[],midpoints:[],interfaceType:null!=f?f:"pointer"},A=()=>k,M=null,P=null,D=e=>{if(Object.assign(k,e),void 0!==e.selectedVertexIndex){var t;if(X.setSelected("vertex"===k.selectedVertexType?k.selectedVertexIndex:-1),_.setSelected("midpoint"===k.selectedVertexType?k.selectedVertexIndex-k.vertices.length:-1),k.selectedVertexIndex<0)null===(t=M)||void 0===t||t();R(),x.emit("vertexselection",{index:"vertex"===k.selectedVertexType?k.selectedVertexIndex:-1,numVertices:k.vertices.length})}if(void 0!==e.vertices){var r,n={type:C.getGeometry().getType(),coordinates:C.getGeometry().getCoordinates()};_.update(n),X.update(n),k.midpoints=_.getCoords(),R(),null===(r=P)||void 0===r||r(),p.render()}},G=()=>{var e=C.getGeometry(),t={type:e.getType(),coordinates:e.getCoordinates()};k.vertices=d(t),k.midpoints=i(t),_.update(t),X.update(t),R()},z=()=>{G(),x.emit("vertexchange",{numVertices:k.vertices.length}),x.emit("update",w.toGeoJSON(C))},N=()=>G();C.getGeometry().on("change",N);var F=new t([C]),O=new e({features:F,style:()=>[],pixelTolerance:12,condition:e=>{if("touch"===k.interfaceType)return!1;var t=p.getEventPixel(e.originalEvent);return null!==T(p,k.vertices,k.midpoints,{x:t[0],y:t[1]})}});p.addInteraction(O);var j=null;O.on("modifystart",()=>{"touch"!==k.interfaceType&&(j=k.vertices.map(e=>[...e]))}),O.on("modifyend",()=>{if("touch"!==k.interfaceType){var e=j;if(z(),e){var t=k.vertices;if(t.length>e.length){var r=t.findIndex((t,r)=>!e[r]||t[0]!==e[r][0]),n=Math.max(0,r);S.push({type:"insert_vertex",vertexIndex:n}),D({selectedVertexIndex:n,selectedVertexType:"vertex"})}else if(t.length===e.length){var o=t.findIndex((t,r)=>t[0]!==e[r][0]||t[1]!==e[r][1]);o>=0&&(S.push({type:"move_vertex",vertexIndex:o,previousCoord:e[o]}),D({selectedVertexIndex:o,selectedVertexType:"vertex"}))}j=null}}});var _=((e,t)=>{var d=t,l=-1,s=new r,c=new n({source:s,style:e=>e.get("midpointIndex")===l?null:[d],zIndex:101});return e.addLayer(c),{update(e){s.clear();var t=i(e).map((e,t)=>{var r=new o({geometry:new a(e)});return r.set("midpointIndex",t),r});s.addFeatures(t)},setSelected(e){l=e,s.changed()},updateStyle(e){d=e,s.changed()},getCoords:()=>s.getFeatures().sort((e,t)=>e.get("midpointIndex")-t.get("midpointIndex")).map(e=>e.getGeometry().getCoordinates()),remove(){s.clear(),e.removeLayer(c)}}})(p,x.styles.midpointStyle),X=((e,t)=>{var i=t,l=-1,s=new r,c=new n({source:s,style:e=>e.get("vertexIndex")===l?null:[i],zIndex:102});return e.addLayer(c),{update(e){s.clear(),d(e).forEach((e,t)=>{var r=new o({geometry:new a(e)});r.set("vertexIndex",t),s.addFeature(r)})},setSelected(e){l=e,s.changed()},updateStyle(e){i=e,s.changed()},remove(){s.clear(),e.removeLayer(c)}}})(p,x.styles.vertexStyle),Y=new r,B=new n({source:Y,zIndex:103});p.addLayer(B);var R=()=>{Y.clear();var{selectedVertexIndex:e,selectedVertexType:t,vertices:r,midpoints:n}=k;if(!(e<0)){var i,d;if("vertex"===t)i=r[e],d=x.styles.selectedVertexStyle;else{if("midpoint"!==t)return;i=n[e-r.length],d=x.styles.selectedMidpointStyle}if(i){var l=new o({geometry:new a(i)});l.setStyle(d),Y.addFeature(l)}}};z();var U=e=>{C.setStyle(e.editFeatureStyle),X.updateStyle(e.vertexStyle),_.updateStyle(e.midpointStyle),R(),Z.updateColors(x.colors)};x.on("styleschanged",U);var J=e=>{if("touch"===e.pointerType)return k.interfaceType="touch",void Z.updateTargetPosition();k.interfaceType="pointer";var t=p.getEventPixel(e),r={x:t[0],y:t[1]},n=T(p,k.vertices,k.midpoints,r);"vertex"===(null==n?void 0:n.type)&&D({selectedVertexIndex:n.index,selectedVertexType:"vertex"})},K=e=>{if("touch"!==k.interfaceType){var t=p.getEventPixel(e),r={x:t[0],y:t[1]},n=T(p,k.vertices,k.midpoints,r);"vertex"===(null==n?void 0:n.type)?D({selectedVertexIndex:n.index,selectedVertexType:"vertex"}):"midpoint"===(null==n?void 0:n.type)||D({selectedVertexIndex:-1,selectedVertexType:null})}},H=e=>{"mouse"===e.pointerType&&"pointer"!==k.interfaceType&&(k.interfaceType="pointer",Z.hide())};g.addEventListener("pointerdown",J),g.addEventListener("pointerenter",H),g.addEventListener("pointermove",H),g.addEventListener("click",K);var W=e=>{m&&e.target.closest("#".concat(m))&&q()};globalThis.addEventListener("click",W);var q=()=>{if(!("vertex"!==k.selectedVertexType||k.selectedVertexIndex<0)){var e=((e,t)=>{var r=e.getGeometry(),n={type:r.getType(),coordinates:r.getCoordinates()},o=d(n),a=l(n),i=s(a,t);if(!i)return null;var{segment:v}=i,p=v.closed?3:2;if(v.length<=p)return null;var x=[...o[t]],u=c(n,v.path);return u.splice(i.localIdx,1),v.closed&&(u[u.length-1]=[...u[0]]),r.setCoordinates(n.coordinates),{deletedIndex:t,deletedCoord:x}})(C,k.selectedVertexIndex);e&&(S.push({type:"delete_vertex",vertexIndex:e.deletedIndex,deletedCoord:e.deletedCoord}),z(),D({selectedVertexIndex:-1,selectedVertexType:null}))}},Q=()=>{var e=S.pop();if(e){var t=k.selectedVertexIndex,r=b(C,e);z();var n,o=t>=0?r:-1;if(D({selectedVertexIndex:o,selectedVertexType:o>=0?"vertex":null}),t>=0&&o>=0)null===(n=P)||void 0===n||n()}},Z=V({map:p,container:g,getState:A,setState:D,colors:x.colors,snap:I,onVertexMoved(e){var{vertexIndex:t,previousCoord:r}=e;S.push({type:"move_vertex",vertexIndex:t,previousCoord:r}),z(),D({selectedVertexIndex:t,selectedVertexType:"vertex"}),Z.updateTargetPosition()},onTap(e){if(e){if("vertex"===e.type)return D({selectedVertexIndex:e.index,selectedVertexType:"vertex"}),void Z.updateTargetPosition();if("midpoint"===e.type){var t=h(C,k.midpoints,e.index,k.vertices.length);if(!t)return;S.push({type:"insert_vertex",vertexIndex:t.insertedIndex}),z(),D({selectedVertexIndex:t.insertedIndex,selectedVertexType:"vertex"}),Z.updateTargetPosition()}}else D({selectedVertexIndex:-1,selectedVertexType:null})}});M=()=>Z.hide(),P=()=>{"touch"===k.interfaceType&&Z.updateTargetPosition()};var $=()=>{"touch"!==k.interfaceType||k.selectedVertexIndex<0||p.once("postrender",()=>Z.updateTargetPosition())};p.on("change:size",$);var ee=(e=>L(e))({map:p,getState:A,setState:D,snap:I,onVertexMoved(e){var{vertexIndex:t,previousCoord:r}=e;S.push({type:"move_vertex",vertexIndex:t,previousCoord:r}),z(),D({selectedVertexIndex:t,selectedVertexType:"vertex"})},onInserted(e){var{insertedIndex:t}=e;S.push({type:"insert_vertex",vertexIndex:t}),z()},onDeleted:q,onUndo:Q,onKeyboardActive(){"keyboard"!==k.interfaceType&&(k.interfaceType="keyboard",Z.hide(),g.focus({preventScroll:!0}))}});return{setInterfaceType(e){e!==k.interfaceType&&(k.interfaceType=e,"touch"===e?Z.updateTargetPosition():Z.hide())},done(){x.emit("editfinish",w.toGeoJSON(C))},cancel(){},undo:Q,deleteVertex:q,destroy(){C.setStyle(E),C.getGeometry().un("change",N),x.off("styleschanged",U),g.removeEventListener("pointerdown",J),g.removeEventListener("pointerenter",H),g.removeEventListener("pointermove",H),g.removeEventListener("click",K),globalThis.removeEventListener("click",W),p.un("change:size",$),p.removeInteraction(O),Y.clear(),p.removeLayer(B),_.remove(),X.remove(),Z.destroy(),ee.destroy()}}};export{k as createEditMode};
|
|
1
|
+
import e from"ol/interaction/Modify.js";import t from"ol/Collection.js";import r from"ol/source/Vector.js";import n from"ol/layer/Vector.js";import o from"ol/Feature.js";import a from"ol/geom/Point.js";import{a as i,g as d,b as l,d as s,e as c,c as v,p,f as x,n as u}from"./geometryHelpers.js";var y=(e,t)=>{e&&(e.style.setProperty("--draw-halo",t.editActive),e.style.setProperty("--draw-bg",t.editHalo),e.style.setProperty("--draw-primary",t.editVertex))},g=(e,t)=>{t&&e&&(e.style.left="".concat(t.x,"px"),e.style.top="".concat(t.y,"px"),e.style.display="block")},m=e=>{e&&(e.style.display="none")},f=e=>{if(!e)return!1;var t=e.parentNode;return t instanceof globalThis.SVGElement||null!=(null==t?void 0:t.ownerSVGElement)},h=(e,t,r,n)=>{var o=r-n,a=t[o];if(!a)return null;var i=e.getGeometry(),d={type:i.getType(),coordinates:i.getCoordinates()},s=l(d),v=0;for(var p of s){var x=p.closed?p.length:p.length-1;if(o<v+x){var u=o-v+1,y=p.start+u;return c(d,p.path).splice(u,0,[...a]),i.setCoordinates(d.coordinates),{insertedIndex:y}}v+=x}return null},I=(e,t,r)=>{var n=e.getGeometry(),o={type:n.getType(),coordinates:n.getCoordinates()},a=l(o),i=s(a,t);if(i){var d=c(o,i.segment.path);d[i.localIdx]=[...r],i.segment.closed&&0===i.localIdx&&(d[d.length-1]=[...r]),n.setCoordinates(o.coordinates)}},T=function(e,t,r,n){var o,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:12;return null!==(o=function(e,t,r){var n=-1,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:12;return t.forEach((t,a)=>{var i=v(e,t);if(i){var d=p(i,r);d<o&&(o=d,n=a)}}),n>=0?{index:n,type:"vertex"}:null}(e,t,n,a))&&void 0!==o?o:function(e,t,r,n){var o=-1,a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:12;return t.forEach((t,n)=>{var i=v(e,t);if(i){var d=p(i,r);d<a&&(a=d,o=n)}}),o>=0?{index:n+o,type:"midpoint"}:null}(e,r,n,t.length,a)},V=e=>{var{map:t,container:r,getState:n,setState:o,onVertexMoved:a,onTap:i,colors:d,snap:l}=e,s=(e=>{var t=e.querySelector("[data-im-draw-touch-target]");return t||(e.insertAdjacentHTML("beforeend","\n <svg width='48' height='48' viewBox='0 0 48 48' fill-rule='evenodd'\n style='display:none;position:absolute;top:0;left:0;margin:24px 0 0 -24px;cursor:grab'\n class='im-draw-touch-target' data-im-draw-touch-target>\n <circle cx='24' cy='24' r='24' fill='var(--draw-halo, #000)'/>\n <path d=\"M37.543 25H34a1 1 0 1 1 0-2h3.629l-.836-.837a1 1 0 0 1 1.414-1.414l2.5 2.501A1 1 0 0 1 41 24a1 1 0 0 1-.487.858l-2.306 2.306a1 1 0 0 1-1.414-1.414l.75-.75zM23 10.414l-.793.793a1 1 0 0 1-1.414-1.414l2.5-2.5C23.481 7.105 23.734 7 24 7s.519.105.707.293l2.5 2.5a1 1 0 0 1-1.414 1.414L25 10.414V14a1 1 0 1 1-2 0v-3.586zM7 24a1 1 0 0 1 .293-.75l2.5-2.501a1 1 0 0 1 1.414 1.414l-.836.837H14a1 1 0 1 1 0 2h-3.543l.75.75a1 1 0 0 1-1.414 1.414l-2.306-2.306A1 1 0 0 1 7 24zm16.293 16.707l-2.5-2.5a1 1 0 0 1 1.414-1.414l.793.793V34a1 1 0 1 1 2 0v3.586l.793-.793a1 1 0 0 1 1.414 1.414l-2.5 2.5c-.188.188-.441.293-.707.293s-.519-.105-.707-.293zM24 20c2.208 0 4 1.792 4 4s-1.792 4-4 4-4-1.792-4-4 1.792-4 4-4z\" fill='var(--draw-bg, #fff)'/>\n </svg>\n"),t=e.querySelector("[data-im-draw-touch-target]")),t})(r);y(s,d);var c={scale:1,ox:0,oy:0},p=e=>({x:e.x*c.scale+c.ox,y:e.y*c.scale+c.oy}),u=()=>{var e=t.getViewport(),n=e.getBoundingClientRect(),o=r.getBoundingClientRect(),a=e.offsetWidth>0?n.width/e.offsetWidth:1,i=r.offsetWidth>0?o.width/r.offsetWidth:1;Object.assign(c,{scale:a/i,ox:(n.left-o.left)/i,oy:(n.top-o.top)/i})},h=(e=>{var{container:t,map:r,targetEl:n,olToCSS:o,cssToOl:a,getState:i,setState:d,onVertexMoved:l,onTap:s,snap:c}=e,p=null,u=null,y=null,m=null,h=null,V=e=>{var t=e.touches[0],o=f(e.target);if(h={x:t.clientX,y:t.clientY,time:Date.now(),onTarget:o},o){var{selectedVertexIndex:d,vertices:l}=i(),s=l[d];if(s){var c=r.getEventPixel({clientX:t.clientX,clientY:t.clientY}),x=v(r,s),g=getComputedStyle(n),I=a({x:Number.parseFloat(g.left),y:Number.parseFloat(g.top)});p=[...s],u=d,y={x:c[0]-x.x,y:c[1]-x.y},m={x:c[0]-I.x,y:c[1]-I.y},e.preventDefault()}}},w=e=>{if(f(e.target)&&null!=u){e.preventDefault();var t=r.getEventPixel({clientX:e.touches[0].clientX,clientY:e.touches[0].clientY}),a=x(r,{x:t[0]-y.x,y:t[1]-y.y}),l=c?c.apply(a):a;null==c||c.hideIndicator();var{olFeature:s,vertices:v}=i();s&&(I(s,u,l),d({vertices:v.map((e,t)=>t===u?l:e)}),g(n,o({x:t[0]-m.x,y:t[1]-m.y})))}},S=e=>{if(null!=u){h=null;var{vertices:t}=i();t[u]&&p&&l({vertexIndex:u,previousCoord:p}),null==c||c.hideIndicator(),p=null,u=null,y=null,m=null,e.preventDefault()}else{if(h&&!h.onTarget&&e.changedTouches.length>0){var n=e.changedTouches[0],o=Date.now()-h.time;if(Math.hypot(n.clientX-h.x,n.clientY-h.y)<10&&o<400){var a=r.getEventPixel({clientX:n.clientX,clientY:n.clientY}),d=i();null==s||s(T(r,d.vertices,d.midpoints,{x:a[0],y:a[1]},24)),e.preventDefault()}}h=null}};return t.addEventListener("touchstart",V,{passive:!1}),t.addEventListener("touchmove",w,{passive:!1}),t.addEventListener("touchend",S,{passive:!1}),{isDragging:()=>null!=u,destroy(){t.removeEventListener("touchstart",V),t.removeEventListener("touchmove",w),t.removeEventListener("touchend",S)}}})({container:r,map:t,targetEl:s,olToCSS:p,cssToOl:e=>({x:(e.x-c.ox)/c.scale,y:(e.y-c.oy)/c.scale}),getState:n,setState:o,onVertexMoved:a,onTap:i,snap:l}),V=()=>{var{selectedVertexIndex:e,vertices:r,interfaceType:o}=n();if(e<0||!r[e]||"touch"!==o)m(s);else{var a=v(t,r[e]);a?g(s,p(a)):m(s)}},w=()=>{var{selectedVertexIndex:e,interfaceType:t}=n();e>=0&&!h.isDragging()&&"touch"===t&&V()};t.on("postrender",w);var S=()=>{u(),t.once("postrender",V)};return t.on("change:size",S),u(),{updateTargetPosition:V,updateColors(e){y(s,e)},hide(){m(s)},destroy(){t.un("change:size",S),t.un("postrender",w),h.destroy(),m(s)}}},w=(e,t,r)=>{var n=t.filter(t=>{var n=Math.abs(t[0]-e[0]),o=Math.abs(t[1]-e[1]);return("ArrowUp"===r?t[1]<=e[1]&&o>=n:"ArrowDown"===r?t[1]>e[1]&&o>=n:"ArrowLeft"===r?t[0]<=e[0]&&o<n:"ArrowRight"!==r||t[0]>e[0]&&o<n)&&JSON.stringify(t)!==JSON.stringify(e)});n.length||n.push(e);var o=t=>Math.hypot(e[0]-t[0],e[1]-t[1]),a=n.reduce((e,t)=>o(t)<o(e)?t:e,n[0]);return t.findIndex(e=>JSON.stringify(e)===JSON.stringify(a))},S=new Set(["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"]),C=new Set(["INPUT","TEXTAREA","BUTTON","SELECT","A"]),E=e=>{var{map:t,snap:r,getState:n,setState:o,onInserted:a}=e,i={start:null,index:null};return{nudge:e=>{var{selectedVertexIndex:d,selectedVertexType:l,vertices:s,midpoints:c,olFeature:v}=n();if(v){var p=e.shiftKey?1:5,x={ArrowUp:[0,-p],ArrowDown:[0,p],ArrowLeft:[-p,0],ArrowRight:[p,0]},[y,g]=x[e.key];if("midpoint"!==l){if(!(d<0)&&s[d]){var m=s[d];i.start||(i.start=[...m],i.index=d);var f=u(t,m,y,g),T=r?r.apply(f):f;null==r||r.hideIndicator();var V=((e,t,r,n,o,a,i)=>{if(!e)return o;var d=[n[0]-r[0],n[1]-r[1]],l=[o[0]-r[0],o[1]-r[1]],s=d[0]**2+d[1]**2;if(s>0&&(l[0]*d[0]+l[1]*d[1])/s<.5){var c=e.snapRadius+1;return u(t,r,0===a?0:Math.sign(a)*c,0===i?0:Math.sign(i)*c)}return o})(r,t,m,f,T,y,g);I(v,d,V),o({vertices:s.map((e,t)=>t===d?V:e)})}}else((e,d,l,s,c,v)=>{var p=h(e,d,l,s.length);if(p){a({insertedIndex:p.insertedIndex});var x=n().vertices,y=x[p.insertedIndex];if(y){i.start=[...y],i.index=p.insertedIndex;var g=u(t,y,c,v),m=r?r.apply(g):g;I(e,p.insertedIndex,m),o({selectedVertexIndex:p.insertedIndex,selectedVertexType:"vertex",vertices:x.map((e,t)=>t===p.insertedIndex?m:e)})}}})(v,c,d,s,y,g)}},keyMove:i}},L=e=>{var t,{map:r,snap:n,getState:o,setState:a,onVertexMoved:i,onInserted:d,onDeleted:l,onUndo:s,onKeyboardActive:c}=e,{nudge:p,keyMove:x}=E({map:r,snap:n,getState:o,setState:a,onInserted:d}),u=null!==(t=r.getViewport().closest('[role="application"]'))&&void 0!==t?t:r.getViewport(),y=()=>(e=>{var t=document.activeElement;if(!t||t===document.body)return!1;if(e.contains(t))return!1;var r=t.tagName;return C.has(r)||t.isContentEditable||t.hasAttribute("tabindex")})(u),g=e=>{e.altKey?(e.preventDefault(),e.stopPropagation(),((e,t,r,n)=>{var{selectedVertexIndex:o,vertices:a,midpoints:i}=r();if(a.length){var d,l=[...a,...i].map(e=>v(t,e)).filter(Boolean).map(e=>[e.x,e.y]),s=o>=0?l[o]:(d=v(t,t.getView().getCenter()))?[d.x,d.y]:null;if(s){var c=w(s,l,e);n({selectedVertexIndex:c,selectedVertexType:c<a.length?"vertex":"midpoint"})}}})(e.key,r,o,a)):o().selectedVertexIndex>=0&&(e.preventDefault(),e.stopPropagation(),p(e))},m=e=>{if(null==c||c()," "===e.key)e.preventDefault(),o().selectedVertexIndex<0&&((e,t,r)=>{var{vertices:n,midpoints:o}=t();if(n.length){var a=e.getView().getCenter(),i=v(e,a);if(i){var d=[...n.map(t=>v(e,t)),...o.map(t=>v(e,t))].filter(Boolean).map(e=>[e.x,e.y]),l=w([i.x,i.y],d,void 0);r({selectedVertexIndex:l,selectedVertexType:l<n.length?"vertex":"midpoint"})}}})(r,o,a);else if(S.has(e.key))g(e);else if("z"===e.key&&(e.metaKey||e.ctrlKey)){var t,n=null===(t=document.activeElement)||void 0===t?void 0:t.tagName;C.has(n)||(e.preventDefault(),e.stopPropagation(),s())}},f=e=>{y()||("Escape"===e.key&&o().selectedVertexIndex>=0?(e.preventDefault(),x.start=null,x.index=null,a({selectedVertexIndex:-1,selectedVertexType:null})):m(e))},h=e=>{y()||(S.has(e.key)&&x.start&&null!=x.index&&(null==n||n.hideIndicator(),i({vertexIndex:x.index,previousCoord:x.start}),x.start=null,x.index=null),"Delete"===e.key&&l())};return window.addEventListener("keydown",f,{capture:!0}),window.addEventListener("keyup",h,{capture:!0}),{destroy(){window.removeEventListener("keydown",f,{capture:!0}),window.removeEventListener("keyup",h,{capture:!0})}}},b=(e,t)=>{switch(t.type){case"move_vertex":return((e,t)=>{var{vertexIndex:r,previousCoord:n}=t,o=e.getGeometry(),a={type:o.getType(),coordinates:o.getCoordinates()},i=l(a),d=s(i,r);if(!d)return-1;var v=c(a,d.segment.path);return v[d.localIdx]=[...n],d.segment.closed&&0===d.localIdx&&(v[v.length-1]=[...n]),o.setCoordinates(a.coordinates),r})(e,t);case"insert_vertex":return((e,t)=>{var{vertexIndex:r}=t,n=e.getGeometry(),o={type:n.getType(),coordinates:n.getCoordinates()},a=l(o),i=s(a,r);if(!i)return-1;var d=c(o,i.segment.path);return d.splice(i.localIdx,1),i.segment.closed&&(d[d.length-1]=[...d[0]]),n.setCoordinates(o.coordinates),-1})(e,t);case"delete_vertex":return((e,t)=>{var{vertexIndex:r,deletedCoord:n}=t,o=e.getGeometry(),a={type:o.getType(),coordinates:o.getCoordinates()},i=l(a),d=s(i,r);if(!d)for(var v of i)if(r===v.start+v.length){d={segment:v,localIdx:v.length};break}if(!d)return-1;var p=c(a,d.segment.path);return p.splice(d.localIdx,0,[...n]),d.segment.closed&&(p[p.length-1]=[...p[0]]),o.setCoordinates(a.coordinates),r})(e,t);default:return-1}},k=v=>{var{map:p,manager:x,options:u}=v,{featureId:y,container:g,interfaceType:m,deleteVertexButtonId:f,snap:I}=u,{store:w,undoStack:S}=x,C=w.getOL(y);if(!C)return null;var E=C.getStyle();C.setStyle(x.styles.editFeatureStyle);var k={olFeature:C,selectedVertexIndex:-1,selectedVertexType:null,vertices:[],midpoints:[],interfaceType:null!=m?m:"mouse"},A=()=>k,M=null,P=null,D=e=>{if(Object.assign(k,e),void 0!==e.selectedVertexIndex){var t;if(X.setSelected("vertex"===k.selectedVertexType?k.selectedVertexIndex:-1),_.setSelected("midpoint"===k.selectedVertexType?k.selectedVertexIndex-k.vertices.length:-1),k.selectedVertexIndex<0)null===(t=M)||void 0===t||t();R(),x.emit("vertexselection",{index:"vertex"===k.selectedVertexType?k.selectedVertexIndex:-1,numVertices:k.vertices.length})}if(void 0!==e.vertices){var r,n={type:C.getGeometry().getType(),coordinates:C.getGeometry().getCoordinates()};_.update(n),X.update(n),k.midpoints=_.getCoords(),R(),null===(r=P)||void 0===r||r(),p.render()}},G=()=>{var e=C.getGeometry(),t={type:e.getType(),coordinates:e.getCoordinates()};k.vertices=d(t),k.midpoints=i(t),_.update(t),X.update(t),R()},z=()=>{G(),x.emit("vertexchange",{numVertices:k.vertices.length}),x.emit("update",w.toGeoJSON(C))},N=()=>G();C.getGeometry().on("change",N);var F=new t([C]),O=new e({features:F,style:()=>[],pixelTolerance:12,condition:e=>{if("touch"===k.interfaceType)return!1;var t=p.getEventPixel(e.originalEvent);return null!==T(p,k.vertices,k.midpoints,{x:t[0],y:t[1]})}});p.addInteraction(O);var j=null;O.on("modifystart",()=>{"touch"!==k.interfaceType&&(j=k.vertices.map(e=>[...e]))}),O.on("modifyend",()=>{if("touch"!==k.interfaceType){var e=j;if(z(),e){var t=k.vertices;if(t.length>e.length){var r=t.findIndex((t,r)=>!e[r]||t[0]!==e[r][0]),n=Math.max(0,r);S.push({type:"insert_vertex",vertexIndex:n}),D({selectedVertexIndex:n,selectedVertexType:"vertex"})}else if(t.length===e.length){var o=t.findIndex((t,r)=>t[0]!==e[r][0]||t[1]!==e[r][1]);o>=0&&(S.push({type:"move_vertex",vertexIndex:o,previousCoord:e[o]}),D({selectedVertexIndex:o,selectedVertexType:"vertex"}))}j=null}}});var _=((e,t)=>{var d=t,l=-1,s=new r,c=new n({source:s,style:e=>e.get("midpointIndex")===l?null:[d],zIndex:101});return e.addLayer(c),{update(e){s.clear();var t=i(e).map((e,t)=>{var r=new o({geometry:new a(e)});return r.set("midpointIndex",t),r});s.addFeatures(t)},setSelected(e){l=e,s.changed()},updateStyle(e){d=e,s.changed()},getCoords:()=>s.getFeatures().sort((e,t)=>e.get("midpointIndex")-t.get("midpointIndex")).map(e=>e.getGeometry().getCoordinates()),remove(){s.clear(),e.removeLayer(c)}}})(p,x.styles.midpointStyle),X=((e,t)=>{var i=t,l=-1,s=new r,c=new n({source:s,style:e=>e.get("vertexIndex")===l?null:[i],zIndex:102});return e.addLayer(c),{update(e){s.clear(),d(e).forEach((e,t)=>{var r=new o({geometry:new a(e)});r.set("vertexIndex",t),s.addFeature(r)})},setSelected(e){l=e,s.changed()},updateStyle(e){i=e,s.changed()},remove(){s.clear(),e.removeLayer(c)}}})(p,x.styles.vertexStyle),Y=new r,B=new n({source:Y,zIndex:103});p.addLayer(B);var R=()=>{Y.clear();var{selectedVertexIndex:e,selectedVertexType:t,vertices:r,midpoints:n}=k;if(!(e<0)){var i,d;if("vertex"===t)i=r[e],d=x.styles.selectedVertexStyle;else{if("midpoint"!==t)return;i=n[e-r.length],d=x.styles.selectedMidpointStyle}if(i){var l=new o({geometry:new a(i)});l.setStyle(d),Y.addFeature(l)}}};z();var U=e=>{C.setStyle(e.editFeatureStyle),X.updateStyle(e.vertexStyle),_.updateStyle(e.midpointStyle),R(),Z.updateColors(x.colors)};x.on("styleschanged",U);var J=e=>{if("touch"===e.pointerType)return k.interfaceType="touch",void Z.updateTargetPosition();k.interfaceType="mouse";var t=p.getEventPixel(e),r={x:t[0],y:t[1]},n=T(p,k.vertices,k.midpoints,r);"vertex"===(null==n?void 0:n.type)&&D({selectedVertexIndex:n.index,selectedVertexType:"vertex"})},K=e=>{if("touch"!==k.interfaceType){var t=p.getEventPixel(e),r={x:t[0],y:t[1]},n=T(p,k.vertices,k.midpoints,r);"vertex"===(null==n?void 0:n.type)?D({selectedVertexIndex:n.index,selectedVertexType:"vertex"}):"midpoint"===(null==n?void 0:n.type)||D({selectedVertexIndex:-1,selectedVertexType:null})}},H=e=>{"mouse"===e.pointerType&&"mouse"!==k.interfaceType&&(k.interfaceType="mouse",Z.hide())};g.addEventListener("pointerdown",J),g.addEventListener("pointerenter",H),g.addEventListener("pointermove",H),g.addEventListener("click",K);var W=e=>{f&&e.target.closest("#".concat(f))&&q()};globalThis.addEventListener("click",W);var q=()=>{if(!("vertex"!==k.selectedVertexType||k.selectedVertexIndex<0)){var e=((e,t)=>{var r=e.getGeometry(),n={type:r.getType(),coordinates:r.getCoordinates()},o=d(n),a=l(n),i=s(a,t);if(!i)return null;var{segment:v}=i,p=v.closed?3:2;if(v.length<=p)return null;var x=[...o[t]],u=c(n,v.path);return u.splice(i.localIdx,1),v.closed&&(u[u.length-1]=[...u[0]]),r.setCoordinates(n.coordinates),{deletedIndex:t,deletedCoord:x}})(C,k.selectedVertexIndex);e&&(S.push({type:"delete_vertex",vertexIndex:e.deletedIndex,deletedCoord:e.deletedCoord}),z(),D({selectedVertexIndex:-1,selectedVertexType:null}))}},Q=()=>{var e=S.pop();if(e){var t=k.selectedVertexIndex,r=b(C,e);z();var n,o=t>=0?r:-1;if(D({selectedVertexIndex:o,selectedVertexType:o>=0?"vertex":null}),t>=0&&o>=0)null===(n=P)||void 0===n||n()}},Z=V({map:p,container:g,getState:A,setState:D,colors:x.colors,snap:I,onVertexMoved(e){var{vertexIndex:t,previousCoord:r}=e;S.push({type:"move_vertex",vertexIndex:t,previousCoord:r}),z(),D({selectedVertexIndex:t,selectedVertexType:"vertex"}),Z.updateTargetPosition()},onTap(e){if(e){if("vertex"===e.type)return D({selectedVertexIndex:e.index,selectedVertexType:"vertex"}),void Z.updateTargetPosition();if("midpoint"===e.type){var t=h(C,k.midpoints,e.index,k.vertices.length);if(!t)return;S.push({type:"insert_vertex",vertexIndex:t.insertedIndex}),z(),D({selectedVertexIndex:t.insertedIndex,selectedVertexType:"vertex"}),Z.updateTargetPosition()}}else D({selectedVertexIndex:-1,selectedVertexType:null})}});M=()=>Z.hide(),P=()=>{"touch"===k.interfaceType&&Z.updateTargetPosition()};var $=()=>{"touch"!==k.interfaceType||k.selectedVertexIndex<0||p.once("postrender",()=>Z.updateTargetPosition())};p.on("change:size",$);var ee=(e=>L(e))({map:p,getState:A,setState:D,snap:I,onVertexMoved(e){var{vertexIndex:t,previousCoord:r}=e;S.push({type:"move_vertex",vertexIndex:t,previousCoord:r}),z(),D({selectedVertexIndex:t,selectedVertexType:"vertex"})},onInserted(e){var{insertedIndex:t}=e;S.push({type:"insert_vertex",vertexIndex:t}),z()},onDeleted:q,onUndo:Q,onKeyboardActive(){"keyboard"!==k.interfaceType&&(k.interfaceType="keyboard",Z.hide(),g.focus({preventScroll:!0}))}});return{setInterfaceType(e){e!==k.interfaceType&&(k.interfaceType=e,"touch"===e?Z.updateTargetPosition():Z.hide())},done(){x.emit("editfinish",w.toGeoJSON(C))},cancel(){},undo:Q,deleteVertex:q,destroy(){C.setStyle(E),C.getGeometry().un("change",N),x.off("styleschanged",U),g.removeEventListener("pointerdown",J),g.removeEventListener("pointerenter",H),g.removeEventListener("pointermove",H),g.removeEventListener("click",K),globalThis.removeEventListener("click",W),p.un("change:size",$),p.removeInteraction(O),Y.clear(),p.removeLayer(B),_.remove(),X.remove(),Z.destroy(),ee.destroy()}}};export{k as createEditMode};
|