@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,417 @@
1
+ import {
2
+ Feature,
3
+ FeatureCollection,
4
+ Geometry,
5
+ Polygon,
6
+ MultiLineString,
7
+ MultiPolygon,
8
+ Position,
9
+ PolygonCoordinates,
10
+ } from '../geojson-types';
11
+
12
+ export class ImmutableFeatureCollection {
13
+ featureCollection: FeatureCollection;
14
+
15
+ constructor(featureCollection: FeatureCollection) {
16
+ this.featureCollection = featureCollection;
17
+ }
18
+
19
+ getObject() {
20
+ return this.featureCollection;
21
+ }
22
+
23
+ /**
24
+ * Replaces the position deeply nested withing the given feature's geometry.
25
+ * Works with Point, MultiPoint, LineString, MultiLineString, Polygon, and MultiPolygon.
26
+ *
27
+ * @param featureIndex The index of the feature to update
28
+ * @param positionIndexes An array containing the indexes of the position to replace
29
+ * @param updatedPosition The updated position to place in the result (i.e. [lng, lat])
30
+ *
31
+ * @returns A new `ImmutableFeatureCollection` with the given position replaced. Does not modify this `ImmutableFeatureCollection`.
32
+ */
33
+ replacePosition(
34
+ featureIndex: number,
35
+ positionIndexes: number[] | null | undefined,
36
+ updatedPosition: Position
37
+ ): ImmutableFeatureCollection {
38
+ const geometry = this.featureCollection.features[featureIndex].geometry;
39
+
40
+ const isPolygonal = geometry.type === 'Polygon' || geometry.type === 'MultiPolygon';
41
+ const updatedGeometry: any = {
42
+ ...geometry,
43
+ coordinates: immutablyReplacePosition(
44
+ geometry.coordinates,
45
+ positionIndexes,
46
+ updatedPosition,
47
+ isPolygonal
48
+ ),
49
+ };
50
+
51
+ return this.replaceGeometry(featureIndex, updatedGeometry);
52
+ }
53
+
54
+ /**
55
+ * Removes a position deeply nested in a GeoJSON geometry coordinates array.
56
+ * Works with MultiPoint, LineString, MultiLineString, Polygon, and MultiPolygon.
57
+ *
58
+ * @param featureIndex The index of the feature to update
59
+ * @param positionIndexes An array containing the indexes of the postion to remove
60
+ *
61
+ * @returns A new `ImmutableFeatureCollection` with the given coordinate removed. Does not modify this `ImmutableFeatureCollection`.
62
+ */
63
+ removePosition(
64
+ featureIndex: number,
65
+ positionIndexes: number[] | null | undefined
66
+ ): ImmutableFeatureCollection {
67
+ const geometry = this.featureCollection.features[featureIndex].geometry;
68
+
69
+ if (geometry.type === 'Point') {
70
+ throw Error('Can\'t remove a position from a Point or there\'d be nothing left');
71
+ }
72
+ if (
73
+ geometry.type === 'MultiPoint' && // only 1 point left
74
+ geometry.coordinates.length < 2
75
+ ) {
76
+ throw Error('Can\'t remove the last point of a MultiPoint or there\'d be nothing left');
77
+ }
78
+ if (
79
+ geometry.type === 'LineString' && // only 2 positions
80
+ geometry.coordinates.length < 3
81
+ ) {
82
+ throw Error('Can\'t remove position. LineString must have at least two positions');
83
+ }
84
+ if (
85
+ geometry.type === 'Polygon' && // outer ring is a triangle
86
+ geometry.coordinates[0].length < 5 &&
87
+ Array.isArray(positionIndexes) && // trying to remove from outer ring
88
+ positionIndexes[0] === 0
89
+ ) {
90
+ throw Error('Can\'t remove position. Polygon\'s outer ring must have at least four positions');
91
+ }
92
+ if (
93
+ geometry.type === 'MultiLineString' && // only 1 LineString left
94
+ geometry.coordinates.length === 1 && // only 2 positions
95
+ geometry.coordinates[0].length < 3
96
+ ) {
97
+ throw Error('Can\'t remove position. MultiLineString must have at least two positions');
98
+ }
99
+ if (
100
+ geometry.type === 'MultiPolygon' && // only 1 polygon left
101
+ geometry.coordinates.length === 1 && // outer ring is a triangle
102
+ geometry.coordinates[0][0].length < 5 &&
103
+ Array.isArray(positionIndexes) && // trying to remove from first polygon
104
+ positionIndexes[0] === 0 && // trying to remove from outer ring
105
+ positionIndexes[1] === 0
106
+ ) {
107
+ throw Error(
108
+ 'Can\'t remove position. MultiPolygon\'s outer ring must have at least four positions'
109
+ );
110
+ }
111
+
112
+ const isPolygonal = geometry.type === 'Polygon' || geometry.type === 'MultiPolygon';
113
+ const updatedGeometry: any = {
114
+ ...geometry,
115
+ coordinates: immutablyRemovePosition(geometry.coordinates, positionIndexes, isPolygonal),
116
+ };
117
+
118
+ // Handle cases where incomplete geometries need pruned (e.g. holes that were triangles)
119
+ pruneGeometryIfNecessary(updatedGeometry);
120
+
121
+ return this.replaceGeometry(featureIndex, updatedGeometry);
122
+ }
123
+
124
+ /**
125
+ * Adds a position deeply nested in a GeoJSON geometry coordinates array.
126
+ * Works with MultiPoint, LineString, MultiLineString, Polygon, and MultiPolygon.
127
+ *
128
+ * @param featureIndex The index of the feature to update
129
+ * @param positionIndexes An array containing the indexes of the position that will proceed the new position
130
+ * @param positionToAdd The new position to place in the result (i.e. [lng, lat])
131
+ *
132
+ * @returns A new `ImmutableFeatureCollection` with the given coordinate removed. Does not modify this `ImmutableFeatureCollection`.
133
+ */
134
+ addPosition(
135
+ featureIndex: number,
136
+ positionIndexes: number[] | null | undefined,
137
+ positionToAdd: Position
138
+ ): ImmutableFeatureCollection {
139
+ const geometry = this.featureCollection.features[featureIndex].geometry;
140
+
141
+ if (geometry.type === 'Point') {
142
+ throw new Error('Unable to add a position to a Point feature');
143
+ }
144
+
145
+ const isPolygonal = geometry.type === 'Polygon' || geometry.type === 'MultiPolygon';
146
+ const updatedGeometry: any = {
147
+ ...geometry,
148
+ coordinates: immutablyAddPosition(
149
+ geometry.coordinates,
150
+ positionIndexes,
151
+ positionToAdd,
152
+ isPolygonal
153
+ ),
154
+ };
155
+
156
+ return this.replaceGeometry(featureIndex, updatedGeometry);
157
+ }
158
+
159
+ replaceGeometry(featureIndex: number, geometry: Geometry): ImmutableFeatureCollection {
160
+ const updatedFeature: any = {
161
+ ...this.featureCollection.features[featureIndex],
162
+ geometry,
163
+ };
164
+
165
+ const updatedFeatureCollection = {
166
+ ...this.featureCollection,
167
+ features: [
168
+ ...this.featureCollection.features.slice(0, featureIndex),
169
+ updatedFeature,
170
+ ...this.featureCollection.features.slice(featureIndex + 1),
171
+ ],
172
+ };
173
+
174
+ return new ImmutableFeatureCollection(updatedFeatureCollection);
175
+ }
176
+
177
+ addFeature(feature: Feature): ImmutableFeatureCollection {
178
+ return this.addFeatures([feature]);
179
+ }
180
+
181
+ addFeatures(features: Feature[]): ImmutableFeatureCollection {
182
+ const updatedFeatureCollection = {
183
+ ...this.featureCollection,
184
+ features: [...this.featureCollection.features, ...features],
185
+ };
186
+
187
+ return new ImmutableFeatureCollection(updatedFeatureCollection);
188
+ }
189
+
190
+ deleteFeature(featureIndex: number) {
191
+ return this.deleteFeatures([featureIndex]);
192
+ }
193
+
194
+ deleteFeatures(featureIndexes: number[]) {
195
+ const features = [...this.featureCollection.features];
196
+ featureIndexes.sort();
197
+ for (let i = featureIndexes.length - 1; i >= 0; i--) {
198
+ const featureIndex = featureIndexes[i];
199
+ if (featureIndex >= 0 && featureIndex < features.length) {
200
+ features.splice(featureIndex, 1);
201
+ }
202
+ }
203
+
204
+ const updatedFeatureCollection = {
205
+ ...this.featureCollection,
206
+ features,
207
+ };
208
+
209
+ return new ImmutableFeatureCollection(updatedFeatureCollection);
210
+ }
211
+ }
212
+
213
+ function getUpdatedPosition(updatedPosition: Position, previousPosition: Position): Position {
214
+ // This function checks if the updatedPosition is missing elevation
215
+ // and copies it from previousPosition
216
+ if (updatedPosition.length === 2 && previousPosition.length === 3) {
217
+ const elevation = (previousPosition as any)[2];
218
+ return [updatedPosition[0], updatedPosition[1], elevation];
219
+ }
220
+
221
+ return updatedPosition;
222
+ }
223
+
224
+ function immutablyReplacePosition(
225
+ coordinates: any,
226
+ positionIndexes: number[] | null | undefined,
227
+ updatedPosition: Position,
228
+ isPolygonal: boolean
229
+ ): any {
230
+ if (!positionIndexes) {
231
+ return coordinates;
232
+ }
233
+ if (positionIndexes.length === 0) {
234
+ return getUpdatedPosition(updatedPosition, coordinates);
235
+ }
236
+ if (positionIndexes.length === 1) {
237
+ const updated = [
238
+ ...coordinates.slice(0, positionIndexes[0]),
239
+ getUpdatedPosition(updatedPosition, coordinates[positionIndexes[0]]),
240
+ ...coordinates.slice(positionIndexes[0] + 1),
241
+ ];
242
+
243
+ if (
244
+ isPolygonal &&
245
+ (positionIndexes[0] === 0 || positionIndexes[0] === coordinates.length - 1)
246
+ ) {
247
+ // for polygons, the first point is repeated at the end of the array
248
+ // so, update it on both ends of the array
249
+ updated[0] = getUpdatedPosition(updatedPosition, coordinates[0]);
250
+ updated[coordinates.length - 1] = getUpdatedPosition(updatedPosition, coordinates[0]);
251
+ }
252
+ return updated;
253
+ }
254
+
255
+ // recursively update inner array
256
+ return [
257
+ ...coordinates.slice(0, positionIndexes[0]),
258
+ immutablyReplacePosition(
259
+ coordinates[positionIndexes[0]],
260
+ positionIndexes.slice(1, positionIndexes.length),
261
+ updatedPosition,
262
+ isPolygonal
263
+ ),
264
+ ...coordinates.slice(positionIndexes[0] + 1),
265
+ ];
266
+ }
267
+
268
+ function immutablyRemovePosition(
269
+ coordinates: any,
270
+ positionIndexes: number[] | null | undefined,
271
+ isPolygonal: boolean
272
+ ): any {
273
+ if (!positionIndexes) {
274
+ return coordinates;
275
+ }
276
+ if (positionIndexes.length === 0) {
277
+ throw Error('Must specify the index of the position to remove');
278
+ }
279
+ if (positionIndexes.length === 1) {
280
+ const updated = [
281
+ ...coordinates.slice(0, positionIndexes[0]),
282
+ ...coordinates.slice(positionIndexes[0] + 1),
283
+ ];
284
+
285
+ if (
286
+ isPolygonal &&
287
+ (positionIndexes[0] === 0 || positionIndexes[0] === coordinates.length - 1)
288
+ ) {
289
+ // for polygons, the first point is repeated at the end of the array
290
+ // so, if the first/last coordinate is to be removed, coordinates[1] will be the new first/last coordinate
291
+ if (positionIndexes[0] === 0) {
292
+ // change the last to be the same as the first
293
+ updated[updated.length - 1] = updated[0];
294
+ } else if (positionIndexes[0] === coordinates.length - 1) {
295
+ // change the first to be the same as the last
296
+ updated[0] = updated[updated.length - 1];
297
+ }
298
+ }
299
+ return updated;
300
+ }
301
+
302
+ // recursively update inner array
303
+ return [
304
+ ...coordinates.slice(0, positionIndexes[0]),
305
+ immutablyRemovePosition(
306
+ coordinates[positionIndexes[0]],
307
+ positionIndexes.slice(1, positionIndexes.length),
308
+ isPolygonal
309
+ ),
310
+ ...coordinates.slice(positionIndexes[0] + 1),
311
+ ];
312
+ }
313
+
314
+ function immutablyAddPosition(
315
+ coordinates: any,
316
+ positionIndexes: number[] | null | undefined,
317
+ positionToAdd: Position,
318
+ isPolygonal: boolean
319
+ ): any {
320
+ if (!positionIndexes) {
321
+ return coordinates;
322
+ }
323
+ if (positionIndexes.length === 0) {
324
+ throw Error('Must specify the index of the position to remove');
325
+ }
326
+ if (positionIndexes.length === 1) {
327
+ const updated = [
328
+ ...coordinates.slice(0, positionIndexes[0]),
329
+ positionToAdd,
330
+ ...coordinates.slice(positionIndexes[0]),
331
+ ];
332
+ return updated;
333
+ }
334
+
335
+ // recursively update inner array
336
+ return [
337
+ ...coordinates.slice(0, positionIndexes[0]),
338
+ immutablyAddPosition(
339
+ coordinates[positionIndexes[0]],
340
+ positionIndexes.slice(1, positionIndexes.length),
341
+ positionToAdd,
342
+ isPolygonal
343
+ ),
344
+ ...coordinates.slice(positionIndexes[0] + 1),
345
+ ];
346
+ }
347
+
348
+ function pruneGeometryIfNecessary(geometry: Geometry) {
349
+ switch (geometry.type) {
350
+ case 'Polygon':
351
+ prunePolygonIfNecessary(geometry);
352
+ break;
353
+ case 'MultiLineString':
354
+ pruneMultiLineStringIfNecessary(geometry);
355
+ break;
356
+ case 'MultiPolygon':
357
+ pruneMultiPolygonIfNecessary(geometry);
358
+ break;
359
+ default:
360
+ // Not downgradable
361
+ break;
362
+ }
363
+ }
364
+
365
+ function prunePolygonIfNecessary(geometry: Polygon) {
366
+ const polygon = geometry.coordinates;
367
+
368
+ // If any hole is no longer a polygon, remove the hole entirely
369
+ for (let holeIndex = 1; holeIndex < polygon.length; holeIndex++) {
370
+ if (removeHoleIfNecessary(polygon, holeIndex)) {
371
+ // It was removed, so keep the index the same
372
+ holeIndex--;
373
+ }
374
+ }
375
+ }
376
+
377
+ function pruneMultiLineStringIfNecessary(geometry: MultiLineString) {
378
+ for (let lineStringIndex = 0; lineStringIndex < geometry.coordinates.length; lineStringIndex++) {
379
+ const lineString = geometry.coordinates[lineStringIndex];
380
+ if (lineString.length === 1) {
381
+ // Only a single position left on this LineString, so remove it (can't have Point in MultiLineString)
382
+ geometry.coordinates.splice(lineStringIndex, 1);
383
+ // Keep the index the same
384
+ lineStringIndex--;
385
+ }
386
+ }
387
+ }
388
+
389
+ function pruneMultiPolygonIfNecessary(geometry: MultiPolygon) {
390
+ for (let polygonIndex = 0; polygonIndex < geometry.coordinates.length; polygonIndex++) {
391
+ const polygon = geometry.coordinates[polygonIndex];
392
+ const outerRing = polygon[0];
393
+
394
+ // If the outer ring is no longer a polygon, remove the whole polygon
395
+ if (outerRing.length <= 3) {
396
+ geometry.coordinates.splice(polygonIndex, 1);
397
+ // It was removed, so keep the index the same
398
+ polygonIndex--;
399
+ }
400
+
401
+ for (let holeIndex = 1; holeIndex < polygon.length; holeIndex++) {
402
+ if (removeHoleIfNecessary(polygon, holeIndex)) {
403
+ // It was removed, so keep the index the same
404
+ holeIndex--;
405
+ }
406
+ }
407
+ }
408
+ }
409
+
410
+ function removeHoleIfNecessary(polygon: PolygonCoordinates, holeIndex: number) {
411
+ const hole = polygon[holeIndex];
412
+ if (hole.length <= 3) {
413
+ polygon.splice(holeIndex, 1);
414
+ return true;
415
+ }
416
+ return false;
417
+ }
@@ -0,0 +1,127 @@
1
+ import turfBearing from '@turf/bearing';
2
+ import turfCenter from '@turf/center';
3
+ import memoize from '../memoize';
4
+
5
+ import { ClickEvent, PointerMoveEvent, Tooltip, ModeProps, GuideFeatureCollection } from './types';
6
+ import { FeatureCollection, Position } from '../geojson-types';
7
+ import { GeoJsonEditMode } from './geojson-edit-mode';
8
+
9
+ const DEFAULT_TOOLTIPS: Tooltip[] = [];
10
+
11
+ export class MeasureAngleMode extends GeoJsonEditMode {
12
+ _getTooltips = memoize(({ modeConfig, vertex, point1, point2 }: {
13
+ modeConfig: any,
14
+ vertex: any,
15
+ point1: Position,
16
+ point2: Position
17
+ }): Tooltip[] => {
18
+ let tooltips = DEFAULT_TOOLTIPS;
19
+
20
+ if (vertex && point1 && point2) {
21
+ const { formatTooltip, measurementCallback } = modeConfig || {};
22
+ const units = 'deg';
23
+
24
+ const angle1 = turfBearing(vertex, point1);
25
+ const angle2 = turfBearing(vertex, point2);
26
+ let angle = Math.abs(angle1 - angle2);
27
+ if (angle > 180) {
28
+ angle = 360 - angle;
29
+ }
30
+
31
+ let text: string;
32
+ if (formatTooltip) {
33
+ text = formatTooltip(angle);
34
+ } else {
35
+ // By default, round to 2 decimal places and append units
36
+ // @ts-expect-error angle isn't string
37
+ text = `${parseFloat(angle).toFixed(2)} ${units}`;
38
+ }
39
+
40
+ if (measurementCallback) {
41
+ measurementCallback(angle);
42
+ }
43
+
44
+ const position = turfCenter({
45
+ type: 'FeatureCollection',
46
+ features: [point1, point2].map((p) => ({
47
+ type: 'Feature',
48
+ geometry: {
49
+ type: 'Point',
50
+ coordinates: p,
51
+ },
52
+ properties: {}
53
+ })),
54
+ }).geometry.coordinates as Position;
55
+
56
+ tooltips = [{position, text}];
57
+ }
58
+
59
+ return tooltips;
60
+ });
61
+
62
+ handleClick(event: ClickEvent, props: ModeProps<FeatureCollection>): void {
63
+ if (this.getClickSequence().length >= 3) {
64
+ this.resetClickSequence();
65
+ }
66
+
67
+ this.addClickSequence(event);
68
+ }
69
+
70
+ // Called when the pointer moved, regardless of whether the pointer is down, up, and whether something was picked
71
+ handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>): void {
72
+ props.onUpdateCursor('cell');
73
+ }
74
+
75
+ getPoints(props: ModeProps<FeatureCollection>): Position[] {
76
+ const clickSequence = this.getClickSequence();
77
+
78
+ const points = [...clickSequence];
79
+
80
+ if (clickSequence.length < 3 && props.lastPointerMoveEvent) {
81
+ points.push(props.lastPointerMoveEvent.mapCoords);
82
+ }
83
+
84
+ return points;
85
+ }
86
+
87
+ // Return features that can be used as a guide for editing the data
88
+ getGuides(props: ModeProps<FeatureCollection>): GuideFeatureCollection {
89
+ const guides: GuideFeatureCollection = { type: 'FeatureCollection', features: [] };
90
+ const { features } = guides;
91
+
92
+ const points = this.getPoints(props);
93
+
94
+ if (points.length > 2) {
95
+ features.push({
96
+ type: 'Feature',
97
+ properties: { guideType: 'tentative' },
98
+ geometry: {
99
+ type: 'LineString',
100
+ coordinates: [points[1], points[0], points[2]],
101
+ },
102
+ });
103
+ } else if (points.length > 1) {
104
+ features.push({
105
+ type: 'Feature',
106
+ properties: { guideType: 'tentative' },
107
+ geometry: {
108
+ type: 'LineString',
109
+ coordinates: [points[1], points[0]],
110
+ },
111
+ });
112
+ }
113
+
114
+ return guides;
115
+ }
116
+
117
+ getTooltips(props: ModeProps<FeatureCollection>): Tooltip[] {
118
+ const points = this.getPoints(props);
119
+
120
+ return this._getTooltips({
121
+ modeConfig: props.modeConfig,
122
+ vertex: points[0],
123
+ point1: points[1],
124
+ point2: points[2],
125
+ }) as Tooltip[];
126
+ }
127
+ }
@@ -0,0 +1,62 @@
1
+ import turfArea from '@turf/area';
2
+ import turfCentroid from '@turf/centroid';
3
+ import { ClickEvent, Tooltip, ModeProps } from './types';
4
+ import { FeatureCollection } from '../geojson-types';
5
+ import { DrawPolygonMode } from './draw-polygon-mode';
6
+
7
+ const DEFAULT_TOOLTIPS = [];
8
+
9
+ export class MeasureAreaMode extends DrawPolygonMode {
10
+ handleClick(event: ClickEvent, props: ModeProps<FeatureCollection>) {
11
+ const propsWithoutEdit = {
12
+ ...props,
13
+ onEdit: () => {},
14
+ };
15
+
16
+ super.handleClick(event, propsWithoutEdit);
17
+ }
18
+
19
+ handleKeyUp(event: KeyboardEvent, props: ModeProps<FeatureCollection>): void {
20
+ const propsWithoutEdit = {
21
+ ...props,
22
+ onEdit: () => {},
23
+ };
24
+
25
+ super.handleKeyUp(event, propsWithoutEdit);
26
+ }
27
+
28
+ getTooltips(props: ModeProps<FeatureCollection>): Tooltip[] {
29
+ const tentativeGuide = this.getTentativeGuide(props);
30
+
31
+ if (tentativeGuide && tentativeGuide.geometry.type === 'Polygon') {
32
+ const { modeConfig } = props;
33
+ const { formatTooltip, measurementCallback } = modeConfig || {};
34
+ const units = 'sq. m';
35
+
36
+ const centroid = turfCentroid(tentativeGuide);
37
+ const area = turfArea(tentativeGuide);
38
+
39
+ let text: string;
40
+ if (formatTooltip) {
41
+ text = formatTooltip(area);
42
+ } else {
43
+ // By default, round to 2 decimal places and append units
44
+ // @ts-expect-error are isn't string
45
+ text = `${parseFloat(area).toFixed(2)} ${units}`;
46
+ }
47
+
48
+ if (measurementCallback) {
49
+ measurementCallback(area);
50
+ }
51
+
52
+ return [
53
+ {
54
+ // @ts-expect-error turf types diff
55
+ position: centroid.geometry.coordinates,
56
+ text,
57
+ },
58
+ ];
59
+ }
60
+ return DEFAULT_TOOLTIPS;
61
+ }
62
+ }