@defra/interactive-map 0.0.3-alpha → 0.0.4-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.
Files changed (268) hide show
  1. package/README.md +16 -57
  2. package/dist/esm/im-core.js +1 -1
  3. package/dist/esm/index.js +1 -1
  4. package/dist/umd/im-core.js +1 -1
  5. package/dist/umd/index.js +1 -1
  6. package/docs/api/button-definition.md +176 -0
  7. package/docs/api/context.md +124 -0
  8. package/docs/api/control-definition.md +72 -0
  9. package/docs/api/icon-definition.md +28 -0
  10. package/docs/api/map-style-config.md +76 -0
  11. package/docs/api/marker-config.md +51 -0
  12. package/docs/api/panel-definition.md +117 -0
  13. package/docs/api/slots.md +25 -0
  14. package/docs/api.md +713 -0
  15. package/docs/architecture.md +139 -0
  16. package/docs/building-a-plugin.md +149 -0
  17. package/docs/getting-started.md +46 -0
  18. package/docs/govuk-prototype.md +0 -0
  19. package/docs/plugins/interact.md +205 -0
  20. package/docs/plugins/map-styles.md +84 -0
  21. package/docs/plugins/plugin-context.md +67 -0
  22. package/docs/plugins/plugin-descriptor.md +71 -0
  23. package/docs/plugins/plugin-manifest.md +118 -0
  24. package/docs/plugins/scale-bar.md +62 -0
  25. package/docs/plugins/search.md +162 -0
  26. package/docs/plugins.md +116 -0
  27. package/govuk-prototype-kit.config.json +7 -7
  28. package/package.json +14 -1
  29. package/plugins/beta/datasets/dist/esm/im-datasets-plugin.js +1 -0
  30. package/plugins/beta/datasets/dist/esm/index.js +2 -0
  31. package/plugins/beta/datasets/dist/umd/im-datasets-plugin.js +1 -0
  32. package/plugins/beta/datasets/dist/umd/index.js +2 -0
  33. package/plugins/{datasets → beta/datasets}/src/manifest.js +1 -1
  34. package/plugins/{datasets → beta/datasets}/src/mapLayers.js +1 -1
  35. package/plugins/{datasets → beta/datasets}/src/panels/Key.jsx +1 -1
  36. package/plugins/beta/draw-ml/dist/esm/im-draw-ml-plugin.js +1 -0
  37. package/plugins/beta/draw-ml/dist/esm/index.js +2 -0
  38. package/plugins/beta/draw-ml/dist/umd/im-draw-ml-plugin.js +1 -0
  39. package/plugins/beta/draw-ml/dist/umd/index.js +2 -0
  40. package/plugins/{draw-ml → beta/draw-ml}/src/api/editFeature.js +1 -1
  41. package/plugins/beta/draw-ml/src/api/merge.js +9 -0
  42. package/plugins/beta/draw-ml/src/api/newLine.js +43 -0
  43. package/plugins/{draw-ml → beta/draw-ml}/src/api/newPolygon.js +5 -5
  44. package/plugins/beta/draw-ml/src/api/split.js +81 -0
  45. package/plugins/{draw-ml → beta/draw-ml}/src/defaults.js +2 -0
  46. package/plugins/{draw-ml → beta/draw-ml}/src/events.js +105 -3
  47. package/plugins/{draw-ml → beta/draw-ml}/src/manifest.js +17 -11
  48. package/plugins/{draw-ml → beta/draw-ml}/src/mapboxDraw.js +51 -2
  49. package/plugins/{draw-ml → beta/draw-ml}/src/mapboxSnap.js +2 -0
  50. package/plugins/beta/draw-ml/src/modes/createDrawMode.js +496 -0
  51. package/plugins/beta/draw-ml/src/modes/drawLineMode.js +18 -0
  52. package/plugins/beta/draw-ml/src/modes/drawPolygonMode.js +16 -0
  53. package/plugins/beta/draw-ml/src/modes/editVertexMode.js +792 -0
  54. package/plugins/{draw-ml → beta/draw-ml}/src/reducer.js +30 -2
  55. package/plugins/{draw-ml → beta/draw-ml}/src/styles.js +66 -36
  56. package/plugins/beta/draw-ml/src/undoStack.js +50 -0
  57. package/plugins/beta/draw-ml/src/utils/debounce.js +16 -0
  58. package/plugins/beta/draw-ml/src/utils/spatial.js +258 -0
  59. package/plugins/beta/frame/dist/esm/im-frame-plugin.js +1 -0
  60. package/plugins/beta/frame/dist/esm/index.js +2 -0
  61. package/plugins/beta/frame/dist/umd/im-frame-plugin.js +1 -0
  62. package/plugins/beta/frame/dist/umd/index.js +2 -0
  63. package/plugins/beta/map-styles/dist/esm/im-map-styles-plugin.js +1 -0
  64. package/plugins/beta/map-styles/dist/esm/index.js +2 -0
  65. package/plugins/beta/map-styles/dist/umd/im-map-styles-plugin.js +1 -0
  66. package/plugins/beta/map-styles/dist/umd/index.js +2 -0
  67. package/plugins/{map-styles → beta/map-styles}/src/MapStyles.jsx +1 -1
  68. package/plugins/{map-styles → beta/map-styles}/src/manifest.js +8 -10
  69. package/plugins/beta/scale-bar/dist/esm/im-scale-bar-plugin.js +1 -0
  70. package/plugins/beta/scale-bar/dist/esm/index.js +2 -0
  71. package/plugins/beta/scale-bar/dist/umd/im-scale-bar-plugin.js +1 -0
  72. package/plugins/beta/scale-bar/dist/umd/index.js +2 -0
  73. package/plugins/beta/use-location/dist/esm/im-use-location-plugin.js +1 -0
  74. package/plugins/beta/use-location/dist/esm/index.js +2 -0
  75. package/plugins/beta/use-location/dist/umd/im-use-location-plugin.js +1 -0
  76. package/plugins/beta/use-location/dist/umd/index.js +2 -0
  77. package/plugins/interact/dist/esm/im-interact-plugin.js +1 -1
  78. package/plugins/interact/dist/esm/index.js +1 -1
  79. package/plugins/interact/dist/umd/im-interact-plugin.js +1 -1
  80. package/plugins/interact/dist/umd/index.js +1 -1
  81. package/plugins/interact/src/InteractInit.test.js +97 -0
  82. package/plugins/interact/src/api/clear.test.js +18 -0
  83. package/plugins/interact/src/api/disable.test.js +12 -0
  84. package/plugins/interact/src/api/enable.test.js +48 -0
  85. package/plugins/interact/src/api/selectFeature.test.js +33 -0
  86. package/plugins/interact/src/api/unselectFeature.test.js +33 -0
  87. package/plugins/interact/src/defaults.js +1 -0
  88. package/plugins/interact/src/events.test.js +151 -0
  89. package/plugins/interact/src/hooks/useHighlightSync.test.js +212 -0
  90. package/plugins/interact/src/hooks/useInteractionHandlers.js +14 -7
  91. package/plugins/interact/src/hooks/useInteractionHandlers.test.js +260 -0
  92. package/plugins/interact/src/index.test.js +22 -0
  93. package/plugins/interact/src/manifest.js +1 -1
  94. package/plugins/interact/src/manifest.test.js +94 -0
  95. package/plugins/interact/src/reducer.js +10 -1
  96. package/plugins/interact/src/reducer.test.js +142 -0
  97. package/plugins/interact/src/utils/buildStylesMap.test.js +57 -0
  98. package/plugins/interact/src/utils/featureQueries.test.js +56 -0
  99. package/plugins/interact/src/utils/turfHelpers.js +30 -0
  100. package/plugins/interact/src/utils/turfHelpers.test.js +30 -0
  101. package/plugins/search/dist/esm/im-search-plugin.js +1 -1
  102. package/plugins/search/dist/esm/index.js +1 -1
  103. package/plugins/search/dist/umd/im-search-plugin.js +1 -1
  104. package/plugins/search/dist/umd/index.js +1 -1
  105. package/plugins/search/src/utils/parseOsNamesResults.js +3 -7
  106. package/providers/{esri → beta/esri}/src/mapEvents.js +2 -2
  107. package/providers/beta/open-names/dist/esm/im-reverse-geocode.js +2 -0
  108. package/providers/beta/open-names/dist/esm/index.js +2 -0
  109. package/providers/beta/open-names/dist/umd/im-reverse-geocode.js +2 -0
  110. package/providers/beta/open-names/dist/umd/index.js +2 -0
  111. package/providers/maplibre/dist/esm/im-maplibre-framework.js +1 -1
  112. package/providers/maplibre/dist/esm/im-maplibre-framework.js.LICENSE.txt +1 -1
  113. package/providers/maplibre/dist/esm/im-maplibre-legacy-framework.js +1 -1
  114. package/providers/maplibre/dist/esm/im-maplibre-provider.js +1 -1
  115. package/providers/maplibre/dist/esm/index.js +1 -1
  116. package/providers/maplibre/dist/umd/im-maplibre-framework.js +1 -1
  117. package/providers/maplibre/dist/umd/im-maplibre-framework.js.LICENSE.txt +1 -1
  118. package/providers/maplibre/dist/umd/im-maplibre-legacy-framework.js +1 -1
  119. package/providers/maplibre/dist/umd/im-maplibre-provider.js +1 -1
  120. package/providers/maplibre/dist/umd/index.js +1 -1
  121. package/providers/maplibre/src/index.js +14 -1
  122. package/providers/maplibre/src/maplibreProvider.js +127 -0
  123. package/sonar-project.properties +1 -1
  124. package/src/App/hooks/useInterfaceAPI.js +24 -1
  125. package/src/App/renderer/mapButtons.js +1 -1
  126. package/src/App/store/appActionsMap.js +22 -1
  127. package/src/InteractiveMap/InteractiveMap.js +114 -6
  128. package/src/config/defaults.js +29 -20
  129. package/src/config/events.js +110 -4
  130. package/src/index.js +5 -2
  131. package/src/scss/tools/_border-focus.scss +20 -4
  132. package/src/types.js +585 -0
  133. package/webpack.esm.mjs +8 -8
  134. package/webpack.umd.mjs +8 -8
  135. package/plugins/datasets/dist/esm/im-datasets-plugin.js +0 -1
  136. package/plugins/datasets/dist/esm/index.js +0 -2
  137. package/plugins/datasets/dist/umd/im-datasets-plugin.js +0 -1
  138. package/plugins/datasets/dist/umd/index.js +0 -2
  139. package/plugins/draw-ml/dist/esm/im-draw-ml-plugin.js +0 -1
  140. package/plugins/draw-ml/dist/esm/index.js +0 -2
  141. package/plugins/draw-ml/dist/umd/im-draw-ml-plugin.js +0 -1
  142. package/plugins/draw-ml/dist/umd/index.js +0 -2
  143. package/plugins/draw-ml/src/modes/drawVertexMode.js +0 -275
  144. package/plugins/draw-ml/src/modes/editVertexMode.js +0 -426
  145. package/plugins/draw-ml/src/utils.js +0 -102
  146. package/plugins/frame/dist/esm/im-frame-plugin.js +0 -1
  147. package/plugins/frame/dist/esm/index.js +0 -2
  148. package/plugins/frame/dist/umd/im-frame-plugin.js +0 -1
  149. package/plugins/frame/dist/umd/index.js +0 -2
  150. package/plugins/map-styles/dist/esm/im-map-styles-plugin.js +0 -1
  151. package/plugins/map-styles/dist/esm/index.js +0 -2
  152. package/plugins/map-styles/dist/umd/im-map-styles-plugin.js +0 -1
  153. package/plugins/map-styles/dist/umd/index.js +0 -2
  154. package/plugins/scale-bar/dist/esm/im-scale-bar-plugin.js +0 -1
  155. package/plugins/scale-bar/dist/esm/index.js +0 -2
  156. package/plugins/scale-bar/dist/umd/im-scale-bar-plugin.js +0 -1
  157. package/plugins/scale-bar/dist/umd/index.js +0 -2
  158. package/plugins/use-location/dist/esm/im-use-location-plugin.js +0 -1
  159. package/plugins/use-location/dist/esm/index.js +0 -2
  160. package/plugins/use-location/dist/umd/im-use-location-plugin.js +0 -1
  161. package/plugins/use-location/dist/umd/index.js +0 -2
  162. package/providers/open-names/dist/esm/im-reverse-geocode.js +0 -2
  163. package/providers/open-names/dist/esm/index.js +0 -2
  164. package/providers/open-names/dist/umd/im-reverse-geocode.js +0 -2
  165. package/providers/open-names/dist/umd/index.js +0 -2
  166. /package/docs/architecture/{ARCHITECTURE_DIAGRAMS.md → architecture-diagrams.md} +0 -0
  167. /package/plugins/{datasets → beta/datasets}/dist/css/index.css +0 -0
  168. /package/plugins/{datasets → beta/datasets}/dist/esm/index.js.LICENSE.txt +0 -0
  169. /package/plugins/{datasets → beta/datasets}/dist/umd/index.js.LICENSE.txt +0 -0
  170. /package/plugins/{datasets → beta/datasets}/src/DatasetsInit.jsx +0 -0
  171. /package/plugins/{datasets → beta/datasets}/src/api/addDataset.js +0 -0
  172. /package/plugins/{datasets → beta/datasets}/src/api/hideDataset.js +0 -0
  173. /package/plugins/{datasets → beta/datasets}/src/api/hideFeatures.js +0 -0
  174. /package/plugins/{datasets → beta/datasets}/src/api/removeDataset.js +0 -0
  175. /package/plugins/{datasets → beta/datasets}/src/api/showDataset.js +0 -0
  176. /package/plugins/{datasets → beta/datasets}/src/api/showFeatures.js +0 -0
  177. /package/plugins/{datasets → beta/datasets}/src/datasets.js +0 -0
  178. /package/plugins/{datasets → beta/datasets}/src/datasets.scss +0 -0
  179. /package/plugins/{datasets → beta/datasets}/src/defaults.js +0 -0
  180. /package/plugins/{datasets → beta/datasets}/src/handleSetMapStyle.js +0 -0
  181. /package/plugins/{datasets → beta/datasets}/src/index.js +0 -0
  182. /package/plugins/{datasets → beta/datasets}/src/panels/Key.module.scss +0 -0
  183. /package/plugins/{datasets → beta/datasets}/src/panels/Layers.jsx +0 -0
  184. /package/plugins/{datasets → beta/datasets}/src/panels/Layers.module.scss +0 -0
  185. /package/plugins/{datasets → beta/datasets}/src/reducer.js +0 -0
  186. /package/plugins/{datasets → beta/datasets}/src/utils/bbox.js +0 -0
  187. /package/plugins/{datasets → beta/datasets}/src/utils/debounce.js +0 -0
  188. /package/plugins/{datasets → beta/datasets}/src/utils/filters.js +0 -0
  189. /package/plugins/{draw-es → beta/draw-es}/src/DrawInit.jsx +0 -0
  190. /package/plugins/{draw-es → beta/draw-es}/src/api/addFeature.js +0 -0
  191. /package/plugins/{draw-es → beta/draw-es}/src/api/deleteFeature.js +0 -0
  192. /package/plugins/{draw-es → beta/draw-es}/src/api/editFeature.js +0 -0
  193. /package/plugins/{draw-es → beta/draw-es}/src/api/newPolygon.js +0 -0
  194. /package/plugins/{draw-es → beta/draw-es}/src/events.js +0 -0
  195. /package/plugins/{draw-es → beta/draw-es}/src/graphic.js +0 -0
  196. /package/plugins/{draw-es → beta/draw-es}/src/index.js +0 -0
  197. /package/plugins/{draw-es → beta/draw-es}/src/manifest.js +0 -0
  198. /package/plugins/{draw-es → beta/draw-es}/src/reducer.js +0 -0
  199. /package/plugins/{draw-es → beta/draw-es}/src/sketchViewModel.js +0 -0
  200. /package/plugins/{draw-ml → beta/draw-ml}/dist/css/index.css +0 -0
  201. /package/plugins/{draw-ml → beta/draw-ml}/dist/esm/index.js.LICENSE.txt +0 -0
  202. /package/plugins/{draw-ml → beta/draw-ml}/dist/umd/index.js.LICENSE.txt +0 -0
  203. /package/plugins/{draw-ml → beta/draw-ml}/src/DrawInit.jsx +0 -0
  204. /package/plugins/{draw-ml → beta/draw-ml}/src/api/addFeature.js +0 -0
  205. /package/plugins/{draw-ml → beta/draw-ml}/src/api/deleteFeature.js +0 -0
  206. /package/plugins/{draw-ml → beta/draw-ml}/src/draw.scss +0 -0
  207. /package/plugins/{draw-ml → beta/draw-ml}/src/index.js +0 -0
  208. /package/plugins/{draw-ml → beta/draw-ml}/src/modes/disabledMode.js +0 -0
  209. /package/plugins/{draw-ml/src → beta/draw-ml/src/utils}/snapHelpers.js +0 -0
  210. /package/plugins/{frame → beta/frame}/dist/css/index.css +0 -0
  211. /package/plugins/{frame → beta/frame}/dist/esm/index.js.LICENSE.txt +0 -0
  212. /package/plugins/{frame → beta/frame}/dist/umd/index.js.LICENSE.txt +0 -0
  213. /package/plugins/{frame → beta/frame}/package.json +0 -0
  214. /package/plugins/{frame → beta/frame}/src/Frame.jsx +0 -0
  215. /package/plugins/{frame → beta/frame}/src/FrameInit.jsx +0 -0
  216. /package/plugins/{frame → beta/frame}/src/api/addFrame.js +0 -0
  217. /package/plugins/{frame → beta/frame}/src/api/editFeature.js +0 -0
  218. /package/plugins/{frame → beta/frame}/src/config.js +0 -0
  219. /package/plugins/{frame → beta/frame}/src/frame.scss +0 -0
  220. /package/plugins/{frame → beta/frame}/src/index.js +0 -0
  221. /package/plugins/{frame → beta/frame}/src/manifest.js +0 -0
  222. /package/plugins/{frame → beta/frame}/src/reducer.js +0 -0
  223. /package/plugins/{frame → beta/frame}/src/utils.js +0 -0
  224. /package/plugins/{map-styles → beta/map-styles}/dist/css/index.css +0 -0
  225. /package/plugins/{map-styles → beta/map-styles}/dist/esm/index.js.LICENSE.txt +0 -0
  226. /package/plugins/{map-styles → beta/map-styles}/dist/umd/index.js.LICENSE.txt +0 -0
  227. /package/plugins/{map-styles → beta/map-styles}/src/MapStylesInit.jsx +0 -0
  228. /package/plugins/{map-styles → beta/map-styles}/src/config.js +0 -0
  229. /package/plugins/{map-styles → beta/map-styles}/src/index.js +0 -0
  230. /package/plugins/{map-styles → beta/map-styles}/src/mapStyles.scss +0 -0
  231. /package/plugins/{scale-bar → beta/scale-bar}/dist/css/index.css +0 -0
  232. /package/plugins/{scale-bar → beta/scale-bar}/dist/esm/index.js.LICENSE.txt +0 -0
  233. /package/plugins/{scale-bar → beta/scale-bar}/dist/umd/index.js.LICENSE.txt +0 -0
  234. /package/plugins/{scale-bar → beta/scale-bar}/package.json +0 -0
  235. /package/plugins/{scale-bar → beta/scale-bar}/src/ScaleBar.jsx +0 -0
  236. /package/plugins/{scale-bar → beta/scale-bar}/src/ScaleBar.test.jsx +0 -0
  237. /package/plugins/{scale-bar → beta/scale-bar}/src/index.js +0 -0
  238. /package/plugins/{scale-bar → beta/scale-bar}/src/index.test.js +0 -0
  239. /package/plugins/{scale-bar → beta/scale-bar}/src/manifest.js +0 -0
  240. /package/plugins/{scale-bar → beta/scale-bar}/src/scaleBar.scss +0 -0
  241. /package/plugins/{scale-bar → beta/scale-bar}/src/utils.js +0 -0
  242. /package/plugins/{scale-bar → beta/scale-bar}/src/utils.test.js +0 -0
  243. /package/plugins/{use-location → beta/use-location}/dist/esm/index.js.LICENSE.txt +0 -0
  244. /package/plugins/{use-location → beta/use-location}/dist/umd/index.js.LICENSE.txt +0 -0
  245. /package/plugins/{use-location → beta/use-location}/src/UseLocation.jsx +0 -0
  246. /package/plugins/{use-location → beta/use-location}/src/UseLocationInit.jsx +0 -0
  247. /package/plugins/{use-location → beta/use-location}/src/defaults.js +0 -0
  248. /package/plugins/{use-location → beta/use-location}/src/events.js +0 -0
  249. /package/plugins/{use-location → beta/use-location}/src/index.js +0 -0
  250. /package/plugins/{use-location → beta/use-location}/src/manifest.js +0 -0
  251. /package/plugins/{use-location → beta/use-location}/src/reducer.js +0 -0
  252. /package/providers/{esri → beta/esri}/src/appEvents.js +0 -0
  253. /package/providers/{esri → beta/esri}/src/defaults.js +0 -0
  254. /package/providers/{esri → beta/esri}/src/esriProvider.js +0 -0
  255. /package/providers/{esri → beta/esri}/src/esriProvider.scss +0 -0
  256. /package/providers/{esri → beta/esri}/src/index.js +0 -0
  257. /package/providers/{esri → beta/esri}/src/utils/coords.js +0 -0
  258. /package/providers/{esri → beta/esri}/src/utils/detectWebGL.js +0 -0
  259. /package/providers/{esri → beta/esri}/src/utils/esriFixes.js +0 -0
  260. /package/providers/{esri → beta/esri}/src/utils/query.js +0 -0
  261. /package/providers/{esri → beta/esri}/src/utils/spatial.js +0 -0
  262. /package/providers/{open-names → beta/open-names}/dist/esm/im-reverse-geocode.js.LICENSE.txt +0 -0
  263. /package/providers/{open-names → beta/open-names}/dist/esm/index.js.LICENSE.txt +0 -0
  264. /package/providers/{open-names → beta/open-names}/dist/umd/im-reverse-geocode.js.LICENSE.txt +0 -0
  265. /package/providers/{open-names → beta/open-names}/dist/umd/index.js.LICENSE.txt +0 -0
  266. /package/providers/{open-names → beta/open-names}/src/index.js +0 -0
  267. /package/providers/{open-names → beta/open-names}/src/reverseGeocode.js +0 -0
  268. /package/providers/{open-names → beta/open-names}/src/utils/mapToLocationModel.js +0 -0
@@ -1,275 +0,0 @@
1
- import DrawPolygon from '../../../../node_modules/@mapbox/mapbox-gl-draw/src/modes/draw_polygon.js'
2
- import createVertex from '../../../../node_modules/@mapbox/mapbox-gl-draw/src/lib/create_vertex.js'
3
- import { isValidClick } from '../utils.js'
4
- import {
5
- getSnapInstance,
6
- isSnapActive,
7
- isSnapEnabled,
8
- getSnapLngLat,
9
- triggerSnapAtPoint,
10
- triggerSnapAtCenter,
11
- createSnappedEvent,
12
- createSnappedClickEvent
13
- } from '../snapHelpers.js'
14
-
15
- export const DrawVertexMode = {
16
- ...DrawPolygon,
17
-
18
- onSetup(options) {
19
- const { map } = this
20
-
21
- const state = {
22
- ...DrawPolygon.onSetup.call(this, options),
23
- ...options
24
- }
25
-
26
- const { container, interfaceType, vertexMarkerId } = state
27
- const vertexMarker = container.querySelector(`#${vertexMarkerId}`)
28
- vertexMarker.style.display = ['touch', 'keyboard'].includes(interfaceType) ? 'block' : 'none'
29
- state.vertexMarker = vertexMarker
30
-
31
- // Bind all handlers once
32
- const bind = (name, fn) => (this[name] = fn.bind(this, state))
33
- const handlers = {
34
- keydownHandler: this.onKeydown,
35
- keyupHandler: this.onKeyup,
36
- focusHandler: this.onFocus,
37
- blurHandler: this.onBlur,
38
- createHandler: this.onCreate,
39
- moveHandler: this.onMove,
40
- pointerdownHandler: this.onPointerdown,
41
- pointermoveHandler: this.onPointermove,
42
- pointerupHandler: this.onPointerup,
43
- vertexButtonClickHandler: this.onVertexButtonClick
44
- }
45
- Object.entries(handlers).forEach(([k, fn]) => bind(k, fn))
46
-
47
- // Register events
48
- this._listeners = [
49
- [window, 'keydown', this.keydownHandler],
50
- [window, 'keyup', this.keyupHandler],
51
- [window, 'click', this.vertexButtonClickHandler],
52
- [container, 'focus', this.focusHandler],
53
- [container, 'blur', this.blurHandler],
54
- [container, 'pointermove', this.pointermoveHandler],
55
- [container, 'pointerup', this.pointerupHandler],
56
- [map, 'pointerdown', this.pointerdownHandler],
57
- [map, 'draw.create', this.createHandler],
58
- [map, 'move', this.moveHandler]
59
- ]
60
- this._listeners.forEach(([t, e, h]) => t.addEventListener ? t.addEventListener(e, h) : t.on(e, h))
61
-
62
- return state
63
- },
64
-
65
- onClick(state, e) {
66
- if (e.originalEvent.button > 0) {
67
- return
68
- }
69
- const snap = getSnapInstance(this.map)
70
- if (isSnapEnabled(state) && isSnapActive(snap)) {
71
- // Use snapped coordinates when snap is enabled and active
72
- e = createSnappedEvent(e, snap)
73
- } else {
74
- // When snap is disabled, ensure polygon uses actual click coordinates
75
- // (not stale snapped coordinates from previous mouse moves)
76
- const coords = state.polygon.coordinates[0]
77
- if (coords.length > 0) {
78
- coords[coords.length - 1] = [e.lngLat.lng, e.lngLat.lat]
79
- }
80
- }
81
- DrawPolygon.onClick.call(this, state, e)
82
- },
83
-
84
- onTap() {
85
- return
86
- },
87
-
88
- doClick(state) {
89
- const coords = state.polygon.coordinates
90
- this.dispatchVertexChange(coords[0])
91
- if (!isValidClick(coords)) {
92
- return
93
- }
94
- // Use snap coordinates if snapping is enabled and active
95
- const snap = getSnapInstance(this.map)
96
- const snappedEvent = isSnapEnabled(state) && createSnappedClickEvent(this.map, snap)
97
-
98
- if (snappedEvent) {
99
- DrawPolygon.onClick.call(this, state, snappedEvent)
100
- this._ctx.store.render()
101
- } else {
102
- this._simulateMouse('click', DrawPolygon.onClick, state)
103
- }
104
- },
105
-
106
- dispatchVertexChange(coords) {
107
- this.map.fire('draw.vertexchange', {
108
- numVertecies: coords.length
109
- })
110
- },
111
-
112
- _simulateMouse(type, fn, state) {
113
- const { map } = this
114
- const center = map.getCenter()
115
- const point = map.project(center)
116
- fn.call(this, state, {
117
- lngLat: center,
118
- point,
119
- originalEvent: new MouseEvent(type, {
120
- clientX: point.x,
121
- clientY: point.y,
122
- bubbles: true,
123
- cancelable: true
124
- })
125
- })
126
- this._ctx.store.render()
127
- },
128
-
129
- _setInterface(state, type, show = true) {
130
- state.interfaceType = type
131
- if (show) {
132
- state.vertexMarker.style.display = 'block'
133
- }
134
- },
135
-
136
- onCreate(state, e) {
137
- const draw = this._ctx.api
138
- const feature = e.features[0]
139
- draw.delete(feature.id)
140
- feature.id = state.featureId
141
- draw.add(feature)
142
- },
143
-
144
- onVertexButtonClick(state, e) {
145
- if (e.target.closest(`#${state.addVertexButtonId}`)) {
146
- this.doClick(state)
147
- }
148
- },
149
-
150
- onTouchStart(state, e) {
151
- this._setInterface(state, 'touch')
152
- this.onMove(state, e)
153
- },
154
-
155
- onTouchEnd(state, e) {
156
- this._setInterface(state, 'touch')
157
- this.onMove(state, e)
158
- },
159
-
160
- onKeydown(state, e) {
161
- if (document.activeElement !== state.container) {
162
- return
163
- }
164
- if (e.key === 'Escape') {
165
- return e.preventDefault()
166
- }
167
- if (e.key === 'Enter') {
168
- state.isActive = true
169
- }
170
- this._setInterface(state, 'keyboard')
171
- this.onMove(state, e)
172
- },
173
-
174
- onKeyup(state, e) {
175
- if (e.key === 'Escape') {
176
- return
177
- }
178
- this._setInterface(state, 'keyboard')
179
- this.onMove(state, e)
180
- if (e.key === 'Enter' && state.isActive) {
181
- this.doClick(state)
182
- }
183
- },
184
-
185
- onFocus(state) {
186
- const { vertexMarker, interfaceType } = state
187
- vertexMarker.style.display = ['touch', 'keyboard'].includes(interfaceType) ? 'block' : 'none'
188
- },
189
-
190
- onBlur(state, e) {
191
- if (e.target !== state.container) {
192
- state.vertexMarker.style.display = 'none'
193
- }
194
- },
195
-
196
- onMouseMove(state, e) {
197
- // Trigger snap detection at mouse position
198
- if (isSnapEnabled(state)) {
199
- const snap = getSnapInstance(this.map)
200
- triggerSnapAtPoint(snap, this.map, e.point)
201
-
202
- // Use snapped coordinates for rubber band if snap is active
203
- const snappedLngLat = getSnapLngLat(snap)
204
- if (snappedLngLat) {
205
- e = { ...e, lngLat: snappedLngLat }
206
- }
207
- }
208
-
209
- DrawPolygon.onMouseMove.call(this, state, e)
210
- },
211
-
212
- onMove(state) {
213
- if (['touch', 'keyboard'].includes(state.interfaceType)) {
214
- // Trigger snap detection at center point for touch/keyboard mode
215
- if (isSnapEnabled(state)) {
216
- triggerSnapAtCenter(getSnapInstance(this.map), this.map)
217
- }
218
-
219
- // Use snapped coordinates if available, otherwise use center
220
- const snap = getSnapInstance(this.map)
221
- const snappedLngLat = isSnapEnabled(state) && getSnapLngLat(snap)
222
-
223
- if (snappedLngLat) {
224
- const point = this.map.project([snappedLngLat.lng, snappedLngLat.lat])
225
- DrawPolygon.onMouseMove.call(this, state, {
226
- lngLat: snappedLngLat,
227
- point,
228
- originalEvent: new MouseEvent('mousemove', {
229
- clientX: point.x,
230
- clientY: point.y,
231
- bubbles: true,
232
- cancelable: true
233
- })
234
- })
235
- this._ctx.store.render()
236
- } else {
237
- this._simulateMouse('mousemove', DrawPolygon.onMouseMove, state)
238
- }
239
- }
240
- },
241
-
242
- onPointerdown(state, e) {
243
- if (e.pointerType !== 'touch') {
244
- this._setInterface(state, 'pointer', false)
245
- }
246
- },
247
-
248
- onPointermove(state, e) {
249
- if (e.pointerType !== 'touch') {
250
- state.vertexMarker.style.display = 'none'
251
- }
252
- },
253
-
254
- onPointerup(state) {
255
- this.dispatchVertexChange(state.polygon.coordinates[0])
256
- },
257
-
258
- toDisplayFeatures(state, geojson, display) {
259
- DrawPolygon.toDisplayFeatures.call(this, state, geojson, display)
260
-
261
- // Create vertex
262
- if (geojson.geometry.type === 'Polygon' && geojson.id === state.polygon.id) {
263
- const ring = geojson.geometry.coordinates[0]
264
- for (let i = 1; i < ring.length - 2; i++) {
265
- display(createVertex(geojson.id, ring[i], `0.${i}`))
266
- }
267
- }
268
- },
269
-
270
- onStop(state) {
271
- DrawPolygon.onStop.call(this, state)
272
- this._listeners.forEach(([t, e, h]) => t.removeEventListener ? t.removeEventListener(e, h) : t.off(e, h))
273
- state.vertexMarker.style.display = 'none'
274
- }
275
- }
@@ -1,426 +0,0 @@
1
- import DirectSelect from '../../../../node_modules/@mapbox/mapbox-gl-draw/src/modes/direct_select.js'
2
- import { spatialNavigate } from '../utils.js'
3
- import {
4
- getSnapInstance, isSnapActive, isSnapEnabled, getSnapLngLat,
5
- getSnapRadius, triggerSnapAtPoint, clearSnapIndicator, clearSnapState
6
- } from '../snapHelpers.js'
7
-
8
- const ARROW_KEYS = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']
9
- const ARROW_OFFSETS = { ArrowUp: [0, -1], ArrowDown: [0, 1], ArrowLeft: [-1, 0], ArrowRight: [1, 0] }
10
- const NUDGE = 1, STEP = 5
11
-
12
- const touchVertexTarget = `
13
- <svg width='48' height='48' viewBox='0 0 48 48' fill-rule='evenodd' style='display:none;position:absolute;top:50%;left:50%;margin:24px 0 0 -24px' class='touch-vertex-target' data-touch-vertex-target>
14
- <circle cx='24' cy='24' r='24' fill='currentColor'/>
15
- <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="#fff"/>
16
- </svg>
17
- `
18
-
19
- const scalePoint = (point, scale) => ({ x: point.x * scale, y: point.y * scale })
20
-
21
- const isOnSVG = (el) => el instanceof window.SVGElement || el.ownerSVGElement
22
-
23
- export const EditVertexMode = {
24
- ...DirectSelect,
25
-
26
- onSetup(options) {
27
- const state = DirectSelect.onSetup.call(this, options)
28
- Object.assign(state, {
29
- container: options.container,
30
- interfaceType: options.interfaceType,
31
- deleteVertexButtonId: options.deleteVertexButtonId,
32
- isPanEnabled: options.isPanEnabled,
33
- getSnapEnabled: options.getSnapEnabled,
34
- featureId: state.featureId || options.featureId,
35
- selectedVertexIndex: options.selectedVertexIndex ?? -1,
36
- selectedVertexType: options.selectedVertexType,
37
- scale: options.scale
38
- })
39
-
40
- state.vertecies = this.getVerticies(state.featureId)
41
- state.midpoints = this.getMidpoints(state.featureId)
42
- this.setupEventListeners(state)
43
-
44
- if (options.selectedVertexType === 'midpoint') {
45
- this.updateMidpoint(state.midpoints[options.selectedVertexIndex - state.vertecies.length])
46
- }
47
- this.addTouchVertexTarget(state)
48
- return state
49
- },
50
-
51
- setupEventListeners(state) {
52
- const bind = (fn) => (e) => fn.call(this, state, e)
53
- const h = this.handlers = {
54
- keydown: bind(this.onKeydown), keyup: bind(this.onKeyup),
55
- pointerdown: bind(this.onPointerevent), pointermove: bind(this.onPointerevent), pointerup: bind(this.onPointerevent),
56
- click: bind(this.onVertexButtonClick),
57
- touchstart: bind(this.onTouchstart), touchmove: bind(this.onTouchmove), touchend: bind(this.onTouchend),
58
- selectionchange: bind(this.onSelectionChange), scalechange: bind(this.onScaleChange),
59
- update: bind(this.onUpdate), move: bind(this.onMove)
60
- }
61
-
62
- window.addEventListener('keydown', h.keydown, { capture: true })
63
- window.addEventListener('keyup', h.keyup, { capture: true })
64
- window.addEventListener('click', h.click)
65
- state.container.addEventListener('pointerdown', h.pointerdown)
66
- state.container.addEventListener('pointermove', h.pointermove)
67
- state.container.addEventListener('pointerup', h.pointerup)
68
- state.container.addEventListener('touchstart', h.touchstart, { passive: false })
69
- state.container.addEventListener('touchmove', h.touchmove, { passive: false })
70
- state.container.addEventListener('touchend', h.touchend, { passive: false })
71
- this.map.on('draw.selectionchange', h.selectionchange)
72
- this.map.on('draw.scalechange', h.scalechange)
73
- this.map.on('draw.update', h.update)
74
- this.map.on('move', h.move)
75
- },
76
-
77
- onSelectionChange(state, e) {
78
- const vertexCoord = e.points[e.points.length - 1]?.geometry.coordinates
79
- const coords = e.features[0].geometry.coordinates.flat(1)
80
- const idx = coords.findIndex(c => vertexCoord && c[0] === vertexCoord[0] && c[1] === vertexCoord[1])
81
-
82
- state.selectedVertexIndex = state.interfaceType === 'keyboard' ? state.selectedVertexIndex : idx
83
- state.selectedVertexType ??= idx >= 0 ? 'vertex' : null
84
-
85
- this.map.fire('draw.vertexselection', {
86
- index: state.selectedVertexType === 'vertex' ? state.selectedVertexIndex : -1,
87
- numVertecies: state.vertecies.length
88
- })
89
- this.updateTouchVertexTarget(state, vertexCoord ? scalePoint(this.map.project(vertexCoord), state.scale) : null)
90
- },
91
-
92
- onScaleChange(state, e) { state.scale = e.scale },
93
-
94
- onUpdate(state) {
95
- const prev = new Set(state.vertecies.map(c => JSON.stringify(c)))
96
- if (prev.size === state.vertecies.length) {
97
- return
98
- }
99
- state.selectedVertexIndex = state.vertecies.findIndex(c => !prev.has(JSON.stringify(c)))
100
- state.selectedVertexType ??= state.selectedVertexIndex >= 0 ? 'vertex' : null
101
- },
102
-
103
- onKeydown(state, e) {
104
- state.interfaceType = 'keyboard'
105
- this.hideTouchVertexIndicator(state)
106
-
107
- if (e.key === ' ' && state.selectedVertexIndex < 0) {
108
- state.isPanEnabled = false
109
- return this.updateVertex(state)
110
- }
111
-
112
- if (!e.altKey && ARROW_KEYS.includes(e.key) && state.selectedVertexIndex >= 0) {
113
- e.preventDefault()
114
- e.stopPropagation()
115
- if (state.selectedVertexType === 'midpoint') {
116
- return this.insertVertex(state, e)
117
- }
118
-
119
- const snap = getSnapInstance(this.map)
120
- const currentCoord = this.getFeature(state.featureId).coordinates.flat(1)[state.selectedVertexIndex]
121
-
122
- // Break out of snap by moving outside snap radius
123
- if (isSnapEnabled(state) && state._isSnapped && snap) {
124
- const offset = getSnapRadius(snap) + 1
125
- const pt = this.map.project(currentCoord)
126
- const [dx, dy] = ARROW_OFFSETS[e.key].map(v => v * offset)
127
- state._isSnapped = false
128
- clearSnapIndicator(snap, this.map)
129
- return this.moveVertex(state, this.map.unproject({ x: pt.x + dx, y: pt.y + dy }))
130
- }
131
-
132
- const newCoord = this.getNewCoord(state, e)
133
- if (isSnapEnabled(state) && snap) {
134
- triggerSnapAtPoint(snap, this.map, this.map.project(newCoord))
135
- if (isSnapActive(snap)) {
136
- state._isSnapped = true
137
- return this.moveVertex(state, getSnapLngLat(snap))
138
- }
139
- }
140
- state._isSnapped = false
141
- return this.moveVertex(state, newCoord)
142
- }
143
-
144
- if (e.altKey && ARROW_KEYS.includes(e.key) && state.selectedVertexIndex >= 0) {
145
- return this.updateVertex(state, e.key)
146
- }
147
-
148
- if (e.key === 'Escape') {
149
- this.changeMode(state, { isPanEnabled: true, selectedVertexIndex: -1, selectedVertexType: null })
150
- }
151
- },
152
-
153
- onKeyup(state, e) {
154
- state.interfaceType = 'keyboard'
155
- if (ARROW_KEYS.includes(e.key) && state.selectedVertexIndex >= 0) e.stopPropagation()
156
- if (e.key === 'Delete') this.deleteVertex(state)
157
- },
158
-
159
- onMouseDown(state, e) {
160
- clearSnapState(getSnapInstance(this.map))
161
- const meta = e.featureTarget?.properties.meta
162
- if (['vertex', 'midpoint'].includes(meta)) {
163
- state.dragMoveLocation = e.lngLat
164
- state.dragMoving = false
165
- DirectSelect.onMouseDown.call(this, state, e)
166
- }
167
- if (meta === 'midpoint') {
168
- state.selectedVertexIndex = this.getVertexIndexFromMidpoint(state.vertecies, e.featureTarget.properties.coord_path)
169
- state.selectedVertexType = 'vertex'
170
- this.map.fire('draw.vertexselection', { index: state.selectedVertexIndex, numVertecies: state.vertecies.length })
171
- }
172
- },
173
-
174
- onMouseUp(state, e) {
175
- clearSnapState(getSnapInstance(this.map))
176
- if (state.dragMoving) this.syncVertices(state)
177
- DirectSelect.onMouseUp.call(this, state, e)
178
- },
179
-
180
- onPointerevent(state, e) {
181
- state.interfaceType = e.pointerType === 'touch' ? 'touch' : 'pointer'
182
- state.isPanEnabled = true
183
- if (e.pointerType === 'touch' && e.type === 'pointermove' && !isOnSVG(e.target.parentNode)) {
184
- this.changeMode(state, { selectedVertexIndex: -1, selectedVertexType: null, coordPath: null })
185
- }
186
- },
187
-
188
- // Empty stubs required by DirectSelect
189
- onTouchStart() {}, onTouchMove() {}, onTouchEnd() {},
190
-
191
- onTouchend(state) {
192
- clearSnapState(getSnapInstance(this.map))
193
- if (state?.featureId) this.syncVertices(state)
194
- },
195
-
196
- clickNoTarget(state) {
197
- this.changeMode(state, { selectedVertexIndex: -1, selectedVertexType: null, isPanEnabled: true })
198
- },
199
-
200
- onTap(state, e) {
201
- const meta = e.featureTarget?.properties.meta
202
- const coordPath = e.featureTarget?.properties.coord_path
203
-
204
- if (meta === 'vertex') {
205
- this.changeMode(state, {
206
- selectedVertexIndex: Number.parseInt(coordPath.split('.')[1], 10),
207
- selectedVertexType: 'vertex', coordPath
208
- })
209
- } else if (meta === 'midpoint') {
210
- this.insertVertex({ ...state, selectedVertexIndex: this.getVertexIndexFromMidpoint(state.vertecies, coordPath), selectedVertexType: 'midpoint' })
211
- } else {
212
- this.clickNoTarget(state)
213
- }
214
- },
215
-
216
- onTouchstart(state, e) {
217
- clearSnapState(getSnapInstance(this.map))
218
- if (state.selectedVertexIndex < 0 || !isOnSVG(e.target.parentNode)) {
219
- return
220
- }
221
-
222
- const touch = { x: e.touches[0].clientX, y: e.touches[0].clientY }
223
- const style = window.getComputedStyle(state.touchVertexTarget)
224
- state.deltaTarget = { x: touch.x - Number.parseFloat(style.left), y: touch.y - Number.parseFloat(style.top) }
225
- const vertexPt = this.map.project(state.vertecies[state.selectedVertexIndex])
226
- state.deltaVertex = { x: (touch.x / state.scale) - vertexPt.x, y: (touch.y / state.scale) - vertexPt.y }
227
- },
228
-
229
- onTouchmove(state, e) {
230
- if (state.selectedVertexIndex < 0 || !isOnSVG(e.target.parentNode)) {
231
- return
232
- }
233
-
234
- const touch = { x: e.touches[0].clientX, y: e.touches[0].clientY }
235
- const screenPt = { x: (touch.x / state.scale) - state.deltaVertex.x, y: (touch.y / state.scale) - state.deltaVertex.y }
236
-
237
- let finalCoord = this.map.unproject(screenPt)
238
- if (isSnapEnabled(state)) {
239
- const snap = getSnapInstance(this.map)
240
- triggerSnapAtPoint(snap, this.map, screenPt)
241
- finalCoord = getSnapLngLat(snap) || finalCoord
242
- }
243
-
244
- this.moveVertex(state, finalCoord)
245
- this.updateTouchVertexTarget(state, { x: touch.x - state.deltaTarget.x, y: touch.y - state.deltaTarget.y })
246
- },
247
-
248
- onDrag(state, e) {
249
- if (state.interfaceType === 'touch') {
250
- return
251
- }
252
-
253
- const snap = getSnapInstance(this.map)
254
- if (snap) {
255
- snap.snapStatus = false; snap.snapCoords = null
256
- }
257
-
258
- if (!isSnapEnabled(state) || !snap?.status) {
259
- DirectSelect.onDrag.call(this, state, e)
260
- return
261
- }
262
-
263
- if (!state.selectedCoordPaths?.length || !state.canDragMove) {
264
- return
265
- }
266
-
267
- state.dragMoving = true
268
- e.originalEvent.stopPropagation()
269
- triggerSnapAtPoint(snap, this.map, e.point)
270
-
271
- const finalLngLat = getSnapLngLat(snap) || e.lngLat
272
- state.feature.updateCoordinate(state.selectedCoordPaths[0], finalLngLat.lng, finalLngLat.lat)
273
- state.dragMoveLocation = e.lngLat
274
- },
275
-
276
- onMove(state) {
277
- const vertex = state.vertecies[state.selectedVertexIndex]
278
- if (vertex) this.updateTouchVertexTarget(state, scalePoint(this.map.project(vertex), state.scale))
279
- },
280
-
281
- onVertexButtonClick(state, e) {
282
- if (e.target.closest(`#${state.deleteVertexButtonId}`) && state.selectedVertexType === 'vertex') {
283
- this.deleteVertex(state)
284
- }
285
- },
286
-
287
- // Utility methods
288
- syncVertices(state) {
289
- state.vertecies = this.getVerticies(state.featureId)
290
- state.midpoints = this.getMidpoints(state.featureId)
291
- },
292
-
293
- getVerticies(featureId) {
294
- return this.getFeature(featureId)?.coordinates?.flat(1) || []
295
- },
296
-
297
- getMidpoints(featureId) {
298
- const coords = this.getFeature(featureId)?.coordinates?.flat(1) || []
299
- return coords.map((c, i) => {
300
- const next = coords[(i + 1) % coords.length]
301
- return [(c[0] + next[0]) / 2, (c[1] + next[1]) / 2]
302
- })
303
- },
304
-
305
- getVertexOrMidpoint(state, direction) {
306
- const project = (p) => Object.values(this.map.project(p))
307
- const pixels = [...state.vertecies.map(project), ...state.midpoints.map(project)]
308
- const start = pixels[state.selectedVertexIndex] || Object.values(this.map.project(this.map.getCenter()))
309
- const idx = spatialNavigate(start, pixels, direction)
310
- return [idx, idx < state.vertecies.length ? 'vertex' : 'midpoint']
311
- },
312
-
313
- getVertexIndexFromMidpoint(vertecies, coordPath) {
314
- const afterIdx = Number.parseInt(coordPath.split('.')[1], 10)
315
- return vertecies.length + ((afterIdx - 1 + vertecies.length) % vertecies.length)
316
- },
317
-
318
- addTouchVertexTarget(state) {
319
- let el = state.container.querySelector('[data-touch-vertex-target]')
320
- if (!el) {
321
- state.container.insertAdjacentHTML('beforeend', touchVertexTarget)
322
- el = state.container.querySelector('[data-touch-vertex-target]')
323
- }
324
- state.touchVertexTarget = el
325
- },
326
-
327
- updateTouchVertexTarget(state, point) {
328
- if (point && state.interfaceType === 'touch' && state.selectedVertexIndex >= 0) {
329
- Object.assign(state.touchVertexTarget.style, { display: 'block', top: `${point.y}px`, left: `${point.x}px` })
330
- } else {
331
- state.touchVertexTarget.style.display = 'none'
332
- }
333
- },
334
-
335
- hideTouchVertexIndicator(state) { state.touchVertexTarget.style.display = 'none' },
336
-
337
- updateMidpoint(coordinates) {
338
- setTimeout(() => {
339
- this.map.getSource('mapbox-gl-draw-hot').setData({
340
- type: 'Feature',
341
- properties: { meta: 'midpoint', active: 'true', id: 'active-midpoint' },
342
- geometry: { type: 'Point', coordinates }
343
- })
344
- }, 0)
345
- },
346
-
347
- updateVertex(state, direction) {
348
- const [idx, type] = this.getVertexOrMidpoint(state, direction)
349
- this.changeMode(state, { selectedVertexIndex: idx, selectedVertexType: type, ...(type === 'vertex' && { coordPath: `0.${idx}` }) })
350
- },
351
-
352
- getOffset(coord, e) {
353
- const pt = this.map.project(coord)
354
- const offset = e?.shiftKey ? NUDGE : STEP
355
- const [dx, dy] = e ? ARROW_OFFSETS[e.key].map(v => v * offset) : [0, 0]
356
- return this.map.unproject({ x: pt.x + dx, y: pt.y + dy })
357
- },
358
-
359
- getNewCoord(state, e) {
360
- return this.getOffset(this.getFeature(state.featureId).coordinates.flat(1)[state.selectedVertexIndex], e)
361
- },
362
-
363
- insertVertex(state, e) {
364
- const feature = this.getFeature(state.featureId)
365
- const midIdx = state.selectedVertexIndex - state.vertecies.length
366
- const newCoord = this.getOffset(state.midpoints[midIdx], e)
367
- const geojson = feature.toGeoJSON()
368
- const coords = geojson.geometry.type === 'Polygon' ? geojson.geometry.coordinates[0] : geojson.geometry.coordinates
369
- coords.splice(midIdx + 1, 0, [newCoord.lng, newCoord.lat])
370
- this._ctx.api.add(geojson)
371
- this.changeMode(state, { selectedVertexIndex: midIdx + 1, selectedVertexType: 'vertex', coordPath: `0.${midIdx + 1}` })
372
- },
373
-
374
- moveVertex(state, coord, options = {}) {
375
- if (options.checkSnap && state.enableSnap !== false) {
376
- const snap = this.map._snapInstance
377
- if (snap?.snapStatus && snap.snapCoords?.length >= 2) {
378
- coord = { lng: snap.snapCoords[0], lat: snap.snapCoords[1] }
379
- }
380
- }
381
- const geojson = this.getFeature(state.featureId).toGeoJSON()
382
- if (geojson.geometry.type === 'Polygon') {
383
- geojson.geometry.coordinates[0][state.selectedVertexIndex] = [coord.lng, coord.lat]
384
- }
385
- this._ctx.api.add(geojson)
386
- state.vertecies = this.getVerticies(state.featureId)
387
- },
388
-
389
- deleteVertex(state) {
390
- const feature = this.getFeature(state.featureId)
391
- // eslint-disable-next-line no-magic-numbers
392
- if (state.vertecies.length <= (feature.type === 'Polygon' ? 3 : 2)) {
393
- return
394
- }
395
- const nextIdx = state.selectedVertexIndex >= state.vertecies.length - 1 ? 0 : state.selectedVertexIndex
396
- this._ctx.api.trash()
397
- this.changeMode(state, { selectedVertexIndex: nextIdx, selectedVertexType: 'vertex', coordPath: `0.${nextIdx}` })
398
- },
399
-
400
- // Prevent selecting other features
401
- changeMode(state, updates) {
402
- if (!state.featureId) {
403
- return
404
- }
405
- this._ctx.api.changeMode('edit_vertex', { ...state, ...updates })
406
- },
407
-
408
- onStop(state) {
409
- const h = this.handlers
410
- state.container.removeEventListener('pointerdown', h.pointerdown)
411
- state.container.removeEventListener('pointermove', h.pointermove)
412
- state.container.removeEventListener('pointerup', h.pointerup)
413
- state.container.removeEventListener('touchstart', h.touchstart)
414
- state.container.removeEventListener('touchmove', h.touchmove)
415
- state.container.removeEventListener('touchend', h.touchend)
416
- this.map.off('draw.selectionchange', h.selectionchange)
417
- this.map.off('draw.scalechange', h.scalechange)
418
- this.map.off('draw.update', h.update)
419
- this.map.off('move', h.move)
420
- this.map.dragPan.enable()
421
- window.removeEventListener('click', h.click)
422
- window.removeEventListener('keydown', h.keydown, { capture: true })
423
- window.removeEventListener('keyup', h.keyup, { capture: true })
424
- this.hideTouchVertexIndicator(state)
425
- }
426
- }