ol 10.6.2-dev.1753985579298 → 10.6.2-dev.1753992411402

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.
@@ -18,6 +18,7 @@ import EventType from '../events/EventType.js';
18
18
  import {
19
19
  altKeyOnly,
20
20
  always,
21
+ never,
21
22
  primaryAction,
22
23
  singleClick,
23
24
  } from '../events/condition.js';
@@ -42,6 +43,11 @@ import RBush from '../structs/RBush.js';
42
43
  import {createEditingStyle} from '../style/Style.js';
43
44
  import {getUid} from '../util.js';
44
45
  import PointerInteraction from './Pointer.js';
46
+ import {
47
+ getCoordinate,
48
+ getTraceTargetUpdate,
49
+ getTraceTargets,
50
+ } from './tracing.js';
45
51
 
46
52
  /**
47
53
  * The segment index assigned to a circle's center when
@@ -130,12 +136,36 @@ const ModifyEventType = {
130
136
  * @property {Collection<Feature>} [features]
131
137
  * The features the interaction works on. If a feature collection is not
132
138
  * provided, a vector source must be provided with the `source` option.
139
+ * @property {boolean|import("../events/condition.js").Condition} [trace=false] Trace a portion of another geometry.
140
+ * Tracing starts when two neighboring vertices are dragged onto a trace target, without any other modification in between..
141
+ * @property {VectorSource} [traceSource] Source for features to trace. If tracing is active and a `traceSource` is
142
+ * not provided, the interaction's `source` will be used. Tracing requires that the interaction is configured with
143
+ * either a `traceSource` or a `source`.
133
144
  * @property {boolean} [wrapX=false] Wrap the world horizontally on the sketch
134
145
  * overlay.
135
146
  * @property {boolean} [snapToPointer=!hitDetection] The vertex, point or segment being modified snaps to the
136
147
  * pointer coordinate when clicked within the `pixelTolerance`.
137
148
  */
138
149
 
150
+ function getCoordinatesArray(coordinates, geometryType, depth) {
151
+ let coordinatesArray;
152
+ switch (geometryType) {
153
+ case 'LineString':
154
+ coordinatesArray = coordinates;
155
+ break;
156
+ case 'MultiLineString':
157
+ case 'Polygon':
158
+ coordinatesArray = coordinates[depth[0]];
159
+ break;
160
+ case 'MultiPolygon':
161
+ coordinatesArray = coordinates[depth[1]][depth[0]];
162
+ break;
163
+ default:
164
+ // pass
165
+ }
166
+ return coordinatesArray;
167
+ }
168
+
139
169
  /**
140
170
  * @classdesc
141
171
  * Events emitted by {@link module:ol/interaction/Modify~Modify} instances are
@@ -270,10 +300,10 @@ class Modify extends PointerInteraction {
270
300
  this.vertexSegments_ = null;
271
301
 
272
302
  /**
273
- * @type {import("../pixel.js").Pixel}
303
+ * @type {import("../coordinate.js").Coordinate}
274
304
  * @private
275
305
  */
276
- this.lastPixel_ = [0, 0];
306
+ this.lastCoordinate_ = [0, 0];
277
307
 
278
308
  /**
279
309
  * Tracks if the next `singleclick` event should be ignored to prevent
@@ -344,15 +374,15 @@ class Modify extends PointerInteraction {
344
374
  * @type {!Object<string, function(Feature, import("../geom/Geometry.js").default): void>}
345
375
  */
346
376
  this.SEGMENT_WRITERS_ = {
347
- 'Point': this.writePointGeometry_.bind(this),
348
- 'LineString': this.writeLineStringGeometry_.bind(this),
349
- 'LinearRing': this.writeLineStringGeometry_.bind(this),
350
- 'Polygon': this.writePolygonGeometry_.bind(this),
351
- 'MultiPoint': this.writeMultiPointGeometry_.bind(this),
352
- 'MultiLineString': this.writeMultiLineStringGeometry_.bind(this),
353
- 'MultiPolygon': this.writeMultiPolygonGeometry_.bind(this),
354
- 'Circle': this.writeCircleGeometry_.bind(this),
355
- 'GeometryCollection': this.writeGeometryCollectionGeometry_.bind(this),
377
+ Point: this.writePointGeometry_.bind(this),
378
+ LineString: this.writeLineStringGeometry_.bind(this),
379
+ LinearRing: this.writeLineStringGeometry_.bind(this),
380
+ Polygon: this.writePolygonGeometry_.bind(this),
381
+ MultiPoint: this.writeMultiPointGeometry_.bind(this),
382
+ MultiLineString: this.writeMultiLineStringGeometry_.bind(this),
383
+ MultiPolygon: this.writeMultiPolygonGeometry_.bind(this),
384
+ Circle: this.writeCircleGeometry_.bind(this),
385
+ GeometryCollection: this.writeGeometryCollectionGeometry_.bind(this),
356
386
  };
357
387
 
358
388
  /**
@@ -361,6 +391,31 @@ class Modify extends PointerInteraction {
361
391
  */
362
392
  this.source_ = null;
363
393
 
394
+ /**
395
+ * @type {VectorSource|null}
396
+ * @private
397
+ */
398
+ this.traceSource_ = options.traceSource || options.source || null;
399
+
400
+ /**
401
+ * @type {import("../events/condition.js").Condition}
402
+ * @private
403
+ */
404
+ this.traceCondition_;
405
+ this.setTrace(options.trace || false);
406
+
407
+ /**
408
+ * @type {import('./tracing.js').TraceState}
409
+ * @private
410
+ */
411
+ this.traceState_ = {active: false};
412
+
413
+ /**
414
+ * @type {Array<DragSegment>|null}
415
+ * @private
416
+ */
417
+ this.traceSegments_ = null;
418
+
364
419
  /**
365
420
  * @type {boolean|import("../layer/BaseVector").default}
366
421
  * @private
@@ -430,6 +485,24 @@ class Modify extends PointerInteraction {
430
485
  : options.snapToPointer;
431
486
  }
432
487
 
488
+ /**
489
+ * Toggle tracing mode or set a tracing condition.
490
+ *
491
+ * @param {boolean|import("../events/condition.js").Condition} trace A boolean to toggle tracing mode or an event
492
+ * condition that will be checked when a feature is clicked to determine if tracing should be active.
493
+ */
494
+ setTrace(trace) {
495
+ let condition;
496
+ if (!trace) {
497
+ condition = never;
498
+ } else if (trace === true) {
499
+ condition = always;
500
+ } else {
501
+ condition = trace;
502
+ }
503
+ this.traceCondition_ = condition;
504
+ }
505
+
433
506
  /**
434
507
  * @param {Feature} feature Feature.
435
508
  * @private
@@ -444,7 +517,7 @@ class Modify extends PointerInteraction {
444
517
  }
445
518
  const map = this.getMap();
446
519
  if (map && map.isRendered() && this.getActive()) {
447
- this.handlePointerAtPixel_(map.getCoordinateFromPixel(this.lastPixel_));
520
+ this.handlePointerAtPixel_(this.lastCoordinate_);
448
521
  }
449
522
  feature.addEventListener(EventType.CHANGE, this.boundHandleFeatureChange_);
450
523
  }
@@ -878,6 +951,11 @@ class Modify extends PointerInteraction {
878
951
  return super.handleEvent(mapBrowserEvent) && !handled;
879
952
  }
880
953
 
954
+ /**
955
+ * @param {import("../coordinate.js").Coordinate} pixelCoordinate Pixel coordinate.
956
+ * @return {Array<SegmentData>|undefined} Insert vertices and update drag segments.
957
+ * @private
958
+ */
881
959
  findInsertVerticesAndUpdateDragSegments_(pixelCoordinate) {
882
960
  this.handlePointerAtPixel_(pixelCoordinate);
883
961
  this.dragSegments_.length = 0;
@@ -888,8 +966,9 @@ class Modify extends PointerInteraction {
888
966
  }
889
967
 
890
968
  const projection = this.getMap().getView().getProjection();
969
+ /** @type {Array<SegmentData>} */
891
970
  const insertVertices = [];
892
- const vertex = vertexFeature.getGeometry().getCoordinates();
971
+ const vertex = this.vertexFeature_.getGeometry().getCoordinates();
893
972
  const vertexExtent = boundingExtent([vertex]);
894
973
  const segmentDataMatches = this.rBush_.getInExtent(vertexExtent);
895
974
  const componentSegments = {};
@@ -974,6 +1053,370 @@ class Modify extends PointerInteraction {
974
1053
  return insertVertices;
975
1054
  }
976
1055
 
1056
+ /**
1057
+ * @private
1058
+ */
1059
+ deactivateTrace_() {
1060
+ this.traceState_ = {active: false};
1061
+ }
1062
+
1063
+ /**
1064
+ * Update the trace.
1065
+ * @param {import("../MapBrowserEvent.js").default} event Event.
1066
+ * @private
1067
+ */
1068
+ updateTrace_(event) {
1069
+ const traceState = this.traceState_;
1070
+ if (!traceState.active) {
1071
+ return;
1072
+ }
1073
+
1074
+ if (traceState.targetIndex === -1) {
1075
+ // check if we are ready to pick a target
1076
+ const startPx = event.map.getPixelFromCoordinate(traceState.startCoord);
1077
+ if (coordinateDistance(startPx, event.pixel) < this.pixelTolerance_) {
1078
+ return;
1079
+ }
1080
+ }
1081
+
1082
+ const updatedTraceTarget = getTraceTargetUpdate(
1083
+ event.coordinate,
1084
+ traceState,
1085
+ event.map,
1086
+ this.pixelTolerance_,
1087
+ );
1088
+
1089
+ if (
1090
+ traceState.targetIndex === -1 &&
1091
+ Math.sqrt(updatedTraceTarget.closestTargetDistance) /
1092
+ event.map.getView().getResolution() >
1093
+ this.pixelTolerance_
1094
+ ) {
1095
+ return;
1096
+ }
1097
+
1098
+ if (traceState.targetIndex !== updatedTraceTarget.index) {
1099
+ // target changed
1100
+ if (traceState.targetIndex !== -1) {
1101
+ // remove points added during previous trace
1102
+ const oldTarget = traceState.targets[traceState.targetIndex];
1103
+ this.removeTracedCoordinates_(oldTarget.startIndex, oldTarget.endIndex);
1104
+ } else {
1105
+ for (const traceSegment of this.traceSegments_) {
1106
+ const segmentData = traceSegment[0];
1107
+ const geometry = segmentData.geometry;
1108
+ const index = traceSegment[1];
1109
+ const coordinates = geometry.getCoordinates();
1110
+ const coordinatesArray = getCoordinatesArray(
1111
+ coordinates,
1112
+ geometry.getType(),
1113
+ segmentData.depth,
1114
+ );
1115
+ coordinatesArray.splice(segmentData.index + index, 1);
1116
+ geometry.setCoordinates(coordinates);
1117
+ if (index === 0) {
1118
+ segmentData.index -= 1;
1119
+ }
1120
+ }
1121
+ }
1122
+ // add points for the new target
1123
+ const newTarget = traceState.targets[updatedTraceTarget.index];
1124
+ this.addTracedCoordinates_(
1125
+ newTarget,
1126
+ newTarget.startIndex,
1127
+ updatedTraceTarget.endIndex,
1128
+ );
1129
+ } else {
1130
+ // target stayed the same
1131
+ const target = traceState.targets[traceState.targetIndex];
1132
+ this.addOrRemoveTracedCoordinates_(target, updatedTraceTarget.endIndex);
1133
+ }
1134
+
1135
+ // modify the state with updated info
1136
+ traceState.targetIndex = updatedTraceTarget.index;
1137
+ const target = traceState.targets[traceState.targetIndex];
1138
+ target.endIndex = updatedTraceTarget.endIndex;
1139
+ }
1140
+
1141
+ getTraceCandidates_(event) {
1142
+ const map = this.getMap();
1143
+ const tolerance = this.pixelTolerance_;
1144
+ const lowerLeft = map.getCoordinateFromPixel([
1145
+ event.pixel[0] - tolerance,
1146
+ event.pixel[1] + tolerance,
1147
+ ]);
1148
+ const upperRight = map.getCoordinateFromPixel([
1149
+ event.pixel[0] + tolerance,
1150
+ event.pixel[1] - tolerance,
1151
+ ]);
1152
+ const extent = boundingExtent([lowerLeft, upperRight]);
1153
+ const features = this.traceSource_.getFeaturesInExtent(extent);
1154
+ return features;
1155
+ }
1156
+
1157
+ /**
1158
+ * Activate or deactivate trace state based on a browser event.
1159
+ * @param {import("../MapBrowserEvent.js").default} event Event.
1160
+ * @private
1161
+ */
1162
+ toggleTraceState_(event) {
1163
+ if (!this.traceSource_ || !this.traceCondition_(event)) {
1164
+ return;
1165
+ }
1166
+
1167
+ if (this.traceState_.active) {
1168
+ this.deactivateTrace_();
1169
+ this.traceSegments_ = null;
1170
+ return;
1171
+ }
1172
+
1173
+ const features = this.getTraceCandidates_(event);
1174
+ if (features.length === 0) {
1175
+ return;
1176
+ }
1177
+
1178
+ const targets = getTraceTargets(event.coordinate, features);
1179
+ if (targets.length) {
1180
+ this.traceState_ = {
1181
+ active: true,
1182
+ startCoord: event.coordinate.slice(),
1183
+ targets: targets,
1184
+ targetIndex: -1,
1185
+ };
1186
+ }
1187
+ }
1188
+
1189
+ /**
1190
+ * @param {import('./tracing.js').TraceTarget} target The trace target.
1191
+ * @param {number} endIndex The new end index of the trace.
1192
+ * @private
1193
+ */
1194
+ addOrRemoveTracedCoordinates_(target, endIndex) {
1195
+ // three cases to handle:
1196
+ // 1. traced in the same direction and points need adding
1197
+ // 2. traced in the same direction and points need removing
1198
+ // 3. traced in a new direction
1199
+ const previouslyForward = target.startIndex <= target.endIndex;
1200
+ const currentlyForward = target.startIndex <= endIndex;
1201
+ if (previouslyForward === currentlyForward) {
1202
+ // same direction
1203
+ if (
1204
+ (previouslyForward && endIndex > target.endIndex) ||
1205
+ (!previouslyForward && endIndex < target.endIndex)
1206
+ ) {
1207
+ // case 1 - add new points
1208
+ this.addTracedCoordinates_(target, target.endIndex, endIndex);
1209
+ } else if (
1210
+ (previouslyForward && endIndex < target.endIndex) ||
1211
+ (!previouslyForward && endIndex > target.endIndex)
1212
+ ) {
1213
+ // case 2 - remove old points
1214
+ this.removeTracedCoordinates_(endIndex, target.endIndex);
1215
+ }
1216
+ } else {
1217
+ // case 3 - remove old points, add new points
1218
+ this.removeTracedCoordinates_(target.startIndex, target.endIndex);
1219
+ this.addTracedCoordinates_(target, target.startIndex, endIndex);
1220
+ }
1221
+ }
1222
+
1223
+ /**
1224
+ * @param {number} fromIndex The start index.
1225
+ * @param {number} toIndex The end index.
1226
+ * @private
1227
+ */
1228
+ removeTracedCoordinates_(fromIndex, toIndex) {
1229
+ if (fromIndex === toIndex) {
1230
+ return;
1231
+ }
1232
+
1233
+ let remove = 0;
1234
+ if (fromIndex < toIndex) {
1235
+ const start = Math.ceil(fromIndex);
1236
+ let end = Math.floor(toIndex);
1237
+ if (end === toIndex) {
1238
+ end -= 1;
1239
+ }
1240
+ remove = end - start + 1;
1241
+ } else {
1242
+ const start = Math.floor(fromIndex);
1243
+ let end = Math.ceil(toIndex);
1244
+ if (end === toIndex) {
1245
+ end += 1;
1246
+ }
1247
+ remove = start - end + 1;
1248
+ }
1249
+
1250
+ if (remove > 0) {
1251
+ for (const traceSegment of this.traceSegments_) {
1252
+ const segmentData = traceSegment[0];
1253
+ const geometry = segmentData.geometry;
1254
+ const index = traceSegment[1];
1255
+ let removeIndex = traceSegment[0].index + 1;
1256
+ if (index === 1) {
1257
+ removeIndex -= remove;
1258
+ }
1259
+ const coordinates = geometry.getCoordinates();
1260
+ const coordinatesArray = getCoordinatesArray(
1261
+ coordinates,
1262
+ geometry.getType(),
1263
+ segmentData.depth,
1264
+ );
1265
+ coordinatesArray.splice(removeIndex, remove);
1266
+ geometry.setCoordinates(coordinates);
1267
+ if (index === 1) {
1268
+ segmentData.index -= remove;
1269
+ }
1270
+ }
1271
+ }
1272
+ }
1273
+
1274
+ /**
1275
+ * @param {import('./tracing.js').TraceTarget} target The trace target.
1276
+ * @param {number} fromIndex The start index.
1277
+ * @param {number} toIndex The end index.
1278
+ * @private
1279
+ */
1280
+ addTracedCoordinates_(target, fromIndex, toIndex) {
1281
+ if (fromIndex === toIndex) {
1282
+ return;
1283
+ }
1284
+
1285
+ const newCoordinates = [];
1286
+ if (fromIndex < toIndex) {
1287
+ // forward trace
1288
+ const start = Math.ceil(fromIndex);
1289
+ let end = Math.floor(toIndex);
1290
+ if (end === toIndex) {
1291
+ // if end is snapped to a vertex, it will be added later
1292
+ end -= 1;
1293
+ }
1294
+ for (let i = start; i <= end; ++i) {
1295
+ newCoordinates.push(getCoordinate(target.coordinates, i));
1296
+ }
1297
+ } else {
1298
+ // reverse trace
1299
+ const start = Math.floor(fromIndex);
1300
+ let end = Math.ceil(toIndex);
1301
+ if (end === toIndex) {
1302
+ end += 1;
1303
+ }
1304
+ for (let i = start; i >= end; --i) {
1305
+ newCoordinates.push(getCoordinate(target.coordinates, i));
1306
+ }
1307
+ }
1308
+
1309
+ if (newCoordinates.length) {
1310
+ for (const traceSegment of this.traceSegments_) {
1311
+ const segmentData = traceSegment[0];
1312
+ const geometry = segmentData.geometry;
1313
+ const index = traceSegment[1];
1314
+ const insertIndex = segmentData.index + 1;
1315
+ if (index === 0) {
1316
+ newCoordinates.reverse();
1317
+ }
1318
+ const coordinates = geometry.getCoordinates();
1319
+ const coordinatesArray = getCoordinatesArray(
1320
+ coordinates,
1321
+ geometry.getType(),
1322
+ segmentData.depth,
1323
+ );
1324
+ coordinatesArray.splice(insertIndex, 0, ...newCoordinates);
1325
+ geometry.setCoordinates(coordinates);
1326
+ if (index === 1) {
1327
+ segmentData.index += newCoordinates.length;
1328
+ }
1329
+ }
1330
+ }
1331
+ }
1332
+
1333
+ /**
1334
+ * @param {import('../coordinate.js').Coordinate} vertex Vertex.
1335
+ * @param {DragSegment} dragSegment Drag segment.
1336
+ */
1337
+ updateGeometry_(vertex, dragSegment) {
1338
+ const segmentData = dragSegment[0];
1339
+ const depth = segmentData.depth;
1340
+ let coordinates;
1341
+ const segment = segmentData.segment;
1342
+ const geometry = segmentData.geometry;
1343
+ const index = dragSegment[1];
1344
+
1345
+ while (vertex.length < geometry.getStride()) {
1346
+ vertex.push(segment[index][vertex.length]);
1347
+ }
1348
+ switch (geometry.getType()) {
1349
+ case 'Point':
1350
+ coordinates = vertex;
1351
+ segment[0] = vertex;
1352
+ segment[1] = vertex;
1353
+ break;
1354
+ case 'MultiPoint':
1355
+ coordinates = geometry.getCoordinates();
1356
+ coordinates[segmentData.index] = vertex;
1357
+ segment[0] = vertex;
1358
+ segment[1] = vertex;
1359
+ break;
1360
+ case 'LineString':
1361
+ coordinates = geometry.getCoordinates();
1362
+ coordinates[segmentData.index + index] = vertex;
1363
+ segment[index] = vertex;
1364
+ break;
1365
+ case 'MultiLineString':
1366
+ coordinates = geometry.getCoordinates();
1367
+ coordinates[depth[0]][segmentData.index + index] = vertex;
1368
+ segment[index] = vertex;
1369
+ break;
1370
+ case 'Polygon':
1371
+ coordinates = geometry.getCoordinates();
1372
+ coordinates[depth[0]][segmentData.index + index] = vertex;
1373
+ segment[index] = vertex;
1374
+ break;
1375
+ case 'MultiPolygon':
1376
+ coordinates = geometry.getCoordinates();
1377
+ coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex;
1378
+ segment[index] = vertex;
1379
+ break;
1380
+ case 'Circle':
1381
+ const circle = /** @type {import("../geom/Circle.js").default} */ (
1382
+ geometry
1383
+ );
1384
+ segment[0] = vertex;
1385
+ segment[1] = vertex;
1386
+ if (segmentData.index === CIRCLE_CENTER_INDEX) {
1387
+ this.changingFeature_ = true;
1388
+ circle.setCenter(vertex);
1389
+ this.changingFeature_ = false;
1390
+ } else {
1391
+ // We're dragging the circle's circumference:
1392
+ this.changingFeature_ = true;
1393
+ const projection = this.getMap().getView().getProjection();
1394
+ let radius = coordinateDistance(
1395
+ fromUserCoordinate(circle.getCenter(), projection),
1396
+ fromUserCoordinate(vertex, projection),
1397
+ );
1398
+ const userProjection = getUserProjection();
1399
+ if (userProjection) {
1400
+ const circleGeometry = circle
1401
+ .clone()
1402
+ .transform(userProjection, projection);
1403
+ circleGeometry.setRadius(radius);
1404
+ radius = circleGeometry
1405
+ .transform(projection, userProjection)
1406
+ .getRadius();
1407
+ }
1408
+ circle.setRadius(radius);
1409
+ this.changingFeature_ = false;
1410
+ }
1411
+ break;
1412
+ default:
1413
+ // pass
1414
+ }
1415
+ if (coordinates) {
1416
+ this.setGeometryCoordinates_(geometry, coordinates);
1417
+ }
1418
+ }
1419
+
977
1420
  /**
978
1421
  * Handle pointer drag events.
979
1422
  * @param {import("../MapBrowserEvent.js").default} evt Event.
@@ -992,6 +1435,26 @@ class Modify extends PointerInteraction {
992
1435
  ];
993
1436
  const features = [];
994
1437
  const geometries = [];
1438
+ const startTraceCoord =
1439
+ this.traceState_.active && !this.traceSegments_
1440
+ ? this.traceState_.startCoord
1441
+ : null;
1442
+ if (startTraceCoord) {
1443
+ this.traceSegments_ = [];
1444
+ for (const dragSegment of this.dragSegments_) {
1445
+ const segmentData = dragSegment[0];
1446
+ const eligibleForTracing =
1447
+ coordinateDistance(
1448
+ closestOnSegment(startTraceCoord, segmentData.segment),
1449
+ startTraceCoord,
1450
+ ) /
1451
+ evt.map.getView().getResolution() <
1452
+ 1;
1453
+ if (eligibleForTracing) {
1454
+ this.traceSegments_.push(dragSegment);
1455
+ }
1456
+ }
1457
+ }
995
1458
  for (let i = 0, ii = this.dragSegments_.length; i < ii; ++i) {
996
1459
  const dragSegment = this.dragSegments_[i];
997
1460
  const segmentData = dragSegment[0];
@@ -1003,87 +1466,10 @@ class Modify extends PointerInteraction {
1003
1466
  if (!geometries.includes(geometry)) {
1004
1467
  geometries.push(geometry);
1005
1468
  }
1006
- const depth = segmentData.depth;
1007
- let coordinates;
1008
- const segment = segmentData.segment;
1009
- const index = dragSegment[1];
1010
-
1011
- while (vertex.length < geometry.getStride()) {
1012
- vertex.push(segment[index][vertex.length]);
1013
- }
1014
1469
 
1015
- switch (geometry.getType()) {
1016
- case 'Point':
1017
- coordinates = vertex;
1018
- segment[0] = vertex;
1019
- segment[1] = vertex;
1020
- break;
1021
- case 'MultiPoint':
1022
- coordinates = geometry.getCoordinates();
1023
- coordinates[segmentData.index] = vertex;
1024
- segment[0] = vertex;
1025
- segment[1] = vertex;
1026
- break;
1027
- case 'LineString':
1028
- coordinates = geometry.getCoordinates();
1029
- coordinates[segmentData.index + index] = vertex;
1030
- segment[index] = vertex;
1031
- break;
1032
- case 'MultiLineString':
1033
- coordinates = geometry.getCoordinates();
1034
- coordinates[depth[0]][segmentData.index + index] = vertex;
1035
- segment[index] = vertex;
1036
- break;
1037
- case 'Polygon':
1038
- coordinates = geometry.getCoordinates();
1039
- coordinates[depth[0]][segmentData.index + index] = vertex;
1040
- segment[index] = vertex;
1041
- break;
1042
- case 'MultiPolygon':
1043
- coordinates = geometry.getCoordinates();
1044
- coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex;
1045
- segment[index] = vertex;
1046
- break;
1047
- case 'Circle':
1048
- const circle = /** @type {import("../geom/Circle.js").default} */ (
1049
- geometry
1050
- );
1051
- segment[0] = vertex;
1052
- segment[1] = vertex;
1053
- if (segmentData.index === CIRCLE_CENTER_INDEX) {
1054
- this.changingFeature_ = true;
1055
- circle.setCenter(vertex);
1056
- this.changingFeature_ = false;
1057
- } else {
1058
- // We're dragging the circle's circumference:
1059
- this.changingFeature_ = true;
1060
- const projection = evt.map.getView().getProjection();
1061
- let radius = coordinateDistance(
1062
- fromUserCoordinate(circle.getCenter(), projection),
1063
- fromUserCoordinate(vertex, projection),
1064
- );
1065
- const userProjection = getUserProjection();
1066
- if (userProjection) {
1067
- const circleGeometry = circle
1068
- .clone()
1069
- .transform(userProjection, projection);
1070
- circleGeometry.setRadius(radius);
1071
- radius = circleGeometry
1072
- .transform(projection, userProjection)
1073
- .getRadius();
1074
- }
1075
- circle.setRadius(radius);
1076
- this.changingFeature_ = false;
1077
- }
1078
- break;
1079
- default:
1080
- // pass
1081
- }
1082
-
1083
- if (coordinates) {
1084
- this.setGeometryCoordinates_(geometry, coordinates);
1085
- }
1470
+ this.updateGeometry_(vertex, dragSegment);
1086
1471
  }
1472
+ this.updateTrace_(evt);
1087
1473
  this.createOrUpdateVertexFeature_(vertex, features, geometries, true);
1088
1474
  }
1089
1475
 
@@ -1161,6 +1547,7 @@ class Modify extends PointerInteraction {
1161
1547
  }
1162
1548
  }
1163
1549
  if (this.featuresBeingModified_) {
1550
+ this.toggleTraceState_(evt);
1164
1551
  this.dispatchEvent(
1165
1552
  new ModifyEvent(
1166
1553
  ModifyEventType.MODIFYEND,
@@ -1178,8 +1565,8 @@ class Modify extends PointerInteraction {
1178
1565
  * @private
1179
1566
  */
1180
1567
  handlePointerMove_(evt) {
1181
- this.lastPixel_ = evt.pixel;
1182
- this.handlePointerAtPixel_(evt.coordinate);
1568
+ this.lastCoordinate_ = evt.coordinate;
1569
+ this.handlePointerAtPixel_(this.lastCoordinate_);
1183
1570
  }
1184
1571
 
1185
1572
  /**
@@ -1409,6 +1796,11 @@ class Modify extends PointerInteraction {
1409
1796
  return true;
1410
1797
  }
1411
1798
 
1799
+ /**
1800
+ * @param {import("../coordinate.js").Coordinate} coordinate The coordinate.
1801
+ * @return {import("../coordinate.js").Coordinate} The updated pointer coordinate.
1802
+ * @private
1803
+ */
1412
1804
  updatePointer_(coordinate) {
1413
1805
  if (coordinate) {
1414
1806
  this.findInsertVerticesAndUpdateDragSegments_(coordinate);