@deck.gl-community/editable-layers 9.0.0-alpha.1

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 (295) hide show
  1. package/README.md +82 -0
  2. package/dist/constants.d.ts +14 -0
  3. package/dist/constants.js +14 -0
  4. package/dist/curve-utils.d.ts +2 -0
  5. package/dist/curve-utils.js +61 -0
  6. package/dist/edit-modes/composite-mode.d.ts +14 -0
  7. package/dist/edit-modes/composite-mode.js +47 -0
  8. package/dist/edit-modes/draw-90degree-polygon-mode.d.ts +11 -0
  9. package/dist/edit-modes/draw-90degree-polygon-mode.js +179 -0
  10. package/dist/edit-modes/draw-circle-by-diameter-mode.d.ts +24 -0
  11. package/dist/edit-modes/draw-circle-by-diameter-mode.js +78 -0
  12. package/dist/edit-modes/draw-circle-from-center-mode.d.ts +22 -0
  13. package/dist/edit-modes/draw-circle-from-center-mode.js +70 -0
  14. package/dist/edit-modes/draw-ellipse-by-bounding-box-mode.d.ts +5 -0
  15. package/dist/edit-modes/draw-ellipse-by-bounding-box-mode.js +20 -0
  16. package/dist/edit-modes/draw-ellipse-using-three-points-mode.d.ts +5 -0
  17. package/dist/edit-modes/draw-ellipse-using-three-points-mode.js +16 -0
  18. package/dist/edit-modes/draw-line-string-mode.d.ts +25 -0
  19. package/dist/edit-modes/draw-line-string-mode.js +170 -0
  20. package/dist/edit-modes/draw-point-mode.d.ts +8 -0
  21. package/dist/edit-modes/draw-point-mode.js +28 -0
  22. package/dist/edit-modes/draw-polygon-by-dragging-mode.d.ts +14 -0
  23. package/dist/edit-modes/draw-polygon-by-dragging-mode.js +87 -0
  24. package/dist/edit-modes/draw-polygon-mode.d.ts +10 -0
  25. package/dist/edit-modes/draw-polygon-mode.js +143 -0
  26. package/dist/edit-modes/draw-rectangle-from-center-mode.d.ts +5 -0
  27. package/dist/edit-modes/draw-rectangle-from-center-mode.js +17 -0
  28. package/dist/edit-modes/draw-rectangle-mode.d.ts +5 -0
  29. package/dist/edit-modes/draw-rectangle-mode.js +11 -0
  30. package/dist/edit-modes/draw-rectangle-using-three-points-mode.d.ts +5 -0
  31. package/dist/edit-modes/draw-rectangle-using-three-points-mode.js +28 -0
  32. package/dist/edit-modes/draw-square-from-center-mode.d.ts +5 -0
  33. package/dist/edit-modes/draw-square-from-center-mode.js +35 -0
  34. package/dist/edit-modes/draw-square-mode.d.ts +5 -0
  35. package/dist/edit-modes/draw-square-mode.js +28 -0
  36. package/dist/edit-modes/duplicate-mode.d.ts +7 -0
  37. package/dist/edit-modes/duplicate-mode.js +17 -0
  38. package/dist/edit-modes/edit-mode.d.ts +11 -0
  39. package/dist/edit-modes/edit-mode.js +2 -0
  40. package/dist/edit-modes/elevation-mode.d.ts +13 -0
  41. package/dist/edit-modes/elevation-mode.js +49 -0
  42. package/dist/edit-modes/extend-line-string-mode.d.ts +9 -0
  43. package/dist/edit-modes/extend-line-string-mode.js +72 -0
  44. package/dist/edit-modes/extrude-mode.d.ts +15 -0
  45. package/dist/edit-modes/extrude-mode.js +186 -0
  46. package/dist/edit-modes/geojson-edit-mode.d.ts +33 -0
  47. package/dist/edit-modes/geojson-edit-mode.js +208 -0
  48. package/dist/edit-modes/immutable-feature-collection.d.ts +43 -0
  49. package/dist/edit-modes/immutable-feature-collection.js +300 -0
  50. package/dist/edit-modes/measure-angle-mode.d.ts +11 -0
  51. package/dist/edit-modes/measure-angle-mode.js +99 -0
  52. package/dist/edit-modes/measure-area-mode.d.ts +8 -0
  53. package/dist/edit-modes/measure-area-mode.js +50 -0
  54. package/dist/edit-modes/measure-distance-mode.d.ts +19 -0
  55. package/dist/edit-modes/measure-distance-mode.js +171 -0
  56. package/dist/edit-modes/modify-mode.d.ts +15 -0
  57. package/dist/edit-modes/modify-mode.js +203 -0
  58. package/dist/edit-modes/resize-circle-mode.d.ts +16 -0
  59. package/dist/edit-modes/resize-circle-mode.js +142 -0
  60. package/dist/edit-modes/rotate-mode.d.ts +17 -0
  61. package/dist/edit-modes/rotate-mode.js +151 -0
  62. package/dist/edit-modes/scale-mode.d.ts +27 -0
  63. package/dist/edit-modes/scale-mode.js +173 -0
  64. package/dist/edit-modes/snappable-mode.d.ts +21 -0
  65. package/dist/edit-modes/snappable-mode.js +109 -0
  66. package/dist/edit-modes/split-polygon-mode.d.ts +10 -0
  67. package/dist/edit-modes/split-polygon-mode.js +164 -0
  68. package/dist/edit-modes/three-click-polygon-mode.d.ts +10 -0
  69. package/dist/edit-modes/three-click-polygon-mode.js +72 -0
  70. package/dist/edit-modes/transform-mode.d.ts +9 -0
  71. package/dist/edit-modes/transform-mode.js +63 -0
  72. package/dist/edit-modes/translate-mode.d.ts +13 -0
  73. package/dist/edit-modes/translate-mode.js +113 -0
  74. package/dist/edit-modes/two-click-polygon-mode.d.ts +13 -0
  75. package/dist/edit-modes/two-click-polygon-mode.js +93 -0
  76. package/dist/edit-modes/types.d.ts +86 -0
  77. package/dist/edit-modes/types.js +1 -0
  78. package/dist/edit-modes/utils.d.ts +36 -0
  79. package/dist/edit-modes/utils.js +381 -0
  80. package/dist/edit-modes/view-mode.d.ts +3 -0
  81. package/dist/edit-modes/view-mode.js +3 -0
  82. package/dist/editable-layers/editable-geojson-layer.d.ts +98 -0
  83. package/dist/editable-layers/editable-geojson-layer.js +450 -0
  84. package/dist/editable-layers/editable-h3-cluster-layer.d.ts +34 -0
  85. package/dist/editable-layers/editable-h3-cluster-layer.js +164 -0
  86. package/dist/editable-layers/editable-layer.d.ts +49 -0
  87. package/dist/editable-layers/editable-layer.js +195 -0
  88. package/dist/editable-layers/editable-path-layer.d.ts +9 -0
  89. package/dist/editable-layers/editable-path-layer.js +34 -0
  90. package/dist/editable-layers/elevated-edit-handle-layer.d.ts +7 -0
  91. package/dist/editable-layers/elevated-edit-handle-layer.js +24 -0
  92. package/dist/editable-layers/junction-scatterplot-layer.d.ts +14 -0
  93. package/dist/editable-layers/junction-scatterplot-layer.js +41 -0
  94. package/dist/editable-layers/path-marker-layer/arrow-2d-geometry.d.ts +4 -0
  95. package/dist/editable-layers/path-marker-layer/arrow-2d-geometry.js +55 -0
  96. package/dist/editable-layers/path-marker-layer/create-path-markers.d.ts +16 -0
  97. package/dist/editable-layers/path-marker-layer/create-path-markers.js +75 -0
  98. package/dist/editable-layers/path-marker-layer/path-marker-layer.d.ts +40 -0
  99. package/dist/editable-layers/path-marker-layer/path-marker-layer.js +121 -0
  100. package/dist/editable-layers/path-marker-layer/polyline.d.ts +18 -0
  101. package/dist/editable-layers/path-marker-layer/polyline.js +37 -0
  102. package/dist/editable-layers/path-outline-layer/path-outline-layer.d.ts +26 -0
  103. package/dist/editable-layers/path-outline-layer/path-outline-layer.js +106 -0
  104. package/dist/editable-layers/selection-layer.d.ts +26 -0
  105. package/dist/editable-layers/selection-layer.js +167 -0
  106. package/dist/geojson-types.d.ts +58 -0
  107. package/dist/geojson-types.js +2 -0
  108. package/dist/index.cjs +5825 -0
  109. package/dist/index.cjs.map +7 -0
  110. package/dist/index.d.ts +60 -0
  111. package/dist/index.js +62 -0
  112. package/dist/lib/constants.d.ts +6 -0
  113. package/dist/lib/constants.js +6 -0
  114. package/dist/lib/deck-renderer/deck-cache.d.ts +14 -0
  115. package/dist/lib/deck-renderer/deck-cache.js +51 -0
  116. package/dist/lib/deck-renderer/deck-drawer.d.ts +63 -0
  117. package/dist/lib/deck-renderer/deck-drawer.js +232 -0
  118. package/dist/lib/feature.d.ts +10 -0
  119. package/dist/lib/feature.js +16 -0
  120. package/dist/lib/layer-mouse-event.d.ts +11 -0
  121. package/dist/lib/layer-mouse-event.js +24 -0
  122. package/dist/lib/layers/junctions-layer.d.ts +8 -0
  123. package/dist/lib/layers/junctions-layer.js +33 -0
  124. package/dist/lib/layers/segments-layer.d.ts +18 -0
  125. package/dist/lib/layers/segments-layer.js +94 -0
  126. package/dist/lib/layers/texts-layer.d.ts +8 -0
  127. package/dist/lib/layers/texts-layer.js +32 -0
  128. package/dist/lib/math.d.ts +11 -0
  129. package/dist/lib/math.js +22 -0
  130. package/dist/lib/nebula-layer.d.ts +13 -0
  131. package/dist/lib/nebula-layer.js +26 -0
  132. package/dist/lib/nebula.d.ts +34 -0
  133. package/dist/lib/nebula.js +254 -0
  134. package/dist/lib/style.d.ts +19 -0
  135. package/dist/lib/style.js +20 -0
  136. package/dist/memoize.d.ts +6 -0
  137. package/dist/memoize.js +40 -0
  138. package/dist/mode-handlers/composite-mode-handler.d.ts +24 -0
  139. package/dist/mode-handlers/composite-mode-handler.js +55 -0
  140. package/dist/mode-handlers/draw-90degree-polygon-handler.d.ts +13 -0
  141. package/dist/mode-handlers/draw-90degree-polygon-handler.js +169 -0
  142. package/dist/mode-handlers/draw-circle-by-bounding-box-handler.d.ts +9 -0
  143. package/dist/mode-handlers/draw-circle-by-bounding-box-handler.js +29 -0
  144. package/dist/mode-handlers/draw-circle-from-center-handler.d.ts +9 -0
  145. package/dist/mode-handlers/draw-circle-from-center-handler.js +27 -0
  146. package/dist/mode-handlers/draw-ellipse-by-bounding-box-handler.d.ts +9 -0
  147. package/dist/mode-handlers/draw-ellipse-by-bounding-box-handler.js +30 -0
  148. package/dist/mode-handlers/draw-ellipse-using-three-points-handler.d.ts +9 -0
  149. package/dist/mode-handlers/draw-ellipse-using-three-points-handler.js +37 -0
  150. package/dist/mode-handlers/draw-line-string-handler.d.ts +9 -0
  151. package/dist/mode-handlers/draw-line-string-handler.js +83 -0
  152. package/dist/mode-handlers/draw-point-handler.d.ts +5 -0
  153. package/dist/mode-handlers/draw-point-handler.js +11 -0
  154. package/dist/mode-handlers/draw-polygon-handler.d.ts +11 -0
  155. package/dist/mode-handlers/draw-polygon-handler.js +92 -0
  156. package/dist/mode-handlers/draw-rectangle-handler.d.ts +9 -0
  157. package/dist/mode-handlers/draw-rectangle-handler.js +18 -0
  158. package/dist/mode-handlers/draw-rectangle-using-three-points-handler.d.ts +9 -0
  159. package/dist/mode-handlers/draw-rectangle-using-three-points-handler.js +49 -0
  160. package/dist/mode-handlers/duplicate-handler.d.ts +9 -0
  161. package/dist/mode-handlers/duplicate-handler.js +19 -0
  162. package/dist/mode-handlers/elevation-handler.d.ts +19 -0
  163. package/dist/mode-handlers/elevation-handler.js +48 -0
  164. package/dist/mode-handlers/extrude-handler.d.ts +18 -0
  165. package/dist/mode-handlers/extrude-handler.js +176 -0
  166. package/dist/mode-handlers/mode-handler.d.ts +61 -0
  167. package/dist/mode-handlers/mode-handler.js +286 -0
  168. package/dist/mode-handlers/modify-handler.d.ts +19 -0
  169. package/dist/mode-handlers/modify-handler.js +193 -0
  170. package/dist/mode-handlers/rotate-handler.d.ts +17 -0
  171. package/dist/mode-handlers/rotate-handler.js +74 -0
  172. package/dist/mode-handlers/scale-handler.d.ts +17 -0
  173. package/dist/mode-handlers/scale-handler.js +76 -0
  174. package/dist/mode-handlers/snappable-handler.d.ts +33 -0
  175. package/dist/mode-handlers/snappable-handler.js +133 -0
  176. package/dist/mode-handlers/split-polygon-handler.d.ts +11 -0
  177. package/dist/mode-handlers/split-polygon-handler.js +154 -0
  178. package/dist/mode-handlers/three-click-polygon-handler.d.ts +5 -0
  179. package/dist/mode-handlers/three-click-polygon-handler.js +18 -0
  180. package/dist/mode-handlers/translate-handler.d.ts +17 -0
  181. package/dist/mode-handlers/translate-handler.js +72 -0
  182. package/dist/mode-handlers/two-click-polygon-handler.d.ts +5 -0
  183. package/dist/mode-handlers/two-click-polygon-handler.js +18 -0
  184. package/dist/mode-handlers/view-handler.d.ts +8 -0
  185. package/dist/mode-handlers/view-handler.js +10 -0
  186. package/dist/shaderlib/color/color.d.ts +8 -0
  187. package/dist/shaderlib/color/color.js +51 -0
  188. package/dist/shaderlib/outline/outline.d.ts +8 -0
  189. package/dist/shaderlib/outline/outline.js +97 -0
  190. package/dist/shaderlib/utils/utils.d.ts +8 -0
  191. package/dist/shaderlib/utils/utils.js +28 -0
  192. package/dist/translateFromCenter.d.ts +4 -0
  193. package/dist/translateFromCenter.js +19 -0
  194. package/dist/types.d.ts +35 -0
  195. package/dist/types.js +1 -0
  196. package/dist/utils.d.ts +20 -0
  197. package/dist/utils.js +144 -0
  198. package/package.json +84 -0
  199. package/src/constants.ts +15 -0
  200. package/src/curve-utils.ts +77 -0
  201. package/src/edit-modes/composite-mode.ts +74 -0
  202. package/src/edit-modes/draw-90degree-polygon-mode.ts +220 -0
  203. package/src/edit-modes/draw-circle-by-diameter-mode.ts +88 -0
  204. package/src/edit-modes/draw-circle-from-center-mode.ts +79 -0
  205. package/src/edit-modes/draw-ellipse-by-bounding-box-mode.ts +25 -0
  206. package/src/edit-modes/draw-ellipse-using-three-points-mode.ts +23 -0
  207. package/src/edit-modes/draw-line-string-mode.ts +200 -0
  208. package/src/edit-modes/draw-point-mode.ts +35 -0
  209. package/src/edit-modes/draw-polygon-by-dragging-mode.ts +106 -0
  210. package/src/edit-modes/draw-polygon-mode.ts +171 -0
  211. package/src/edit-modes/draw-rectangle-from-center-mode.ts +23 -0
  212. package/src/edit-modes/draw-rectangle-mode.ts +14 -0
  213. package/src/edit-modes/draw-rectangle-using-three-points-mode.ts +36 -0
  214. package/src/edit-modes/draw-square-from-center-mode.ts +46 -0
  215. package/src/edit-modes/draw-square-mode.ts +36 -0
  216. package/src/edit-modes/duplicate-mode.ts +21 -0
  217. package/src/edit-modes/edit-mode.ts +30 -0
  218. package/src/edit-modes/elevation-mode.ts +86 -0
  219. package/src/edit-modes/extend-line-string-mode.ts +87 -0
  220. package/src/edit-modes/extrude-mode.ts +254 -0
  221. package/src/edit-modes/geojson-edit-mode.ts +283 -0
  222. package/src/edit-modes/immutable-feature-collection.ts +417 -0
  223. package/src/edit-modes/measure-angle-mode.ts +127 -0
  224. package/src/edit-modes/measure-area-mode.ts +62 -0
  225. package/src/edit-modes/measure-distance-mode.ts +215 -0
  226. package/src/edit-modes/modify-mode.ts +293 -0
  227. package/src/edit-modes/resize-circle-mode.ts +202 -0
  228. package/src/edit-modes/rotate-mode.ts +208 -0
  229. package/src/edit-modes/scale-mode.ts +231 -0
  230. package/src/edit-modes/snappable-mode.ts +174 -0
  231. package/src/edit-modes/split-polygon-mode.ts +201 -0
  232. package/src/edit-modes/three-click-polygon-mode.ts +111 -0
  233. package/src/edit-modes/transform-mode.ts +75 -0
  234. package/src/edit-modes/translate-mode.ts +161 -0
  235. package/src/edit-modes/two-click-polygon-mode.ts +132 -0
  236. package/src/edit-modes/types.ts +135 -0
  237. package/src/edit-modes/utils.ts +513 -0
  238. package/src/edit-modes/view-mode.ts +3 -0
  239. package/src/editable-layers/editable-geojson-layer.ts +603 -0
  240. package/src/editable-layers/editable-h3-cluster-layer.ts +226 -0
  241. package/src/editable-layers/editable-layer.ts +252 -0
  242. package/src/editable-layers/editable-path-layer.ts +51 -0
  243. package/src/editable-layers/elevated-edit-handle-layer.ts +33 -0
  244. package/src/editable-layers/junction-scatterplot-layer.ts +53 -0
  245. package/src/editable-layers/path-marker-layer/arrow-2d-geometry.ts +61 -0
  246. package/src/editable-layers/path-marker-layer/create-path-markers.ts +107 -0
  247. package/src/editable-layers/path-marker-layer/path-marker-layer.ts +179 -0
  248. package/src/editable-layers/path-marker-layer/polyline.ts +40 -0
  249. package/src/editable-layers/path-outline-layer/path-outline-layer.ts +147 -0
  250. package/src/editable-layers/selection-layer.ts +209 -0
  251. package/src/geojson-types.ts +89 -0
  252. package/src/index.ts +125 -0
  253. package/src/lib/constants.ts +6 -0
  254. package/src/lib/deck-renderer/deck-cache.ts +61 -0
  255. package/src/lib/deck-renderer/deck-drawer.ts +263 -0
  256. package/src/lib/feature.ts +27 -0
  257. package/src/lib/layer-mouse-event.ts +32 -0
  258. package/src/lib/layers/junctions-layer.ts +40 -0
  259. package/src/lib/layers/segments-layer.ts +108 -0
  260. package/src/lib/layers/texts-layer.ts +43 -0
  261. package/src/lib/math.ts +26 -0
  262. package/src/lib/nebula-layer.ts +33 -0
  263. package/src/lib/nebula.ts +323 -0
  264. package/src/lib/style.ts +22 -0
  265. package/src/memoize.ts +43 -0
  266. package/src/mode-handlers/composite-mode-handler.ts +89 -0
  267. package/src/mode-handlers/draw-90degree-polygon-handler.ts +201 -0
  268. package/src/mode-handlers/draw-circle-by-bounding-box-handler.ts +39 -0
  269. package/src/mode-handlers/draw-circle-from-center-handler.ts +38 -0
  270. package/src/mode-handlers/draw-ellipse-by-bounding-box-handler.ts +41 -0
  271. package/src/mode-handlers/draw-ellipse-using-three-points-handler.ts +46 -0
  272. package/src/mode-handlers/draw-line-string-handler.ts +108 -0
  273. package/src/mode-handlers/draw-point-handler.ts +15 -0
  274. package/src/mode-handlers/draw-polygon-handler.ts +121 -0
  275. package/src/mode-handlers/draw-rectangle-handler.ts +28 -0
  276. package/src/mode-handlers/draw-rectangle-using-three-points-handler.ts +60 -0
  277. package/src/mode-handlers/duplicate-handler.ts +25 -0
  278. package/src/mode-handlers/elevation-handler.ts +88 -0
  279. package/src/mode-handlers/extrude-handler.ts +245 -0
  280. package/src/mode-handlers/mode-handler.ts +394 -0
  281. package/src/mode-handlers/modify-handler.ts +263 -0
  282. package/src/mode-handlers/rotate-handler.ts +107 -0
  283. package/src/mode-handlers/scale-handler.ts +105 -0
  284. package/src/mode-handlers/snappable-handler.ts +184 -0
  285. package/src/mode-handlers/split-polygon-handler.ts +177 -0
  286. package/src/mode-handlers/three-click-polygon-handler.ts +25 -0
  287. package/src/mode-handlers/translate-handler.ts +110 -0
  288. package/src/mode-handlers/two-click-polygon-handler.ts +25 -0
  289. package/src/mode-handlers/view-handler.ts +13 -0
  290. package/src/shaderlib/color/color.ts +56 -0
  291. package/src/shaderlib/outline/outline.ts +101 -0
  292. package/src/shaderlib/utils/utils.ts +33 -0
  293. package/src/translateFromCenter.ts +48 -0
  294. package/src/types.ts +39 -0
  295. package/src/utils.ts +185 -0
@@ -0,0 +1,394 @@
1
+ // TODO edit-modes: delete handlers once EditMode fully implemented
2
+
3
+ import turfUnion from '@turf/union';
4
+ import turfDifference from '@turf/difference';
5
+ import turfIntersect from '@turf/intersect';
6
+
7
+ import {
8
+ FeatureCollection,
9
+ Feature,
10
+ Polygon,
11
+ Geometry,
12
+ Position,
13
+ } from '../geojson-types';
14
+
15
+ import {
16
+ ClickEvent,
17
+ Pick,
18
+ PointerMoveEvent,
19
+ StartDraggingEvent,
20
+ StopDraggingEvent,
21
+ } from '../edit-modes/types';
22
+ import { ImmutableFeatureCollection } from '../edit-modes/immutable-feature-collection';
23
+
24
+ export type EditHandleType = 'existing' | 'intermediate' | 'snap';
25
+
26
+ export type EditHandle = {
27
+ position: Position;
28
+ positionIndexes: number[];
29
+ featureIndex: number;
30
+ type: EditHandleType;
31
+ };
32
+
33
+ export type EditAction = {
34
+ updatedData: FeatureCollection;
35
+ editType: string;
36
+ featureIndexes: number[];
37
+ editContext: any;
38
+ };
39
+
40
+ export class ModeHandler {
41
+ // TODO: add underscore
42
+ featureCollection: ImmutableFeatureCollection = undefined!;
43
+ _tentativeFeature: Feature | null | undefined;
44
+ _modeConfig: any = null;
45
+ _selectedFeatureIndexes: number[] = [];
46
+ _clickSequence: Position[] = [];
47
+
48
+ constructor(featureCollection?: FeatureCollection) {
49
+ if (featureCollection) {
50
+ this.setFeatureCollection(featureCollection);
51
+ }
52
+ }
53
+
54
+ getFeatureCollection(): FeatureCollection {
55
+ return this.featureCollection.getObject();
56
+ }
57
+
58
+ getImmutableFeatureCollection(): ImmutableFeatureCollection {
59
+ return this.featureCollection;
60
+ }
61
+
62
+ getSelectedFeature(): Feature | null | undefined {
63
+ if (this._selectedFeatureIndexes.length === 1) {
64
+ return this.featureCollection.getObject().features[this._selectedFeatureIndexes[0]];
65
+ }
66
+ return null;
67
+ }
68
+
69
+ getSelectedGeometry(): Geometry | null | undefined {
70
+ const feature = this.getSelectedFeature();
71
+ if (feature) {
72
+ return feature.geometry;
73
+ }
74
+ return null;
75
+ }
76
+
77
+ getSelectedFeaturesAsFeatureCollection(): FeatureCollection {
78
+ const { features } = this.featureCollection.getObject();
79
+ const selectedFeatures = this.getSelectedFeatureIndexes().map(
80
+ (selectedIndex) => features[selectedIndex]
81
+ );
82
+ return {
83
+ type: 'FeatureCollection',
84
+ features: selectedFeatures,
85
+ };
86
+ }
87
+
88
+ setFeatureCollection(featureCollection: FeatureCollection): void {
89
+ this.featureCollection = new ImmutableFeatureCollection(featureCollection);
90
+ }
91
+
92
+ getModeConfig(): any {
93
+ return this._modeConfig;
94
+ }
95
+
96
+ setModeConfig(modeConfig: any): void {
97
+ if (this._modeConfig === modeConfig) {
98
+ return;
99
+ }
100
+
101
+ this._modeConfig = modeConfig;
102
+ this._setTentativeFeature(null);
103
+ }
104
+
105
+ getSelectedFeatureIndexes(): number[] {
106
+ return this._selectedFeatureIndexes;
107
+ }
108
+
109
+ setSelectedFeatureIndexes(indexes: number[]): void {
110
+ if (this._selectedFeatureIndexes === indexes) {
111
+ return;
112
+ }
113
+
114
+ this._selectedFeatureIndexes = indexes;
115
+ this._setTentativeFeature(null);
116
+ }
117
+
118
+ getClickSequence(): Position[] {
119
+ return this._clickSequence;
120
+ }
121
+
122
+ resetClickSequence(): void {
123
+ this._clickSequence = [];
124
+ }
125
+
126
+ getTentativeFeature(): Feature | null | undefined {
127
+ return this._tentativeFeature;
128
+ }
129
+
130
+ // TODO: remove the underscore
131
+ _setTentativeFeature(tentativeFeature: Feature | null | undefined): void {
132
+ this._tentativeFeature = tentativeFeature;
133
+ if (!tentativeFeature) {
134
+ // Reset the click sequence
135
+ this._clickSequence = [];
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Returns a flat array of positions for the given feature along with their indexes into the feature's geometry's coordinates.
141
+ *
142
+ * @param featureIndex The index of the feature to get edit handles
143
+ */
144
+ getEditHandles(picks?: Array<Record<string, any>>, mapCoords?: Position): EditHandle[] {
145
+ return [];
146
+ }
147
+
148
+ getCursor({ isDragging }: { isDragging: boolean }): string {
149
+ return 'cell';
150
+ }
151
+
152
+ isSelectionPicked(picks: Pick[]): boolean {
153
+ if (!picks.length) return false;
154
+ const pickedIndexes = picks.map(({ index }) => index);
155
+ const selectedFeatureIndexes = this.getSelectedFeatureIndexes();
156
+ return selectedFeatureIndexes.some((index) => pickedIndexes.includes(index));
157
+ }
158
+
159
+ getAddFeatureAction(geometry: Geometry): EditAction {
160
+ // Unsure why flow can't deal with Geometry type, but there I fixed it
161
+ const geometryAsAny: any = geometry;
162
+
163
+ const updatedData = this.getImmutableFeatureCollection()
164
+ .addFeature({
165
+ type: 'Feature',
166
+ properties: {},
167
+ geometry: geometryAsAny,
168
+ })
169
+ .getObject();
170
+
171
+ return {
172
+ updatedData,
173
+ editType: 'addFeature',
174
+ featureIndexes: [updatedData.features.length - 1],
175
+ editContext: {
176
+ featureIndexes: [updatedData.features.length - 1],
177
+ },
178
+ };
179
+ }
180
+
181
+ getAddManyFeaturesAction(featureCollection: FeatureCollection): EditAction {
182
+ const features = featureCollection.features;
183
+ let updatedData = this.getImmutableFeatureCollection();
184
+ const initialIndex = updatedData.getObject().features.length;
185
+ const updatedIndexes: number[] = [];
186
+ for (const feature of features) {
187
+ const { properties, geometry } = feature;
188
+ const geometryAsAny: any = geometry;
189
+ updatedData = updatedData.addFeature({
190
+ type: 'Feature',
191
+ properties,
192
+ geometry: geometryAsAny,
193
+ });
194
+ updatedIndexes.push(initialIndex + updatedIndexes.length);
195
+ }
196
+
197
+ return {
198
+ updatedData: updatedData.getObject(),
199
+ editType: 'addFeature',
200
+ featureIndexes: updatedIndexes,
201
+ editContext: {
202
+ featureIndexes: updatedIndexes,
203
+ },
204
+ };
205
+ }
206
+
207
+ getAddFeatureOrBooleanPolygonAction(geometry: Polygon): EditAction | null | undefined {
208
+ const selectedFeature = this.getSelectedFeature();
209
+ const modeConfig = this.getModeConfig();
210
+ if (modeConfig && modeConfig.booleanOperation) {
211
+ if (
212
+ !selectedFeature ||
213
+ (selectedFeature.geometry.type !== 'Polygon' &&
214
+ selectedFeature.geometry.type !== 'MultiPolygon')
215
+ ) {
216
+ // eslint-disable-next-line no-console,no-undef
217
+ console.warn(
218
+ 'booleanOperation only supported for single Polygon or MultiPolygon selection'
219
+ );
220
+ return null;
221
+ }
222
+
223
+ const feature = {
224
+ type: 'Feature',
225
+ geometry,
226
+ };
227
+
228
+ let updatedGeometry;
229
+ if (modeConfig.booleanOperation === 'union') {
230
+ // @ts-expect-error turf types diff
231
+ updatedGeometry = turfUnion(selectedFeature, feature);
232
+ } else if (modeConfig.booleanOperation === 'difference') {
233
+ // @ts-expect-error turf type diff
234
+ updatedGeometry = turfDifference(selectedFeature, feature);
235
+ } else if (modeConfig.booleanOperation === 'intersection') {
236
+ // @ts-expect-error turf type diff
237
+ updatedGeometry = turfIntersect(selectedFeature, feature);
238
+ } else {
239
+ // eslint-disable-next-line no-console,no-undef
240
+ console.warn(`Invalid booleanOperation ${modeConfig.booleanOperation}`);
241
+ return null;
242
+ }
243
+
244
+ if (!updatedGeometry) {
245
+ // eslint-disable-next-line no-console,no-undef
246
+ console.warn('Canceling edit. Boolean operation erased entire polygon.');
247
+ return null;
248
+ }
249
+
250
+ const featureIndex = this.getSelectedFeatureIndexes()[0];
251
+
252
+ const updatedData = this.getImmutableFeatureCollection()
253
+ .replaceGeometry(featureIndex, updatedGeometry.geometry)
254
+ .getObject();
255
+
256
+ const editAction: EditAction = {
257
+ updatedData,
258
+ editType: 'unionGeometry',
259
+ featureIndexes: [featureIndex],
260
+ editContext: {
261
+ featureIndexes: [featureIndex],
262
+ },
263
+ };
264
+
265
+ return editAction;
266
+ }
267
+ return this.getAddFeatureAction(geometry);
268
+ }
269
+
270
+ handleClick(event: ClickEvent): EditAction | null | undefined {
271
+ this._clickSequence.push(event.mapCoords);
272
+
273
+ return null;
274
+ }
275
+
276
+ handlePointerMove(event: PointerMoveEvent): {
277
+ editAction: EditAction | null | undefined;
278
+ cancelMapPan: boolean;
279
+ } {
280
+ return { editAction: null, cancelMapPan: false };
281
+ }
282
+
283
+ handleStartDragging(event: StartDraggingEvent): EditAction | null | undefined {
284
+ return null;
285
+ }
286
+
287
+ handleStopDragging(event: StopDraggingEvent): EditAction | null | undefined {
288
+ return null;
289
+ }
290
+ }
291
+
292
+ export function getPickedEditHandle(
293
+ picks: any[] | null | undefined
294
+ ): EditHandle | null | undefined {
295
+ const info = picks && picks.find((pick) => pick.isEditingHandle);
296
+ if (info) {
297
+ return info.object;
298
+ }
299
+ return null;
300
+ }
301
+
302
+ export function getIntermediatePosition(position1: Position, position2: Position): Position {
303
+ const intermediatePosition: Position = [
304
+ (position1[0] + position2[0]) / 2.0,
305
+ (position1[1] + position2[1]) / 2.0,
306
+ ];
307
+
308
+ return intermediatePosition;
309
+ }
310
+
311
+ export function getEditHandlesForGeometry(
312
+ geometry: Geometry,
313
+ featureIndex: number,
314
+ editHandleType: EditHandleType = 'existing'
315
+ ): EditHandle[] {
316
+ let handles: EditHandle[] = [];
317
+
318
+ switch (geometry.type) {
319
+ case 'Point':
320
+ // positions are not nested
321
+ handles = [
322
+ {
323
+ position: geometry.coordinates,
324
+ positionIndexes: [],
325
+ featureIndex,
326
+ type: editHandleType,
327
+ },
328
+ ];
329
+ break;
330
+ case 'MultiPoint':
331
+ case 'LineString':
332
+ // positions are nested 1 level
333
+ handles = handles.concat(
334
+ getEditHandlesForCoordinates(geometry.coordinates, [], featureIndex, editHandleType)
335
+ );
336
+ break;
337
+ case 'Polygon':
338
+ case 'MultiLineString':
339
+ // positions are nested 2 levels
340
+ for (let a = 0; a < geometry.coordinates.length; a++) {
341
+ handles = handles.concat(
342
+ getEditHandlesForCoordinates(geometry.coordinates[a], [a], featureIndex, editHandleType)
343
+ );
344
+ if (geometry.type === 'Polygon') {
345
+ // Don't repeat the first/last handle for Polygons
346
+ handles = handles.slice(0, -1);
347
+ }
348
+ }
349
+
350
+ break;
351
+ case 'MultiPolygon':
352
+ // positions are nested 3 levels
353
+ for (let a = 0; a < geometry.coordinates.length; a++) {
354
+ for (let b = 0; b < geometry.coordinates[a].length; b++) {
355
+ handles = handles.concat(
356
+ getEditHandlesForCoordinates(
357
+ geometry.coordinates[a][b],
358
+ [a, b],
359
+ featureIndex,
360
+ editHandleType
361
+ )
362
+ );
363
+ // Don't repeat the first/last handle for Polygons
364
+ handles = handles.slice(0, -1);
365
+ }
366
+ }
367
+
368
+ break;
369
+ default:
370
+ // @ts-expect-error unexpected case
371
+ throw Error(`Unhandled geometry type: ${geometry.type}`);
372
+ }
373
+
374
+ return handles;
375
+ }
376
+
377
+ function getEditHandlesForCoordinates(
378
+ coordinates: any[],
379
+ positionIndexPrefix: number[],
380
+ featureIndex: number,
381
+ editHandleType: EditHandleType = 'existing'
382
+ ): EditHandle[] {
383
+ const editHandles: EditHandle[] = [];
384
+ for (let i = 0; i < coordinates.length; i++) {
385
+ const position = coordinates[i] as Position;
386
+ editHandles.push({
387
+ position,
388
+ positionIndexes: [...positionIndexPrefix, i],
389
+ featureIndex,
390
+ type: editHandleType,
391
+ });
392
+ }
393
+ return editHandles;
394
+ }
@@ -0,0 +1,263 @@
1
+ import nearestPointOnLine from '@turf/nearest-point-on-line';
2
+ import { point, lineString as toLineString } from '@turf/helpers';
3
+ import { Position, FeatureOf, Point, LineString } from '../geojson-types';
4
+ import {
5
+ recursivelyTraverseNestedArrays,
6
+ nearestPointOnProjectedLine,
7
+ NearestPointType,
8
+ } from '../utils';
9
+ import {
10
+ ClickEvent,
11
+ PointerMoveEvent,
12
+ StartDraggingEvent,
13
+ StopDraggingEvent,
14
+ } from '../edit-modes/types';
15
+ import {
16
+ EditAction,
17
+ EditHandle,
18
+ ModeHandler,
19
+ getPickedEditHandle,
20
+ getEditHandlesForGeometry,
21
+ } from './mode-handler';
22
+
23
+ // TODO edit-modes: delete handlers once EditMode fully implemented
24
+ export class ModifyHandler extends ModeHandler {
25
+ _lastPointerMovePicks: any;
26
+
27
+ getEditHandles(picks?: Array<Record<string, any>>, mapCoords?: Position): EditHandle[] {
28
+ let handles: EditHandle[] = [];
29
+ const { features } = this.featureCollection.getObject();
30
+
31
+ for (const index of this.getSelectedFeatureIndexes()) {
32
+ if (index < features.length) {
33
+ const { geometry } = features[index];
34
+ handles.push(...getEditHandlesForGeometry(geometry, index));
35
+ } else {
36
+ console.warn(`selectedFeatureIndexes out of range ${index}`); // eslint-disable-line no-console,no-undef
37
+ }
38
+ }
39
+
40
+ // intermediate edit handle
41
+ if (picks && picks.length && mapCoords) {
42
+ const existingEditHandle = picks.find(
43
+ (pick) => pick.isEditingHandle && pick.object && pick.object.type === 'existing'
44
+ );
45
+ // don't show intermediate point when too close to an existing edit handle
46
+ const featureAsPick = !existingEditHandle && picks.find((pick) => !pick.isEditingHandle);
47
+
48
+ // is the feature in the pick selected
49
+ if (
50
+ featureAsPick &&
51
+ !featureAsPick.object.geometry.type.includes('Point') &&
52
+ this.getSelectedFeatureIndexes().includes(featureAsPick.index)
53
+ ) {
54
+ let intermediatePoint: NearestPointType | null | undefined = null;
55
+ let positionIndexPrefix = [];
56
+ const referencePoint = point(mapCoords);
57
+ // process all lines of the (single) feature
58
+ recursivelyTraverseNestedArrays(
59
+ featureAsPick.object.geometry.coordinates,
60
+ [],
61
+ (lineString, prefix) => {
62
+ const lineStringFeature = toLineString(lineString);
63
+
64
+ const candidateIntermediatePoint = this.nearestPointOnLine(
65
+ // @ts-expect-error turf type diff
66
+ lineStringFeature,
67
+ referencePoint
68
+ );
69
+ if (
70
+ !intermediatePoint ||
71
+ candidateIntermediatePoint.properties.dist < intermediatePoint.properties.dist
72
+ ) {
73
+ intermediatePoint = candidateIntermediatePoint;
74
+ positionIndexPrefix = prefix;
75
+ }
76
+ }
77
+ );
78
+ // tack on the lone intermediate point to the set of handles
79
+ if (intermediatePoint) {
80
+ const {
81
+ geometry: { coordinates: position },
82
+ properties: { index },
83
+ } = intermediatePoint;
84
+ handles = [
85
+ ...handles,
86
+ {
87
+ position,
88
+ positionIndexes: [...positionIndexPrefix, index + 1],
89
+ featureIndex: featureAsPick.index,
90
+ type: 'intermediate',
91
+ },
92
+ ];
93
+ }
94
+ }
95
+ }
96
+
97
+ return handles;
98
+ }
99
+
100
+ // turf.js does not support elevation for nearestPointOnLine
101
+ nearestPointOnLine(line: FeatureOf<LineString>, inPoint: FeatureOf<Point>): NearestPointType {
102
+ const { coordinates } = line.geometry;
103
+ if (coordinates.some((coord) => coord.length > 2)) {
104
+ const modeConfig = this.getModeConfig();
105
+ if (modeConfig && modeConfig.viewport) {
106
+ // This line has elevation, we need to use alternative algorithm
107
+ return nearestPointOnProjectedLine(line, inPoint, modeConfig.viewport);
108
+ }
109
+ // eslint-disable-next-line no-console,no-undef
110
+ console.log(
111
+ 'Editing 3D point but modeConfig.viewport not provided. Falling back to 2D logic.'
112
+ );
113
+ }
114
+ // @ts-expect-error geojson types diff
115
+ return nearestPointOnLine(line, inPoint);
116
+ }
117
+
118
+ handleClick(event: ClickEvent): EditAction | null | undefined {
119
+ let editAction: EditAction | null | undefined = null;
120
+
121
+ const clickedEditHandle = getPickedEditHandle(event.picks);
122
+
123
+ if (clickedEditHandle && clickedEditHandle.featureIndex >= 0) {
124
+ if (clickedEditHandle.type === 'existing') {
125
+ let updatedData;
126
+ try {
127
+ updatedData = this.getImmutableFeatureCollection()
128
+ .removePosition(clickedEditHandle.featureIndex, clickedEditHandle.positionIndexes)
129
+ .getObject();
130
+ } catch (ignored) {
131
+ // This happens if user attempts to remove the last point
132
+ }
133
+
134
+ if (updatedData) {
135
+ editAction = {
136
+ updatedData,
137
+ editType: 'removePosition',
138
+ featureIndexes: [clickedEditHandle.featureIndex],
139
+ editContext: {
140
+ positionIndexes: clickedEditHandle.positionIndexes,
141
+ position: clickedEditHandle.position,
142
+ },
143
+ };
144
+ }
145
+ } else if (clickedEditHandle.type === 'intermediate') {
146
+ const updatedData = this.getImmutableFeatureCollection()
147
+ .addPosition(
148
+ clickedEditHandle.featureIndex,
149
+ clickedEditHandle.positionIndexes,
150
+ clickedEditHandle.position
151
+ )
152
+ .getObject();
153
+
154
+ if (updatedData) {
155
+ editAction = {
156
+ updatedData,
157
+ editType: 'addPosition',
158
+ featureIndexes: [clickedEditHandle.featureIndex],
159
+ editContext: {
160
+ positionIndexes: clickedEditHandle.positionIndexes,
161
+ position: clickedEditHandle.position,
162
+ },
163
+ };
164
+ }
165
+ }
166
+ }
167
+ return editAction;
168
+ }
169
+
170
+ handlePointerMove(event: PointerMoveEvent): {
171
+ editAction: EditAction | null | undefined;
172
+ cancelMapPan: boolean;
173
+ } {
174
+ this._lastPointerMovePicks = event.picks;
175
+
176
+ let editAction: EditAction | null | undefined = null;
177
+
178
+ const editHandle = getPickedEditHandle(event.pointerDownPicks);
179
+
180
+ if (event.isDragging && editHandle) {
181
+ const updatedData = this.getImmutableFeatureCollection()
182
+ .replacePosition(editHandle.featureIndex, editHandle.positionIndexes, event.mapCoords)
183
+ .getObject();
184
+
185
+ editAction = {
186
+ updatedData,
187
+ editType: 'movePosition',
188
+ featureIndexes: [editHandle.featureIndex],
189
+ editContext: {
190
+ positionIndexes: editHandle.positionIndexes,
191
+ position: event.mapCoords,
192
+ },
193
+ };
194
+ }
195
+
196
+ // Cancel map panning if pointer went down on an edit handle
197
+ const cancelMapPan = Boolean(editHandle);
198
+
199
+ return { editAction, cancelMapPan };
200
+ }
201
+
202
+ handleStartDragging(event: StartDraggingEvent): EditAction | null | undefined {
203
+ let editAction: EditAction | null | undefined = null;
204
+
205
+ const selectedFeatureIndexes = this.getSelectedFeatureIndexes();
206
+
207
+ const editHandle = getPickedEditHandle(event.picks);
208
+ if (selectedFeatureIndexes.length && editHandle && editHandle.type === 'intermediate') {
209
+ const updatedData = this.getImmutableFeatureCollection()
210
+ .addPosition(editHandle.featureIndex, editHandle.positionIndexes, event.mapCoords)
211
+ .getObject();
212
+
213
+ editAction = {
214
+ updatedData,
215
+ editType: 'addPosition',
216
+ featureIndexes: [editHandle.featureIndex],
217
+ editContext: {
218
+ positionIndexes: editHandle.positionIndexes,
219
+ position: event.mapCoords,
220
+ },
221
+ };
222
+ }
223
+
224
+ return editAction;
225
+ }
226
+
227
+ handleStopDragging(event: StopDraggingEvent): EditAction | null | undefined {
228
+ let editAction: EditAction | null | undefined = null;
229
+
230
+ const selectedFeatureIndexes = this.getSelectedFeatureIndexes();
231
+ const editHandle = getPickedEditHandle(event.picks);
232
+ if (selectedFeatureIndexes.length && editHandle) {
233
+ const updatedData = this.getImmutableFeatureCollection()
234
+ .replacePosition(editHandle.featureIndex, editHandle.positionIndexes, event.mapCoords)
235
+ .getObject();
236
+
237
+ editAction = {
238
+ updatedData,
239
+ editType: 'finishMovePosition',
240
+ featureIndexes: [editHandle.featureIndex],
241
+ editContext: {
242
+ positionIndexes: editHandle.positionIndexes,
243
+ position: event.mapCoords,
244
+ },
245
+ };
246
+ }
247
+
248
+ return editAction;
249
+ }
250
+
251
+ getCursor({ isDragging }: { isDragging: boolean }): string {
252
+ const picks = this._lastPointerMovePicks;
253
+
254
+ if (picks && picks.length > 0) {
255
+ const handlePicked = picks.some((pick) => pick.isEditingHandle);
256
+ if (handlePicked) {
257
+ return 'cell';
258
+ }
259
+ }
260
+
261
+ return isDragging ? 'grabbing' : 'grab';
262
+ }
263
+ }