@deck.gl-community/editable-layers 9.3.1-alpha.0 → 9.3.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 (67) hide show
  1. package/dist/edit-modes/coordinate-system.d.ts +94 -0
  2. package/dist/edit-modes/coordinate-system.d.ts.map +1 -0
  3. package/dist/edit-modes/coordinate-system.js +105 -0
  4. package/dist/edit-modes/coordinate-system.js.map +1 -0
  5. package/dist/edit-modes/draw-circle-by-diameter-mode.d.ts +1 -1
  6. package/dist/edit-modes/draw-circle-by-diameter-mode.d.ts.map +1 -1
  7. package/dist/edit-modes/draw-circle-from-center-mode.d.ts +1 -1
  8. package/dist/edit-modes/draw-circle-from-center-mode.d.ts.map +1 -1
  9. package/dist/edit-modes/draw-line-string-mode.d.ts +5 -4
  10. package/dist/edit-modes/draw-line-string-mode.d.ts.map +1 -1
  11. package/dist/edit-modes/draw-line-string-mode.js +15 -9
  12. package/dist/edit-modes/draw-line-string-mode.js.map +1 -1
  13. package/dist/edit-modes/geojson-edit-mode.d.ts +9 -9
  14. package/dist/edit-modes/geojson-edit-mode.d.ts.map +1 -1
  15. package/dist/edit-modes/geojson-edit-mode.js +9 -9
  16. package/dist/edit-modes/geojson-edit-mode.js.map +1 -1
  17. package/dist/edit-modes/measure-angle-mode.d.ts +6 -1
  18. package/dist/edit-modes/measure-angle-mode.d.ts.map +1 -1
  19. package/dist/edit-modes/measure-angle-mode.js.map +1 -1
  20. package/dist/edit-modes/measure-distance-mode.d.ts +2 -1
  21. package/dist/edit-modes/measure-distance-mode.d.ts.map +1 -1
  22. package/dist/edit-modes/measure-distance-mode.js +12 -10
  23. package/dist/edit-modes/measure-distance-mode.js.map +1 -1
  24. package/dist/edit-modes/modify-mode.d.ts +2 -1
  25. package/dist/edit-modes/modify-mode.d.ts.map +1 -1
  26. package/dist/edit-modes/modify-mode.js +4 -4
  27. package/dist/edit-modes/modify-mode.js.map +1 -1
  28. package/dist/edit-modes/translate-mode.d.ts.map +1 -1
  29. package/dist/edit-modes/translate-mode.js +5 -8
  30. package/dist/edit-modes/translate-mode.js.map +1 -1
  31. package/dist/edit-modes/types.d.ts +7 -0
  32. package/dist/edit-modes/types.d.ts.map +1 -1
  33. package/dist/edit-modes/utils.d.ts +5 -3
  34. package/dist/edit-modes/utils.d.ts.map +1 -1
  35. package/dist/edit-modes/utils.js +41 -43
  36. package/dist/edit-modes/utils.js.map +1 -1
  37. package/dist/editable-layers/editable-geojson-layer.d.ts.map +1 -1
  38. package/dist/editable-layers/editable-geojson-layer.js +5 -0
  39. package/dist/editable-layers/editable-geojson-layer.js.map +1 -1
  40. package/dist/index.cjs +224 -152
  41. package/dist/index.cjs.map +4 -4
  42. package/dist/index.d.ts +3 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +2 -0
  45. package/dist/index.js.map +1 -1
  46. package/dist/utils/memoize.d.ts +1 -1
  47. package/dist/utils/memoize.d.ts.map +1 -1
  48. package/dist/utils/memoize.js +8 -2
  49. package/dist/utils/memoize.js.map +1 -1
  50. package/dist/utils/translate-from-center.d.ts +2 -1
  51. package/dist/utils/translate-from-center.d.ts.map +1 -1
  52. package/dist/utils/translate-from-center.js +7 -10
  53. package/dist/utils/translate-from-center.js.map +1 -1
  54. package/package.json +2 -2
  55. package/src/edit-modes/coordinate-system.ts +164 -0
  56. package/src/edit-modes/draw-line-string-mode.ts +25 -12
  57. package/src/edit-modes/geojson-edit-mode.ts +12 -11
  58. package/src/edit-modes/measure-angle-mode.ts +1 -1
  59. package/src/edit-modes/measure-distance-mode.ts +13 -11
  60. package/src/edit-modes/modify-mode.ts +7 -4
  61. package/src/edit-modes/translate-mode.ts +5 -8
  62. package/src/edit-modes/types.ts +10 -0
  63. package/src/edit-modes/utils.ts +85 -51
  64. package/src/editable-layers/editable-geojson-layer.ts +5 -0
  65. package/src/index.ts +9 -0
  66. package/src/utils/memoize.ts +10 -4
  67. package/src/utils/translate-from-center.ts +13 -15
@@ -2,10 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import turfBearing from '@turf/bearing';
6
- import turfDistance from '@turf/distance';
7
5
  import clone from '@turf/clone';
8
- import {point} from '@turf/helpers';
9
6
  import {WebMercatorViewport} from '@math.gl/web-mercator';
10
7
  import {
11
8
  FeatureCollection,
@@ -24,6 +21,7 @@ import {mapCoords} from './utils';
24
21
  import {translateFromCenter} from '../utils/translate-from-center';
25
22
  import {GeoJsonEditMode, GeoJsonEditAction} from './geojson-edit-mode';
26
23
  import {ImmutableFeatureCollection} from './immutable-feature-collection';
24
+ import {getEditModeCoordinateSystem} from './coordinate-system';
27
25
 
28
26
  export class TranslateMode extends GeoJsonEditMode {
29
27
  _geometryBeforeTranslate: SimpleFeatureCollection | null | undefined;
@@ -142,14 +140,13 @@ export class TranslateMode extends GeoJsonEditMode {
142
140
  }
143
141
  }
144
142
  } else {
145
- const p1 = point(startDragPoint);
146
- const p2 = point(currentPoint);
143
+ const coordinateSystem = getEditModeCoordinateSystem(props.coordinateSystem);
147
144
 
148
- const distanceMoved = turfDistance(p1, p2);
149
- const direction = turfBearing(p1, p2);
145
+ const distanceMoved = coordinateSystem.distance(startDragPoint, currentPoint);
146
+ const direction = coordinateSystem.bearing(startDragPoint, currentPoint);
150
147
 
151
148
  const movedFeatures = this._geometryBeforeTranslate.features.map((feature) =>
152
- translateFromCenter(clone(feature), distanceMoved, direction)
149
+ translateFromCenter(clone(feature), distanceMoved, direction, coordinateSystem)
153
150
  );
154
151
 
155
152
  for (let i = 0; i < selectedIndexes.length; i++) {
@@ -3,6 +3,7 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
5
  import {Position, Point, SimpleGeometry, Feature} from '../utils/geojson-types';
6
+ import type {EditModeCoordinateSystem} from './coordinate-system';
6
7
 
7
8
  export type ScreenCoordinates = [number, number];
8
9
 
@@ -135,9 +136,18 @@ export type ModeProps<TData> = {
135
136
  // The last pointer move event that occurred
136
137
  lastPointerMoveEvent: PointerMoveEvent;
137
138
 
139
+ // Coordinate system to use for geometric calculations (defaults to GeoCoordinateSystem)
140
+ coordinateSystem?: EditModeCoordinateSystem;
141
+
138
142
  // Callback used to notify applications of an edit action
139
143
  onEdit: (editAction: EditAction<TData>) => void;
140
144
 
141
145
  // Callback used to update cursor
142
146
  onUpdateCursor: (cursor: string | null | undefined) => void;
143
147
  };
148
+
149
+ export type PointWithIndex = {
150
+ index: number;
151
+ x0: number;
152
+ y0: number;
153
+ };
@@ -4,14 +4,21 @@
4
4
 
5
5
  /* eslint-disable no-shadow */
6
6
 
7
- import destination from '@turf/destination';
8
- import bearing from '@turf/bearing';
9
- import pointToLineDistance from '@turf/point-to-line-distance';
7
+ import {destination} from '@turf/destination';
8
+ import {bearing} from '@turf/bearing';
9
+ import {pointToLineDistance} from '@turf/point-to-line-distance';
10
10
  import {flattenEach} from '@turf/meta';
11
11
  import {point} from '@turf/helpers';
12
12
  import {getCoords} from '@turf/invariant';
13
13
  import {WebMercatorViewport} from '@math.gl/web-mercator';
14
- import {Viewport, Pick, EditHandleFeature, EditHandleType, StartDraggingEvent} from './types';
14
+ import {
15
+ Viewport,
16
+ Pick,
17
+ EditHandleFeature,
18
+ EditHandleType,
19
+ StartDraggingEvent,
20
+ PointWithIndex
21
+ } from './types';
15
22
  import {
16
23
  SimpleGeometry,
17
24
  Position,
@@ -21,6 +28,7 @@ import {
21
28
  Feature,
22
29
  SimpleGeometryCoordinates
23
30
  } from '../utils/geojson-types';
31
+ import {CartesianCoordinateSystem, EditModeCoordinateSystem} from './coordinate-system';
24
32
 
25
33
  export type NearestPointType = Feature<Point, {dist: number; index: number}>;
26
34
 
@@ -116,20 +124,49 @@ export function mix(a: number, b: number, ratio: number): number {
116
124
  return b * ratio + a * (1 - ratio);
117
125
  }
118
126
 
127
+ export function projectOrUnprojectPoints(
128
+ inputPoints: Position,
129
+ coordinateSystem: EditModeCoordinateSystem,
130
+ project: 'PROJECT' | 'UNPROJECT',
131
+ wmViewport?: WebMercatorViewport
132
+ ): Position {
133
+ if (coordinateSystem === undefined || wmViewport === undefined) return [...inputPoints];
134
+ else if (coordinateSystem instanceof CartesianCoordinateSystem) return [...inputPoints];
135
+ return project === 'PROJECT'
136
+ ? wmViewport.project([...inputPoints])
137
+ : wmViewport.unproject([...inputPoints]);
138
+ }
139
+
119
140
  export function nearestPointOnProjectedLine(
120
141
  line: Feature<LineString>,
121
142
  inPoint: Feature<Point>,
122
- viewport: Viewport
143
+ viewport: Viewport,
144
+ coordinateSystem?: EditModeCoordinateSystem
123
145
  ): NearestPointType {
124
- const wmViewport = new WebMercatorViewport(viewport);
146
+ // return sentinel value if no coordinates key
147
+ let minDistance = Infinity;
148
+ const coordinates = line?.geometry?.coordinates;
149
+ if (!coordinates)
150
+ return {
151
+ type: 'Feature',
152
+ geometry: {type: 'Point', coordinates: [0, 0, 0]},
153
+ properties: {dist: minDistance, index: -1}
154
+ };
155
+
125
156
  // Project the line to viewport, then find the nearest point
126
- const coordinates: Array<Array<number>> = line.geometry.coordinates as any;
127
- const projectedCoords = coordinates.map(([x, y, z = 0]) => wmViewport.project([x, y, z]));
128
- const [x, y] = wmViewport.project(inPoint.geometry.coordinates);
129
- // console.log('projectedCoords', JSON.stringify(projectedCoords));
157
+ const wmViewport = new WebMercatorViewport(viewport);
130
158
 
131
- let minDistance = Infinity;
132
- let minPointInfo = {};
159
+ const [x, y] = projectOrUnprojectPoints(
160
+ inPoint.geometry.coordinates,
161
+ coordinateSystem,
162
+ 'PROJECT',
163
+ wmViewport
164
+ );
165
+ const projectedCoords = coordinates.map(([px, py, pz = 0]) =>
166
+ projectOrUnprojectPoints([px, py, pz], coordinateSystem, 'PROJECT', wmViewport)
167
+ );
168
+
169
+ let minPointInfo: PointWithIndex = {index: 0, x0: 0, y0: 0};
133
170
 
134
171
  projectedCoords.forEach(([x2, y2], index) => {
135
172
  if (index === 0) {
@@ -159,7 +196,7 @@ export function nearestPointOnProjectedLine(
159
196
  };
160
197
  }
161
198
  });
162
- // @ts-expect-error TODO
199
+
163
200
  const {index, x0, y0} = minPointInfo;
164
201
  const [x1, y1, z1 = 0] = projectedCoords[index - 1];
165
202
  const [x2, y2, z2 = 0] = projectedCoords[index];
@@ -174,7 +211,7 @@ export function nearestPointOnProjectedLine(
174
211
  type: 'Feature',
175
212
  geometry: {
176
213
  type: 'Point',
177
- coordinates: wmViewport.unproject([x0, y0, z0])
214
+ coordinates: projectOrUnprojectPoints([x0, y0, z0], coordinateSystem, 'UNPROJECT', wmViewport)
178
215
  },
179
216
  properties: {
180
217
  // TODO: calculate the distance in proper units
@@ -184,19 +221,15 @@ export function nearestPointOnProjectedLine(
184
221
  };
185
222
  }
186
223
 
187
- export function nearestPointOnLine( // <G extends LineString | MultiLineString>(
224
+ export function nearestPointOnLine(
188
225
  lines: Feature<LineString>,
189
226
  inPoint: Feature<Point>,
190
- viewport?: Viewport
227
+ viewport?: Viewport,
228
+ coordinateSystem?: EditModeCoordinateSystem
191
229
  ): NearestPointType {
192
- let mercator;
230
+ const wmViewport = viewport ? new WebMercatorViewport(viewport) : undefined;
193
231
 
194
- if (viewport) {
195
- mercator = new WebMercatorViewport(viewport);
196
- }
197
- let closestPoint: any = point([Infinity, Infinity], {
198
- dist: Infinity
199
- });
232
+ let closestPoint: any = point([Infinity, Infinity], {dist: Infinity});
200
233
 
201
234
  if (!lines.geometry?.coordinates.length || lines.geometry?.coordinates.length < 2) {
202
235
  return closestPoint;
@@ -207,26 +240,24 @@ export function nearestPointOnLine( // <G extends LineString | MultiLineString>(
207
240
  const coords: any = getCoords(line);
208
241
  const pointCoords: any = getCoords(inPoint);
209
242
 
210
- let minDist;
211
- let to;
212
- let from;
213
- let x;
214
- let y;
215
- let segmentIdx;
216
- let dist;
243
+ let minDist: null | undefined | number;
244
+ let to: null | undefined | number;
245
+ let from: null | undefined | number;
246
+ let x: null | undefined | number;
247
+ let y: null | undefined | number;
248
+ let segmentIdx: null | undefined | number;
249
+ let dist: null | undefined | number;
217
250
 
218
251
  if (coords.length > 1 && pointCoords.length) {
219
- let lineCoordinates;
220
- let pointCoordinate;
221
-
222
- // If viewport is given, then translate these coordinates to pixels to increase precision
223
- if (mercator) {
224
- lineCoordinates = coords.map((lineCoordinate) => mercator.project(lineCoordinate));
225
- pointCoordinate = mercator.project(pointCoords);
226
- } else {
227
- lineCoordinates = coords;
228
- pointCoordinate = pointCoords;
229
- }
252
+ const pointCoordinate = projectOrUnprojectPoints(
253
+ pointCoords,
254
+ coordinateSystem,
255
+ 'PROJECT',
256
+ wmViewport
257
+ );
258
+ const lineCoordinates = coords.map(([px, py, pz = 0]) =>
259
+ projectOrUnprojectPoints([px, py, pz], coordinateSystem, 'PROJECT', wmViewport)
260
+ );
230
261
 
231
262
  for (let n = 1; n < lineCoordinates.length; n++) {
232
263
  if (lineCoordinates[n][0] !== lineCoordinates[n - 1][0]) {
@@ -297,16 +328,19 @@ export function nearestPointOnLine( // <G extends LineString | MultiLineString>(
297
328
  // index needs to be -1 because we have to account for the shift from initial backscan
298
329
  let snapPoint = {x, y, idx: segmentIdx - 1, to, from};
299
330
 
300
- if (mercator) {
301
- const pixelToLatLong = mercator.unproject([snapPoint.x, snapPoint.y]);
302
- snapPoint = {
303
- x: pixelToLatLong[0],
304
- y: pixelToLatLong[1],
305
- idx: segmentIdx - 1,
306
- to,
307
- from
308
- };
309
- }
331
+ const pixelToLatLong = projectOrUnprojectPoints(
332
+ [snapPoint.x, snapPoint.y],
333
+ coordinateSystem,
334
+ 'UNPROJECT',
335
+ wmViewport
336
+ );
337
+ snapPoint = {
338
+ x: pixelToLatLong[0],
339
+ y: pixelToLatLong[1],
340
+ idx: segmentIdx - 1,
341
+ to,
342
+ from
343
+ };
310
344
 
311
345
  closestPoint = point([snapPoint.x, snapPoint.y], {
312
346
  dist: Math.abs(snapPoint.from - snapPoint.to),
@@ -16,6 +16,7 @@ import {
16
16
  DoubleClickEvent,
17
17
  ModeProps
18
18
  } from '../edit-modes/types';
19
+ import {fromDeckCoordinateSystem} from '../edit-modes/coordinate-system';
19
20
 
20
21
  import {ViewMode} from '../edit-modes/view-mode';
21
22
  import {TranslateMode} from '../edit-modes/translate-mode';
@@ -438,6 +439,10 @@ export class EditableGeoJsonLayer extends EditableLayer<
438
439
  selectedIndexes: props.selectedFeatureIndexes,
439
440
  lastPointerMoveEvent: this.state.lastPointerMoveEvent,
440
441
  cursor: this.state.cursor,
442
+ // Derive edit-mode math from deck.gl's coordinateSystem layer prop.
443
+ // This ensures that when the layer is configured for Cartesian or other
444
+ // non-geographic rendering, edit modes automatically use the correct geometry math.
445
+ coordinateSystem: fromDeckCoordinateSystem(this.props.coordinateSystem),
441
446
  onEdit: (editAction) => {
442
447
  // Force a re-render
443
448
  // This supports double-click where we need to ensure that there's a re-render between the two clicks
package/src/index.ts CHANGED
@@ -40,6 +40,15 @@ export type {EditMode} from './edit-modes/edit-mode';
40
40
  export type {GeoJsonEditModeType} from './edit-modes/geojson-edit-mode';
41
41
  export type {GeoJsonEditModeConstructor} from './edit-modes/geojson-edit-mode';
42
42
 
43
+ export type {EditModeCoordinateSystem} from './edit-modes/coordinate-system';
44
+ export {GeoCoordinateSystem, CartesianCoordinateSystem} from './edit-modes/coordinate-system';
45
+ export {
46
+ geoCoordinateSystem,
47
+ cartesianCoordinateSystem,
48
+ getEditModeCoordinateSystem,
49
+ fromDeckCoordinateSystem
50
+ } from './edit-modes/coordinate-system';
51
+
43
52
  export type {EditableGeoJsonLayerProps} from './editable-layers/editable-geojson-layer';
44
53
  export type {SelectionLayerProps} from './editable-layers/selection-layer';
45
54
 
@@ -30,11 +30,17 @@ function isEqual(a: any, b: any) {
30
30
  * https://en.wikipedia.org/wiki/Memoization
31
31
  * @param {function} compute - the function to be memoized
32
32
  */
33
- export function memoize(compute: Function) {
34
- let cachedArgs = {};
35
- let cachedResult;
33
+ export function memoize<T, R>(compute: (args: T) => R): (args: T) => R {
34
+ let cachedArgs: T | null = null;
35
+ let cachedResult: R | null = null;
36
36
 
37
- return (args: any) => {
37
+ return (args: T) => {
38
+ // check for null args on first run
39
+ if (!cachedArgs) {
40
+ cachedResult = compute(args);
41
+ cachedArgs = args;
42
+ return cachedResult;
43
+ }
38
44
  for (const key in args) {
39
45
  if (!isEqual(args[key], cachedArgs[key])) {
40
46
  cachedResult = compute(args);
@@ -3,29 +3,27 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
5
  import turfCenter from '@turf/center';
6
- import turfRhumbBearing from '@turf/rhumb-bearing';
7
- import turfRhumbDistance from '@turf/rhumb-distance';
8
- import turfRhumbDestination from '@turf/rhumb-destination';
9
6
  import {mapCoords} from '../edit-modes/utils';
7
+ import {geoCoordinateSystem} from '../edit-modes/coordinate-system';
8
+ import type {EditModeCoordinateSystem} from '../edit-modes/coordinate-system';
10
9
  import type {SimpleFeature} from './geojson-types';
11
10
 
12
11
  // This function takes feature's center, moves it,
13
12
  // and builds new feature around it keeping the proportions
14
- export function translateFromCenter(feature: SimpleFeature, distance: number, direction: number) {
15
- const initialCenterPoint = turfCenter(feature);
13
+ export function translateFromCenter(
14
+ feature: SimpleFeature,
15
+ distance: number,
16
+ direction: number,
17
+ coordinateSystem: EditModeCoordinateSystem = geoCoordinateSystem
18
+ ) {
19
+ const initialCenter = turfCenter(feature).geometry.coordinates;
16
20
 
17
- const movedCenterPoint = turfRhumbDestination(initialCenterPoint, distance, direction);
21
+ const movedCenter = coordinateSystem.destination(initialCenter, distance, direction);
18
22
 
19
23
  const movedCoordinates = mapCoords(feature.geometry.coordinates, (coordinate) => {
20
- const rhumbDistance = turfRhumbDistance(initialCenterPoint.geometry.coordinates, coordinate);
21
- const rhumbDirection = turfRhumbBearing(initialCenterPoint.geometry.coordinates, coordinate);
22
-
23
- const movedPosition = turfRhumbDestination(
24
- movedCenterPoint.geometry.coordinates,
25
- rhumbDistance,
26
- rhumbDirection
27
- ).geometry.coordinates;
28
- return movedPosition;
24
+ const dist = coordinateSystem.distance(initialCenter, coordinate);
25
+ const dir = coordinateSystem.bearing(initialCenter, coordinate);
26
+ return coordinateSystem.destination(movedCenter, dist, dir);
29
27
  });
30
28
 
31
29
  feature.geometry.coordinates = movedCoordinates;