@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,208 @@
1
+ import bbox from '@turf/bbox';
2
+ import turfCentroid from '@turf/centroid';
3
+ import turfBearing from '@turf/bearing';
4
+ import bboxPolygon from '@turf/bbox-polygon';
5
+ import turfDistance from '@turf/distance';
6
+ import { coordEach } from '@turf/meta';
7
+ import { getGeom } from '@turf/invariant';
8
+ import { point, featureCollection, lineString } from '@turf/helpers';
9
+ import turfTransformRotate from '@turf/transform-rotate';
10
+ import polygonToLine from '@turf/polygon-to-line';
11
+ import {
12
+ PointerMoveEvent,
13
+ StartDraggingEvent,
14
+ StopDraggingEvent,
15
+ DraggingEvent,
16
+ ModeProps,
17
+ EditHandleFeature,
18
+ GuideFeatureCollection,
19
+ } from './types';
20
+ import { getPickedEditHandle } from './utils';
21
+ import { FeatureCollection, Position } from '../geojson-types';
22
+ import { GeoJsonEditMode, GeoJsonEditAction, getIntermediatePosition } from './geojson-edit-mode';
23
+ import { ImmutableFeatureCollection } from './immutable-feature-collection';
24
+
25
+ export class RotateMode extends GeoJsonEditMode {
26
+ _selectedEditHandle: EditHandleFeature | null | undefined;
27
+ _geometryBeingRotated: FeatureCollection | null | undefined;
28
+ _isRotating = false;
29
+
30
+ _isSinglePointGeometrySelected = (geometry: FeatureCollection | null | undefined): boolean => {
31
+ const { features } = geometry || {};
32
+ if (Array.isArray(features) && features.length === 1) {
33
+ // @ts-expect-error turf type diff
34
+ const { type }: { type: string } = getGeom(features[0]);
35
+ return type === 'Point';
36
+ }
37
+ return false;
38
+ };
39
+
40
+ getIsRotating = () => this._isRotating;
41
+
42
+ getGuides(props: ModeProps<FeatureCollection>): GuideFeatureCollection {
43
+ const selectedGeometry =
44
+ this._geometryBeingRotated || this.getSelectedFeaturesAsFeatureCollection(props);
45
+
46
+ if (this._isSinglePointGeometrySelected(selectedGeometry)) {
47
+ return { type: 'FeatureCollection', features: [] };
48
+ }
49
+
50
+ if (this._isRotating) {
51
+ // Display rotate pivot
52
+ // @ts-expect-error turf types diff
53
+ return featureCollection([turfCentroid(selectedGeometry)]) as GuideFeatureCollection;
54
+ }
55
+
56
+ const boundingBox = bboxPolygon(bbox(selectedGeometry));
57
+
58
+ let previousCoord: Position | null = null;
59
+ let topEdgeMidpointCoords: Position | null = null;
60
+ let longestEdgeLength = 0;
61
+
62
+ coordEach(boundingBox, (coord: any) => {
63
+ if (previousCoord) {
64
+ const edgeMidpoint = getIntermediatePosition(coord, previousCoord);
65
+ if (!topEdgeMidpointCoords || edgeMidpoint[1] > topEdgeMidpointCoords[1]) {
66
+ // Get the top edge midpoint of the enveloping box
67
+ topEdgeMidpointCoords = edgeMidpoint;
68
+ }
69
+ // Get the length of the longest edge of the enveloping box
70
+ const edgeDistance = turfDistance(coord, previousCoord);
71
+ longestEdgeLength = Math.max(longestEdgeLength, edgeDistance);
72
+ }
73
+ previousCoord = coord;
74
+ });
75
+
76
+ // Scale the length of the line between the rotate handler and the enveloping box
77
+ // relative to the length of the longest edge of the enveloping box
78
+ const rotateHandleCoords = topEdgeMidpointCoords && [
79
+ topEdgeMidpointCoords[0],
80
+ topEdgeMidpointCoords[1] + longestEdgeLength / 1000,
81
+ ];
82
+
83
+ const lineFromEnvelopeToRotateHandle = lineString([topEdgeMidpointCoords!, rotateHandleCoords!]);
84
+ const rotateHandle = point(rotateHandleCoords!, {
85
+ guideType: 'editHandle',
86
+ editHandleType: 'rotate',
87
+ });
88
+
89
+ const outFeatures = [polygonToLine(boundingBox), rotateHandle, lineFromEnvelopeToRotateHandle];
90
+
91
+ // @ts-expect-error turf type diff
92
+ return featureCollection(outFeatures);
93
+ }
94
+
95
+ handleDragging(event: DraggingEvent, props: ModeProps<FeatureCollection>) {
96
+ if (!this._isRotating) {
97
+ return;
98
+ }
99
+
100
+ const rotateAction = this.getRotateAction(
101
+ event.pointerDownMapCoords,
102
+ event.mapCoords,
103
+ 'rotating',
104
+ props
105
+ );
106
+ if (rotateAction) {
107
+ props.onEdit(rotateAction);
108
+ }
109
+
110
+ event.cancelPan();
111
+ }
112
+
113
+ handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>) {
114
+ if (!this._isRotating) {
115
+ const selectedEditHandle = getPickedEditHandle(event.picks);
116
+ this._selectedEditHandle =
117
+ selectedEditHandle && selectedEditHandle.properties.editHandleType === 'rotate'
118
+ ? selectedEditHandle
119
+ : null;
120
+ }
121
+
122
+ this.updateCursor(props);
123
+ }
124
+
125
+ handleStartDragging(event: StartDraggingEvent, props: ModeProps<FeatureCollection>) {
126
+ if (this._selectedEditHandle) {
127
+ this._isRotating = true;
128
+ this._geometryBeingRotated = this.getSelectedFeaturesAsFeatureCollection(props);
129
+ }
130
+ }
131
+
132
+ handleStopDragging(event: StopDraggingEvent, props: ModeProps<FeatureCollection>) {
133
+ if (this._isRotating) {
134
+ // Rotate the geometry
135
+ const rotateAction = this.getRotateAction(
136
+ event.pointerDownMapCoords,
137
+ event.mapCoords,
138
+ 'rotated',
139
+ props
140
+ );
141
+
142
+ if (rotateAction) {
143
+ props.onEdit(rotateAction);
144
+ }
145
+
146
+ this._geometryBeingRotated = null;
147
+ this._selectedEditHandle = null;
148
+ this._isRotating = false;
149
+ }
150
+ }
151
+
152
+ updateCursor(props: ModeProps<FeatureCollection>) {
153
+ if (this._selectedEditHandle) {
154
+ // TODO: look at doing SVG cursors to get a better "rotate" cursor
155
+ props.onUpdateCursor('crosshair');
156
+ } else {
157
+ props.onUpdateCursor(null);
158
+ }
159
+ }
160
+
161
+ getRotateAction(
162
+ startDragPoint: Position,
163
+ currentPoint: Position,
164
+ editType: string,
165
+ props: ModeProps<FeatureCollection>
166
+ ): GeoJsonEditAction | null | undefined {
167
+ if (!this._geometryBeingRotated) {
168
+ return null;
169
+ }
170
+ // @ts-expect-error turf types diff
171
+ const centroid = turfCentroid(this._geometryBeingRotated);
172
+ // @ts-expect-error turf types diff
173
+ const angle = getRotationAngle(centroid, startDragPoint, currentPoint);
174
+
175
+ // @ts-expect-error turf types too wide
176
+ const rotatedFeatures: FeatureCollection = turfTransformRotate(
177
+ // @ts-expect-error turf types too wide
178
+ this._geometryBeingRotated,
179
+ angle,
180
+ {
181
+ pivot: centroid,
182
+ }
183
+ );
184
+
185
+ let updatedData = new ImmutableFeatureCollection(props.data);
186
+
187
+ const selectedIndexes = props.selectedIndexes;
188
+ for (let i = 0; i < selectedIndexes.length; i++) {
189
+ const selectedIndex = selectedIndexes[i];
190
+ const movedFeature = rotatedFeatures.features[i];
191
+ updatedData = updatedData.replaceGeometry(selectedIndex, movedFeature.geometry);
192
+ }
193
+
194
+ return {
195
+ updatedData: updatedData.getObject(),
196
+ editType,
197
+ editContext: {
198
+ featureIndexes: selectedIndexes,
199
+ },
200
+ };
201
+ }
202
+ }
203
+
204
+ function getRotationAngle(centroid: Position, startDragPoint: Position, currentPoint: Position) {
205
+ const bearing1 = turfBearing(centroid, startDragPoint);
206
+ const bearing2 = turfBearing(centroid, currentPoint);
207
+ return bearing2 - bearing1;
208
+ }
@@ -0,0 +1,231 @@
1
+ import bbox from '@turf/bbox';
2
+ import turfCentroid from '@turf/centroid';
3
+ import turfBearing from '@turf/bearing';
4
+ import bboxPolygon from '@turf/bbox-polygon';
5
+ import { point, featureCollection } from '@turf/helpers';
6
+ import polygonToLine from '@turf/polygon-to-line';
7
+ import { coordEach } from '@turf/meta';
8
+ import turfDistance from '@turf/distance';
9
+ import turfTransformScale from '@turf/transform-scale';
10
+ import { getCoord, getGeom } from '@turf/invariant';
11
+ import { FeatureCollection, Position } from '../geojson-types';
12
+ import {
13
+ ModeProps,
14
+ PointerMoveEvent,
15
+ StartDraggingEvent,
16
+ StopDraggingEvent,
17
+ DraggingEvent,
18
+ EditHandleFeature,
19
+ GuideFeatureCollection,
20
+ } from './types';
21
+ import { getPickedEditHandle } from './utils';
22
+ import { GeoJsonEditMode } from './geojson-edit-mode';
23
+ import { ImmutableFeatureCollection } from './immutable-feature-collection';
24
+
25
+ export class ScaleMode extends GeoJsonEditMode {
26
+ _geometryBeingScaled: FeatureCollection | null | undefined;
27
+ _selectedEditHandle: EditHandleFeature | null | undefined;
28
+ _cornerGuidePoints: Array<EditHandleFeature> = [];
29
+ _cursor: string | null | undefined;
30
+ _isScaling = false;
31
+
32
+ _isSinglePointGeometrySelected = (geometry: FeatureCollection | null | undefined): boolean => {
33
+ const { features } = geometry || {};
34
+ if (Array.isArray(features) && features.length === 1) {
35
+ // @ts-expect-error turf types diff
36
+ const { type }: { type: string } = getGeom(features[0]);
37
+ return type === 'Point';
38
+ }
39
+ return false;
40
+ };
41
+
42
+ _getOppositeScaleHandle = (selectedHandle: EditHandleFeature): EditHandleFeature | null => {
43
+ const selectedHandleIndex =
44
+ selectedHandle &&
45
+ selectedHandle.properties &&
46
+ Array.isArray(selectedHandle.properties.positionIndexes) &&
47
+ selectedHandle.properties.positionIndexes[0];
48
+
49
+ if (typeof selectedHandleIndex !== 'number') {
50
+ return null;
51
+ }
52
+ const guidePointCount = this._cornerGuidePoints.length;
53
+ const oppositeIndex = (selectedHandleIndex + guidePointCount / 2) % guidePointCount;
54
+ return this._cornerGuidePoints.find((p) => {
55
+ if (!Array.isArray(p.properties.positionIndexes)) {
56
+ return false;
57
+ }
58
+ return p.properties.positionIndexes[0] === oppositeIndex;
59
+ }) || null;
60
+ };
61
+
62
+ _getUpdatedData = (props: ModeProps<FeatureCollection>, editedData: FeatureCollection) => {
63
+ let updatedData = new ImmutableFeatureCollection(props.data);
64
+ const selectedIndexes = props.selectedIndexes;
65
+ for (let i = 0; i < selectedIndexes.length; i++) {
66
+ const selectedIndex = selectedIndexes[i];
67
+ const movedFeature = editedData.features[i];
68
+ updatedData = updatedData.replaceGeometry(selectedIndex, movedFeature.geometry);
69
+ }
70
+ return updatedData.getObject();
71
+ };
72
+
73
+ isEditHandleSelected = (): boolean => Boolean(this._selectedEditHandle);
74
+
75
+ getScaleAction = (
76
+ startDragPoint: Position,
77
+ currentPoint: Position,
78
+ editType: string,
79
+ props: ModeProps<FeatureCollection>
80
+ ) => {
81
+ if (!this._selectedEditHandle) {
82
+ return null;
83
+ }
84
+
85
+ const oppositeHandle = this._getOppositeScaleHandle(this._selectedEditHandle);
86
+ const origin = getCoord(oppositeHandle!) as Position;
87
+
88
+ const scaleFactor = getScaleFactor(origin, startDragPoint, currentPoint);
89
+
90
+ // @ts-expect-error turf types diff
91
+ const scaledFeatures: FeatureCollection = turfTransformScale(
92
+ // @ts-expect-error turf types diff
93
+ this._geometryBeingScaled,
94
+ scaleFactor,
95
+ { origin }
96
+ );
97
+
98
+ return {
99
+ updatedData: this._getUpdatedData(props, scaledFeatures),
100
+ editType,
101
+ editContext: {
102
+ featureIndexes: props.selectedIndexes,
103
+ },
104
+ };
105
+ };
106
+
107
+ updateCursor = (props: ModeProps<FeatureCollection>) => {
108
+ if (this._selectedEditHandle) {
109
+ if (this._cursor) {
110
+ props.onUpdateCursor(this._cursor);
111
+ }
112
+ const cursorGeometry = this.getSelectedFeaturesAsFeatureCollection(props);
113
+
114
+ // Get resize cursor direction from the hovered scale editHandle (e.g. nesw or nwse)
115
+ // @ts-expect-error turf types diff
116
+ const centroid = turfCentroid(cursorGeometry);
117
+ const bearing = turfBearing(centroid, this._selectedEditHandle);
118
+ const positiveBearing = bearing < 0 ? bearing + 180 : bearing;
119
+ if (
120
+ (positiveBearing >= 0 && positiveBearing <= 90) ||
121
+ (positiveBearing >= 180 && positiveBearing <= 270)
122
+ ) {
123
+ this._cursor = 'nesw-resize';
124
+ props.onUpdateCursor('nesw-resize');
125
+ } else {
126
+ this._cursor = 'nwse-resize';
127
+ props.onUpdateCursor('nwse-resize');
128
+ }
129
+ } else {
130
+ props.onUpdateCursor(null);
131
+ this._cursor = null;
132
+ }
133
+ };
134
+
135
+ handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>) {
136
+ if (!this._isScaling) {
137
+ const selectedEditHandle = getPickedEditHandle(event.picks);
138
+ this._selectedEditHandle =
139
+ selectedEditHandle && selectedEditHandle.properties.editHandleType === 'scale'
140
+ ? selectedEditHandle
141
+ : null;
142
+
143
+ this.updateCursor(props);
144
+ }
145
+ }
146
+
147
+ handleStartDragging(event: StartDraggingEvent, props: ModeProps<FeatureCollection>) {
148
+ if (this._selectedEditHandle) {
149
+ this._isScaling = true;
150
+ this._geometryBeingScaled = this.getSelectedFeaturesAsFeatureCollection(props);
151
+ }
152
+ }
153
+
154
+ handleDragging(event: DraggingEvent, props: ModeProps<FeatureCollection>) {
155
+ if (!this._isScaling) {
156
+ return;
157
+ }
158
+
159
+ props.onUpdateCursor(this._cursor);
160
+
161
+ const scaleAction = this.getScaleAction(
162
+ event.pointerDownMapCoords,
163
+ event.mapCoords,
164
+ 'scaling',
165
+ props
166
+ );
167
+ if (scaleAction) {
168
+ props.onEdit(scaleAction);
169
+ }
170
+
171
+ event.cancelPan();
172
+ }
173
+
174
+ handleStopDragging(event: StopDraggingEvent, props: ModeProps<FeatureCollection>) {
175
+ if (this._isScaling) {
176
+ // Scale the geometry
177
+ const scaleAction = this.getScaleAction(
178
+ event.pointerDownMapCoords,
179
+ event.mapCoords,
180
+ 'scaled',
181
+ props
182
+ );
183
+ if (scaleAction) {
184
+ props.onEdit(scaleAction);
185
+ }
186
+
187
+ props.onUpdateCursor(null);
188
+
189
+ this._geometryBeingScaled = null;
190
+ this._selectedEditHandle = null;
191
+ this._cursor = null;
192
+ this._isScaling = false;
193
+ }
194
+ }
195
+
196
+ getGuides(props: ModeProps<FeatureCollection>): GuideFeatureCollection {
197
+ this._cornerGuidePoints = [];
198
+ const selectedGeometry = this.getSelectedFeaturesAsFeatureCollection(props);
199
+
200
+ // Add buffer to the enveloping box if a single Point feature is selected
201
+ if (this._isSinglePointGeometrySelected(selectedGeometry)) {
202
+ return { type: 'FeatureCollection', features: [] };
203
+ }
204
+
205
+ const boundingBox = bboxPolygon(bbox(selectedGeometry));
206
+ boundingBox.properties!.mode = 'scale';
207
+ const cornerGuidePoints: EditHandleFeature[] = [];
208
+
209
+ coordEach(boundingBox, (coord, coordIndex) => {
210
+ if (coordIndex < 4) {
211
+ // Get corner midpoint guides from the enveloping box
212
+ const cornerPoint = point(coord, {
213
+ guideType: 'editHandle',
214
+ editHandleType: 'scale',
215
+ positionIndexes: [coordIndex],
216
+ });
217
+ cornerGuidePoints.push(cornerPoint as EditHandleFeature);
218
+ }
219
+ });
220
+
221
+ this._cornerGuidePoints = cornerGuidePoints;
222
+ // @ts-expect-error turf types diff
223
+ return featureCollection([polygonToLine(boundingBox), ...this._cornerGuidePoints]);
224
+ }
225
+ }
226
+
227
+ function getScaleFactor(centroid: Position, startDragPoint: Position, currentPoint: Position) {
228
+ const startDistance = turfDistance(centroid, startDragPoint);
229
+ const endDistance = turfDistance(centroid, currentPoint);
230
+ return endDistance / startDistance;
231
+ }
@@ -0,0 +1,174 @@
1
+ import { Position, Feature, FeatureCollection } from '../geojson-types';
2
+ import {
3
+ PointerMoveEvent,
4
+ StartDraggingEvent,
5
+ StopDraggingEvent,
6
+ DraggingEvent,
7
+ ModeProps,
8
+ Pick,
9
+ GuideFeatureCollection,
10
+ EditHandleFeature,
11
+ } from './types';
12
+ import {
13
+ getPickedSnapSourceEditHandle,
14
+ getPickedEditHandles,
15
+ getEditHandlesForGeometry,
16
+ } from './utils';
17
+ import { GeoJsonEditMode } from './geojson-edit-mode';
18
+
19
+ type MovementTypeEvent = PointerMoveEvent | StartDraggingEvent | StopDraggingEvent | DraggingEvent;
20
+
21
+ export class SnappableMode extends GeoJsonEditMode {
22
+ _handler: GeoJsonEditMode;
23
+
24
+ constructor(handler: GeoJsonEditMode) {
25
+ super();
26
+ this._handler = handler;
27
+ }
28
+
29
+ _getSnappedMouseEvent<T extends MovementTypeEvent>(
30
+ event: T,
31
+ snapSource: EditHandleFeature,
32
+ snapTarget: EditHandleFeature
33
+ ): T {
34
+ return Object.assign(event, {
35
+ mapCoords: snapTarget.geometry.coordinates,
36
+ pointerDownMapCoords: snapSource && snapSource.geometry.coordinates,
37
+ });
38
+ }
39
+
40
+ _getPickedSnapTarget(picks: Pick[]): EditHandleFeature | null | undefined {
41
+ return getPickedEditHandles(picks).find(
42
+ (handle) => handle.properties.editHandleType === 'snap-target'
43
+ );
44
+ }
45
+
46
+ _getPickedSnapSource(
47
+ pointerDownPicks: Pick[] | null | undefined
48
+ ): EditHandleFeature | null | undefined {
49
+ return getPickedSnapSourceEditHandle(pointerDownPicks);
50
+ }
51
+
52
+ _getUpdatedSnapSourceHandle(
53
+ snapSourceHandle: EditHandleFeature,
54
+ data: FeatureCollection
55
+ ): EditHandleFeature {
56
+ const { featureIndex, positionIndexes } = snapSourceHandle.properties;
57
+ if (!Array.isArray(positionIndexes)) {
58
+ return snapSourceHandle;
59
+ }
60
+ const snapSourceFeature = data.features[featureIndex];
61
+
62
+ // $FlowFixMe
63
+ const snapSourceCoordinates = positionIndexes.reduce(
64
+ (a: any[], b: number) => a[b],
65
+ snapSourceFeature.geometry.coordinates
66
+ ) as Position;
67
+
68
+ return {
69
+ ...snapSourceHandle,
70
+ geometry: {
71
+ type: 'Point',
72
+ coordinates: snapSourceCoordinates,
73
+ },
74
+ };
75
+ }
76
+
77
+ // If additionalSnapTargets is present in modeConfig and is populated, this
78
+ // method will return those features along with the features
79
+ // that live in the current layer. Otherwise, this method will simply return the
80
+ // features from the current layer
81
+ _getSnapTargets(props: ModeProps<FeatureCollection>): Feature[] {
82
+ let { additionalSnapTargets } = props.modeConfig || {};
83
+ additionalSnapTargets = additionalSnapTargets || [];
84
+
85
+ const features = [...props.data.features, ...additionalSnapTargets];
86
+ return features;
87
+ }
88
+
89
+ _getSnapTargetHandles(props: ModeProps<FeatureCollection>): EditHandleFeature[] {
90
+ const handles: EditHandleFeature[] = [];
91
+ const features = this._getSnapTargets(props);
92
+
93
+ for (let i = 0; i < features.length; i++) {
94
+ // Filter out the currently selected feature(s)
95
+ const isCurrentIndexFeatureNotSelected = !props.selectedIndexes.includes(i);
96
+
97
+ if (isCurrentIndexFeatureNotSelected) {
98
+ const { geometry } = features[i];
99
+ handles.push(...getEditHandlesForGeometry(geometry, i, 'snap-target'));
100
+ }
101
+ }
102
+ return handles;
103
+ }
104
+
105
+ // If no snap handle has been picked, only display the edit handles of the
106
+ // selected feature. If a snap handle has been picked, display said snap handle
107
+ // along with all snappable points on all non-selected features.
108
+ getGuides(props: ModeProps<FeatureCollection>): GuideFeatureCollection {
109
+ const { modeConfig, lastPointerMoveEvent } = props;
110
+ const { enableSnapping } = modeConfig || {};
111
+
112
+ const guides: GuideFeatureCollection = {
113
+ type: 'FeatureCollection',
114
+ features: [...this._handler.getGuides(props).features],
115
+ };
116
+
117
+ if (!enableSnapping) {
118
+ return guides;
119
+ }
120
+
121
+ const snapSourceHandle: EditHandleFeature | null | undefined =
122
+ lastPointerMoveEvent && this._getPickedSnapSource(lastPointerMoveEvent.pointerDownPicks);
123
+
124
+ // They started dragging a handle
125
+ // So render the picked handle (in its updated location) and all possible snap targets
126
+ if (snapSourceHandle) {
127
+ guides.features.push(
128
+ ...this._getSnapTargetHandles(props),
129
+ this._getUpdatedSnapSourceHandle(snapSourceHandle, props.data)
130
+ );
131
+
132
+ return guides;
133
+ }
134
+
135
+ // Render the possible snap source handles
136
+ const { features } = props.data;
137
+ for (const index of props.selectedIndexes) {
138
+ if (index < features.length) {
139
+ const { geometry } = features[index];
140
+ guides.features.push(...getEditHandlesForGeometry(geometry, index, 'snap-source'));
141
+ }
142
+ }
143
+
144
+ return guides;
145
+ }
146
+
147
+ _getSnapAwareEvent<T extends MovementTypeEvent>(
148
+ event: T,
149
+ props: ModeProps<FeatureCollection>
150
+ ): T {
151
+ const snapSource = this._getPickedSnapSource(props.lastPointerMoveEvent.pointerDownPicks);
152
+ const snapTarget = this._getPickedSnapTarget(event.picks);
153
+
154
+ return snapSource && snapTarget
155
+ ? this._getSnappedMouseEvent(event, snapSource, snapTarget)
156
+ : event;
157
+ }
158
+
159
+ handleStartDragging(event: StartDraggingEvent, props: ModeProps<FeatureCollection>) {
160
+ this._handler.handleStartDragging(event, props);
161
+ }
162
+
163
+ handleStopDragging(event: StopDraggingEvent, props: ModeProps<FeatureCollection>) {
164
+ this._handler.handleStopDragging(this._getSnapAwareEvent(event, props), props);
165
+ }
166
+
167
+ handleDragging(event: DraggingEvent, props: ModeProps<FeatureCollection>) {
168
+ this._handler.handleDragging(this._getSnapAwareEvent(event, props), props);
169
+ }
170
+
171
+ handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>) {
172
+ this._handler.handlePointerMove(this._getSnapAwareEvent(event, props), props);
173
+ }
174
+ }