@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.
- package/README.md +82 -0
- package/dist/constants.d.ts +14 -0
- package/dist/constants.js +14 -0
- package/dist/curve-utils.d.ts +2 -0
- package/dist/curve-utils.js +61 -0
- package/dist/edit-modes/composite-mode.d.ts +14 -0
- package/dist/edit-modes/composite-mode.js +47 -0
- package/dist/edit-modes/draw-90degree-polygon-mode.d.ts +11 -0
- package/dist/edit-modes/draw-90degree-polygon-mode.js +179 -0
- package/dist/edit-modes/draw-circle-by-diameter-mode.d.ts +24 -0
- package/dist/edit-modes/draw-circle-by-diameter-mode.js +78 -0
- package/dist/edit-modes/draw-circle-from-center-mode.d.ts +22 -0
- package/dist/edit-modes/draw-circle-from-center-mode.js +70 -0
- package/dist/edit-modes/draw-ellipse-by-bounding-box-mode.d.ts +5 -0
- package/dist/edit-modes/draw-ellipse-by-bounding-box-mode.js +20 -0
- package/dist/edit-modes/draw-ellipse-using-three-points-mode.d.ts +5 -0
- package/dist/edit-modes/draw-ellipse-using-three-points-mode.js +16 -0
- package/dist/edit-modes/draw-line-string-mode.d.ts +25 -0
- package/dist/edit-modes/draw-line-string-mode.js +170 -0
- package/dist/edit-modes/draw-point-mode.d.ts +8 -0
- package/dist/edit-modes/draw-point-mode.js +28 -0
- package/dist/edit-modes/draw-polygon-by-dragging-mode.d.ts +14 -0
- package/dist/edit-modes/draw-polygon-by-dragging-mode.js +87 -0
- package/dist/edit-modes/draw-polygon-mode.d.ts +10 -0
- package/dist/edit-modes/draw-polygon-mode.js +143 -0
- package/dist/edit-modes/draw-rectangle-from-center-mode.d.ts +5 -0
- package/dist/edit-modes/draw-rectangle-from-center-mode.js +17 -0
- package/dist/edit-modes/draw-rectangle-mode.d.ts +5 -0
- package/dist/edit-modes/draw-rectangle-mode.js +11 -0
- package/dist/edit-modes/draw-rectangle-using-three-points-mode.d.ts +5 -0
- package/dist/edit-modes/draw-rectangle-using-three-points-mode.js +28 -0
- package/dist/edit-modes/draw-square-from-center-mode.d.ts +5 -0
- package/dist/edit-modes/draw-square-from-center-mode.js +35 -0
- package/dist/edit-modes/draw-square-mode.d.ts +5 -0
- package/dist/edit-modes/draw-square-mode.js +28 -0
- package/dist/edit-modes/duplicate-mode.d.ts +7 -0
- package/dist/edit-modes/duplicate-mode.js +17 -0
- package/dist/edit-modes/edit-mode.d.ts +11 -0
- package/dist/edit-modes/edit-mode.js +2 -0
- package/dist/edit-modes/elevation-mode.d.ts +13 -0
- package/dist/edit-modes/elevation-mode.js +49 -0
- package/dist/edit-modes/extend-line-string-mode.d.ts +9 -0
- package/dist/edit-modes/extend-line-string-mode.js +72 -0
- package/dist/edit-modes/extrude-mode.d.ts +15 -0
- package/dist/edit-modes/extrude-mode.js +186 -0
- package/dist/edit-modes/geojson-edit-mode.d.ts +33 -0
- package/dist/edit-modes/geojson-edit-mode.js +208 -0
- package/dist/edit-modes/immutable-feature-collection.d.ts +43 -0
- package/dist/edit-modes/immutable-feature-collection.js +300 -0
- package/dist/edit-modes/measure-angle-mode.d.ts +11 -0
- package/dist/edit-modes/measure-angle-mode.js +99 -0
- package/dist/edit-modes/measure-area-mode.d.ts +8 -0
- package/dist/edit-modes/measure-area-mode.js +50 -0
- package/dist/edit-modes/measure-distance-mode.d.ts +19 -0
- package/dist/edit-modes/measure-distance-mode.js +171 -0
- package/dist/edit-modes/modify-mode.d.ts +15 -0
- package/dist/edit-modes/modify-mode.js +203 -0
- package/dist/edit-modes/resize-circle-mode.d.ts +16 -0
- package/dist/edit-modes/resize-circle-mode.js +142 -0
- package/dist/edit-modes/rotate-mode.d.ts +17 -0
- package/dist/edit-modes/rotate-mode.js +151 -0
- package/dist/edit-modes/scale-mode.d.ts +27 -0
- package/dist/edit-modes/scale-mode.js +173 -0
- package/dist/edit-modes/snappable-mode.d.ts +21 -0
- package/dist/edit-modes/snappable-mode.js +109 -0
- package/dist/edit-modes/split-polygon-mode.d.ts +10 -0
- package/dist/edit-modes/split-polygon-mode.js +164 -0
- package/dist/edit-modes/three-click-polygon-mode.d.ts +10 -0
- package/dist/edit-modes/three-click-polygon-mode.js +72 -0
- package/dist/edit-modes/transform-mode.d.ts +9 -0
- package/dist/edit-modes/transform-mode.js +63 -0
- package/dist/edit-modes/translate-mode.d.ts +13 -0
- package/dist/edit-modes/translate-mode.js +113 -0
- package/dist/edit-modes/two-click-polygon-mode.d.ts +13 -0
- package/dist/edit-modes/two-click-polygon-mode.js +93 -0
- package/dist/edit-modes/types.d.ts +86 -0
- package/dist/edit-modes/types.js +1 -0
- package/dist/edit-modes/utils.d.ts +36 -0
- package/dist/edit-modes/utils.js +381 -0
- package/dist/edit-modes/view-mode.d.ts +3 -0
- package/dist/edit-modes/view-mode.js +3 -0
- package/dist/editable-layers/editable-geojson-layer.d.ts +98 -0
- package/dist/editable-layers/editable-geojson-layer.js +450 -0
- package/dist/editable-layers/editable-h3-cluster-layer.d.ts +34 -0
- package/dist/editable-layers/editable-h3-cluster-layer.js +164 -0
- package/dist/editable-layers/editable-layer.d.ts +49 -0
- package/dist/editable-layers/editable-layer.js +195 -0
- package/dist/editable-layers/editable-path-layer.d.ts +9 -0
- package/dist/editable-layers/editable-path-layer.js +34 -0
- package/dist/editable-layers/elevated-edit-handle-layer.d.ts +7 -0
- package/dist/editable-layers/elevated-edit-handle-layer.js +24 -0
- package/dist/editable-layers/junction-scatterplot-layer.d.ts +14 -0
- package/dist/editable-layers/junction-scatterplot-layer.js +41 -0
- package/dist/editable-layers/path-marker-layer/arrow-2d-geometry.d.ts +4 -0
- package/dist/editable-layers/path-marker-layer/arrow-2d-geometry.js +55 -0
- package/dist/editable-layers/path-marker-layer/create-path-markers.d.ts +16 -0
- package/dist/editable-layers/path-marker-layer/create-path-markers.js +75 -0
- package/dist/editable-layers/path-marker-layer/path-marker-layer.d.ts +40 -0
- package/dist/editable-layers/path-marker-layer/path-marker-layer.js +121 -0
- package/dist/editable-layers/path-marker-layer/polyline.d.ts +18 -0
- package/dist/editable-layers/path-marker-layer/polyline.js +37 -0
- package/dist/editable-layers/path-outline-layer/path-outline-layer.d.ts +26 -0
- package/dist/editable-layers/path-outline-layer/path-outline-layer.js +106 -0
- package/dist/editable-layers/selection-layer.d.ts +26 -0
- package/dist/editable-layers/selection-layer.js +167 -0
- package/dist/geojson-types.d.ts +58 -0
- package/dist/geojson-types.js +2 -0
- package/dist/index.cjs +5825 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +62 -0
- package/dist/lib/constants.d.ts +6 -0
- package/dist/lib/constants.js +6 -0
- package/dist/lib/deck-renderer/deck-cache.d.ts +14 -0
- package/dist/lib/deck-renderer/deck-cache.js +51 -0
- package/dist/lib/deck-renderer/deck-drawer.d.ts +63 -0
- package/dist/lib/deck-renderer/deck-drawer.js +232 -0
- package/dist/lib/feature.d.ts +10 -0
- package/dist/lib/feature.js +16 -0
- package/dist/lib/layer-mouse-event.d.ts +11 -0
- package/dist/lib/layer-mouse-event.js +24 -0
- package/dist/lib/layers/junctions-layer.d.ts +8 -0
- package/dist/lib/layers/junctions-layer.js +33 -0
- package/dist/lib/layers/segments-layer.d.ts +18 -0
- package/dist/lib/layers/segments-layer.js +94 -0
- package/dist/lib/layers/texts-layer.d.ts +8 -0
- package/dist/lib/layers/texts-layer.js +32 -0
- package/dist/lib/math.d.ts +11 -0
- package/dist/lib/math.js +22 -0
- package/dist/lib/nebula-layer.d.ts +13 -0
- package/dist/lib/nebula-layer.js +26 -0
- package/dist/lib/nebula.d.ts +34 -0
- package/dist/lib/nebula.js +254 -0
- package/dist/lib/style.d.ts +19 -0
- package/dist/lib/style.js +20 -0
- package/dist/memoize.d.ts +6 -0
- package/dist/memoize.js +40 -0
- package/dist/mode-handlers/composite-mode-handler.d.ts +24 -0
- package/dist/mode-handlers/composite-mode-handler.js +55 -0
- package/dist/mode-handlers/draw-90degree-polygon-handler.d.ts +13 -0
- package/dist/mode-handlers/draw-90degree-polygon-handler.js +169 -0
- package/dist/mode-handlers/draw-circle-by-bounding-box-handler.d.ts +9 -0
- package/dist/mode-handlers/draw-circle-by-bounding-box-handler.js +29 -0
- package/dist/mode-handlers/draw-circle-from-center-handler.d.ts +9 -0
- package/dist/mode-handlers/draw-circle-from-center-handler.js +27 -0
- package/dist/mode-handlers/draw-ellipse-by-bounding-box-handler.d.ts +9 -0
- package/dist/mode-handlers/draw-ellipse-by-bounding-box-handler.js +30 -0
- package/dist/mode-handlers/draw-ellipse-using-three-points-handler.d.ts +9 -0
- package/dist/mode-handlers/draw-ellipse-using-three-points-handler.js +37 -0
- package/dist/mode-handlers/draw-line-string-handler.d.ts +9 -0
- package/dist/mode-handlers/draw-line-string-handler.js +83 -0
- package/dist/mode-handlers/draw-point-handler.d.ts +5 -0
- package/dist/mode-handlers/draw-point-handler.js +11 -0
- package/dist/mode-handlers/draw-polygon-handler.d.ts +11 -0
- package/dist/mode-handlers/draw-polygon-handler.js +92 -0
- package/dist/mode-handlers/draw-rectangle-handler.d.ts +9 -0
- package/dist/mode-handlers/draw-rectangle-handler.js +18 -0
- package/dist/mode-handlers/draw-rectangle-using-three-points-handler.d.ts +9 -0
- package/dist/mode-handlers/draw-rectangle-using-three-points-handler.js +49 -0
- package/dist/mode-handlers/duplicate-handler.d.ts +9 -0
- package/dist/mode-handlers/duplicate-handler.js +19 -0
- package/dist/mode-handlers/elevation-handler.d.ts +19 -0
- package/dist/mode-handlers/elevation-handler.js +48 -0
- package/dist/mode-handlers/extrude-handler.d.ts +18 -0
- package/dist/mode-handlers/extrude-handler.js +176 -0
- package/dist/mode-handlers/mode-handler.d.ts +61 -0
- package/dist/mode-handlers/mode-handler.js +286 -0
- package/dist/mode-handlers/modify-handler.d.ts +19 -0
- package/dist/mode-handlers/modify-handler.js +193 -0
- package/dist/mode-handlers/rotate-handler.d.ts +17 -0
- package/dist/mode-handlers/rotate-handler.js +74 -0
- package/dist/mode-handlers/scale-handler.d.ts +17 -0
- package/dist/mode-handlers/scale-handler.js +76 -0
- package/dist/mode-handlers/snappable-handler.d.ts +33 -0
- package/dist/mode-handlers/snappable-handler.js +133 -0
- package/dist/mode-handlers/split-polygon-handler.d.ts +11 -0
- package/dist/mode-handlers/split-polygon-handler.js +154 -0
- package/dist/mode-handlers/three-click-polygon-handler.d.ts +5 -0
- package/dist/mode-handlers/three-click-polygon-handler.js +18 -0
- package/dist/mode-handlers/translate-handler.d.ts +17 -0
- package/dist/mode-handlers/translate-handler.js +72 -0
- package/dist/mode-handlers/two-click-polygon-handler.d.ts +5 -0
- package/dist/mode-handlers/two-click-polygon-handler.js +18 -0
- package/dist/mode-handlers/view-handler.d.ts +8 -0
- package/dist/mode-handlers/view-handler.js +10 -0
- package/dist/shaderlib/color/color.d.ts +8 -0
- package/dist/shaderlib/color/color.js +51 -0
- package/dist/shaderlib/outline/outline.d.ts +8 -0
- package/dist/shaderlib/outline/outline.js +97 -0
- package/dist/shaderlib/utils/utils.d.ts +8 -0
- package/dist/shaderlib/utils/utils.js +28 -0
- package/dist/translateFromCenter.d.ts +4 -0
- package/dist/translateFromCenter.js +19 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +20 -0
- package/dist/utils.js +144 -0
- package/package.json +84 -0
- package/src/constants.ts +15 -0
- package/src/curve-utils.ts +77 -0
- package/src/edit-modes/composite-mode.ts +74 -0
- package/src/edit-modes/draw-90degree-polygon-mode.ts +220 -0
- package/src/edit-modes/draw-circle-by-diameter-mode.ts +88 -0
- package/src/edit-modes/draw-circle-from-center-mode.ts +79 -0
- package/src/edit-modes/draw-ellipse-by-bounding-box-mode.ts +25 -0
- package/src/edit-modes/draw-ellipse-using-three-points-mode.ts +23 -0
- package/src/edit-modes/draw-line-string-mode.ts +200 -0
- package/src/edit-modes/draw-point-mode.ts +35 -0
- package/src/edit-modes/draw-polygon-by-dragging-mode.ts +106 -0
- package/src/edit-modes/draw-polygon-mode.ts +171 -0
- package/src/edit-modes/draw-rectangle-from-center-mode.ts +23 -0
- package/src/edit-modes/draw-rectangle-mode.ts +14 -0
- package/src/edit-modes/draw-rectangle-using-three-points-mode.ts +36 -0
- package/src/edit-modes/draw-square-from-center-mode.ts +46 -0
- package/src/edit-modes/draw-square-mode.ts +36 -0
- package/src/edit-modes/duplicate-mode.ts +21 -0
- package/src/edit-modes/edit-mode.ts +30 -0
- package/src/edit-modes/elevation-mode.ts +86 -0
- package/src/edit-modes/extend-line-string-mode.ts +87 -0
- package/src/edit-modes/extrude-mode.ts +254 -0
- package/src/edit-modes/geojson-edit-mode.ts +283 -0
- package/src/edit-modes/immutable-feature-collection.ts +417 -0
- package/src/edit-modes/measure-angle-mode.ts +127 -0
- package/src/edit-modes/measure-area-mode.ts +62 -0
- package/src/edit-modes/measure-distance-mode.ts +215 -0
- package/src/edit-modes/modify-mode.ts +293 -0
- package/src/edit-modes/resize-circle-mode.ts +202 -0
- package/src/edit-modes/rotate-mode.ts +208 -0
- package/src/edit-modes/scale-mode.ts +231 -0
- package/src/edit-modes/snappable-mode.ts +174 -0
- package/src/edit-modes/split-polygon-mode.ts +201 -0
- package/src/edit-modes/three-click-polygon-mode.ts +111 -0
- package/src/edit-modes/transform-mode.ts +75 -0
- package/src/edit-modes/translate-mode.ts +161 -0
- package/src/edit-modes/two-click-polygon-mode.ts +132 -0
- package/src/edit-modes/types.ts +135 -0
- package/src/edit-modes/utils.ts +513 -0
- package/src/edit-modes/view-mode.ts +3 -0
- package/src/editable-layers/editable-geojson-layer.ts +603 -0
- package/src/editable-layers/editable-h3-cluster-layer.ts +226 -0
- package/src/editable-layers/editable-layer.ts +252 -0
- package/src/editable-layers/editable-path-layer.ts +51 -0
- package/src/editable-layers/elevated-edit-handle-layer.ts +33 -0
- package/src/editable-layers/junction-scatterplot-layer.ts +53 -0
- package/src/editable-layers/path-marker-layer/arrow-2d-geometry.ts +61 -0
- package/src/editable-layers/path-marker-layer/create-path-markers.ts +107 -0
- package/src/editable-layers/path-marker-layer/path-marker-layer.ts +179 -0
- package/src/editable-layers/path-marker-layer/polyline.ts +40 -0
- package/src/editable-layers/path-outline-layer/path-outline-layer.ts +147 -0
- package/src/editable-layers/selection-layer.ts +209 -0
- package/src/geojson-types.ts +89 -0
- package/src/index.ts +125 -0
- package/src/lib/constants.ts +6 -0
- package/src/lib/deck-renderer/deck-cache.ts +61 -0
- package/src/lib/deck-renderer/deck-drawer.ts +263 -0
- package/src/lib/feature.ts +27 -0
- package/src/lib/layer-mouse-event.ts +32 -0
- package/src/lib/layers/junctions-layer.ts +40 -0
- package/src/lib/layers/segments-layer.ts +108 -0
- package/src/lib/layers/texts-layer.ts +43 -0
- package/src/lib/math.ts +26 -0
- package/src/lib/nebula-layer.ts +33 -0
- package/src/lib/nebula.ts +323 -0
- package/src/lib/style.ts +22 -0
- package/src/memoize.ts +43 -0
- package/src/mode-handlers/composite-mode-handler.ts +89 -0
- package/src/mode-handlers/draw-90degree-polygon-handler.ts +201 -0
- package/src/mode-handlers/draw-circle-by-bounding-box-handler.ts +39 -0
- package/src/mode-handlers/draw-circle-from-center-handler.ts +38 -0
- package/src/mode-handlers/draw-ellipse-by-bounding-box-handler.ts +41 -0
- package/src/mode-handlers/draw-ellipse-using-three-points-handler.ts +46 -0
- package/src/mode-handlers/draw-line-string-handler.ts +108 -0
- package/src/mode-handlers/draw-point-handler.ts +15 -0
- package/src/mode-handlers/draw-polygon-handler.ts +121 -0
- package/src/mode-handlers/draw-rectangle-handler.ts +28 -0
- package/src/mode-handlers/draw-rectangle-using-three-points-handler.ts +60 -0
- package/src/mode-handlers/duplicate-handler.ts +25 -0
- package/src/mode-handlers/elevation-handler.ts +88 -0
- package/src/mode-handlers/extrude-handler.ts +245 -0
- package/src/mode-handlers/mode-handler.ts +394 -0
- package/src/mode-handlers/modify-handler.ts +263 -0
- package/src/mode-handlers/rotate-handler.ts +107 -0
- package/src/mode-handlers/scale-handler.ts +105 -0
- package/src/mode-handlers/snappable-handler.ts +184 -0
- package/src/mode-handlers/split-polygon-handler.ts +177 -0
- package/src/mode-handlers/three-click-polygon-handler.ts +25 -0
- package/src/mode-handlers/translate-handler.ts +110 -0
- package/src/mode-handlers/two-click-polygon-handler.ts +25 -0
- package/src/mode-handlers/view-handler.ts +13 -0
- package/src/shaderlib/color/color.ts +56 -0
- package/src/shaderlib/outline/outline.ts +101 -0
- package/src/shaderlib/utils/utils.ts +33 -0
- package/src/translateFromCenter.ts +48 -0
- package/src/types.ts +39 -0
- package/src/utils.ts +185 -0
|
@@ -0,0 +1,151 @@
|
|
|
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 { getPickedEditHandle } from './utils';
|
|
12
|
+
import { GeoJsonEditMode, getIntermediatePosition } from './geojson-edit-mode';
|
|
13
|
+
import { ImmutableFeatureCollection } from './immutable-feature-collection';
|
|
14
|
+
export class RotateMode extends GeoJsonEditMode {
|
|
15
|
+
_selectedEditHandle;
|
|
16
|
+
_geometryBeingRotated;
|
|
17
|
+
_isRotating = false;
|
|
18
|
+
_isSinglePointGeometrySelected = (geometry) => {
|
|
19
|
+
const { features } = geometry || {};
|
|
20
|
+
if (Array.isArray(features) && features.length === 1) {
|
|
21
|
+
// @ts-expect-error turf type diff
|
|
22
|
+
const { type } = getGeom(features[0]);
|
|
23
|
+
return type === 'Point';
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
};
|
|
27
|
+
getIsRotating = () => this._isRotating;
|
|
28
|
+
getGuides(props) {
|
|
29
|
+
const selectedGeometry = this._geometryBeingRotated || this.getSelectedFeaturesAsFeatureCollection(props);
|
|
30
|
+
if (this._isSinglePointGeometrySelected(selectedGeometry)) {
|
|
31
|
+
return { type: 'FeatureCollection', features: [] };
|
|
32
|
+
}
|
|
33
|
+
if (this._isRotating) {
|
|
34
|
+
// Display rotate pivot
|
|
35
|
+
// @ts-expect-error turf types diff
|
|
36
|
+
return featureCollection([turfCentroid(selectedGeometry)]);
|
|
37
|
+
}
|
|
38
|
+
const boundingBox = bboxPolygon(bbox(selectedGeometry));
|
|
39
|
+
let previousCoord = null;
|
|
40
|
+
let topEdgeMidpointCoords = null;
|
|
41
|
+
let longestEdgeLength = 0;
|
|
42
|
+
coordEach(boundingBox, (coord) => {
|
|
43
|
+
if (previousCoord) {
|
|
44
|
+
const edgeMidpoint = getIntermediatePosition(coord, previousCoord);
|
|
45
|
+
if (!topEdgeMidpointCoords || edgeMidpoint[1] > topEdgeMidpointCoords[1]) {
|
|
46
|
+
// Get the top edge midpoint of the enveloping box
|
|
47
|
+
topEdgeMidpointCoords = edgeMidpoint;
|
|
48
|
+
}
|
|
49
|
+
// Get the length of the longest edge of the enveloping box
|
|
50
|
+
const edgeDistance = turfDistance(coord, previousCoord);
|
|
51
|
+
longestEdgeLength = Math.max(longestEdgeLength, edgeDistance);
|
|
52
|
+
}
|
|
53
|
+
previousCoord = coord;
|
|
54
|
+
});
|
|
55
|
+
// Scale the length of the line between the rotate handler and the enveloping box
|
|
56
|
+
// relative to the length of the longest edge of the enveloping box
|
|
57
|
+
const rotateHandleCoords = topEdgeMidpointCoords && [
|
|
58
|
+
topEdgeMidpointCoords[0],
|
|
59
|
+
topEdgeMidpointCoords[1] + longestEdgeLength / 1000,
|
|
60
|
+
];
|
|
61
|
+
const lineFromEnvelopeToRotateHandle = lineString([topEdgeMidpointCoords, rotateHandleCoords]);
|
|
62
|
+
const rotateHandle = point(rotateHandleCoords, {
|
|
63
|
+
guideType: 'editHandle',
|
|
64
|
+
editHandleType: 'rotate',
|
|
65
|
+
});
|
|
66
|
+
const outFeatures = [polygonToLine(boundingBox), rotateHandle, lineFromEnvelopeToRotateHandle];
|
|
67
|
+
// @ts-expect-error turf type diff
|
|
68
|
+
return featureCollection(outFeatures);
|
|
69
|
+
}
|
|
70
|
+
handleDragging(event, props) {
|
|
71
|
+
if (!this._isRotating) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const rotateAction = this.getRotateAction(event.pointerDownMapCoords, event.mapCoords, 'rotating', props);
|
|
75
|
+
if (rotateAction) {
|
|
76
|
+
props.onEdit(rotateAction);
|
|
77
|
+
}
|
|
78
|
+
event.cancelPan();
|
|
79
|
+
}
|
|
80
|
+
handlePointerMove(event, props) {
|
|
81
|
+
if (!this._isRotating) {
|
|
82
|
+
const selectedEditHandle = getPickedEditHandle(event.picks);
|
|
83
|
+
this._selectedEditHandle =
|
|
84
|
+
selectedEditHandle && selectedEditHandle.properties.editHandleType === 'rotate'
|
|
85
|
+
? selectedEditHandle
|
|
86
|
+
: null;
|
|
87
|
+
}
|
|
88
|
+
this.updateCursor(props);
|
|
89
|
+
}
|
|
90
|
+
handleStartDragging(event, props) {
|
|
91
|
+
if (this._selectedEditHandle) {
|
|
92
|
+
this._isRotating = true;
|
|
93
|
+
this._geometryBeingRotated = this.getSelectedFeaturesAsFeatureCollection(props);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
handleStopDragging(event, props) {
|
|
97
|
+
if (this._isRotating) {
|
|
98
|
+
// Rotate the geometry
|
|
99
|
+
const rotateAction = this.getRotateAction(event.pointerDownMapCoords, event.mapCoords, 'rotated', props);
|
|
100
|
+
if (rotateAction) {
|
|
101
|
+
props.onEdit(rotateAction);
|
|
102
|
+
}
|
|
103
|
+
this._geometryBeingRotated = null;
|
|
104
|
+
this._selectedEditHandle = null;
|
|
105
|
+
this._isRotating = false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
updateCursor(props) {
|
|
109
|
+
if (this._selectedEditHandle) {
|
|
110
|
+
// TODO: look at doing SVG cursors to get a better "rotate" cursor
|
|
111
|
+
props.onUpdateCursor('crosshair');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
props.onUpdateCursor(null);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
getRotateAction(startDragPoint, currentPoint, editType, props) {
|
|
118
|
+
if (!this._geometryBeingRotated) {
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
// @ts-expect-error turf types diff
|
|
122
|
+
const centroid = turfCentroid(this._geometryBeingRotated);
|
|
123
|
+
// @ts-expect-error turf types diff
|
|
124
|
+
const angle = getRotationAngle(centroid, startDragPoint, currentPoint);
|
|
125
|
+
// @ts-expect-error turf types too wide
|
|
126
|
+
const rotatedFeatures = turfTransformRotate(
|
|
127
|
+
// @ts-expect-error turf types too wide
|
|
128
|
+
this._geometryBeingRotated, angle, {
|
|
129
|
+
pivot: centroid,
|
|
130
|
+
});
|
|
131
|
+
let updatedData = new ImmutableFeatureCollection(props.data);
|
|
132
|
+
const selectedIndexes = props.selectedIndexes;
|
|
133
|
+
for (let i = 0; i < selectedIndexes.length; i++) {
|
|
134
|
+
const selectedIndex = selectedIndexes[i];
|
|
135
|
+
const movedFeature = rotatedFeatures.features[i];
|
|
136
|
+
updatedData = updatedData.replaceGeometry(selectedIndex, movedFeature.geometry);
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
updatedData: updatedData.getObject(),
|
|
140
|
+
editType,
|
|
141
|
+
editContext: {
|
|
142
|
+
featureIndexes: selectedIndexes,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function getRotationAngle(centroid, startDragPoint, currentPoint) {
|
|
148
|
+
const bearing1 = turfBearing(centroid, startDragPoint);
|
|
149
|
+
const bearing2 = turfBearing(centroid, currentPoint);
|
|
150
|
+
return bearing2 - bearing1;
|
|
151
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FeatureCollection, Position } from '../geojson-types';
|
|
2
|
+
import { ModeProps, PointerMoveEvent, StartDraggingEvent, StopDraggingEvent, DraggingEvent, EditHandleFeature, GuideFeatureCollection } from './types';
|
|
3
|
+
import { GeoJsonEditMode } from './geojson-edit-mode';
|
|
4
|
+
export declare class ScaleMode extends GeoJsonEditMode {
|
|
5
|
+
_geometryBeingScaled: FeatureCollection | null | undefined;
|
|
6
|
+
_selectedEditHandle: EditHandleFeature | null | undefined;
|
|
7
|
+
_cornerGuidePoints: Array<EditHandleFeature>;
|
|
8
|
+
_cursor: string | null | undefined;
|
|
9
|
+
_isScaling: boolean;
|
|
10
|
+
_isSinglePointGeometrySelected: (geometry: FeatureCollection | null | undefined) => boolean;
|
|
11
|
+
_getOppositeScaleHandle: (selectedHandle: EditHandleFeature) => EditHandleFeature | null;
|
|
12
|
+
_getUpdatedData: (props: ModeProps<FeatureCollection>, editedData: FeatureCollection) => FeatureCollection;
|
|
13
|
+
isEditHandleSelected: () => boolean;
|
|
14
|
+
getScaleAction: (startDragPoint: Position, currentPoint: Position, editType: string, props: ModeProps<FeatureCollection>) => {
|
|
15
|
+
updatedData: FeatureCollection;
|
|
16
|
+
editType: string;
|
|
17
|
+
editContext: {
|
|
18
|
+
featureIndexes: number[];
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
updateCursor: (props: ModeProps<FeatureCollection>) => void;
|
|
22
|
+
handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>): void;
|
|
23
|
+
handleStartDragging(event: StartDraggingEvent, props: ModeProps<FeatureCollection>): void;
|
|
24
|
+
handleDragging(event: DraggingEvent, props: ModeProps<FeatureCollection>): void;
|
|
25
|
+
handleStopDragging(event: StopDraggingEvent, props: ModeProps<FeatureCollection>): void;
|
|
26
|
+
getGuides(props: ModeProps<FeatureCollection>): GuideFeatureCollection;
|
|
27
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
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 { getPickedEditHandle } from './utils';
|
|
12
|
+
import { GeoJsonEditMode } from './geojson-edit-mode';
|
|
13
|
+
import { ImmutableFeatureCollection } from './immutable-feature-collection';
|
|
14
|
+
export class ScaleMode extends GeoJsonEditMode {
|
|
15
|
+
_geometryBeingScaled;
|
|
16
|
+
_selectedEditHandle;
|
|
17
|
+
_cornerGuidePoints = [];
|
|
18
|
+
_cursor;
|
|
19
|
+
_isScaling = false;
|
|
20
|
+
_isSinglePointGeometrySelected = (geometry) => {
|
|
21
|
+
const { features } = geometry || {};
|
|
22
|
+
if (Array.isArray(features) && features.length === 1) {
|
|
23
|
+
// @ts-expect-error turf types diff
|
|
24
|
+
const { type } = getGeom(features[0]);
|
|
25
|
+
return type === 'Point';
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
29
|
+
_getOppositeScaleHandle = (selectedHandle) => {
|
|
30
|
+
const selectedHandleIndex = selectedHandle &&
|
|
31
|
+
selectedHandle.properties &&
|
|
32
|
+
Array.isArray(selectedHandle.properties.positionIndexes) &&
|
|
33
|
+
selectedHandle.properties.positionIndexes[0];
|
|
34
|
+
if (typeof selectedHandleIndex !== 'number') {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const guidePointCount = this._cornerGuidePoints.length;
|
|
38
|
+
const oppositeIndex = (selectedHandleIndex + guidePointCount / 2) % guidePointCount;
|
|
39
|
+
return this._cornerGuidePoints.find((p) => {
|
|
40
|
+
if (!Array.isArray(p.properties.positionIndexes)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return p.properties.positionIndexes[0] === oppositeIndex;
|
|
44
|
+
}) || null;
|
|
45
|
+
};
|
|
46
|
+
_getUpdatedData = (props, editedData) => {
|
|
47
|
+
let updatedData = new ImmutableFeatureCollection(props.data);
|
|
48
|
+
const selectedIndexes = props.selectedIndexes;
|
|
49
|
+
for (let i = 0; i < selectedIndexes.length; i++) {
|
|
50
|
+
const selectedIndex = selectedIndexes[i];
|
|
51
|
+
const movedFeature = editedData.features[i];
|
|
52
|
+
updatedData = updatedData.replaceGeometry(selectedIndex, movedFeature.geometry);
|
|
53
|
+
}
|
|
54
|
+
return updatedData.getObject();
|
|
55
|
+
};
|
|
56
|
+
isEditHandleSelected = () => Boolean(this._selectedEditHandle);
|
|
57
|
+
getScaleAction = (startDragPoint, currentPoint, editType, props) => {
|
|
58
|
+
if (!this._selectedEditHandle) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const oppositeHandle = this._getOppositeScaleHandle(this._selectedEditHandle);
|
|
62
|
+
const origin = getCoord(oppositeHandle);
|
|
63
|
+
const scaleFactor = getScaleFactor(origin, startDragPoint, currentPoint);
|
|
64
|
+
// @ts-expect-error turf types diff
|
|
65
|
+
const scaledFeatures = turfTransformScale(
|
|
66
|
+
// @ts-expect-error turf types diff
|
|
67
|
+
this._geometryBeingScaled, scaleFactor, { origin });
|
|
68
|
+
return {
|
|
69
|
+
updatedData: this._getUpdatedData(props, scaledFeatures),
|
|
70
|
+
editType,
|
|
71
|
+
editContext: {
|
|
72
|
+
featureIndexes: props.selectedIndexes,
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
updateCursor = (props) => {
|
|
77
|
+
if (this._selectedEditHandle) {
|
|
78
|
+
if (this._cursor) {
|
|
79
|
+
props.onUpdateCursor(this._cursor);
|
|
80
|
+
}
|
|
81
|
+
const cursorGeometry = this.getSelectedFeaturesAsFeatureCollection(props);
|
|
82
|
+
// Get resize cursor direction from the hovered scale editHandle (e.g. nesw or nwse)
|
|
83
|
+
// @ts-expect-error turf types diff
|
|
84
|
+
const centroid = turfCentroid(cursorGeometry);
|
|
85
|
+
const bearing = turfBearing(centroid, this._selectedEditHandle);
|
|
86
|
+
const positiveBearing = bearing < 0 ? bearing + 180 : bearing;
|
|
87
|
+
if ((positiveBearing >= 0 && positiveBearing <= 90) ||
|
|
88
|
+
(positiveBearing >= 180 && positiveBearing <= 270)) {
|
|
89
|
+
this._cursor = 'nesw-resize';
|
|
90
|
+
props.onUpdateCursor('nesw-resize');
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this._cursor = 'nwse-resize';
|
|
94
|
+
props.onUpdateCursor('nwse-resize');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
props.onUpdateCursor(null);
|
|
99
|
+
this._cursor = null;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
handlePointerMove(event, props) {
|
|
103
|
+
if (!this._isScaling) {
|
|
104
|
+
const selectedEditHandle = getPickedEditHandle(event.picks);
|
|
105
|
+
this._selectedEditHandle =
|
|
106
|
+
selectedEditHandle && selectedEditHandle.properties.editHandleType === 'scale'
|
|
107
|
+
? selectedEditHandle
|
|
108
|
+
: null;
|
|
109
|
+
this.updateCursor(props);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
handleStartDragging(event, props) {
|
|
113
|
+
if (this._selectedEditHandle) {
|
|
114
|
+
this._isScaling = true;
|
|
115
|
+
this._geometryBeingScaled = this.getSelectedFeaturesAsFeatureCollection(props);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
handleDragging(event, props) {
|
|
119
|
+
if (!this._isScaling) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
props.onUpdateCursor(this._cursor);
|
|
123
|
+
const scaleAction = this.getScaleAction(event.pointerDownMapCoords, event.mapCoords, 'scaling', props);
|
|
124
|
+
if (scaleAction) {
|
|
125
|
+
props.onEdit(scaleAction);
|
|
126
|
+
}
|
|
127
|
+
event.cancelPan();
|
|
128
|
+
}
|
|
129
|
+
handleStopDragging(event, props) {
|
|
130
|
+
if (this._isScaling) {
|
|
131
|
+
// Scale the geometry
|
|
132
|
+
const scaleAction = this.getScaleAction(event.pointerDownMapCoords, event.mapCoords, 'scaled', props);
|
|
133
|
+
if (scaleAction) {
|
|
134
|
+
props.onEdit(scaleAction);
|
|
135
|
+
}
|
|
136
|
+
props.onUpdateCursor(null);
|
|
137
|
+
this._geometryBeingScaled = null;
|
|
138
|
+
this._selectedEditHandle = null;
|
|
139
|
+
this._cursor = null;
|
|
140
|
+
this._isScaling = false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
getGuides(props) {
|
|
144
|
+
this._cornerGuidePoints = [];
|
|
145
|
+
const selectedGeometry = this.getSelectedFeaturesAsFeatureCollection(props);
|
|
146
|
+
// Add buffer to the enveloping box if a single Point feature is selected
|
|
147
|
+
if (this._isSinglePointGeometrySelected(selectedGeometry)) {
|
|
148
|
+
return { type: 'FeatureCollection', features: [] };
|
|
149
|
+
}
|
|
150
|
+
const boundingBox = bboxPolygon(bbox(selectedGeometry));
|
|
151
|
+
boundingBox.properties.mode = 'scale';
|
|
152
|
+
const cornerGuidePoints = [];
|
|
153
|
+
coordEach(boundingBox, (coord, coordIndex) => {
|
|
154
|
+
if (coordIndex < 4) {
|
|
155
|
+
// Get corner midpoint guides from the enveloping box
|
|
156
|
+
const cornerPoint = point(coord, {
|
|
157
|
+
guideType: 'editHandle',
|
|
158
|
+
editHandleType: 'scale',
|
|
159
|
+
positionIndexes: [coordIndex],
|
|
160
|
+
});
|
|
161
|
+
cornerGuidePoints.push(cornerPoint);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
this._cornerGuidePoints = cornerGuidePoints;
|
|
165
|
+
// @ts-expect-error turf types diff
|
|
166
|
+
return featureCollection([polygonToLine(boundingBox), ...this._cornerGuidePoints]);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function getScaleFactor(centroid, startDragPoint, currentPoint) {
|
|
170
|
+
const startDistance = turfDistance(centroid, startDragPoint);
|
|
171
|
+
const endDistance = turfDistance(centroid, currentPoint);
|
|
172
|
+
return endDistance / startDistance;
|
|
173
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Feature, FeatureCollection } from '../geojson-types';
|
|
2
|
+
import { PointerMoveEvent, StartDraggingEvent, StopDraggingEvent, DraggingEvent, ModeProps, Pick, GuideFeatureCollection, EditHandleFeature } from './types';
|
|
3
|
+
import { GeoJsonEditMode } from './geojson-edit-mode';
|
|
4
|
+
type MovementTypeEvent = PointerMoveEvent | StartDraggingEvent | StopDraggingEvent | DraggingEvent;
|
|
5
|
+
export declare class SnappableMode extends GeoJsonEditMode {
|
|
6
|
+
_handler: GeoJsonEditMode;
|
|
7
|
+
constructor(handler: GeoJsonEditMode);
|
|
8
|
+
_getSnappedMouseEvent<T extends MovementTypeEvent>(event: T, snapSource: EditHandleFeature, snapTarget: EditHandleFeature): T;
|
|
9
|
+
_getPickedSnapTarget(picks: Pick[]): EditHandleFeature | null | undefined;
|
|
10
|
+
_getPickedSnapSource(pointerDownPicks: Pick[] | null | undefined): EditHandleFeature | null | undefined;
|
|
11
|
+
_getUpdatedSnapSourceHandle(snapSourceHandle: EditHandleFeature, data: FeatureCollection): EditHandleFeature;
|
|
12
|
+
_getSnapTargets(props: ModeProps<FeatureCollection>): Feature[];
|
|
13
|
+
_getSnapTargetHandles(props: ModeProps<FeatureCollection>): EditHandleFeature[];
|
|
14
|
+
getGuides(props: ModeProps<FeatureCollection>): GuideFeatureCollection;
|
|
15
|
+
_getSnapAwareEvent<T extends MovementTypeEvent>(event: T, props: ModeProps<FeatureCollection>): T;
|
|
16
|
+
handleStartDragging(event: StartDraggingEvent, props: ModeProps<FeatureCollection>): void;
|
|
17
|
+
handleStopDragging(event: StopDraggingEvent, props: ModeProps<FeatureCollection>): void;
|
|
18
|
+
handleDragging(event: DraggingEvent, props: ModeProps<FeatureCollection>): void;
|
|
19
|
+
handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>): void;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { getPickedSnapSourceEditHandle, getPickedEditHandles, getEditHandlesForGeometry, } from './utils';
|
|
2
|
+
import { GeoJsonEditMode } from './geojson-edit-mode';
|
|
3
|
+
export class SnappableMode extends GeoJsonEditMode {
|
|
4
|
+
_handler;
|
|
5
|
+
constructor(handler) {
|
|
6
|
+
super();
|
|
7
|
+
this._handler = handler;
|
|
8
|
+
}
|
|
9
|
+
_getSnappedMouseEvent(event, snapSource, snapTarget) {
|
|
10
|
+
return Object.assign(event, {
|
|
11
|
+
mapCoords: snapTarget.geometry.coordinates,
|
|
12
|
+
pointerDownMapCoords: snapSource && snapSource.geometry.coordinates,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
_getPickedSnapTarget(picks) {
|
|
16
|
+
return getPickedEditHandles(picks).find((handle) => handle.properties.editHandleType === 'snap-target');
|
|
17
|
+
}
|
|
18
|
+
_getPickedSnapSource(pointerDownPicks) {
|
|
19
|
+
return getPickedSnapSourceEditHandle(pointerDownPicks);
|
|
20
|
+
}
|
|
21
|
+
_getUpdatedSnapSourceHandle(snapSourceHandle, data) {
|
|
22
|
+
const { featureIndex, positionIndexes } = snapSourceHandle.properties;
|
|
23
|
+
if (!Array.isArray(positionIndexes)) {
|
|
24
|
+
return snapSourceHandle;
|
|
25
|
+
}
|
|
26
|
+
const snapSourceFeature = data.features[featureIndex];
|
|
27
|
+
// $FlowFixMe
|
|
28
|
+
const snapSourceCoordinates = positionIndexes.reduce((a, b) => a[b], snapSourceFeature.geometry.coordinates);
|
|
29
|
+
return {
|
|
30
|
+
...snapSourceHandle,
|
|
31
|
+
geometry: {
|
|
32
|
+
type: 'Point',
|
|
33
|
+
coordinates: snapSourceCoordinates,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// If additionalSnapTargets is present in modeConfig and is populated, this
|
|
38
|
+
// method will return those features along with the features
|
|
39
|
+
// that live in the current layer. Otherwise, this method will simply return the
|
|
40
|
+
// features from the current layer
|
|
41
|
+
_getSnapTargets(props) {
|
|
42
|
+
let { additionalSnapTargets } = props.modeConfig || {};
|
|
43
|
+
additionalSnapTargets = additionalSnapTargets || [];
|
|
44
|
+
const features = [...props.data.features, ...additionalSnapTargets];
|
|
45
|
+
return features;
|
|
46
|
+
}
|
|
47
|
+
_getSnapTargetHandles(props) {
|
|
48
|
+
const handles = [];
|
|
49
|
+
const features = this._getSnapTargets(props);
|
|
50
|
+
for (let i = 0; i < features.length; i++) {
|
|
51
|
+
// Filter out the currently selected feature(s)
|
|
52
|
+
const isCurrentIndexFeatureNotSelected = !props.selectedIndexes.includes(i);
|
|
53
|
+
if (isCurrentIndexFeatureNotSelected) {
|
|
54
|
+
const { geometry } = features[i];
|
|
55
|
+
handles.push(...getEditHandlesForGeometry(geometry, i, 'snap-target'));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return handles;
|
|
59
|
+
}
|
|
60
|
+
// If no snap handle has been picked, only display the edit handles of the
|
|
61
|
+
// selected feature. If a snap handle has been picked, display said snap handle
|
|
62
|
+
// along with all snappable points on all non-selected features.
|
|
63
|
+
getGuides(props) {
|
|
64
|
+
const { modeConfig, lastPointerMoveEvent } = props;
|
|
65
|
+
const { enableSnapping } = modeConfig || {};
|
|
66
|
+
const guides = {
|
|
67
|
+
type: 'FeatureCollection',
|
|
68
|
+
features: [...this._handler.getGuides(props).features],
|
|
69
|
+
};
|
|
70
|
+
if (!enableSnapping) {
|
|
71
|
+
return guides;
|
|
72
|
+
}
|
|
73
|
+
const snapSourceHandle = lastPointerMoveEvent && this._getPickedSnapSource(lastPointerMoveEvent.pointerDownPicks);
|
|
74
|
+
// They started dragging a handle
|
|
75
|
+
// So render the picked handle (in its updated location) and all possible snap targets
|
|
76
|
+
if (snapSourceHandle) {
|
|
77
|
+
guides.features.push(...this._getSnapTargetHandles(props), this._getUpdatedSnapSourceHandle(snapSourceHandle, props.data));
|
|
78
|
+
return guides;
|
|
79
|
+
}
|
|
80
|
+
// Render the possible snap source handles
|
|
81
|
+
const { features } = props.data;
|
|
82
|
+
for (const index of props.selectedIndexes) {
|
|
83
|
+
if (index < features.length) {
|
|
84
|
+
const { geometry } = features[index];
|
|
85
|
+
guides.features.push(...getEditHandlesForGeometry(geometry, index, 'snap-source'));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return guides;
|
|
89
|
+
}
|
|
90
|
+
_getSnapAwareEvent(event, props) {
|
|
91
|
+
const snapSource = this._getPickedSnapSource(props.lastPointerMoveEvent.pointerDownPicks);
|
|
92
|
+
const snapTarget = this._getPickedSnapTarget(event.picks);
|
|
93
|
+
return snapSource && snapTarget
|
|
94
|
+
? this._getSnappedMouseEvent(event, snapSource, snapTarget)
|
|
95
|
+
: event;
|
|
96
|
+
}
|
|
97
|
+
handleStartDragging(event, props) {
|
|
98
|
+
this._handler.handleStartDragging(event, props);
|
|
99
|
+
}
|
|
100
|
+
handleStopDragging(event, props) {
|
|
101
|
+
this._handler.handleStopDragging(this._getSnapAwareEvent(event, props), props);
|
|
102
|
+
}
|
|
103
|
+
handleDragging(event, props) {
|
|
104
|
+
this._handler.handleDragging(this._getSnapAwareEvent(event, props), props);
|
|
105
|
+
}
|
|
106
|
+
handlePointerMove(event, props) {
|
|
107
|
+
this._handler.handlePointerMove(this._getSnapAwareEvent(event, props), props);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FeatureCollection } from '../geojson-types';
|
|
2
|
+
import { ClickEvent, PointerMoveEvent, ModeProps, GuideFeatureCollection, TentativeFeature } from './types';
|
|
3
|
+
import { GeoJsonEditMode, GeoJsonEditAction } from './geojson-edit-mode';
|
|
4
|
+
export declare class SplitPolygonMode extends GeoJsonEditMode {
|
|
5
|
+
calculateMapCoords(clickSequence: any, mapCoords: any, props: ModeProps<FeatureCollection>): any;
|
|
6
|
+
getGuides(props: ModeProps<FeatureCollection>): GuideFeatureCollection;
|
|
7
|
+
handleClick(event: ClickEvent, props: ModeProps<FeatureCollection>): void;
|
|
8
|
+
handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>): void;
|
|
9
|
+
splitPolygon(tentativeFeature: TentativeFeature, props: ModeProps<FeatureCollection>): GeoJsonEditAction;
|
|
10
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
|
|
2
|
+
import turfDifference from '@turf/difference';
|
|
3
|
+
import turfBuffer from '@turf/buffer';
|
|
4
|
+
import lineIntersect from '@turf/line-intersect';
|
|
5
|
+
import { lineString } from '@turf/helpers';
|
|
6
|
+
import turfBearing from '@turf/bearing';
|
|
7
|
+
import turfDistance from '@turf/distance';
|
|
8
|
+
import turfDestination from '@turf/destination';
|
|
9
|
+
import turfPolygonToLine from '@turf/polygon-to-line';
|
|
10
|
+
import nearestPointOnLine from '@turf/nearest-point-on-line';
|
|
11
|
+
import { generatePointsParallelToLinePoints } from './utils';
|
|
12
|
+
import { GeoJsonEditMode } from './geojson-edit-mode';
|
|
13
|
+
import { ImmutableFeatureCollection } from './immutable-feature-collection';
|
|
14
|
+
export class SplitPolygonMode extends GeoJsonEditMode {
|
|
15
|
+
calculateMapCoords(clickSequence, mapCoords, props) {
|
|
16
|
+
const modeConfig = props.modeConfig;
|
|
17
|
+
if (!modeConfig || !modeConfig.lock90Degree || !clickSequence.length) {
|
|
18
|
+
return mapCoords;
|
|
19
|
+
}
|
|
20
|
+
if (clickSequence.length === 1) {
|
|
21
|
+
// if first point is clicked, then find closest polygon point and build ~90deg vector
|
|
22
|
+
const firstPoint = clickSequence[0];
|
|
23
|
+
const selectedGeometry = this.getSelectedGeometry(props);
|
|
24
|
+
// @ts-expect-error turf types diff
|
|
25
|
+
const feature = turfPolygonToLine(selectedGeometry);
|
|
26
|
+
const lines = feature.type === 'FeatureCollection' ? feature.features : [feature];
|
|
27
|
+
let minDistance = Number.MAX_SAFE_INTEGER;
|
|
28
|
+
let closestPoint = null;
|
|
29
|
+
// If Multipolygon, then we should find nearest polygon line and stick split to it.
|
|
30
|
+
lines.forEach((line) => {
|
|
31
|
+
const snapPoint = nearestPointOnLine(line, firstPoint);
|
|
32
|
+
const distanceFromOrigin = turfDistance(snapPoint, firstPoint);
|
|
33
|
+
if (minDistance > distanceFromOrigin) {
|
|
34
|
+
minDistance = distanceFromOrigin;
|
|
35
|
+
closestPoint = snapPoint;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
if (closestPoint) {
|
|
39
|
+
// closest point is used as 90degree entry to the polygon
|
|
40
|
+
const lastBearing = turfBearing(firstPoint, closestPoint);
|
|
41
|
+
const currentDistance = turfDistance(firstPoint, mapCoords, { units: 'meters' });
|
|
42
|
+
return turfDestination(firstPoint, currentDistance, lastBearing, {
|
|
43
|
+
units: 'meters',
|
|
44
|
+
}).geometry.coordinates;
|
|
45
|
+
}
|
|
46
|
+
return mapCoords;
|
|
47
|
+
}
|
|
48
|
+
// Allow only 90 degree turns
|
|
49
|
+
const lastPoint = clickSequence[clickSequence.length - 1];
|
|
50
|
+
const [approximatePoint] = generatePointsParallelToLinePoints(clickSequence[clickSequence.length - 2], lastPoint, mapCoords);
|
|
51
|
+
// align point with current ground
|
|
52
|
+
const nearestPt = nearestPointOnLine(lineString([lastPoint, approximatePoint]), mapCoords)
|
|
53
|
+
.geometry.coordinates;
|
|
54
|
+
return nearestPt;
|
|
55
|
+
}
|
|
56
|
+
getGuides(props) {
|
|
57
|
+
const clickSequence = this.getClickSequence();
|
|
58
|
+
const guides = {
|
|
59
|
+
type: 'FeatureCollection',
|
|
60
|
+
features: [],
|
|
61
|
+
};
|
|
62
|
+
if (clickSequence.length === 0 || !props.lastPointerMoveEvent) {
|
|
63
|
+
// nothing to do yet
|
|
64
|
+
return guides;
|
|
65
|
+
}
|
|
66
|
+
const { mapCoords } = props.lastPointerMoveEvent;
|
|
67
|
+
guides.features.push({
|
|
68
|
+
type: 'Feature',
|
|
69
|
+
properties: {
|
|
70
|
+
guideType: 'tentative',
|
|
71
|
+
},
|
|
72
|
+
geometry: {
|
|
73
|
+
type: 'LineString',
|
|
74
|
+
coordinates: [...clickSequence, this.calculateMapCoords(clickSequence, mapCoords, props)],
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
return guides;
|
|
78
|
+
}
|
|
79
|
+
handleClick(event, props) {
|
|
80
|
+
const tentativeFeature = this.getTentativeGuide(props);
|
|
81
|
+
const selectedGeometry = this.getSelectedGeometry(props);
|
|
82
|
+
if (!selectedGeometry) {
|
|
83
|
+
// eslint-disable-next-line no-console,no-undef
|
|
84
|
+
console.warn('A polygon must be selected for splitting');
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const clickSequence = this.getClickSequence();
|
|
88
|
+
if (tentativeFeature && tentativeFeature.geometry.type === 'LineString') {
|
|
89
|
+
clickSequence.push(tentativeFeature.geometry.coordinates[tentativeFeature.geometry.coordinates.length - 1]);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
this.addClickSequence(event);
|
|
93
|
+
}
|
|
94
|
+
const pt = {
|
|
95
|
+
type: 'Point',
|
|
96
|
+
coordinates: clickSequence[clickSequence.length - 1],
|
|
97
|
+
};
|
|
98
|
+
// @ts-expect-error turf types diff
|
|
99
|
+
const isPointInPolygon = booleanPointInPolygon(pt, selectedGeometry);
|
|
100
|
+
if (clickSequence.length > 1 && tentativeFeature && !isPointInPolygon) {
|
|
101
|
+
this.resetClickSequence();
|
|
102
|
+
// @ts-expect-error narrow type
|
|
103
|
+
const isLineInterectingWithPolygon = lineIntersect(tentativeFeature, selectedGeometry);
|
|
104
|
+
if (isLineInterectingWithPolygon.features.length === 0) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const editAction = this.splitPolygon(tentativeFeature, props);
|
|
108
|
+
if (editAction) {
|
|
109
|
+
props.onEdit(editAction);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
handlePointerMove(event, props) {
|
|
114
|
+
props.onUpdateCursor('cell');
|
|
115
|
+
}
|
|
116
|
+
splitPolygon(tentativeFeature, props) {
|
|
117
|
+
const selectedGeometry = this.getSelectedGeometry(props);
|
|
118
|
+
const featureIndex = props.selectedIndexes[0];
|
|
119
|
+
const modeConfig = props.modeConfig || {};
|
|
120
|
+
// Default gap in between the polygon
|
|
121
|
+
let { gap = 0.1, units = 'centimeters' } = modeConfig;
|
|
122
|
+
if (gap === 0) {
|
|
123
|
+
gap = 0.1;
|
|
124
|
+
units = 'centimeters';
|
|
125
|
+
}
|
|
126
|
+
const buffer = turfBuffer(tentativeFeature, gap, { units });
|
|
127
|
+
// @ts-expect-error turf types diff
|
|
128
|
+
const updatedGeometry = turfDifference(selectedGeometry, buffer);
|
|
129
|
+
if (!updatedGeometry) {
|
|
130
|
+
// eslint-disable-next-line no-console,no-undef
|
|
131
|
+
console.warn('Canceling edit. Split Polygon erased');
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const { type, coordinates } = updatedGeometry.geometry;
|
|
135
|
+
let updatedCoordinates = []; // TODO
|
|
136
|
+
if (type === 'Polygon') {
|
|
137
|
+
// Update the coordinates as per Multipolygon
|
|
138
|
+
updatedCoordinates = coordinates.map((c) => [c]);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Handle Case when Multipolygon has holes
|
|
142
|
+
updatedCoordinates = coordinates.reduce((agg, prev) => {
|
|
143
|
+
prev.forEach((p) => {
|
|
144
|
+
// @ts-expect-error revisit coordinates type here
|
|
145
|
+
agg.push([p]);
|
|
146
|
+
});
|
|
147
|
+
return agg;
|
|
148
|
+
}, []);
|
|
149
|
+
}
|
|
150
|
+
// Update the type to Mulitpolygon
|
|
151
|
+
const updatedData = new ImmutableFeatureCollection(props.data).replaceGeometry(featureIndex, {
|
|
152
|
+
type: 'MultiPolygon',
|
|
153
|
+
coordinates: updatedCoordinates,
|
|
154
|
+
});
|
|
155
|
+
const editAction = {
|
|
156
|
+
updatedData: updatedData.getObject(),
|
|
157
|
+
editType: 'split',
|
|
158
|
+
editContext: {
|
|
159
|
+
featureIndexes: [featureIndex],
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
return editAction;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ClickEvent, PointerMoveEvent, ModeProps, GuideFeatureCollection, TentativeFeature } from './types';
|
|
2
|
+
import { Position, Polygon, FeatureOf, FeatureCollection } from '../geojson-types';
|
|
3
|
+
import { GeoJsonEditMode } from './geojson-edit-mode';
|
|
4
|
+
export declare class ThreeClickPolygonMode extends GeoJsonEditMode {
|
|
5
|
+
handleClick(event: ClickEvent, props: ModeProps<FeatureCollection>): void;
|
|
6
|
+
getGuides(props: ModeProps<FeatureCollection>): GuideFeatureCollection;
|
|
7
|
+
getThreeClickPolygon(coord1: Position, coord2: Position, coord3: Position, modeConfig: any): FeatureOf<Polygon> | null | undefined;
|
|
8
|
+
handlePointerMove(event: PointerMoveEvent, props: ModeProps<FeatureCollection>): void;
|
|
9
|
+
createTentativeFeature(props: ModeProps<FeatureCollection>): TentativeFeature;
|
|
10
|
+
}
|