ol 7.0.1-dev.1661277132609 → 7.0.1-dev.1661440420569

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.
@@ -131,6 +131,17 @@ export type Options = {
131
131
  * Shift key activates freehand drawing.
132
132
  */
133
133
  freehandCondition?: import("../events/condition.js").Condition | undefined;
134
+ /**
135
+ * Trace a portion of another geometry.
136
+ * Ignored when in freehand mode.
137
+ */
138
+ trace?: boolean | import("../events/condition.js").Condition | undefined;
139
+ /**
140
+ * Source for features to trace. If tracing is active and a `traceSource` is
141
+ * not provided, the interaction's `source` will be used. Tracing requires that the interaction is configured with
142
+ * either a `traceSource` or a `source`.
143
+ */
144
+ traceSource?: VectorSource<import("../geom/Geometry.js").default> | undefined;
134
145
  /**
135
146
  * Wrap the world horizontally on the sketch
136
147
  * overlay.
@@ -158,6 +169,44 @@ export type PolyCoordType = Array<Array<import("../coordinate.js").Coordinate>>;
158
169
  * Types used for drawing coordinates.
159
170
  */
160
171
  export type SketchCoordType = number[] | LineCoordType | PolyCoordType;
172
+ export type TraceState = {
173
+ /**
174
+ * Tracing active.
175
+ */
176
+ active: boolean;
177
+ /**
178
+ * The initially clicked pixel location.
179
+ */
180
+ startPx?: import("../pixel.js").Pixel | undefined;
181
+ /**
182
+ * Targets available for tracing.
183
+ */
184
+ targets?: TraceTarget[] | undefined;
185
+ /**
186
+ * The index of the currently traced target. A value of -1 indicates
187
+ * that no trace target is active.
188
+ */
189
+ targetIndex?: number | undefined;
190
+ };
191
+ export type TraceTarget = {
192
+ /**
193
+ * Target coordinates.
194
+ */
195
+ coordinates: Array<import("../coordinate.js").Coordinate>;
196
+ /**
197
+ * The target coordinates are a linear ring.
198
+ */
199
+ ring: boolean;
200
+ /**
201
+ * The index of first traced coordinate. A fractional index represents an
202
+ * edge intersection. Index values for rings will wrap (may be negative or larger than coordinates length).
203
+ */
204
+ startIndex: number;
205
+ /**
206
+ * The index of last traced coordinate. Details from startIndex also apply here.
207
+ */
208
+ endIndex: number;
209
+ };
161
210
  /**
162
211
  * Function that takes an array of coordinates and an optional existing geometry
163
212
  * and a projection as arguments, and returns a geometry. The optional existing
@@ -170,6 +219,26 @@ export type GeometryFunction = (arg0: SketchCoordType, arg1: import("../geom/Sim
170
219
  * cousins.
171
220
  */
172
221
  export type Mode = 'Point' | 'LineString' | 'Polygon' | 'Circle';
222
+ export type TraceTargetUpdateInfo = {
223
+ /**
224
+ * The new target index.
225
+ */
226
+ index: number;
227
+ /**
228
+ * The new segment end index.
229
+ */
230
+ endIndex: number;
231
+ };
232
+ export type PointSegmentRelationship = {
233
+ /**
234
+ * The closest point expressed as a fraction along the segment length.
235
+ */
236
+ along: number;
237
+ /**
238
+ * The squared distance of the point to the segment.
239
+ */
240
+ squaredDistance: number;
241
+ };
173
242
  /**
174
243
  * *
175
244
  */
@@ -386,6 +455,28 @@ declare class Draw extends PointerInteraction {
386
455
  * @type {import("../events/condition.js").Condition}
387
456
  */
388
457
  private freehandCondition_;
458
+ /**
459
+ * @type {import("../events/condition.js").Condition}
460
+ * @private
461
+ */
462
+ private traceCondition_;
463
+ /**
464
+ * @type {TraceState}
465
+ * @private
466
+ */
467
+ private traceState_;
468
+ /**
469
+ * @type {VectorSource|null}
470
+ * @private
471
+ */
472
+ private traceSource_;
473
+ /**
474
+ * Toggle tracing mode or set a tracing condition.
475
+ *
476
+ * @param {boolean|import("../events/condition.js").Condition} trace A boolean to toggle tracing mode or an event
477
+ * condition that will be checked when a feature is clicked to determine if tracing should be active.
478
+ */
479
+ setTrace(trace: boolean | import("../events/condition.js").Condition): void;
389
480
  /**
390
481
  * Remove the interaction from its current map and attach it to the new map.
391
482
  * Subclasses may set up event handlers to get notified about changes to
@@ -399,6 +490,41 @@ declare class Draw extends PointerInteraction {
399
490
  * @api
400
491
  */
401
492
  getOverlay(): VectorLayer<any>;
493
+ /**
494
+ * @private
495
+ */
496
+ private deactivateTrace_;
497
+ /**
498
+ * Activate or deactivate trace state based on a browser event.
499
+ * @param {import("../MapBrowserEvent.js").default} event Event.
500
+ * @private
501
+ */
502
+ private toggleTraceState_;
503
+ /**
504
+ * @param {TraceTarget} target The trace target.
505
+ * @param {number} endIndex The new end index of the trace.
506
+ * @private
507
+ */
508
+ private addOrRemoveTracedCoordinates_;
509
+ /**
510
+ * @param {number} fromIndex The start index.
511
+ * @param {number} toIndex The end index.
512
+ * @private
513
+ */
514
+ private removeTracedCoordinates_;
515
+ /**
516
+ * @param {TraceTarget} target The trace target.
517
+ * @param {number} fromIndex The start index.
518
+ * @param {number} toIndex The end index.
519
+ * @private
520
+ */
521
+ private addTracedCoordinates_;
522
+ /**
523
+ * Update the trace.
524
+ * @param {import("../MapBrowserEvent.js").default} event Event.
525
+ * @private
526
+ */
527
+ private updateTrace_;
402
528
  /**
403
529
  * Handle move events.
404
530
  * @param {import("../MapBrowserEvent.js").default} event A move event.
@@ -408,6 +534,7 @@ declare class Draw extends PointerInteraction {
408
534
  /**
409
535
  * Determine if an event is within the snapping tolerance of the start coord.
410
536
  * @param {import("../pixel.js").Pixel} pixel Pixel.
537
+ * @param {boolean} [tracing] Drawing in trace mode (only stop if at the starting point).
411
538
  * @return {boolean} The event is within the snapping tolerance of the start.
412
539
  * @private
413
540
  */
@@ -440,6 +567,10 @@ declare class Draw extends PointerInteraction {
440
567
  * @private
441
568
  */
442
569
  private addToDrawing_;
570
+ /**
571
+ * @param {number} n The number of points to remove.
572
+ */
573
+ removeLastPoints_(n: number): void;
443
574
  /**
444
575
  * Remove last point of the feature currently being drawn. Does not do anything when
445
576
  * drawing POINT or MULTI_POINT geometries.
@@ -1 +1 @@
1
- {"version":3,"file":"Draw.d.ts","sourceRoot":"","sources":["Draw.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Draw.d.ts","sourceRoot":"","sources":["Draw.js"],"names":[],"mappings":"AAgzDA;;;;;;;;;;;;GAYG;AACH,8FAHY,gBAAgB,CAmC3B;AAED;;;;;;GAMG;AACH,6BAHY,gBAAgB,CAiC3B;AA/sDD;;;;GAIG;AACH;IACE;;;OAGG;IACH,kBAHW,aAAa,WACb,OAAO,EAWjB;IANC;;;;OAIG;IACH,SAHU,OAAO,CAGK;CAEzB;;;;;;;UA5Ja,OAAO,qBAAqB,EAAE,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6BA4DnC,OAAO,kBAAkB,EAAE,UAAU;;;;4BAKrC,MAAM,OAAO,kBAAkB,EAAE,UAAU,CAAC;;;;4BAK5C,MAAM,MAAM,OAAO,kBAAkB,EAAE,UAAU,CAAC,CAAC;;;;8BAKnD,wCAA0C;;;;;YAKzC,OAAO;;;;;;;;;;;;;;;;;;;iBASP,MAAM,OAAO,kBAAkB,EAAE,UAAU,CAAC;;;;UAC5C,OAAO;;;;;gBACP,MAAM;;;;cAEN,MAAM;;;;;;;;sCAQG,eAAe,QAAE,OAAO,2BAA2B,EAAE,OAAO,QAClF,OAAa,uBAAuB,EAAE,OAAO,KAC7C,OAAa,2BAA2B,EAAE,OAAO;;;;;mBAIrC,OAAO,GAAG,YAAY,GAAG,SAAS,GAAG,QAAQ;;;;;WAiM5C,MAAM;;;;cACN,MAAM;;;;;;WA6IN,MAAM;;;;qBACN,MAAM;;;;;sCAsEP,OAAO,eAAe,EAAE,WAAW,CAAC,OAAO,eAAe,EAAE,UAAU,EAAE,OAAO,oBAAoB,EAAE,OAAO,EAAE,MAAM,CAAC,GACjI,OAAW,eAAe,EAAE,WAAW,CAAC,OAAO,oBAAoB,EAAE,KAAK,GAC1E,eAAqB,EAAE,OAAO,WAAW,EAAE,WAAW,EAAE,MAAM,CAAC,GAC/D,OAAW,eAAe,EAAE,WAAW,CAAC,WAAW,GAAC,SAAS,GAAC,WAAW,EAAE,SAAS,EAAE,MAAM,CAAC,GAC7F,OAAW,eAAe,EAAE,mBAAmB,CAAC,OAAO,eAAe,EAAE,UAAU,GAAC,OAAO,oBAAoB,EAAE,KAAK,GACrH,eAAqB,GAAC,WAAW,GAAC,SAAS,GAAC,WAAW,EAAE,MAAM,CAAC;;;qBArZvD,MAAM;;;;;;AA8YhB;;;;;;;;GAQG;AAEH;;;;;;GAMG;AACH;IACE;;OAEG;IACH,qBAFW,OAAO,EA2VjB;IA/UC;;OAEG;IACH,IAFU,gBAAgB,OAAO,WAAW,EAAE,SAAS,CAAC,CAEjD;IAEP;;OAEG;IACH,MAFU,gBAAgB,OAAO,WAAW,EAAE,SAAS,CAAC,CAE/C;IAET;;OAEG;IACH,IAFU,gBAAgB,IAAI,CAAC,CAExB;IAEP;;;OAGG;IACH,sBAA0B;IAE1B;;;OAGG;IACH,gBAAmB;IAEnB;;;OAGG;IACH,qBAAiB;IAEjB;;;OAGG;IACH,sBAAkB;IAElB;;;;OAIG;IACH,qBAAiB;IAEjB;;;OAGG;IACH,kBAAsB;IAEtB;;;;OAIG;IACH,gBAAqD;IAErD;;;;OAIG;IACH,kBAA2D;IAE3D;;;;OAIG;IACH,uBAAwE;IAExE;;;;OAIG;IACH,cAEC;IAED;;;;OAIG;IACH,cAAgC;IAEhC;;;;;OAKG;IACH,mBAAqC;IAErC;;;;;;OAMG;IACH,mBAIK;IAEL;;;;;OAKG;IACH,mBAKc;IAEd;;;;OAIG;IACH,yBAEQ;IAER;;;OAGG;IACH,wBAEQ;IAsER;;;OAGG;IACH,0BAAyC;IAEzC;;;OAGG;IACH,yBACuE;IAEvE;;;;;OAKG;IACH,0BAA6B;IAE7B;;;;OAIG;IACH,uBAA0B;IAE1B;;;;OAIG;IACH,qBAAwB;IAExB;;;;OAIG;IACH,sBAAyB;IAEzB;;;;OAIG;IACH,oBAAuB;IAEvB;;;;OAIG;IACH,0BAA6B;IAE7B;;;;;;OAMG;IACH,+BAEM;IAEN;;;;OAIG;IACH,iBAOE;IAEF;;;;OAIG;IACH,sBAAyC;IAEzC;;;OAGG;IACH,mBAAwE;IAExE;;;OAGG;IACH,2BAAuB;IASvB;;;OAGG;IACH,wBAAoB;IAGpB;;;OAGG;IACH,oBAAkC;IAElC;;;OAGG;IACH,qBAAiE;IAKnE;;;;;OAKG;IACH,gBAHW,OAAO,GAAC,OAAO,wBAAwB,EAAE,SAAS,QAa5D;IAED;;;;;OAKG;IACH,YAFW,OAAO,WAAW,EAAE,OAAO,QAKrC;IAED;;;;OAIG;IACH,+BAEC;IA4GD;;OAEG;IACH,yBAEC;IAED;;;;OAIG;IACH,0BAkCC;IAED;;;;OAIG;IACH,sCA2BC;IAED;;;;OAIG;IACH,iCAyBC;IAED;;;;;OAKG;IACH,8BA+BC;IAED;;;;OAIG;IACH,qBAmDC;IAmDD;;;;OAIG;IACH,2BA2BC;IAED;;;;;;OAMG;IACH,kBA8CC;IAED;;;OAGG;IACH,mCAQC;IAED;;;OAGG;IACH,wCAmBC;IAED;;;;OAIG;IACH,sBAgCC;IAED;;;;OAIG;IACH,uBAwCC;IAED;;;;OAIG;IACH,sBAsCC;IAED;;OAEG;IACH,qBAFW,MAAM,QA8ChB;IAED;;;;OAIG;IACH,wBAEC;IAED;;;;;OAKG;IACH,sBA4CC;IAED;;;;OAIG;IACH,sBASC;IAED;;;OAGG;IACH,qBAKC;IAED;;;;;;;;OAQG;IACH,oDAmCC;IAED;;;;;;;;;;;OAWG;IACH,gBAHY,QAAQ,UAAU,CAAC,QAgB9B;IAED;;;OAGG;IACH,8BAcC;IAED;;OAEG;IACH,qBAOC;CACF"}
@@ -5,6 +5,7 @@ import Circle from '../geom/Circle.js';
5
5
  import Event from '../events/Event.js';
6
6
  import EventType from '../events/EventType.js';
7
7
  import Feature from '../Feature.js';
8
+ import GeometryCollection from '../geom/GeometryCollection.js';
8
9
  import InteractionProperty from './Property.js';
9
10
  import LineString from '../geom/LineString.js';
10
11
  import MapBrowserEvent from '../MapBrowserEvent.js';
@@ -18,7 +19,12 @@ import Polygon, {fromCircle, makeRegular} from '../geom/Polygon.js';
18
19
  import VectorLayer from '../layer/Vector.js';
19
20
  import VectorSource from '../source/Vector.js';
20
21
  import {FALSE, TRUE} from '../functions.js';
21
- import {always, noModifierKeys, shiftKeyOnly} from '../events/condition.js';
22
+ import {
23
+ always,
24
+ never,
25
+ noModifierKeys,
26
+ shiftKeyOnly,
27
+ } from '../events/condition.js';
22
28
  import {
23
29
  boundingExtent,
24
30
  getBottomLeft,
@@ -26,10 +32,14 @@ import {
26
32
  getTopLeft,
27
33
  getTopRight,
28
34
  } from '../extent.js';
35
+ import {clamp, squaredDistance, toFixed} from '../math.js';
29
36
  import {createEditingStyle} from '../style/Style.js';
37
+ import {
38
+ distance,
39
+ squaredDistance as squaredCoordinateDistance,
40
+ } from '../coordinate.js';
30
41
  import {fromUserCoordinate, getUserProjection} from '../proj.js';
31
42
  import {getStrideForLayout} from '../geom/SimpleGeometry.js';
32
- import {squaredDistance as squaredCoordinateDistance} from '../coordinate.js';
33
43
 
34
44
  /**
35
45
  * @typedef {Object} Options
@@ -80,6 +90,11 @@ import {squaredDistance as squaredCoordinateDistance} from '../coordinate.js';
80
90
  * returns a boolean to indicate whether that event should be handled. The
81
91
  * default is {@link module:ol/events/condition.shiftKeyOnly}, meaning that the
82
92
  * Shift key activates freehand drawing.
93
+ * @property {boolean|import("../events/condition.js").Condition} [trace=false] Trace a portion of another geometry.
94
+ * Ignored when in freehand mode.
95
+ * @property {VectorSource} [traceSource] Source for features to trace. If tracing is active and a `traceSource` is
96
+ * not provided, the interaction's `source` will be used. Tracing requires that the interaction is configured with
97
+ * either a `traceSource` or a `source`.
83
98
  * @property {boolean} [wrapX=false] Wrap the world horizontally on the sketch
84
99
  * overlay.
85
100
  * @property {import("../geom/Geometry.js").GeometryLayout} [geometryLayout='XY'] Layout of the
@@ -106,6 +121,24 @@ import {squaredDistance as squaredCoordinateDistance} from '../coordinate.js';
106
121
  * @typedef {PointCoordType|LineCoordType|PolyCoordType} SketchCoordType
107
122
  */
108
123
 
124
+ /**
125
+ * @typedef {Object} TraceState
126
+ * @property {boolean} active Tracing active.
127
+ * @property {import("../pixel.js").Pixel} [startPx] The initially clicked pixel location.
128
+ * @property {Array<TraceTarget>} [targets] Targets available for tracing.
129
+ * @property {number} [targetIndex] The index of the currently traced target. A value of -1 indicates
130
+ * that no trace target is active.
131
+ */
132
+
133
+ /**
134
+ * @typedef {Object} TraceTarget
135
+ * @property {Array<import("../coordinate.js").Coordinate>} coordinates Target coordinates.
136
+ * @property {boolean} ring The target coordinates are a linear ring.
137
+ * @property {number} startIndex The index of first traced coordinate. A fractional index represents an
138
+ * edge intersection. Index values for rings will wrap (may be negative or larger than coordinates length).
139
+ * @property {number} endIndex The index of last traced coordinate. Details from startIndex also apply here.
140
+ */
141
+
109
142
  /**
110
143
  * Function that takes an array of coordinates and an optional existing geometry
111
144
  * and a projection as arguments, and returns a geometry. The optional existing
@@ -168,6 +201,359 @@ export class DrawEvent extends Event {
168
201
  }
169
202
  }
170
203
 
204
+ /**
205
+ * @param {import("../coordinate.js").Coordinate} coordinate The coordinate.
206
+ * @param {Array<Feature>} features The candidate features.
207
+ * @return {Array<TraceTarget>} The trace targets.
208
+ */
209
+ function getTraceTargets(coordinate, features) {
210
+ /**
211
+ * @type {Array<TraceTarget>}
212
+ */
213
+ const targets = [];
214
+
215
+ for (let i = 0; i < features.length; ++i) {
216
+ const feature = features[i];
217
+ const geometry = feature.getGeometry();
218
+ appendGeometryTraceTargets(coordinate, geometry, targets);
219
+ }
220
+
221
+ return targets;
222
+ }
223
+
224
+ /**
225
+ * @param {import("../coordinate.js").Coordinate} a One coordinate.
226
+ * @param {import("../coordinate.js").Coordinate} b Another coordinate.
227
+ * @return {number} The squared distance between the two coordinates.
228
+ */
229
+ function getSquaredDistance(a, b) {
230
+ return squaredDistance(a[0], a[1], b[0], b[1]);
231
+ }
232
+
233
+ /**
234
+ * @param {LineCoordType} coordinates The ring coordinates.
235
+ * @param {number} index The index. May be wrapped.
236
+ * @return {import("../coordinate.js").Coordinate} The coordinate.
237
+ */
238
+ function getCoordinate(coordinates, index) {
239
+ const count = coordinates.length;
240
+ if (index < 0) {
241
+ return coordinates[index + count];
242
+ }
243
+ if (index >= count) {
244
+ return coordinates[index - count];
245
+ }
246
+ return coordinates[index];
247
+ }
248
+
249
+ /**
250
+ * Get the cumulative squared distance along a ring path. The end index index may be "wrapped" and it may
251
+ * be less than the start index to indicate the direction of travel. The start and end index may have
252
+ * a fractional part to indicate a point between two coordinates.
253
+ * @param {LineCoordType} coordinates Ring coordinates.
254
+ * @param {number} startIndex The start index.
255
+ * @param {number} endIndex The end index.
256
+ * @return {number} The cumulative squared distance along the ring path.
257
+ */
258
+ function getCumulativeSquaredDistance(coordinates, startIndex, endIndex) {
259
+ let lowIndex, highIndex;
260
+ if (startIndex < endIndex) {
261
+ lowIndex = startIndex;
262
+ highIndex = endIndex;
263
+ } else {
264
+ lowIndex = endIndex;
265
+ highIndex = startIndex;
266
+ }
267
+ const lowWholeIndex = Math.ceil(lowIndex);
268
+ const highWholeIndex = Math.floor(highIndex);
269
+
270
+ if (lowWholeIndex > highWholeIndex) {
271
+ // both start and end are on the same segment
272
+ const start = interpolateCoordinate(coordinates, lowIndex);
273
+ const end = interpolateCoordinate(coordinates, highIndex);
274
+ return getSquaredDistance(start, end);
275
+ }
276
+
277
+ let sd = 0;
278
+
279
+ if (lowIndex < lowWholeIndex) {
280
+ const start = interpolateCoordinate(coordinates, lowIndex);
281
+ const end = getCoordinate(coordinates, lowWholeIndex);
282
+ sd += getSquaredDistance(start, end);
283
+ }
284
+
285
+ if (highWholeIndex < highIndex) {
286
+ const start = getCoordinate(coordinates, highWholeIndex);
287
+ const end = interpolateCoordinate(coordinates, highIndex);
288
+ sd += getSquaredDistance(start, end);
289
+ }
290
+
291
+ for (let i = lowWholeIndex; i < highWholeIndex - 1; ++i) {
292
+ const start = getCoordinate(coordinates, i);
293
+ const end = getCoordinate(coordinates, i + 1);
294
+ sd += getSquaredDistance(start, end);
295
+ }
296
+
297
+ return sd;
298
+ }
299
+
300
+ /**
301
+ * @param {import("../coordinate.js").Coordinate} coordinate The coordinate.
302
+ * @param {import("../geom/Geometry.js").default} geometry The candidate geometry.
303
+ * @param {Array<TraceTarget>} targets The trace targets.
304
+ */
305
+ function appendGeometryTraceTargets(coordinate, geometry, targets) {
306
+ if (geometry instanceof LineString) {
307
+ appendTraceTarget(coordinate, geometry.getCoordinates(), false, targets);
308
+ return;
309
+ }
310
+ if (geometry instanceof MultiLineString) {
311
+ const coordinates = geometry.getCoordinates();
312
+ for (let i = 0, ii = coordinates.length; i < ii; ++i) {
313
+ appendTraceTarget(coordinate, coordinates[i], false, targets);
314
+ }
315
+ return;
316
+ }
317
+ if (geometry instanceof Polygon) {
318
+ const coordinates = geometry.getCoordinates();
319
+ for (let i = 0, ii = coordinates.length; i < ii; ++i) {
320
+ appendTraceTarget(coordinate, coordinates[i], true, targets);
321
+ }
322
+ return;
323
+ }
324
+ if (geometry instanceof MultiPolygon) {
325
+ const polys = geometry.getCoordinates();
326
+ for (let i = 0, ii = polys.length; i < ii; ++i) {
327
+ const coordinates = polys[i];
328
+ for (let j = 0, jj = coordinates.length; j < jj; ++j) {
329
+ appendTraceTarget(coordinate, coordinates[j], true, targets);
330
+ }
331
+ }
332
+ return;
333
+ }
334
+ if (geometry instanceof GeometryCollection) {
335
+ const geometries = geometry.getGeometries();
336
+ for (let i = 0; i < geometries.length; ++i) {
337
+ appendGeometryTraceTargets(coordinate, geometries[i], targets);
338
+ }
339
+ return;
340
+ }
341
+ // other types cannot be traced
342
+ }
343
+
344
+ /**
345
+ * @typedef {Object} TraceTargetUpdateInfo
346
+ * @property {number} index The new target index.
347
+ * @property {number} endIndex The new segment end index.
348
+ */
349
+
350
+ /**
351
+ * @type {TraceTargetUpdateInfo}
352
+ */
353
+ const sharedUpdateInfo = {index: -1, endIndex: NaN};
354
+
355
+ /**
356
+ * @param {import("../coordinate.js").Coordinate} coordinate The coordinate.
357
+ * @param {TraceState} traceState The trace state.
358
+ * @return {TraceTargetUpdateInfo} Information about the new trace target. The returned
359
+ * object is reused between calls and must not be modified by the caller.
360
+ */
361
+ function getTraceTargetUpdate(coordinate, traceState) {
362
+ const x = coordinate[0];
363
+ const y = coordinate[1];
364
+
365
+ let closestTargetDistance = Infinity;
366
+
367
+ let newTargetIndex = -1;
368
+ let newEndIndex = NaN;
369
+
370
+ for (
371
+ let targetIndex = 0;
372
+ targetIndex < traceState.targets.length;
373
+ ++targetIndex
374
+ ) {
375
+ const target = traceState.targets[targetIndex];
376
+ const coordinates = target.coordinates;
377
+
378
+ let minSegmentDistance = Infinity;
379
+ let endIndex;
380
+ for (
381
+ let coordinateIndex = 0;
382
+ coordinateIndex < coordinates.length - 1;
383
+ ++coordinateIndex
384
+ ) {
385
+ const start = coordinates[coordinateIndex];
386
+ const end = coordinates[coordinateIndex + 1];
387
+ const rel = getPointSegmentRelationship(x, y, start, end);
388
+ if (rel.squaredDistance < minSegmentDistance) {
389
+ minSegmentDistance = rel.squaredDistance;
390
+ endIndex = coordinateIndex + rel.along;
391
+ }
392
+ }
393
+
394
+ if (minSegmentDistance < closestTargetDistance) {
395
+ closestTargetDistance = minSegmentDistance;
396
+ if (target.ring && traceState.targetIndex === targetIndex) {
397
+ // same target, maintain the same trace direction
398
+ if (target.endIndex > target.startIndex) {
399
+ // forward trace
400
+ if (endIndex < target.startIndex) {
401
+ endIndex += coordinates.length;
402
+ }
403
+ } else if (target.endIndex < target.startIndex) {
404
+ // reverse trace
405
+ if (endIndex > target.startIndex) {
406
+ endIndex -= coordinates.length;
407
+ }
408
+ }
409
+ }
410
+ newEndIndex = endIndex;
411
+ newTargetIndex = targetIndex;
412
+ }
413
+ }
414
+
415
+ if (
416
+ traceState.targetIndex !== newTargetIndex &&
417
+ traceState.targets[newTargetIndex].ring
418
+ ) {
419
+ const target = traceState.targets[newTargetIndex];
420
+ const coordinates = target.coordinates;
421
+ const count = coordinates.length;
422
+ const startIndex = target.startIndex;
423
+ const endIndex = newEndIndex;
424
+ if (startIndex < endIndex) {
425
+ const forwardDistance = getCumulativeSquaredDistance(
426
+ coordinates,
427
+ startIndex,
428
+ endIndex
429
+ );
430
+ const reverseDistance = getCumulativeSquaredDistance(
431
+ coordinates,
432
+ startIndex,
433
+ endIndex - count
434
+ );
435
+ if (reverseDistance < forwardDistance) {
436
+ newEndIndex -= count;
437
+ }
438
+ } else {
439
+ const reverseDistance = getCumulativeSquaredDistance(
440
+ coordinates,
441
+ startIndex,
442
+ endIndex
443
+ );
444
+ const forwardDistance = getCumulativeSquaredDistance(
445
+ coordinates,
446
+ startIndex,
447
+ endIndex + count
448
+ );
449
+ if (forwardDistance < reverseDistance) {
450
+ newEndIndex += count;
451
+ }
452
+ }
453
+ }
454
+
455
+ sharedUpdateInfo.index = newTargetIndex;
456
+ sharedUpdateInfo.endIndex = newEndIndex;
457
+ return sharedUpdateInfo;
458
+ }
459
+
460
+ /**
461
+ * @param {import("../coordinate.js").Coordinate} coordinate The clicked coordinate.
462
+ * @param {Array<import("../coordinate.js").Coordinate>} coordinates The geometry component coordinates.
463
+ * @param {boolean} ring The coordinates represent a linear ring.
464
+ * @param {Array<TraceTarget>} targets The trace targets.
465
+ */
466
+ function appendTraceTarget(coordinate, coordinates, ring, targets) {
467
+ const x = coordinate[0];
468
+ const y = coordinate[1];
469
+ for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) {
470
+ const start = coordinates[i];
471
+ const end = coordinates[i + 1];
472
+ const rel = getPointSegmentRelationship(x, y, start, end);
473
+ if (rel.squaredDistance === 0) {
474
+ const index = i + rel.along;
475
+ targets.push({
476
+ coordinates: coordinates,
477
+ ring: ring,
478
+ startIndex: index,
479
+ endIndex: index,
480
+ });
481
+ return;
482
+ }
483
+ }
484
+ }
485
+
486
+ /**
487
+ * @typedef {Object} PointSegmentRelationship
488
+ * @property {number} along The closest point expressed as a fraction along the segment length.
489
+ * @property {number} squaredDistance The squared distance of the point to the segment.
490
+ */
491
+
492
+ /**
493
+ * @type {PointSegmentRelationship}
494
+ */
495
+ const sharedRel = {along: 0, squaredDistance: 0};
496
+
497
+ /**
498
+ * @param {number} x The point x.
499
+ * @param {number} y The point y.
500
+ * @param {import("../coordinate.js").Coordinate} start The segment start.
501
+ * @param {import("../coordinate.js").Coordinate} end The segment end.
502
+ * @return {PointSegmentRelationship} The point segment relationship. The returned object is
503
+ * shared between calls and must not be modified by the caller.
504
+ */
505
+ function getPointSegmentRelationship(x, y, start, end) {
506
+ const x1 = start[0];
507
+ const y1 = start[1];
508
+ const x2 = end[0];
509
+ const y2 = end[1];
510
+ const dx = x2 - x1;
511
+ const dy = y2 - y1;
512
+ let along = 0;
513
+ let px = x1;
514
+ let py = y1;
515
+ if (dx !== 0 || dy !== 0) {
516
+ along = clamp(((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy), 0, 1);
517
+ px += dx * along;
518
+ py += dy * along;
519
+ }
520
+
521
+ sharedRel.along = along;
522
+ sharedRel.squaredDistance = toFixed(squaredDistance(x, y, px, py), 10);
523
+ return sharedRel;
524
+ }
525
+
526
+ /**
527
+ * @param {LineCoordType} coordinates The coordinates.
528
+ * @param {number} index The index. May be fractional and may wrap.
529
+ * @return {import("../coordinate.js").Coordinate} The interpolated coordinate.
530
+ */
531
+ function interpolateCoordinate(coordinates, index) {
532
+ const count = coordinates.length;
533
+
534
+ let startIndex = Math.floor(index);
535
+ const along = index - startIndex;
536
+ if (startIndex >= count) {
537
+ startIndex -= count;
538
+ } else if (startIndex < 0) {
539
+ startIndex += count;
540
+ }
541
+
542
+ let endIndex = startIndex + 1;
543
+ if (endIndex >= count) {
544
+ endIndex -= count;
545
+ }
546
+
547
+ const start = coordinates[startIndex];
548
+ const x0 = start[0];
549
+ const y0 = start[1];
550
+ const end = coordinates[endIndex];
551
+ const dx = end[0] - x0;
552
+ const dy = end[1] - y0;
553
+
554
+ return [x0 + dx * along, y0 + dy * along];
555
+ }
556
+
171
557
  /***
172
558
  * @template Return
173
559
  * @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> &
@@ -514,9 +900,46 @@ class Draw extends PointerInteraction {
514
900
  : shiftKeyOnly;
515
901
  }
516
902
 
903
+ /**
904
+ * @type {import("../events/condition.js").Condition}
905
+ * @private
906
+ */
907
+ this.traceCondition_;
908
+ this.setTrace(options.trace || false);
909
+
910
+ /**
911
+ * @type {TraceState}
912
+ * @private
913
+ */
914
+ this.traceState_ = {active: false};
915
+
916
+ /**
917
+ * @type {VectorSource|null}
918
+ * @private
919
+ */
920
+ this.traceSource_ = options.traceSource || options.source || null;
921
+
517
922
  this.addChangeListener(InteractionProperty.ACTIVE, this.updateState_);
518
923
  }
519
924
 
925
+ /**
926
+ * Toggle tracing mode or set a tracing condition.
927
+ *
928
+ * @param {boolean|import("../events/condition.js").Condition} trace A boolean to toggle tracing mode or an event
929
+ * condition that will be checked when a feature is clicked to determine if tracing should be active.
930
+ */
931
+ setTrace(trace) {
932
+ let condition;
933
+ if (!trace) {
934
+ condition = never;
935
+ } else if (trace === true) {
936
+ condition = always;
937
+ } else {
938
+ condition = trace;
939
+ }
940
+ this.traceCondition_ = condition;
941
+ }
942
+
520
943
  /**
521
944
  * Remove the interaction from its current map and attach it to the new map.
522
945
  * Subclasses may set up event handlers to get notified about changes to
@@ -617,28 +1040,241 @@ class Draw extends PointerInteraction {
617
1040
  this.startDrawing_(event.coordinate);
618
1041
  }
619
1042
  return true;
620
- } else if (this.condition_(event)) {
621
- this.lastDragTime_ = Date.now();
622
- this.downTimeout_ = setTimeout(
623
- function () {
624
- this.handlePointerMove_(
625
- new MapBrowserEvent(
626
- MapBrowserEventType.POINTERMOVE,
627
- event.map,
628
- event.originalEvent,
629
- false,
630
- event.frameState
631
- )
632
- );
633
- }.bind(this),
634
- this.dragVertexDelay_
635
- );
636
- this.downPx_ = event.pixel;
637
- return true;
638
- } else {
1043
+ }
1044
+
1045
+ if (!this.condition_(event)) {
639
1046
  this.lastDragTime_ = undefined;
640
1047
  return false;
641
1048
  }
1049
+
1050
+ this.lastDragTime_ = Date.now();
1051
+ this.downTimeout_ = setTimeout(
1052
+ function () {
1053
+ this.handlePointerMove_(
1054
+ new MapBrowserEvent(
1055
+ MapBrowserEventType.POINTERMOVE,
1056
+ event.map,
1057
+ event.originalEvent,
1058
+ false,
1059
+ event.frameState
1060
+ )
1061
+ );
1062
+ }.bind(this),
1063
+ this.dragVertexDelay_
1064
+ );
1065
+ this.downPx_ = event.pixel;
1066
+ return true;
1067
+ }
1068
+
1069
+ /**
1070
+ * @private
1071
+ */
1072
+ deactivateTrace_() {
1073
+ this.traceState_ = {active: false};
1074
+ }
1075
+
1076
+ /**
1077
+ * Activate or deactivate trace state based on a browser event.
1078
+ * @param {import("../MapBrowserEvent.js").default} event Event.
1079
+ * @private
1080
+ */
1081
+ toggleTraceState_(event) {
1082
+ if (!this.traceSource_ || !this.traceCondition_(event)) {
1083
+ return;
1084
+ }
1085
+
1086
+ if (this.traceState_.active) {
1087
+ this.deactivateTrace_();
1088
+ return;
1089
+ }
1090
+
1091
+ const map = this.getMap();
1092
+ const lowerLeft = map.getCoordinateFromPixel([
1093
+ event.pixel[0] - this.snapTolerance_,
1094
+ event.pixel[1] + this.snapTolerance_,
1095
+ ]);
1096
+ const upperRight = map.getCoordinateFromPixel([
1097
+ event.pixel[0] + this.snapTolerance_,
1098
+ event.pixel[1] - this.snapTolerance_,
1099
+ ]);
1100
+ const extent = boundingExtent([lowerLeft, upperRight]);
1101
+ const features = this.traceSource_.getFeaturesInExtent(extent);
1102
+ if (features.length === 0) {
1103
+ return;
1104
+ }
1105
+
1106
+ const targets = getTraceTargets(event.coordinate, features);
1107
+ if (targets.length) {
1108
+ this.traceState_ = {
1109
+ active: true,
1110
+ startPx: event.pixel.slice(),
1111
+ targets: targets,
1112
+ targetIndex: -1,
1113
+ };
1114
+ }
1115
+ }
1116
+
1117
+ /**
1118
+ * @param {TraceTarget} target The trace target.
1119
+ * @param {number} endIndex The new end index of the trace.
1120
+ * @private
1121
+ */
1122
+ addOrRemoveTracedCoordinates_(target, endIndex) {
1123
+ // three cases to handle:
1124
+ // 1. traced in the same direction and points need adding
1125
+ // 2. traced in the same direction and points need removing
1126
+ // 3. traced in a new direction
1127
+ const previouslyForward = target.startIndex <= target.endIndex;
1128
+ const currentlyForward = target.startIndex <= endIndex;
1129
+ if (previouslyForward === currentlyForward) {
1130
+ // same direction
1131
+ if (
1132
+ (previouslyForward && endIndex > target.endIndex) ||
1133
+ (!previouslyForward && endIndex < target.endIndex)
1134
+ ) {
1135
+ // case 1 - add new points
1136
+ this.addTracedCoordinates_(target, target.endIndex, endIndex);
1137
+ } else if (
1138
+ (previouslyForward && endIndex < target.endIndex) ||
1139
+ (!previouslyForward && endIndex > target.endIndex)
1140
+ ) {
1141
+ // case 2 - remove old points
1142
+ this.removeTracedCoordinates_(endIndex, target.endIndex);
1143
+ }
1144
+ } else {
1145
+ // case 3 - remove old points, add new points
1146
+ this.removeTracedCoordinates_(target.startIndex, target.endIndex);
1147
+ this.addTracedCoordinates_(target, target.startIndex, endIndex);
1148
+ }
1149
+ }
1150
+
1151
+ /**
1152
+ * @param {number} fromIndex The start index.
1153
+ * @param {number} toIndex The end index.
1154
+ * @private
1155
+ */
1156
+ removeTracedCoordinates_(fromIndex, toIndex) {
1157
+ if (fromIndex === toIndex) {
1158
+ return;
1159
+ }
1160
+
1161
+ let remove = 0;
1162
+ if (fromIndex < toIndex) {
1163
+ const start = Math.ceil(fromIndex);
1164
+ let end = Math.floor(toIndex);
1165
+ if (end === toIndex) {
1166
+ end -= 1;
1167
+ }
1168
+ remove = end - start + 1;
1169
+ } else {
1170
+ const start = Math.floor(fromIndex);
1171
+ let end = Math.ceil(toIndex);
1172
+ if (end === toIndex) {
1173
+ end += 1;
1174
+ }
1175
+ remove = start - end + 1;
1176
+ }
1177
+
1178
+ if (remove > 0) {
1179
+ this.removeLastPoints_(remove);
1180
+ }
1181
+ }
1182
+
1183
+ /**
1184
+ * @param {TraceTarget} target The trace target.
1185
+ * @param {number} fromIndex The start index.
1186
+ * @param {number} toIndex The end index.
1187
+ * @private
1188
+ */
1189
+ addTracedCoordinates_(target, fromIndex, toIndex) {
1190
+ if (fromIndex === toIndex) {
1191
+ return;
1192
+ }
1193
+
1194
+ const coordinates = [];
1195
+ if (fromIndex < toIndex) {
1196
+ // forward trace
1197
+ const start = Math.ceil(fromIndex);
1198
+ let end = Math.floor(toIndex);
1199
+ if (end === toIndex) {
1200
+ // if end is snapped to a vertex, it will be added later
1201
+ end -= 1;
1202
+ }
1203
+ for (let i = start; i <= end; ++i) {
1204
+ coordinates.push(getCoordinate(target.coordinates, i));
1205
+ }
1206
+ } else {
1207
+ // reverse trace
1208
+ const start = Math.floor(fromIndex);
1209
+ let end = Math.ceil(toIndex);
1210
+ if (end === toIndex) {
1211
+ end += 1;
1212
+ }
1213
+ for (let i = start; i >= end; --i) {
1214
+ coordinates.push(getCoordinate(target.coordinates, i));
1215
+ }
1216
+ }
1217
+ if (coordinates.length) {
1218
+ this.appendCoordinates(coordinates);
1219
+ }
1220
+ }
1221
+
1222
+ /**
1223
+ * Update the trace.
1224
+ * @param {import("../MapBrowserEvent.js").default} event Event.
1225
+ * @private
1226
+ */
1227
+ updateTrace_(event) {
1228
+ const traceState = this.traceState_;
1229
+ if (!traceState.active) {
1230
+ return;
1231
+ }
1232
+
1233
+ if (traceState.targetIndex === -1) {
1234
+ // check if we are ready to pick a target
1235
+ if (distance(traceState.startPx, event.pixel) < this.snapTolerance_) {
1236
+ return;
1237
+ }
1238
+ }
1239
+
1240
+ const updatedTraceTarget = getTraceTargetUpdate(
1241
+ event.coordinate,
1242
+ traceState
1243
+ );
1244
+
1245
+ if (traceState.targetIndex !== updatedTraceTarget.index) {
1246
+ // target changed
1247
+ if (traceState.targetIndex !== -1) {
1248
+ // remove points added during previous trace
1249
+ const oldTarget = traceState.targets[traceState.targetIndex];
1250
+ this.removeTracedCoordinates_(oldTarget.startIndex, oldTarget.endIndex);
1251
+ }
1252
+ // add points for the new target
1253
+ const newTarget = traceState.targets[updatedTraceTarget.index];
1254
+ this.addTracedCoordinates_(
1255
+ newTarget,
1256
+ newTarget.startIndex,
1257
+ updatedTraceTarget.endIndex
1258
+ );
1259
+ } else {
1260
+ // target stayed the same
1261
+ const target = traceState.targets[traceState.targetIndex];
1262
+ this.addOrRemoveTracedCoordinates_(target, updatedTraceTarget.endIndex);
1263
+ }
1264
+
1265
+ // modify the state with updated info
1266
+ traceState.targetIndex = updatedTraceTarget.index;
1267
+ const target = traceState.targets[traceState.targetIndex];
1268
+ target.endIndex = updatedTraceTarget.endIndex;
1269
+
1270
+ // update event coordinate and pixel to match end point of final segment
1271
+ const coordinate = interpolateCoordinate(
1272
+ target.coordinates,
1273
+ target.endIndex
1274
+ );
1275
+ const pixel = this.getMap().getPixelFromCoordinate(coordinate);
1276
+ event.coordinate = coordinate;
1277
+ event.pixel = [Math.round(pixel[0]), Math.round(pixel[1])];
642
1278
  }
643
1279
 
644
1280
  /**
@@ -656,6 +1292,8 @@ class Draw extends PointerInteraction {
656
1292
  }
657
1293
 
658
1294
  this.handlePointerMove_(event);
1295
+ const tracing = this.traceState_.active;
1296
+ this.toggleTraceState_(event);
659
1297
 
660
1298
  if (this.shouldHandle_) {
661
1299
  const startingToDraw = !this.finishCoordinate_;
@@ -668,7 +1306,7 @@ class Draw extends PointerInteraction {
668
1306
  !this.freehand_ &&
669
1307
  (!startingToDraw || this.mode_ === 'Point')
670
1308
  ) {
671
- if (this.atFinish_(event.pixel)) {
1309
+ if (this.atFinish_(event.pixel, tracing)) {
672
1310
  if (this.finishCondition_(event)) {
673
1311
  this.finishDrawing();
674
1312
  }
@@ -713,20 +1351,23 @@ class Draw extends PointerInteraction {
713
1351
  }
714
1352
  }
715
1353
 
716
- if (this.finishCoordinate_) {
717
- this.modifyDrawing_(event.coordinate);
718
- } else {
1354
+ if (!this.finishCoordinate_) {
719
1355
  this.createOrUpdateSketchPoint_(event.coordinate.slice());
1356
+ return;
720
1357
  }
1358
+
1359
+ this.updateTrace_(event);
1360
+ this.modifyDrawing_(event.coordinate);
721
1361
  }
722
1362
 
723
1363
  /**
724
1364
  * Determine if an event is within the snapping tolerance of the start coord.
725
1365
  * @param {import("../pixel.js").Pixel} pixel Pixel.
1366
+ * @param {boolean} [tracing] Drawing in trace mode (only stop if at the starting point).
726
1367
  * @return {boolean} The event is within the snapping tolerance of the start.
727
1368
  * @private
728
1369
  */
729
- atFinish_(pixel) {
1370
+ atFinish_(pixel, tracing) {
730
1371
  let at = false;
731
1372
  if (this.sketchFeature_) {
732
1373
  let potentiallyDone = false;
@@ -737,7 +1378,8 @@ class Draw extends PointerInteraction {
737
1378
  } else if (mode === 'Circle') {
738
1379
  at = this.sketchCoords_.length === 2;
739
1380
  } else if (mode === 'LineString') {
740
- potentiallyDone = this.sketchCoords_.length > this.minPoints_;
1381
+ potentiallyDone =
1382
+ !tracing && this.sketchCoords_.length > this.minPoints_;
741
1383
  } else if (mode === 'Polygon') {
742
1384
  const sketchCoords = /** @type {PolyCoordType} */ (this.sketchCoords_);
743
1385
  potentiallyDone = sketchCoords[0].length > this.minPoints_;
@@ -745,6 +1387,14 @@ class Draw extends PointerInteraction {
745
1387
  sketchCoords[0][0],
746
1388
  sketchCoords[0][sketchCoords[0].length - 2],
747
1389
  ];
1390
+ if (tracing) {
1391
+ potentiallyFinishCoordinates = [sketchCoords[0][0]];
1392
+ } else {
1393
+ potentiallyFinishCoordinates = [
1394
+ sketchCoords[0][0],
1395
+ sketchCoords[0][sketchCoords[0].length - 2],
1396
+ ];
1397
+ }
748
1398
  }
749
1399
  if (potentiallyDone) {
750
1400
  const map = this.getMap();
@@ -936,51 +1586,63 @@ class Draw extends PointerInteraction {
936
1586
  }
937
1587
 
938
1588
  /**
939
- * Remove last point of the feature currently being drawn. Does not do anything when
940
- * drawing POINT or MULTI_POINT geometries.
941
- * @api
1589
+ * @param {number} n The number of points to remove.
942
1590
  */
943
- removeLastPoint() {
1591
+ removeLastPoints_(n) {
944
1592
  if (!this.sketchFeature_) {
945
1593
  return;
946
1594
  }
947
1595
  const geometry = this.sketchFeature_.getGeometry();
948
1596
  const projection = this.getMap().getView().getProjection();
949
- let coordinates;
950
1597
  const mode = this.mode_;
951
- if (mode === 'LineString' || mode === 'Circle') {
952
- coordinates = /** @type {LineCoordType} */ (this.sketchCoords_);
953
- coordinates.splice(-2, 1);
954
- if (coordinates.length >= 2) {
955
- this.finishCoordinate_ = coordinates[coordinates.length - 2].slice();
956
- const finishCoordinate = this.finishCoordinate_.slice();
957
- coordinates[coordinates.length - 1] = finishCoordinate;
958
- this.createOrUpdateSketchPoint_(finishCoordinate);
959
- }
960
- this.geometryFunction_(coordinates, geometry, projection);
961
- if (geometry.getType() === 'Polygon' && this.sketchLine_) {
962
- this.createOrUpdateCustomSketchLine_(/** @type {Polygon} */ (geometry));
963
- }
964
- } else if (mode === 'Polygon') {
965
- coordinates = /** @type {PolyCoordType} */ (this.sketchCoords_)[0];
966
- coordinates.splice(-2, 1);
967
- const sketchLineGeom = this.sketchLine_.getGeometry();
968
- if (coordinates.length >= 2) {
969
- const finishCoordinate = coordinates[coordinates.length - 2].slice();
970
- coordinates[coordinates.length - 1] = finishCoordinate;
971
- this.createOrUpdateSketchPoint_(finishCoordinate);
1598
+ for (let i = 0; i < n; ++i) {
1599
+ let coordinates;
1600
+ if (mode === 'LineString' || mode === 'Circle') {
1601
+ coordinates = /** @type {LineCoordType} */ (this.sketchCoords_);
1602
+ coordinates.splice(-2, 1);
1603
+ if (coordinates.length >= 2) {
1604
+ this.finishCoordinate_ = coordinates[coordinates.length - 2].slice();
1605
+ const finishCoordinate = this.finishCoordinate_.slice();
1606
+ coordinates[coordinates.length - 1] = finishCoordinate;
1607
+ this.createOrUpdateSketchPoint_(finishCoordinate);
1608
+ }
1609
+ this.geometryFunction_(coordinates, geometry, projection);
1610
+ if (geometry.getType() === 'Polygon' && this.sketchLine_) {
1611
+ this.createOrUpdateCustomSketchLine_(
1612
+ /** @type {Polygon} */ (geometry)
1613
+ );
1614
+ }
1615
+ } else if (mode === 'Polygon') {
1616
+ coordinates = /** @type {PolyCoordType} */ (this.sketchCoords_)[0];
1617
+ coordinates.splice(-2, 1);
1618
+ const sketchLineGeom = this.sketchLine_.getGeometry();
1619
+ if (coordinates.length >= 2) {
1620
+ const finishCoordinate = coordinates[coordinates.length - 2].slice();
1621
+ coordinates[coordinates.length - 1] = finishCoordinate;
1622
+ this.createOrUpdateSketchPoint_(finishCoordinate);
1623
+ }
1624
+ sketchLineGeom.setCoordinates(coordinates);
1625
+ this.geometryFunction_(this.sketchCoords_, geometry, projection);
972
1626
  }
973
- sketchLineGeom.setCoordinates(coordinates);
974
- this.geometryFunction_(this.sketchCoords_, geometry, projection);
975
- }
976
1627
 
977
- if (coordinates.length === 1) {
978
- this.abortDrawing();
1628
+ if (coordinates.length === 1) {
1629
+ this.abortDrawing();
1630
+ break;
1631
+ }
979
1632
  }
980
1633
 
981
1634
  this.updateSketchFeatures_();
982
1635
  }
983
1636
 
1637
+ /**
1638
+ * Remove last point of the feature currently being drawn. Does not do anything when
1639
+ * drawing POINT or MULTI_POINT geometries.
1640
+ * @api
1641
+ */
1642
+ removeLastPoint() {
1643
+ this.removeLastPoints_(1);
1644
+ }
1645
+
984
1646
  /**
985
1647
  * Stop drawing and add the sketch feature to the target layer.
986
1648
  * The {@link module:ol/interaction/Draw~DrawEventType.DRAWEND} event is
@@ -1045,6 +1707,7 @@ class Draw extends PointerInteraction {
1045
1707
  this.sketchPoint_ = null;
1046
1708
  this.sketchLine_ = null;
1047
1709
  this.overlay_.getSource().clear(true);
1710
+ this.deactivateTrace_();
1048
1711
  return sketchFeature;
1049
1712
  }
1050
1713
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ol",
3
- "version": "7.0.1-dev.1661277132609",
3
+ "version": "7.0.1-dev.1661440420569",
4
4
  "description": "OpenLayers mapping library",
5
5
  "keywords": [
6
6
  "map",
@@ -1 +1 @@
1
- {"version":3,"file":"TileLayer.d.ts","sourceRoot":"","sources":["TileLayer.js"],"names":[],"mappings":";AA8BA;;;;;;GAMG;AACH;IACE;;OAEG;IACH,uBAFW,SAAS,EA0DnB;IArDC;;;OAGG;IACH,eAFU,OAAO,CAEQ;IAEzB;;;OAGG;IACH,wBAA2B;IAE3B;;;OAGG;IACH,8BAFU,MAAM,CAEO;IAEvB;;;OAGG;IACH,8BAFU,OAAO,0BAA0B,EAAE,OAAO,CAEtB;IAE9B;;;OAGG;IACH,4BAFU,MAAM,CAEK;IAErB;;;OAGG;IACH,yBAFW,MAAM,OAAO,eAAe,EAAE,OAAO,CAAC,CAE1B;IAEvB;;;OAGG;IACH,kBAAsB;IAEtB;;;OAGG;IACH,qBAFU,OAAO,iBAAiB,EAAE,MAAM,CAEZ;IAE9B;;;OAGG;IACH,sBAA8C;IAGhD;;;;OAIG;IACH,+BAHW,OAAO,eAAe,EAAE,OAAO,GAC9B,OAAO,CAWlB;IAED;;;;;;OAMG;IACH,WANW,MAAM,KACN,MAAM,KACN,MAAM,cACN,OAAO,cAAc,EAAE,UAAU,GAC/B,OAAO,eAAe,EAAE,OAAO,CAkB3C;IAED;;;OAGG;IACH,eAHW,OAAO,gBAAgB,EAAE,KAAK,GAC7B,iBAAiB,CAyE5B;IAoWD;;;;;;;;;OASG;IACH,oBATW,OAAO,oBAAoB,EAAE,OAAO,cACpC,OAAO,cAAc,EAAE,UAAU,KACjC,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,UACN,MAAM,cACN,OAAO,QAqCjB;IAED;;OAEG;IACH,YAFY,iBAAiB,CAK5B;IAED;;;;;OAKG;IACH,6BAJW,OAAO,oBAAoB,EAAE,OAAO,GACnC,iBAAiB,GAAC,gBAAgB,GAAC,gBAAgB,CAK9D;IAED;;;;OAIG;IACH,0CAJW,OAAO,cAAc,EAAE,UAAU,cACjC,OAAO,sBAAsB,EAAE,OAAO,QA0BhD;IAED;;;;;OAKG;IACH;YALmB,MAAM;gBAAU,MAAM,GAAE,OAAO;;mBACvC,OAAO,sBAAsB,EAAE,OAAO,QACtC,OAAO,eAAe,EAAE,OAAO,QAUzC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,wCAXW,OAAO,cAAc,EAAE,UAAU,cACjC,OAAO,sBAAsB,EAAE,OAAO,YACtC,OAAO,4BAA4B,EAAE,OAAO,cAC5C,MAAM,cACN,OAAO,0BAA0B,EAAE,OAAO,UAC1C,OAAO,iBAAiB,EAAE,MAAM,YAChC,MAAM,WACN,MAAM,yBACG,OAAO,eAAe,EAAE,OAAO,KAAE,IAAI,qBAmExD;CACF"}
1
+ {"version":3,"file":"TileLayer.d.ts","sourceRoot":"","sources":["TileLayer.js"],"names":[],"mappings":";AA8BA;;;;;;GAMG;AACH;IACE;;OAEG;IACH,uBAFW,SAAS,EA0DnB;IArDC;;;OAGG;IACH,eAFU,OAAO,CAEQ;IAEzB;;;OAGG;IACH,wBAA2B;IAE3B;;;OAGG;IACH,8BAFU,MAAM,CAEO;IAEvB;;;OAGG;IACH,8BAFU,OAAO,0BAA0B,EAAE,OAAO,CAEtB;IAE9B;;;OAGG;IACH,4BAFU,MAAM,CAEK;IAErB;;;OAGG;IACH,yBAFW,MAAM,OAAO,eAAe,EAAE,OAAO,CAAC,CAE1B;IAEvB;;;OAGG;IACH,kBAAsB;IAEtB;;;OAGG;IACH,qBAFU,OAAO,iBAAiB,EAAE,MAAM,CAEZ;IAE9B;;;OAGG;IACH,sBAA8C;IAGhD;;;;OAIG;IACH,+BAHW,OAAO,eAAe,EAAE,OAAO,GAC9B,OAAO,CAWlB;IAED;;;;;;OAMG;IACH,WANW,MAAM,KACN,MAAM,KACN,MAAM,cACN,OAAO,cAAc,EAAE,UAAU,GAC/B,OAAO,eAAe,EAAE,OAAO,CAkB3C;IAED;;;OAGG;IACH,eAHW,OAAO,gBAAgB,EAAE,KAAK,GAC7B,iBAAiB,CA4E5B;IAoWD;;;;;;;;;OASG;IACH,oBATW,OAAO,oBAAoB,EAAE,OAAO,cACpC,OAAO,cAAc,EAAE,UAAU,KACjC,MAAM,KACN,MAAM,KACN,MAAM,KACN,MAAM,UACN,MAAM,cACN,OAAO,QAqCjB;IAED;;OAEG;IACH,YAFY,iBAAiB,CAK5B;IAED;;;;;OAKG;IACH,6BAJW,OAAO,oBAAoB,EAAE,OAAO,GACnC,iBAAiB,GAAC,gBAAgB,GAAC,gBAAgB,CAK9D;IAED;;;;OAIG;IACH,0CAJW,OAAO,cAAc,EAAE,UAAU,cACjC,OAAO,sBAAsB,EAAE,OAAO,QA0BhD;IAED;;;;;OAKG;IACH;YALmB,MAAM;gBAAU,MAAM,GAAE,OAAO;;mBACvC,OAAO,sBAAsB,EAAE,OAAO,QACtC,OAAO,eAAe,EAAE,OAAO,QAUzC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,wCAXW,OAAO,cAAc,EAAE,UAAU,cACjC,OAAO,sBAAsB,EAAE,OAAO,YACtC,OAAO,4BAA4B,EAAE,OAAO,cAC5C,MAAM,cACN,OAAO,0BAA0B,EAAE,OAAO,UAC1C,OAAO,iBAAiB,EAAE,MAAM,YAChC,MAAM,WACN,MAAM,yBACG,OAAO,eAAe,EAAE,OAAO,KAAE,IAAI,qBAmExD;CACF"}
@@ -181,7 +181,10 @@ class CanvasTileLayerRenderer extends CanvasLayerRenderer {
181
181
  pixelRatio,
182
182
  projection
183
183
  );
184
- if (!(tile instanceof ImageTile || tile instanceof ReprojTile)) {
184
+ if (
185
+ !(tile instanceof ImageTile || tile instanceof ReprojTile) ||
186
+ (tile instanceof ReprojTile && tile.getState() === TileState.EMPTY)
187
+ ) {
185
188
  return null;
186
189
  }
187
190
 
@@ -158,10 +158,11 @@ declare class WebGLTileLayerRenderer extends WebGLLayerRenderer<import("../../la
158
158
  * @param {import("../../extent.js").Extent} extent The extent to be rendered.
159
159
  * @param {number} initialZ The zoom level.
160
160
  * @param {Object<number, Array<TileTexture>>} tileTexturesByZ The zoom level.
161
+ * @param {number} preload Number of additional levels to load.
161
162
  */
162
163
  enqueueTiles(frameState: import("../../Map.js").FrameState, extent: import("../../extent.js").Extent, initialZ: number, tileTexturesByZ: {
163
164
  [x: number]: Array<TileTexture>;
164
- }): void;
165
+ }, preload: number): void;
165
166
  /**
166
167
  * Render the layer.
167
168
  * @param {import("../../Map.js").FrameState} frameState Frame state.
@@ -1 +1 @@
1
- {"version":3,"file":"TileLayer.d.ts","sourceRoot":"","sources":["TileLayer.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;kBAiIc,MAAM;;;;oBACN,MAAM;;;;;;;;;;;;;;;;;wBAQP,OAAO,0BAA0B,EAAE,OAAO;AAXvD;;;;;;;;GAQG;AAEH;;GAEG;AAEH;;;;;GAKG;AACH;IACE;;;OAGG;IACH,uBAHW,SAAS,WACT,OAAO,EAmGjB;IA5FC;;;OAGG;IACH,gBAFU,OAAO,CAEU;IAE3B;;;;OAIG;IACH,uBAAuC;IAEvC;;;OAGG;IACH,kBAA6B;IAE7B;;;OAGG;IACH,uBAA+C;IAE/C;;;OAGG;IACH,uBAA8C;IAE9C;;;OAGG;IACH,kBAAuB;IAEvB;;;OAGG;IACH,iBAAa;IAEb;;OAEG;IACH,sBAAyC;IAEzC;;OAEG;IACH,wBAA6C;IAE7C;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAuE;IAKvE;;;OAGG;IACH,0BAAgD;IAEhD;;;OAGG;IACH,yBAAqD;IAErD;;;OAGG;IACH,oBAAuB;IAGzB;;OAEG;IACH,eAFW,OAAO,QAgBjB;IAWD;;;;OAIG;IACH,wBASC;IAoBD;;;;;OAKG;IACH,yBALW,OAAO,cAAc,EAAE,UAAU,UACjC,OAAO,iBAAiB,EAAE,MAAM,YAChC,MAAM;YACC,MAAM,GAAE,MAAM,WAAW,CAAC;aA6F3C;IAED;;;;OAIG;IACH,wBAHW,OAAO,cAAc,EAAE,UAAU,GAChC,WAAW,CA6QtB;IAED;;;OAGG;IACH,eAHW,OAAO,gBAAgB,EAAE,KAAK,GAC7B,iBAAiB,GAAC,UAAU,GAAC,YAAY,GAAC,QAAQ,CAqF7D;IAED;;;;;;;;;;OAUG;IACH,sBA+BC;CA+BF"}
1
+ {"version":3,"file":"TileLayer.d.ts","sourceRoot":"","sources":["TileLayer.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;kBAkIc,MAAM;;;;oBACN,MAAM;;;;;;;;;;;;;;;;;wBAQP,OAAO,0BAA0B,EAAE,OAAO;AAXvD;;;;;;;;GAQG;AAEH;;GAEG;AAEH;;;;;GAKG;AACH;IACE;;;OAGG;IACH,uBAHW,SAAS,WACT,OAAO,EAmGjB;IA5FC;;;OAGG;IACH,gBAFU,OAAO,CAEU;IAE3B;;;;OAIG;IACH,uBAAuC;IAEvC;;;OAGG;IACH,kBAA6B;IAE7B;;;OAGG;IACH,uBAA+C;IAE/C;;;OAGG;IACH,uBAA8C;IAE9C;;;OAGG;IACH,kBAAuB;IAEvB;;;OAGG;IACH,iBAAa;IAEb;;OAEG;IACH,sBAAyC;IAEzC;;OAEG;IACH,wBAA6C;IAE7C;;;;;;;;;;;;;;;;OAgBG;IACH,iBAAuE;IAKvE;;;OAGG;IACH,0BAAgD;IAEhD;;;OAGG;IACH,yBAAqD;IAErD;;;OAGG;IACH,oBAAuB;IAGzB;;OAEG;IACH,eAFW,OAAO,QAgBjB;IAWD;;;;OAIG;IACH,wBASC;IAoBD;;;;;;OAMG;IACH,yBANW,OAAO,cAAc,EAAE,UAAU,UACjC,OAAO,iBAAiB,EAAE,MAAM,YAChC,MAAM;YACC,MAAM,GAAE,MAAM,WAAW,CAAC;gBACjC,MAAM,QAwGhB;IAED;;;;OAIG;IACH,wBAHW,OAAO,cAAc,EAAE,UAAU,GAChC,WAAW,CAkStB;IAED;;;OAGG;IACH,eAHW,OAAO,gBAAgB,EAAE,KAAK,GAC7B,iBAAiB,GAAC,UAAU,GAAC,YAAY,GAAC,QAAQ,CAyF7D;IAED;;;;;;;;;;OAUG;IACH,sBA+BC;CA+BF"}
@@ -2,6 +2,7 @@
2
2
  * @module ol/renderer/webgl/TileLayer
3
3
  */
4
4
  import LRUCache from '../../structs/LRUCache.js';
5
+ import ReprojTile from '../../reproj/Tile.js';
5
6
  import TileRange from '../../TileRange.js';
6
7
  import TileState from '../../TileState.js';
7
8
  import TileTexture from '../../webgl/TileTexture.js';
@@ -316,8 +317,9 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
316
317
  * @param {import("../../extent.js").Extent} extent The extent to be rendered.
317
318
  * @param {number} initialZ The zoom level.
318
319
  * @param {Object<number, Array<TileTexture>>} tileTexturesByZ The zoom level.
320
+ * @param {number} preload Number of additional levels to load.
319
321
  */
320
- enqueueTiles(frameState, extent, initialZ, tileTexturesByZ) {
322
+ enqueueTiles(frameState, extent, initialZ, tileTexturesByZ, preload) {
321
323
  const viewState = frameState.viewState;
322
324
  const tileLayer = this.getLayer();
323
325
  const tileSource = tileLayer.getRenderSource();
@@ -330,12 +332,23 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
330
332
  }
331
333
 
332
334
  const wantedTiles = frameState.wantedTiles[tileSourceKey];
333
-
334
335
  const tileTextureCache = this.tileTextureCache_;
336
+
337
+ const map = tileLayer.getMapInternal();
335
338
  const minZ = Math.max(
336
- initialZ - tileLayer.getPreload(),
339
+ initialZ - preload,
337
340
  tileGrid.getMinZoom(),
338
- tileLayer.getMinZoom()
341
+ tileGrid.getZForResolution(
342
+ Math.min(
343
+ tileLayer.getMaxResolution(),
344
+ map
345
+ ? map
346
+ .getView()
347
+ .getResolutionForZoom(Math.max(tileLayer.getMinZoom(), 0))
348
+ : tileGrid.getResolution(0)
349
+ ),
350
+ tileSource.zDirection
351
+ )
339
352
  );
340
353
  for (let z = initialZ; z >= minZ; --z) {
341
354
  const tileRange = tileGrid.getTileRangeForExtentAndZ(
@@ -437,16 +450,34 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
437
450
  */
438
451
  const tileTexturesByZ = {};
439
452
 
453
+ const preload = tileLayer.getPreload();
440
454
  if (frameState.nextExtent) {
441
455
  const targetZ = tileGrid.getZForResolution(
442
456
  viewState.nextResolution,
443
457
  tileSource.zDirection
444
458
  );
445
459
  const nextExtent = getRenderExtent(frameState, frameState.nextExtent);
446
- this.enqueueTiles(frameState, nextExtent, targetZ, tileTexturesByZ);
460
+ this.enqueueTiles(
461
+ frameState,
462
+ nextExtent,
463
+ targetZ,
464
+ tileTexturesByZ,
465
+ preload
466
+ );
447
467
  }
448
468
 
449
- this.enqueueTiles(frameState, extent, z, tileTexturesByZ);
469
+ this.enqueueTiles(frameState, extent, z, tileTexturesByZ, 0);
470
+ if (preload > 0) {
471
+ setTimeout(() => {
472
+ this.enqueueTiles(
473
+ frameState,
474
+ extent,
475
+ z - 1,
476
+ tileTexturesByZ,
477
+ preload - 1
478
+ );
479
+ }, 0);
480
+ }
450
481
 
451
482
  /**
452
483
  * A lookup of alpha values for tiles at the target rendering resolution
@@ -465,6 +496,9 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
465
496
  for (let i = 0, ii = tileTextures.length; i < ii; ++i) {
466
497
  const tileTexture = tileTextures[i];
467
498
  const tile = tileTexture.tile;
499
+ if (tile instanceof ReprojTile && tile.getState() === TileState.EMPTY) {
500
+ continue;
501
+ }
468
502
  const tileCoord = tile.tileCoord;
469
503
 
470
504
  if (tileTexture.loaded) {
@@ -753,6 +787,10 @@ class WebGLTileLayerRenderer extends WebGLLayerRenderer {
753
787
  continue;
754
788
  }
755
789
  const tileTexture = tileTextureCache.get(cacheKey);
790
+ const tile = tileTexture.tile;
791
+ if (tile instanceof ReprojTile && tile.getState() === TileState.EMPTY) {
792
+ return null;
793
+ }
756
794
  if (!tileTexture.loaded) {
757
795
  continue;
758
796
  }
package/util.js CHANGED
@@ -33,4 +33,4 @@ export function getUid(obj) {
33
33
  * OpenLayers version.
34
34
  * @type {string}
35
35
  */
36
- export const VERSION = '7.0.1-dev.1661277132609';
36
+ export const VERSION = '7.0.1-dev.1661440420569';