import { Draw_default, getCoordinate, getTraceTargetUpdate, getTraceTargets } from "./chunk-MEQVYVYE.js"; import { Select_default } from "./chunk-6DXBPPKF.js"; import { RBush_default, Vector_default as Vector_default2 } from "./chunk-PD2E5XZ4.js"; import { VectorEventType_default } from "./chunk-V7WRBSQ6.js"; import "./chunk-W7BDJOQY.js"; import "./chunk-7JXPN73Q.js"; import { Feature_default } from "./chunk-E53S5GN6.js"; import { Vector_default } from "./chunk-T3TT2KJN.js"; import "./chunk-HM3IY3H4.js"; import "./chunk-JFXZSSOM.js"; import "./chunk-ZUI5NXIU.js"; import { DoubleClickZoom_default, DragBox_default, DragPan_default, DragRotate_default, DragZoom_default, KeyboardPan_default, KeyboardZoom_default, MouseWheelZoom_default, PinchRotate_default, PinchZoom_default, Pointer_default, defaults } from "./chunk-RTVPCGIJ.js"; import { Interaction_default, Property_default } from "./chunk-MSWSBYBR.js"; import { MapBrowserEventType_default, altKeyOnly, always, mouseOnly, never, primaryAction, shiftKeyOnly, singleClick } from "./chunk-QCJTGAWF.js"; import { CollectionEventType_default, Collection_default } from "./chunk-M5TTSD4C.js"; import "./chunk-ZCRXKB7J.js"; import "./chunk-RW3V7S4F.js"; import { createEditingStyle } from "./chunk-PAB2HIXK.js"; import "./chunk-I6K7MRGV.js"; import "./chunk-PGWX4545.js"; import "./chunk-AYBYZSAV.js"; import "./chunk-YLJGUH5Z.js"; import { Point_default, fromCircle, fromExtent } from "./chunk-AZGMK675.js"; import { MapEventType_default } from "./chunk-BHVDQB66.js"; import "./chunk-6EWLK2BW.js"; import "./chunk-6Y7C6NBJ.js"; import "./chunk-SHUBVYN4.js"; import "./chunk-FM44FOIC.js"; import "./chunk-LMC3RO5P.js"; import { getIntersectionPoint } from "./chunk-X52LGBOS.js"; import "./chunk-QFCIXVZ3.js"; import { closestOnCircle, closestOnSegment, distance, equals as equals2, fromUserCoordinate, fromUserExtent, get, getUserProjection, squaredDistance, squaredDistanceToSegment, toUserCoordinate, toUserExtent } from "./chunk-A3RXLHYB.js"; import "./chunk-ZLPTRF2L.js"; import { toFixed } from "./chunk-54BTDBAD.js"; import "./chunk-UPTVWZ45.js"; import "./chunk-5XHD7RSF.js"; import { getUid } from "./chunk-Q5ZULJHM.js"; import { Event_default, listen, unlistenByKey } from "./chunk-NGFXCWUF.js"; import { EventType_default, FALSE, TRUE, equals } from "./chunk-K25ZO44T.js"; import { boundingExtent, buffer, containsCoordinate, createEmpty, createOrUpdateFromCoordinate, getArea, intersects } from "./chunk-SRXHWJOY.js"; import { clear } from "./chunk-5RHQVMYD.js"; import "./chunk-DC5AMYBS.js"; // node_modules/ol/interaction/DblClickDragZoom.js var DblClickDragZoom = class extends Interaction_default { /** * @param {Options} [opt_options] Options. */ constructor(opt_options) { const options = opt_options ? opt_options : {}; super( /** @type {import("./Interaction.js").InteractionOptions} */ options ); if (options.stopDown) { this.stopDown = options.stopDown; } this.scaleDeltaByPixel_ = options.delta ? options.delta : 0.01; this.duration_ = options.duration !== void 0 ? options.duration : 250; this.handlingDownUpSequence_ = false; this.handlingDoubleDownSequence_ = false; this.doubleTapTimeoutId_ = void 0; this.trackedPointers_ = {}; this.down_ = null; this.targetPointers = []; } /** * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} and may call into * other functions, if event sequences like e.g. 'drag' or 'down-up' etc. are * detected. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. * @return {boolean} `false` to stop event propagation. * @api * @override */ handleEvent(mapBrowserEvent) { if (!mapBrowserEvent.originalEvent) { return true; } let stopEvent = false; this.updateTrackedPointers_(mapBrowserEvent); if (this.handlingDownUpSequence_) { if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERDRAG) { this.handleDragEvent(mapBrowserEvent); mapBrowserEvent.originalEvent.preventDefault(); } else if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERUP) { const handledUp = this.handleUpEvent(mapBrowserEvent); this.handlingDownUpSequence_ = handledUp; } } else { if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERDOWN) { if (this.handlingDoubleDownSequence_) { this.handlingDoubleDownSequence_ = false; const handled = this.handleDownEvent(mapBrowserEvent); this.handlingDownUpSequence_ = handled; stopEvent = this.stopDown(handled); } else { stopEvent = this.stopDown(false); this.waitForDblTap_(); } } } return !stopEvent; } /** * Handle pointer drag events. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. */ handleDragEvent(mapBrowserEvent) { let scaleDelta = 1; const touch0 = this.targetPointers[0]; const touch1 = this.down_; const distance2 = touch0.clientY - touch1.clientY; if (this.lastDistance_ !== void 0) { scaleDelta = 1 - (this.lastDistance_ - distance2) * this.scaleDeltaByPixel_; } this.lastDistance_ = distance2; if (scaleDelta != 1) { this.lastScaleDelta_ = scaleDelta; } const map = mapBrowserEvent.map; const view = map.getView(); map.render(); view.adjustResolutionInternal(scaleDelta); } /** * Handle pointer down events. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. * @return {boolean} If the event was consumed. */ handleDownEvent(mapBrowserEvent) { if (this.targetPointers.length == 1) { const map = mapBrowserEvent.map; this.anchor_ = null; this.lastDistance_ = void 0; this.lastScaleDelta_ = 1; this.down_ = mapBrowserEvent.originalEvent; if (!this.handlingDownUpSequence_) { map.getView().beginInteraction(); } return true; } return false; } /** * Handle pointer up events zooming out. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. * @return {boolean} If the event was consumed. */ handleUpEvent(mapBrowserEvent) { if (this.targetPointers.length == 0) { const map = mapBrowserEvent.map; const view = map.getView(); const direction = this.lastScaleDelta_ > 1 ? 1 : -1; view.endInteraction(this.duration_, direction); this.handlingDownUpSequence_ = false; this.handlingDoubleDownSequence_ = false; return false; } return true; } /** * This function is used to determine if "down" events should be propagated * to other interactions or should be stopped. * @param {boolean} handled Was the event handled by the interaction? * @return {boolean} Should the `down` event be stopped? */ stopDown(handled) { return handled; } /** * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. * @private */ updateTrackedPointers_(mapBrowserEvent) { if (isPointerDraggingEvent(mapBrowserEvent)) { const event = mapBrowserEvent.originalEvent; const id = event.pointerId.toString(); if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERUP) { delete this.trackedPointers_[id]; } else if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERDOWN) { this.trackedPointers_[id] = event; } else if (id in this.trackedPointers_) { this.trackedPointers_[id] = event; } this.targetPointers = Object.values(this.trackedPointers_); } } /** * Wait the second double finger tap. * @private */ waitForDblTap_() { if (this.doubleTapTimeoutId_ !== void 0) { clearTimeout(this.doubleTapTimeoutId_); this.doubleTapTimeoutId_ = void 0; } else { this.handlingDoubleDownSequence_ = true; this.doubleTapTimeoutId_ = setTimeout( this.endInteraction_.bind(this), 250 ); } } /** * @private */ endInteraction_() { this.handlingDoubleDownSequence_ = false; this.doubleTapTimeoutId_ = void 0; } }; function isPointerDraggingEvent(mapBrowserEvent) { const type = mapBrowserEvent.type; return type === MapBrowserEventType_default.POINTERDOWN || type === MapBrowserEventType_default.POINTERDRAG || type === MapBrowserEventType_default.POINTERUP; } var DblClickDragZoom_default = DblClickDragZoom; // node_modules/ol/interaction/DragAndDrop.js var DragAndDropEventType = { /** * Triggered when features are added * @event DragAndDropEvent#addfeatures * @api */ ADD_FEATURES: "addfeatures" }; var DragAndDropEvent = class extends Event_default { /** * @param {DragAndDropEventType} type Type. * @param {File} file File. * @param {Array} [features] Features. * @param {import("../proj/Projection.js").default} [projection] Projection. */ constructor(type, file, features, projection) { super(type); this.features = features; this.file = file; this.projection = projection; } }; var DragAndDrop = class extends Interaction_default { /** * @param {Options} [options] Options. */ constructor(options) { options = options ? options : {}; super({ handleEvent: TRUE }); this.on; this.once; this.un; this.readAsBuffer_ = false; this.formats_ = []; const formatConstructors = options.formatConstructors ? options.formatConstructors : []; for (let i = 0, ii = formatConstructors.length; i < ii; ++i) { let format = formatConstructors[i]; if (typeof format === "function") { format = new format(); } this.formats_.push(format); this.readAsBuffer_ = this.readAsBuffer_ || format.getType() === "arraybuffer"; } this.projection_ = options.projection ? get(options.projection) : null; this.dropListenKeys_ = null; this.source_ = options.source || null; this.target = options.target ? options.target : null; } /** * @param {File} file File. * @param {Event} event Load event. * @private */ handleResult_(file, event) { const result = event.target.result; const map = this.getMap(); let projection = this.projection_; if (!projection) { projection = getUserProjection(); if (!projection) { const view = map.getView(); projection = view.getProjection(); } } let text; const formats = this.formats_; for (let i = 0, ii = formats.length; i < ii; ++i) { const format = formats[i]; let input = result; if (this.readAsBuffer_ && format.getType() !== "arraybuffer") { if (text === void 0) { text = new TextDecoder().decode(result); } input = text; } const features = this.tryReadFeatures_(format, input, { featureProjection: projection }); if (features && features.length > 0) { if (this.source_) { this.source_.clear(); this.source_.addFeatures(features); } this.dispatchEvent( new DragAndDropEvent( DragAndDropEventType.ADD_FEATURES, file, features, projection ) ); break; } } } /** * @private */ registerListeners_() { const map = this.getMap(); if (map) { const dropArea = this.target ? this.target : map.getViewport(); this.dropListenKeys_ = [ listen(dropArea, EventType_default.DROP, this.handleDrop, this), listen(dropArea, EventType_default.DRAGENTER, this.handleStop, this), listen(dropArea, EventType_default.DRAGOVER, this.handleStop, this), listen(dropArea, EventType_default.DROP, this.handleStop, this) ]; } } /** * Activate or deactivate the interaction. * @param {boolean} active Active. * @observable * @api * @override */ setActive(active) { if (!this.getActive() && active) { this.registerListeners_(); } if (this.getActive() && !active) { this.unregisterListeners_(); } super.setActive(active); } /** * Remove the interaction from its current map and attach it to the new map. * Subclasses may set up event handlers to get notified about changes to * the map here. * @param {import("../Map.js").default} map Map. * @override */ setMap(map) { this.unregisterListeners_(); super.setMap(map); if (this.getActive()) { this.registerListeners_(); } } /** * @param {import("../format/Feature.js").default} format Format. * @param {string} text Text. * @param {import("../format/Feature.js").ReadOptions} options Read options. * @private * @return {Array} Features. */ tryReadFeatures_(format, text, options) { try { return ( /** @type {Array} */ format.readFeatures(text, options) ); } catch { return null; } } /** * @private */ unregisterListeners_() { if (this.dropListenKeys_) { this.dropListenKeys_.forEach(unlistenByKey); this.dropListenKeys_ = null; } } /** * @param {DragEvent} event Event. */ handleDrop(event) { const files = event.dataTransfer.files; for (let i = 0, ii = files.length; i < ii; ++i) { const file = files.item(i); const reader = new FileReader(); reader.addEventListener( EventType_default.LOAD, this.handleResult_.bind(this, file) ); if (this.readAsBuffer_) { reader.readAsArrayBuffer(file); } else { reader.readAsText(file); } } } /** * @param {DragEvent} event Event. */ handleStop(event) { event.stopPropagation(); event.preventDefault(); event.dataTransfer.dropEffect = "copy"; } }; var DragAndDrop_default = DragAndDrop; // node_modules/ol/interaction/DragRotateAndZoom.js var DragRotateAndZoom = class extends Pointer_default { /** * @param {Options} [options] Options. */ constructor(options) { options = options ? options : {}; super( /** @type {import("./Pointer.js").Options} */ options ); this.condition_ = options.condition ? options.condition : shiftKeyOnly; this.lastAngle_ = void 0; this.lastMagnitude_ = void 0; this.lastScaleDelta_ = 0; this.duration_ = options.duration !== void 0 ? options.duration : 400; } /** * Handle pointer drag events. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. * @override */ handleDragEvent(mapBrowserEvent) { if (!mouseOnly(mapBrowserEvent)) { return; } const map = mapBrowserEvent.map; const size = map.getSize(); const offset = mapBrowserEvent.pixel; const deltaX = offset[0] - size[0] / 2; const deltaY = size[1] / 2 - offset[1]; const theta = Math.atan2(deltaY, deltaX); const magnitude = Math.sqrt(deltaX * deltaX + deltaY * deltaY); const view = map.getView(); if (this.lastAngle_ !== void 0) { const angleDelta = this.lastAngle_ - theta; view.adjustRotationInternal(angleDelta); } this.lastAngle_ = theta; if (this.lastMagnitude_ !== void 0) { view.adjustResolutionInternal(this.lastMagnitude_ / magnitude); } if (this.lastMagnitude_ !== void 0) { this.lastScaleDelta_ = this.lastMagnitude_ / magnitude; } this.lastMagnitude_ = magnitude; } /** * Handle pointer up events. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. * @return {boolean} If the event was consumed. * @override */ handleUpEvent(mapBrowserEvent) { if (!mouseOnly(mapBrowserEvent)) { return true; } const map = mapBrowserEvent.map; const view = map.getView(); const direction = this.lastScaleDelta_ > 1 ? 1 : -1; view.endInteraction(this.duration_, direction); this.lastScaleDelta_ = 0; return false; } /** * Handle pointer down events. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. * @return {boolean} If the event was consumed. * @override */ handleDownEvent(mapBrowserEvent) { if (!mouseOnly(mapBrowserEvent)) { return false; } if (this.condition_(mapBrowserEvent)) { mapBrowserEvent.map.getView().beginInteraction(); this.lastAngle_ = void 0; this.lastMagnitude_ = void 0; return true; } return false; } }; var DragRotateAndZoom_default = DragRotateAndZoom; // node_modules/ol/interaction/Extent.js var ExtentEventType = { /** * Triggered after the extent is changed * @event ExtentEvent#extentchanged * @api */ EXTENTCHANGED: "extentchanged" }; var ExtentEvent = class extends Event_default { /** * @param {import("../extent.js").Extent} extent the new extent */ constructor(extent) { super(ExtentEventType.EXTENTCHANGED); this.extent = extent; } }; var Extent = class extends Pointer_default { /** * @param {Options} [options] Options. */ constructor(options) { options = options || {}; super( /** @type {import("./Pointer.js").Options} */ options ); this.on; this.once; this.un; this.condition_ = options.condition ? options.condition : always; this.createCondition_ = options.createCondition || this.condition_; this.drag_ = options.drag || false; this.extent_ = null; this.pointerHandler_ = null; this.pixelTolerance_ = options.pixelTolerance !== void 0 ? options.pixelTolerance : 10; this.snappedToVertex_ = false; this.extentFeature_ = null; this.vertexFeature_ = null; if (!options) { options = {}; } this.extentOverlay_ = new Vector_default({ source: new Vector_default2({ useSpatialIndex: false, wrapX: !!options.wrapX }), style: options.boxStyle ? options.boxStyle : getDefaultExtentStyleFunction(), updateWhileAnimating: true, updateWhileInteracting: true }); this.vertexOverlay_ = new Vector_default({ source: new Vector_default2({ useSpatialIndex: false, wrapX: !!options.wrapX }), style: options.pointerStyle ? options.pointerStyle : getDefaultPointerStyleFunction(), updateWhileAnimating: true, updateWhileInteracting: true }); if (options.extent) { this.setExtent(options.extent); } } /** * @param {import("../pixel.js").Pixel} pixel cursor location * @param {import("../Map.js").default} map map * @return {import("../coordinate.js").Coordinate|null} snapped vertex on extent * @private */ snapToVertex_(pixel, map) { const pixelCoordinate = map.getCoordinateFromPixelInternal(pixel); const sortByDistance = function(a, b) { return squaredDistanceToSegment(pixelCoordinate, a) - squaredDistanceToSegment(pixelCoordinate, b); }; const extent = this.getExtentInternal(); if (extent) { const segments = getSegments(extent); segments.sort(sortByDistance); const closestSegment = segments[0]; let vertex = closestOnSegment(pixelCoordinate, closestSegment); const vertexPixel = map.getPixelFromCoordinateInternal(vertex); if (distance(pixel, vertexPixel) <= this.pixelTolerance_) { const pixel1 = map.getPixelFromCoordinateInternal(closestSegment[0]); const pixel2 = map.getPixelFromCoordinateInternal(closestSegment[1]); const squaredDist1 = squaredDistance(vertexPixel, pixel1); const squaredDist2 = squaredDistance(vertexPixel, pixel2); const dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); this.snappedToVertex_ = dist <= this.pixelTolerance_; if (this.snappedToVertex_) { vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0]; } return vertex; } } return null; } /** * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent pointer move event * @return {boolean} The event was handled. * @private */ handlePointerMove_(mapBrowserEvent) { const pixel = mapBrowserEvent.pixel; const map = mapBrowserEvent.map; const draggable = this.drag_ && containsCoordinate(this.extent_, mapBrowserEvent.coordinate); let vertex = this.snapToVertex_(pixel, map); if (!vertex && this.createCondition_(mapBrowserEvent) && !draggable) { vertex = map.getCoordinateFromPixelInternal(pixel); } if (draggable && !vertex) { this.getMap().getViewport().classList.add("ol-grab"); } else { this.getMap().getViewport().classList.remove("ol-grab"); } if (vertex) { this.updatePointerFeature_(vertex); return true; } this.noVertexFeature_(); return false; } /** * @param {import("../extent.js").Extent} extent extent * @return {Feature} extent as featrue * @private */ createOrUpdateExtentFeature_(extent) { let extentFeature = this.extentFeature_; if (!extentFeature) { if (!extent) { extentFeature = new Feature_default({}); } else { extentFeature = new Feature_default(fromExtent(extent)); } this.extentFeature_ = extentFeature; this.extentOverlay_.getSource().addFeature(extentFeature); } else { if (!extent) { extentFeature.setGeometry(void 0); } else { extentFeature.setGeometry(fromExtent(extent)); } } return extentFeature; } /** * @param {import("../coordinate.js").Coordinate} vertex location of feature * @param {boolean} [createIfNotExists] create the feature if it does not exist * @return {Feature} vertex as feature * @private */ updatePointerFeature_(vertex, createIfNotExists = true) { let vertexFeature = this.vertexFeature_; if (createIfNotExists && !vertexFeature) { vertexFeature = new Feature_default(new Point_default(vertex)); this.vertexFeature_ = vertexFeature; this.vertexOverlay_.getSource().addFeature(vertexFeature); } if (vertexFeature) { const geometry = vertexFeature.getGeometry(); geometry.setCoordinates(vertex); } return vertexFeature; } /** * Remove the vertex feature if it exists. * @private */ noVertexFeature_() { if (this.vertexFeature_) { this.vertexOverlay_.getSource().removeFeature(this.vertexFeature_); this.vertexFeature_ = null; } } /** * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. * @return {boolean} `false` to stop event propagation. * @override */ handleEvent(mapBrowserEvent) { if (!mapBrowserEvent.originalEvent || !this.condition_(mapBrowserEvent)) { this.noVertexFeature_(); return true; } let handled = this.handlingDownUpSequence; if (mapBrowserEvent.type == MapBrowserEventType_default.POINTERMOVE && !this.handlingDownUpSequence) { handled = this.handlePointerMove_(mapBrowserEvent); } super.handleEvent(mapBrowserEvent); return !handled; } /** * Handle pointer down events. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. * @return {boolean} If the event was consumed. * @override */ handleDownEvent(mapBrowserEvent) { const pixel = mapBrowserEvent.pixel; const map = mapBrowserEvent.map; const extent = this.getExtentInternal(); let vertex = this.snapToVertex_(pixel, map); const getOpposingPoint = function(point) { let x_ = null; let y_ = null; if (point[0] == extent[0]) { x_ = extent[2]; } else if (point[0] == extent[2]) { x_ = extent[0]; } if (point[1] == extent[1]) { y_ = extent[3]; } else if (point[1] == extent[3]) { y_ = extent[1]; } if (x_ !== null && y_ !== null) { return [x_, y_]; } return null; }; if (vertex && extent) { const x = vertex[0] == extent[0] || vertex[0] == extent[2] ? vertex[0] : null; const y = vertex[1] == extent[1] || vertex[1] == extent[3] ? vertex[1] : null; if (x !== null && y !== null) { this.pointerHandler_ = getPointHandler(getOpposingPoint(vertex)); } else if (x !== null) { this.pointerHandler_ = getEdgeHandler( getOpposingPoint([x, extent[1]]), getOpposingPoint([x, extent[3]]) ); } else if (y !== null) { this.pointerHandler_ = getEdgeHandler( getOpposingPoint([extent[0], y]), getOpposingPoint([extent[2], y]) ); } } else { vertex = map.getCoordinateFromPixelInternal(pixel); let drag = false; if (this.drag_) { if (containsCoordinate(extent, vertex)) { this.pointerHandler_ = getDragHandler(extent, vertex); drag = true; } } if (!drag && this.createCondition_(mapBrowserEvent)) { this.setExtent([vertex[0], vertex[1], vertex[0], vertex[1]]); this.pointerHandler_ = getPointHandler(vertex); } } return !!this.pointerHandler_; } /** * Handle pointer drag events. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. * @override */ handleDragEvent(mapBrowserEvent) { if (this.pointerHandler_) { const pixelCoordinate = mapBrowserEvent.coordinate; this.setExtent(this.pointerHandler_(pixelCoordinate)); this.updatePointerFeature_(pixelCoordinate, false); } } /** * Handle pointer up events. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Event. * @return {boolean} If the event was consumed. * @override */ handleUpEvent(mapBrowserEvent) { this.pointerHandler_ = null; const extent = this.getExtentInternal(); if (!extent || getArea(extent) === 0) { this.setExtent(null); } return false; } /** * Remove the interaction from its current map and attach it to the new map. * Subclasses may set up event handlers to get notified about changes to * the map here. * @param {import("../Map.js").default} map Map. * @override */ setMap(map) { this.extentOverlay_.setMap(map); this.vertexOverlay_.setMap(map); super.setMap(map); } /** * Returns the current drawn extent in the view projection (or user projection if set) * * @return {import("../extent.js").Extent} Drawn extent in the view projection. * @api */ getExtent() { return toUserExtent( this.getExtentInternal(), this.getMap().getView().getProjection() ); } /** * Returns the current drawn extent in the view projection * * @return {import("../extent.js").Extent} Drawn extent in the view projection. * @api * @deprecated Use {@link module:ol/interaction/Extent~Extent#getExtent} instead. */ getExtentInternal() { return this.extent_; } /** * Manually sets the drawn extent, using the view projection. * * @param {import("../extent.js").Extent} extent Extent * @api */ setExtent(extent) { this.extent_ = extent ? extent : null; this.createOrUpdateExtentFeature_(extent); this.dispatchEvent(new ExtentEvent(this.extent_)); } }; function getDefaultExtentStyleFunction() { const style = createEditingStyle(); return function(feature, resolution) { return style["Polygon"]; }; } function getDefaultPointerStyleFunction() { const style = createEditingStyle(); return function(feature, resolution) { return style["Point"]; }; } function getPointHandler(fixedPoint) { return function(point) { return boundingExtent([fixedPoint, point]); }; } function getEdgeHandler(fixedP1, fixedP2) { if (fixedP1[0] == fixedP2[0]) { return function(point) { return boundingExtent([fixedP1, [point[0], fixedP2[1]]]); }; } if (fixedP1[1] == fixedP2[1]) { return function(point) { return boundingExtent([fixedP1, [fixedP2[0], point[1]]]); }; } return null; } function getDragHandler(extent, vertex) { return function(point) { const deltaX = point[0] - vertex[0]; const deltaY = point[1] - vertex[1]; return [ extent[0] + deltaX, extent[1] + deltaY, extent[2] + deltaX, extent[3] + deltaY ]; }; } function getSegments(extent) { return [ [ [extent[0], extent[1]], [extent[0], extent[3]] ], [ [extent[0], extent[3]], [extent[2], extent[3]] ], [ [extent[2], extent[3]], [extent[2], extent[1]] ], [ [extent[2], extent[1]], [extent[0], extent[1]] ] ]; } var Extent_default = Extent; // node_modules/ol/interaction/Link.js function to5(number) { return toFixed(number, 5); } function readNumber(string) { return parseFloat(string); } function writeNumber(number) { return to5(number).toString(); } function differentNumber(a, b) { if (isNaN(a)) { return false; } return a !== readNumber(writeNumber(b)); } function differentArray(a, b) { return differentNumber(a[0], b[0]) || differentNumber(a[1], b[1]); } var Link = class extends Interaction_default { /** * @param {Options} [options] Link options. */ constructor(options) { super(); options = Object.assign( { animate: true, params: ["x", "y", "z", "r", "l"], replace: false, prefix: "" }, options || {} ); let animationOptions; if (options.animate === true) { animationOptions = { duration: 250 }; } else if (!options.animate) { animationOptions = null; } else { animationOptions = options.animate; } this.animationOptions_ = animationOptions; this.params_ = options.params.reduce((acc, value) => { acc[value] = true; return acc; }, {}); this.replace_ = options.replace; this.prefix_ = options.prefix; this.listenerKeys_ = []; this.initial_ = true; this.updateState_ = this.updateState_.bind(this); this.trackedCallbacks_ = {}; this.trackedValues_ = {}; } /** * @private * @param {string} name A parameter name. * @return {string} A name with the prefix applied. */ getParamName_(name) { if (!this.prefix_) { return name; } return this.prefix_ + name; } /** * @private * @param {URLSearchParams} params The search params. * @param {string} name The unprefixed parameter name. * @return {string|null} The parameter value. */ get_(params, name) { return params.get(this.getParamName_(name)); } /** * @private * @param {URLSearchParams} params The search params. * @param {string} name The unprefixed parameter name. * @param {string} value The param value. */ set_(params, name, value) { if (!(name in this.params_)) { return; } params.set(this.getParamName_(name), value); } /** * @private * @param {URLSearchParams} params The search params. * @param {string} name The unprefixed parameter name. */ delete_(params, name) { if (!(name in this.params_)) { return; } params.delete(this.getParamName_(name)); } /** * @param {import("../Map.js").default|null} map Map. * @override */ setMap(map) { const oldMap = this.getMap(); super.setMap(map); if (map === oldMap) { return; } if (oldMap) { this.unregisterListeners_(oldMap); } if (map) { this.initial_ = true; this.updateState_(); this.registerListeners_(map); } } /** * @param {import("../Map.js").default} map Map. * @private */ registerListeners_(map) { this.listenerKeys_.push( listen(map, MapEventType_default.MOVEEND, this.updateUrl_, this), listen(map.getLayerGroup(), EventType_default.CHANGE, this.updateUrl_, this), listen(map, "change:layergroup", this.handleChangeLayerGroup_, this) ); if (!this.replace_) { addEventListener("popstate", this.updateState_); } } /** * @param {import("../Map.js").default} map Map. * @private */ unregisterListeners_(map) { for (let i = 0, ii = this.listenerKeys_.length; i < ii; ++i) { unlistenByKey(this.listenerKeys_[i]); } this.listenerKeys_.length = 0; if (!this.replace_) { removeEventListener("popstate", this.updateState_); } const url = new URL(window.location.href); const params = url.searchParams; this.delete_(params, "x"); this.delete_(params, "y"); this.delete_(params, "z"); this.delete_(params, "r"); this.delete_(params, "l"); window.history.replaceState(null, "", url); } /** * @private */ handleChangeLayerGroup_() { const map = this.getMap(); if (!map) { return; } this.unregisterListeners_(map); this.registerListeners_(map); this.initial_ = true; this.updateUrl_(); } /** * @private */ updateState_() { const url = new URL(window.location.href); const params = url.searchParams; for (const key in this.trackedCallbacks_) { const value = params.get(key); if (key in this.trackedCallbacks_ && value !== this.trackedValues_[key]) { this.trackedValues_[key] = value; this.trackedCallbacks_[key](value); } } const map = this.getMap(); if (!map) { return; } const view = map.getView(); if (!view) { return; } let updateView = false; const viewProperties = {}; const zoom = readNumber(this.get_(params, "z")); if ("z" in this.params_ && differentNumber(zoom, view.getZoom())) { updateView = true; viewProperties.zoom = zoom; } const rotation = readNumber(this.get_(params, "r")); if ("r" in this.params_ && differentNumber(rotation, view.getRotation())) { updateView = true; viewProperties.rotation = rotation; } const center = [ readNumber(this.get_(params, "x")), readNumber(this.get_(params, "y")) ]; if (("x" in this.params_ || "y" in this.params_) && differentArray(center, view.getCenter())) { updateView = true; viewProperties.center = center; } if (updateView) { if (!this.initial_ && this.animationOptions_) { view.animate(Object.assign(viewProperties, this.animationOptions_)); } else { if (viewProperties.center) { view.setCenter(viewProperties.center); } if ("zoom" in viewProperties) { view.setZoom(viewProperties.zoom); } if ("rotation" in viewProperties) { view.setRotation(viewProperties.rotation); } } } const layers = map.getAllLayers(); const layersParam = this.get_(params, "l"); if ("l" in this.params_ && layersParam && layersParam.length === layers.length) { for (let i = 0, ii = layers.length; i < ii; ++i) { const value = parseInt(layersParam[i]); if (!isNaN(value)) { const visible = Boolean(value); const layer = layers[i]; if (layer.getVisible() !== visible) { layer.setVisible(visible); } } } } } /** * Register a listener for a URL search parameter. The callback will be called with a new value * when the corresponding search parameter changes due to history events (e.g. browser navigation). * * @param {string} key The URL search parameter. * @param {Callback} callback The function to call when the search parameter changes. * @return {string|null} The initial value of the search parameter (or null if absent from the URL). * @api */ track(key, callback) { this.trackedCallbacks_[key] = callback; const url = new URL(window.location.href); const params = url.searchParams; const value = params.get(key); this.trackedValues_[key] = value; return value; } /** * Update the URL with a new search parameter value. If the value is null, it will be * deleted from the search parameters. * * @param {string} key The URL search parameter. * @param {string|null} value The updated value (or null to remove it from the URL). * @api */ update(key, value) { const url = new URL(window.location.href); const params = url.searchParams; if (value === null) { params.delete(key); } else { params.set(key, value); } if (key in this.trackedValues_) { this.trackedValues_[key] = value; } this.updateHistory_(url); } /** * @private */ updateUrl_() { const map = this.getMap(); if (!map) { return; } const view = map.getView(); if (!view) { return; } const center = view.getCenter(); const zoom = view.getZoom(); const rotation = view.getRotation(); const layers = map.getAllLayers(); const visibilities = new Array(layers.length); for (let i = 0, ii = layers.length; i < ii; ++i) { visibilities[i] = layers[i].getVisible() ? "1" : "0"; } const url = new URL(window.location.href); const params = url.searchParams; this.set_(params, "x", writeNumber(center[0])); this.set_(params, "y", writeNumber(center[1])); this.set_(params, "z", writeNumber(zoom)); this.set_(params, "r", writeNumber(rotation)); this.set_(params, "l", visibilities.join("")); this.updateHistory_(url); this.initial_ = false; } /** * @private * @param {URL} url The URL. */ updateHistory_(url) { if (url.href !== window.location.href) { if (this.initial_ || this.replace_) { window.history.replaceState(history.state, "", url); } else { window.history.pushState(null, "", url); } } } }; var Link_default = Link; // node_modules/ol/interaction/Modify.js var CIRCLE_CENTER_INDEX = 0; var CIRCLE_CIRCUMFERENCE_INDEX = 1; var tempExtent = [0, 0, 0, 0]; var tempSegment = []; var ModifyEventType = { /** * Triggered upon feature modification start * @event ModifyEvent#modifystart * @api */ MODIFYSTART: "modifystart", /** * Triggered upon feature modification end * @event ModifyEvent#modifyend * @api */ MODIFYEND: "modifyend" }; function getCoordinatesArray(coordinates, geometryType, depth) { let coordinatesArray; switch (geometryType) { case "LineString": coordinatesArray = coordinates; break; case "MultiLineString": case "Polygon": coordinatesArray = coordinates[depth[0]]; break; case "MultiPolygon": coordinatesArray = coordinates[depth[1]][depth[0]]; break; default: } return coordinatesArray; } var ModifyEvent = class extends Event_default { /** * @param {ModifyEventType} type Type. * @param {Collection} features * The features modified. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent * Associated {@link module:ol/MapBrowserEvent~MapBrowserEvent}. */ constructor(type, features, mapBrowserEvent) { super(type); this.features = features; this.mapBrowserEvent = mapBrowserEvent; } }; var Modify = class extends Pointer_default { /** * @param {Options} options Options. */ constructor(options) { super( /** @type {import("./Pointer.js").Options} */ options ); this.on; this.once; this.un; this.boundHandleFeatureChange_ = this.handleFeatureChange_.bind(this); this.condition_ = options.condition ? options.condition : primaryAction; this.defaultDeleteCondition_ = function(mapBrowserEvent) { return altKeyOnly(mapBrowserEvent) && singleClick(mapBrowserEvent); }; this.deleteCondition_ = options.deleteCondition ? options.deleteCondition : this.defaultDeleteCondition_; this.insertVertexCondition_ = options.insertVertexCondition ? options.insertVertexCondition : always; this.vertexFeature_ = null; this.vertexSegments_ = null; this.lastCoordinate_ = [0, 0]; this.ignoreNextSingleClick_ = false; this.featuresBeingModified_ = null; this.rBush_ = new RBush_default(); this.pixelTolerance_ = options.pixelTolerance !== void 0 ? options.pixelTolerance : 10; this.snappedToVertex_ = false; this.changingFeature_ = false; this.dragSegments_ = []; this.overlay_ = new Vector_default({ source: new Vector_default2({ useSpatialIndex: false, wrapX: !!options.wrapX }), style: options.style ? options.style : getDefaultStyleFunction(), updateWhileAnimating: true, updateWhileInteracting: true }); this.SEGMENT_WRITERS_ = { Point: this.writePointGeometry_.bind(this), LineString: this.writeLineStringGeometry_.bind(this), LinearRing: this.writeLineStringGeometry_.bind(this), Polygon: this.writePolygonGeometry_.bind(this), MultiPoint: this.writeMultiPointGeometry_.bind(this), MultiLineString: this.writeMultiLineStringGeometry_.bind(this), MultiPolygon: this.writeMultiPolygonGeometry_.bind(this), Circle: this.writeCircleGeometry_.bind(this), GeometryCollection: this.writeGeometryCollectionGeometry_.bind(this) }; this.source_ = null; this.traceSource_ = options.traceSource || options.source || null; this.traceCondition_; this.setTrace(options.trace || false); this.traceState_ = { active: false }; this.traceSegments_ = null; this.hitDetection_ = null; let features; if (options.features) { features = options.features; } else if (options.source) { this.source_ = options.source; features = new Collection_default(this.source_.getFeatures()); this.source_.addEventListener( VectorEventType_default.ADDFEATURE, this.handleSourceAdd_.bind(this) ); this.source_.addEventListener( VectorEventType_default.REMOVEFEATURE, this.handleSourceRemove_.bind(this) ); } if (!features) { throw new Error( "The modify interaction requires features, a source or a layer" ); } if (options.hitDetection) { this.hitDetection_ = options.hitDetection; } this.features_ = features; this.features_.forEach(this.addFeature_.bind(this)); this.features_.addEventListener( CollectionEventType_default.ADD, this.handleFeatureAdd_.bind(this) ); this.features_.addEventListener( CollectionEventType_default.REMOVE, this.handleFeatureRemove_.bind(this) ); this.lastPointerEvent_ = null; this.delta_ = [0, 0]; this.snapToPointer_ = options.snapToPointer === void 0 ? !this.hitDetection_ : options.snapToPointer; } /** * Toggle tracing mode or set a tracing condition. * * @param {boolean|import("../events/condition.js").Condition} trace A boolean to toggle tracing mode or an event * condition that will be checked when a feature is clicked to determine if tracing should be active. */ setTrace(trace) { let condition; if (!trace) { condition = never; } else if (trace === true) { condition = always; } else { condition = trace; } this.traceCondition_ = condition; } /** * @param {Feature} feature Feature. * @private */ addFeature_(feature) { const geometry = feature.getGeometry(); if (geometry) { const writer = this.SEGMENT_WRITERS_[geometry.getType()]; if (writer) { writer(feature, geometry); } } const map = this.getMap(); if (map && map.isRendered() && this.getActive()) { this.handlePointerAtPixel_(this.lastCoordinate_); } feature.addEventListener(EventType_default.CHANGE, this.boundHandleFeatureChange_); } /** * @param {import("../MapBrowserEvent.js").default} evt Map browser event. * @param {Array} segments The segments subject to modification. * @private */ willModifyFeatures_(evt, segments) { if (!this.featuresBeingModified_) { this.featuresBeingModified_ = new Collection_default(); const features = this.featuresBeingModified_.getArray(); for (let i = 0, ii = segments.length; i < ii; ++i) { const feature = segments[i].feature; if (feature && !features.includes(feature)) { this.featuresBeingModified_.push(feature); } } if (this.featuresBeingModified_.getLength() === 0) { this.featuresBeingModified_ = null; } else { this.dispatchEvent( new ModifyEvent( ModifyEventType.MODIFYSTART, this.featuresBeingModified_, evt ) ); } } } /** * @param {Feature} feature Feature. * @private */ removeFeature_(feature) { this.removeFeatureSegmentData_(feature); if (this.vertexFeature_ && this.features_.getLength() === 0) { this.overlay_.getSource().removeFeature(this.vertexFeature_); this.vertexFeature_ = null; } feature.removeEventListener( EventType_default.CHANGE, this.boundHandleFeatureChange_ ); } /** * @param {Feature} feature Feature. * @private */ removeFeatureSegmentData_(feature) { const rBush = this.rBush_; const nodesToRemove = []; rBush.forEach( /** * @param {SegmentData} node RTree node. */ function(node) { if (feature === node.feature) { nodesToRemove.push(node); } } ); for (let i = nodesToRemove.length - 1; i >= 0; --i) { const nodeToRemove = nodesToRemove[i]; for (let j = this.dragSegments_.length - 1; j >= 0; --j) { if (this.dragSegments_[j][0] === nodeToRemove) { this.dragSegments_.splice(j, 1); } } rBush.remove(nodeToRemove); } } /** * Activate or deactivate the interaction. * @param {boolean} active Active. * @observable * @api * @override */ setActive(active) { if (this.vertexFeature_ && !active) { this.overlay_.getSource().removeFeature(this.vertexFeature_); this.vertexFeature_ = null; } super.setActive(active); } /** * Remove the interaction from its current map and attach it to the new map. * Subclasses may set up event handlers to get notified about changes to * the map here. * @param {import("../Map.js").default} map Map. * @override */ setMap(map) { this.overlay_.setMap(map); super.setMap(map); } /** * Get the overlay layer that this interaction renders the modification point or vertex to. * @return {VectorLayer} Overlay layer. * @api */ getOverlay() { return this.overlay_; } /** * @param {import("../source/Vector.js").VectorSourceEvent} event Event. * @private */ handleSourceAdd_(event) { if (event.feature) { this.features_.push(event.feature); } } /** * @param {import("../source/Vector.js").VectorSourceEvent} event Event. * @private */ handleSourceRemove_(event) { if (event.feature) { this.features_.remove(event.feature); } } /** * @param {import("../Collection.js").CollectionEvent} evt Event. * @private */ handleFeatureAdd_(evt) { this.addFeature_(evt.element); } /** * @param {import("../events/Event.js").default} evt Event. * @private */ handleFeatureChange_(evt) { if (!this.changingFeature_) { const feature = ( /** @type {Feature} */ evt.target ); this.removeFeature_(feature); this.addFeature_(feature); } } /** * @param {import("../Collection.js").CollectionEvent} evt Event. * @private */ handleFeatureRemove_(evt) { this.removeFeature_(evt.element); } /** * @param {Feature} feature Feature * @param {Point} geometry Geometry. * @private */ writePointGeometry_(feature, geometry) { const coordinates = geometry.getCoordinates(); const segmentData = { feature, geometry, segment: [coordinates, coordinates] }; this.rBush_.insert(geometry.getExtent(), segmentData); } /** * @param {Feature} feature Feature * @param {import("../geom/MultiPoint.js").default} geometry Geometry. * @private */ writeMultiPointGeometry_(feature, geometry) { const points = geometry.getCoordinates(); for (let i = 0, ii = points.length; i < ii; ++i) { const coordinates = points[i]; const segmentData = { feature, geometry, depth: [i], index: i, segment: [coordinates, coordinates] }; this.rBush_.insert(geometry.getExtent(), segmentData); } } /** * @param {Feature} feature Feature * @param {import("../geom/LineString.js").default} geometry Geometry. * @private */ writeLineStringGeometry_(feature, geometry) { const coordinates = geometry.getCoordinates(); for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) { const segment = coordinates.slice(i, i + 2); const segmentData = { feature, geometry, index: i, segment }; this.rBush_.insert(boundingExtent(segment), segmentData); } } /** * @param {Feature} feature Feature * @param {import("../geom/MultiLineString.js").default} geometry Geometry. * @private */ writeMultiLineStringGeometry_(feature, geometry) { const lines = geometry.getCoordinates(); for (let j = 0, jj = lines.length; j < jj; ++j) { const coordinates = lines[j]; for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) { const segment = coordinates.slice(i, i + 2); const segmentData = { feature, geometry, depth: [j], index: i, segment }; this.rBush_.insert(boundingExtent(segment), segmentData); } } } /** * @param {Feature} feature Feature * @param {import("../geom/Polygon.js").default} geometry Geometry. * @private */ writePolygonGeometry_(feature, geometry) { const rings = geometry.getCoordinates(); for (let j = 0, jj = rings.length; j < jj; ++j) { const coordinates = rings[j]; for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) { const segment = coordinates.slice(i, i + 2); const segmentData = { feature, geometry, depth: [j], index: i, segment }; this.rBush_.insert(boundingExtent(segment), segmentData); } } } /** * @param {Feature} feature Feature * @param {import("../geom/MultiPolygon.js").default} geometry Geometry. * @private */ writeMultiPolygonGeometry_(feature, geometry) { const polygons = geometry.getCoordinates(); for (let k = 0, kk = polygons.length; k < kk; ++k) { const rings = polygons[k]; for (let j = 0, jj = rings.length; j < jj; ++j) { const coordinates = rings[j]; for (let i = 0, ii = coordinates.length - 1; i < ii; ++i) { const segment = coordinates.slice(i, i + 2); const segmentData = { feature, geometry, depth: [j, k], index: i, segment }; this.rBush_.insert(boundingExtent(segment), segmentData); } } } } /** * We convert a circle into two segments. The segment at index * {@link CIRCLE_CENTER_INDEX} is the * circle's center (a point). The segment at index * {@link CIRCLE_CIRCUMFERENCE_INDEX} is * the circumference, and is not a line segment. * * @param {Feature} feature Feature. * @param {import("../geom/Circle.js").default} geometry Geometry. * @private */ writeCircleGeometry_(feature, geometry) { const coordinates = geometry.getCenter(); const centerSegmentData = { feature, geometry, index: CIRCLE_CENTER_INDEX, segment: [coordinates, coordinates] }; const circumferenceSegmentData = { feature, geometry, index: CIRCLE_CIRCUMFERENCE_INDEX, segment: [coordinates, coordinates] }; const featureSegments = [centerSegmentData, circumferenceSegmentData]; centerSegmentData.featureSegments = featureSegments; circumferenceSegmentData.featureSegments = featureSegments; this.rBush_.insert(createOrUpdateFromCoordinate(coordinates), centerSegmentData); let circleGeometry = ( /** @type {import("../geom/Geometry.js").default} */ geometry ); const userProjection = getUserProjection(); if (userProjection && this.getMap()) { const projection = this.getMap().getView().getProjection(); circleGeometry = circleGeometry.clone().transform(userProjection, projection); circleGeometry = fromCircle( /** @type {import("../geom/Circle.js").default} */ circleGeometry ).transform(projection, userProjection); } this.rBush_.insert(circleGeometry.getExtent(), circumferenceSegmentData); } /** * @param {Feature} feature Feature * @param {import("../geom/GeometryCollection.js").default} geometry Geometry. * @private */ writeGeometryCollectionGeometry_(feature, geometry) { const geometries = geometry.getGeometriesArray(); for (let i = 0; i < geometries.length; ++i) { const geometry2 = geometries[i]; const writer = this.SEGMENT_WRITERS_[geometry2.getType()]; writer(feature, geometry2); } } /** * @param {import("../coordinate.js").Coordinate} coordinates Coordinates. * @param {Array} features The features being modified. * @param {Array} geometries The geometries being modified. * @param {boolean} existing The vertex represents an existing vertex. * @return {Feature} Vertex feature. * @private */ createOrUpdateVertexFeature_(coordinates, features, geometries, existing) { let vertexFeature = this.vertexFeature_; if (!vertexFeature) { vertexFeature = new Feature_default(new Point_default(coordinates)); this.vertexFeature_ = vertexFeature; this.overlay_.getSource().addFeature(vertexFeature); } else { const geometry = vertexFeature.getGeometry(); geometry.setCoordinates(coordinates); } vertexFeature.set("features", features); vertexFeature.set("geometries", geometries); vertexFeature.set("existing", existing); return vertexFeature; } /** * Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} and may modify the geometry. * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. * @return {boolean} `false` to stop event propagation. * @override */ handleEvent(mapBrowserEvent) { if (!mapBrowserEvent.originalEvent) { return true; } this.lastPointerEvent_ = mapBrowserEvent; let handled; if (!mapBrowserEvent.map.getView().getInteracting() && mapBrowserEvent.type == MapBrowserEventType_default.POINTERMOVE && !this.handlingDownUpSequence) { this.handlePointerMove_(mapBrowserEvent); } if (this.vertexFeature_ && this.deleteCondition_(mapBrowserEvent)) { if (mapBrowserEvent.type != MapBrowserEventType_default.SINGLECLICK || !this.ignoreNextSingleClick_) { handled = this.removePoint(); } else { handled = true; } } if (mapBrowserEvent.type == MapBrowserEventType_default.SINGLECLICK) { this.ignoreNextSingleClick_ = false; } return super.handleEvent(mapBrowserEvent) && !handled; } /** * @param {import("../coordinate.js").Coordinate} pixelCoordinate Pixel coordinate. * @return {Array|undefined} Insert vertices and update drag segments. * @private */ findInsertVerticesAndUpdateDragSegments_(pixelCoordinate) { this.handlePointerAtPixel_(pixelCoordinate); this.dragSegments_.length = 0; this.featuresBeingModified_ = null; const vertexFeature = this.vertexFeature_; if (!vertexFeature) { return; } const projection = this.getMap().getView().getProjection(); const insertVertices = []; const vertex = this.vertexFeature_.getGeometry().getCoordinates(); const vertexExtent = boundingExtent([vertex]); const segmentDataMatches = this.rBush_.getInExtent(vertexExtent); const componentSegments = {}; segmentDataMatches.sort(compareIndexes); for (let i = 0, ii = segmentDataMatches.length; i < ii; ++i) { const segmentDataMatch = segmentDataMatches[i]; const segment = segmentDataMatch.segment; let uid = getUid(segmentDataMatch.geometry); const depth = segmentDataMatch.depth; if (depth) { uid += "-" + depth.join("-"); } if (!componentSegments[uid]) { componentSegments[uid] = new Array(2); } if (segmentDataMatch.geometry.getType() === "Circle" && segmentDataMatch.index === CIRCLE_CIRCUMFERENCE_INDEX) { const closestVertex = closestOnSegmentData( pixelCoordinate, segmentDataMatch, projection ); if (equals2(closestVertex, vertex) && !componentSegments[uid][0]) { this.dragSegments_.push([segmentDataMatch, 0]); componentSegments[uid][0] = segmentDataMatch; } continue; } if (equals2(segment[0], vertex) && !componentSegments[uid][0]) { this.dragSegments_.push([segmentDataMatch, 0]); componentSegments[uid][0] = segmentDataMatch; continue; } if (equals2(segment[1], vertex) && !componentSegments[uid][1]) { if (componentSegments[uid][0] && componentSegments[uid][0].index === 0) { let coordinates = segmentDataMatch.geometry.getCoordinates(); switch (segmentDataMatch.geometry.getType()) { // prevent dragging closed linestrings by the connecting node case "LineString": case "MultiLineString": continue; // if dragging the first vertex of a polygon, ensure the other segment // belongs to the closing vertex of the linear ring case "MultiPolygon": coordinates = coordinates[depth[1]]; /* falls through */ case "Polygon": if (segmentDataMatch.index !== coordinates[depth[0]].length - 2) { continue; } break; default: } } this.dragSegments_.push([segmentDataMatch, 1]); componentSegments[uid][1] = segmentDataMatch; continue; } if (getUid(segment) in this.vertexSegments_ && !componentSegments[uid][0] && !componentSegments[uid][1]) { insertVertices.push(segmentDataMatch); } } return insertVertices; } /** * @private */ deactivateTrace_() { this.traceState_ = { active: false }; } /** * Update the trace. * @param {import("../MapBrowserEvent.js").default} event Event. * @private */ updateTrace_(event) { const traceState = this.traceState_; if (!traceState.active) { return; } if (traceState.targetIndex === -1) { const startPx = event.map.getPixelFromCoordinate(traceState.startCoord); if (distance(startPx, event.pixel) < this.pixelTolerance_) { return; } } const updatedTraceTarget = getTraceTargetUpdate( event.coordinate, traceState, event.map, this.pixelTolerance_ ); if (traceState.targetIndex === -1 && Math.sqrt(updatedTraceTarget.closestTargetDistance) / event.map.getView().getResolution() > this.pixelTolerance_) { return; } if (traceState.targetIndex !== updatedTraceTarget.index) { if (traceState.targetIndex !== -1) { const oldTarget = traceState.targets[traceState.targetIndex]; this.removeTracedCoordinates_(oldTarget.startIndex, oldTarget.endIndex); } else { for (const traceSegment of this.traceSegments_) { const segmentData = traceSegment[0]; const geometry = segmentData.geometry; const index = traceSegment[1]; const coordinates = geometry.getCoordinates(); const coordinatesArray = getCoordinatesArray( coordinates, geometry.getType(), segmentData.depth ); coordinatesArray.splice(segmentData.index + index, 1); geometry.setCoordinates(coordinates); if (index === 0) { segmentData.index -= 1; } } } const newTarget = traceState.targets[updatedTraceTarget.index]; this.addTracedCoordinates_( newTarget, newTarget.startIndex, updatedTraceTarget.endIndex ); } else { const target2 = traceState.targets[traceState.targetIndex]; this.addOrRemoveTracedCoordinates_(target2, updatedTraceTarget.endIndex); } traceState.targetIndex = updatedTraceTarget.index; const target = traceState.targets[traceState.targetIndex]; target.endIndex = updatedTraceTarget.endIndex; } getTraceCandidates_(event) { const map = this.getMap(); const tolerance = this.pixelTolerance_; const lowerLeft = map.getCoordinateFromPixel([ event.pixel[0] - tolerance, event.pixel[1] + tolerance ]); const upperRight = map.getCoordinateFromPixel([ event.pixel[0] + tolerance, event.pixel[1] - tolerance ]); const extent = boundingExtent([lowerLeft, upperRight]); const features = this.traceSource_.getFeaturesInExtent(extent); return features; } /** * Activate or deactivate trace state based on a browser event. * @param {import("../MapBrowserEvent.js").default} event Event. * @private */ toggleTraceState_(event) { if (!this.traceSource_ || !this.traceCondition_(event)) { return; } if (this.traceState_.active) { this.deactivateTrace_(); this.traceSegments_ = null; return; } const features = this.getTraceCandidates_(event); if (features.length === 0) { return; } const targets = getTraceTargets(event.coordinate, features); if (targets.length) { this.traceState_ = { active: true, startCoord: event.coordinate.slice(), targets, targetIndex: -1 }; } } /** * @param {import('./tracing.js').TraceTarget} target The trace target. * @param {number} endIndex The new end index of the trace. * @private */ addOrRemoveTracedCoordinates_(target, endIndex) { const previouslyForward = target.startIndex <= target.endIndex; const currentlyForward = target.startIndex <= endIndex; if (previouslyForward === currentlyForward) { if (previouslyForward && endIndex > target.endIndex || !previouslyForward && endIndex < target.endIndex) { this.addTracedCoordinates_(target, target.endIndex, endIndex); } else if (previouslyForward && endIndex < target.endIndex || !previouslyForward && endIndex > target.endIndex) { this.removeTracedCoordinates_(endIndex, target.endIndex); } } else { this.removeTracedCoordinates_(target.startIndex, target.endIndex); this.addTracedCoordinates_(target, target.startIndex, endIndex); } } /** * @param {number} fromIndex The start index. * @param {number} toIndex The end index. * @private */ removeTracedCoordinates_(fromIndex, toIndex) { if (fromIndex === toIndex) { return; } let remove = 0; if (fromIndex < toIndex) { const start = Math.ceil(fromIndex); let end = Math.floor(toIndex); if (end === toIndex) { end -= 1; } remove = end - start + 1; } else { const start = Math.floor(fromIndex); let end = Math.ceil(toIndex); if (end === toIndex) { end += 1; } remove = start - end + 1; } if (remove > 0) { for (const traceSegment of this.traceSegments_) { const segmentData = traceSegment[0]; const geometry = segmentData.geometry; const index = traceSegment[1]; let removeIndex = traceSegment[0].index + 1; if (index === 1) { removeIndex -= remove; } const coordinates = geometry.getCoordinates(); const coordinatesArray = getCoordinatesArray( coordinates, geometry.getType(), segmentData.depth ); coordinatesArray.splice(removeIndex, remove); geometry.setCoordinates(coordinates); if (index === 1) { segmentData.index -= remove; } } } } /** * @param {import('./tracing.js').TraceTarget} target The trace target. * @param {number} fromIndex The start index. * @param {number} toIndex The end index. * @private */ addTracedCoordinates_(target, fromIndex, toIndex) { if (fromIndex === toIndex) { return; } const newCoordinates = []; if (fromIndex < toIndex) { const start = Math.ceil(fromIndex); let end = Math.floor(toIndex); if (end === toIndex) { end -= 1; } for (let i = start; i <= end; ++i) { newCoordinates.push(getCoordinate(target.coordinates, i)); } } else { const start = Math.floor(fromIndex); let end = Math.ceil(toIndex); if (end === toIndex) { end += 1; } for (let i = start; i >= end; --i) { newCoordinates.push(getCoordinate(target.coordinates, i)); } } if (newCoordinates.length) { for (const traceSegment of this.traceSegments_) { const segmentData = traceSegment[0]; const geometry = segmentData.geometry; const index = traceSegment[1]; const insertIndex = segmentData.index + 1; if (index === 0) { newCoordinates.reverse(); } const coordinates = geometry.getCoordinates(); const coordinatesArray = getCoordinatesArray( coordinates, geometry.getType(), segmentData.depth ); coordinatesArray.splice(insertIndex, 0, ...newCoordinates); geometry.setCoordinates(coordinates); if (index === 1) { segmentData.index += newCoordinates.length; } } } } /** * @param {import('../coordinate.js').Coordinate} vertex Vertex. * @param {DragSegment} dragSegment Drag segment. */ updateGeometry_(vertex, dragSegment) { const segmentData = dragSegment[0]; const depth = segmentData.depth; let coordinates; const segment = segmentData.segment; const geometry = segmentData.geometry; const index = dragSegment[1]; while (vertex.length < geometry.getStride()) { vertex.push(segment[index][vertex.length]); } switch (geometry.getType()) { case "Point": coordinates = vertex; segment[0] = vertex; segment[1] = vertex; break; case "MultiPoint": coordinates = geometry.getCoordinates(); coordinates[segmentData.index] = vertex; segment[0] = vertex; segment[1] = vertex; break; case "LineString": coordinates = geometry.getCoordinates(); coordinates[segmentData.index + index] = vertex; segment[index] = vertex; break; case "MultiLineString": coordinates = geometry.getCoordinates(); coordinates[depth[0]][segmentData.index + index] = vertex; segment[index] = vertex; break; case "Polygon": coordinates = geometry.getCoordinates(); coordinates[depth[0]][segmentData.index + index] = vertex; segment[index] = vertex; break; case "MultiPolygon": coordinates = geometry.getCoordinates(); coordinates[depth[1]][depth[0]][segmentData.index + index] = vertex; segment[index] = vertex; break; case "Circle": const circle = ( /** @type {import("../geom/Circle.js").default} */ geometry ); segment[0] = vertex; segment[1] = vertex; if (segmentData.index === CIRCLE_CENTER_INDEX) { this.changingFeature_ = true; circle.setCenter(vertex); this.changingFeature_ = false; } else { this.changingFeature_ = true; const projection = this.getMap().getView().getProjection(); let radius = distance( fromUserCoordinate(circle.getCenter(), projection), fromUserCoordinate(vertex, projection) ); const userProjection = getUserProjection(); if (userProjection) { const circleGeometry = circle.clone().transform(userProjection, projection); circleGeometry.setRadius(radius); radius = circleGeometry.transform(projection, userProjection).getRadius(); } circle.setRadius(radius); this.changingFeature_ = false; } break; default: } if (coordinates) { this.setGeometryCoordinates_(geometry, coordinates); } } /** * Handle pointer drag events. * @param {import("../MapBrowserEvent.js").default} evt Event. * @override */ handleDragEvent(evt) { this.ignoreNextSingleClick_ = false; this.willModifyFeatures_( evt, this.dragSegments_.map(([segment]) => segment) ); const vertex = [ evt.coordinate[0] + this.delta_[0], evt.coordinate[1] + this.delta_[1] ]; const features = []; const geometries = []; const startTraceCoord = this.traceState_.active && !this.traceSegments_ ? this.traceState_.startCoord : null; if (startTraceCoord) { this.traceSegments_ = []; for (const dragSegment of this.dragSegments_) { const segmentData = dragSegment[0]; const eligibleForTracing = distance( closestOnSegment(startTraceCoord, segmentData.segment), startTraceCoord ) / evt.map.getView().getResolution() < 1; if (eligibleForTracing) { this.traceSegments_.push(dragSegment); } } } for (let i = 0, ii = this.dragSegments_.length; i < ii; ++i) { const dragSegment = this.dragSegments_[i]; const segmentData = dragSegment[0]; const feature = segmentData.feature; if (!features.includes(feature)) { features.push(feature); } const geometry = segmentData.geometry; if (!geometries.includes(geometry)) { geometries.push(geometry); } this.updateGeometry_(vertex, dragSegment); } this.updateTrace_(evt); this.createOrUpdateVertexFeature_(vertex, features, geometries, true); } /** * Handle pointer down events. * @param {import("../MapBrowserEvent.js").default} evt Event. * @return {boolean} If the event was consumed. * @override */ handleDownEvent(evt) { if (!this.condition_(evt)) { return false; } const pixelCoordinate = evt.coordinate; const insertVertices = this.findInsertVerticesAndUpdateDragSegments_(pixelCoordinate); if ((insertVertices == null ? void 0 : insertVertices.length) && this.insertVertexCondition_(evt)) { this.willModifyFeatures_(evt, insertVertices); if (this.vertexFeature_) { const vertex = this.vertexFeature_.getGeometry().getCoordinates(); for (let j = insertVertices.length - 1; j >= 0; --j) { this.insertVertex_(insertVertices[j], vertex); } this.ignoreNextSingleClick_ = true; } } return !!this.vertexFeature_; } /** * Handle pointer up events. * @param {import("../MapBrowserEvent.js").default} evt Event. * @return {boolean} If the event was consumed. * @override */ handleUpEvent(evt) { for (let i = this.dragSegments_.length - 1; i >= 0; --i) { const segmentData = this.dragSegments_[i][0]; const geometry = segmentData.geometry; if (geometry.getType() === "Circle") { const circle = ( /** @type {import("../geom/Circle.js").default} */ geometry ); const coordinates = circle.getCenter(); const centerSegmentData = segmentData.featureSegments[0]; const circumferenceSegmentData = segmentData.featureSegments[1]; centerSegmentData.segment[0] = coordinates; centerSegmentData.segment[1] = coordinates; circumferenceSegmentData.segment[0] = coordinates; circumferenceSegmentData.segment[1] = coordinates; this.rBush_.update(createOrUpdateFromCoordinate(coordinates), centerSegmentData); let circleGeometry = circle; const userProjection = getUserProjection(); if (userProjection) { const projection = evt.map.getView().getProjection(); circleGeometry = circleGeometry.clone().transform(userProjection, projection); circleGeometry = fromCircle(circleGeometry).transform( projection, userProjection ); } this.rBush_.update( circleGeometry.getExtent(), circumferenceSegmentData ); } else { this.rBush_.update(boundingExtent(segmentData.segment), segmentData); } } if (this.featuresBeingModified_) { this.toggleTraceState_(evt); this.dispatchEvent( new ModifyEvent( ModifyEventType.MODIFYEND, this.featuresBeingModified_, evt ) ); this.featuresBeingModified_ = null; } return false; } /** * @param {import("../MapBrowserEvent.js").default} evt Event. * @private */ handlePointerMove_(evt) { this.lastCoordinate_ = evt.coordinate; this.handlePointerAtPixel_(this.lastCoordinate_); } /** * @param {import("../coordinate.js").Coordinate} pixelCoordinate The pixel Coordinate. * @private */ handlePointerAtPixel_(pixelCoordinate) { const map = this.getMap(); const pixel = map.getPixelFromCoordinate(pixelCoordinate); const projection = map.getView().getProjection(); const sortByDistance = function(a, b) { return projectedDistanceToSegmentDataSquared(pixelCoordinate, a, projection) - projectedDistanceToSegmentDataSquared(pixelCoordinate, b, projection); }; let nodes; let hitPointGeometry; if (this.hitDetection_) { const layerFilter = typeof this.hitDetection_ === "object" ? (layer) => layer === this.hitDetection_ : void 0; map.forEachFeatureAtPixel( pixel, (feature, layer, geometry) => { if (geometry && geometry.getType() === "Point") { geometry = new Point_default( toUserCoordinate(geometry.getCoordinates(), projection) ); } const geom = geometry || feature.getGeometry(); if (geom && geom.getType() === "Point" && feature instanceof Feature_default && this.features_.getArray().includes(feature)) { hitPointGeometry = /** @type {Point} */ geom; const coordinate = ( /** @type {Point} */ feature.getGeometry().getFlatCoordinates().slice(0, 2) ); nodes = [ { feature, geometry: hitPointGeometry, segment: [coordinate, coordinate] } ]; } return true; }, { layerFilter } ); } if (!nodes) { const viewExtent = fromUserExtent( createOrUpdateFromCoordinate(pixelCoordinate, tempExtent), projection ); const buffer2 = map.getView().getResolution() * this.pixelTolerance_; const box = toUserExtent( buffer(viewExtent, buffer2, tempExtent), projection ); nodes = this.rBush_.getInExtent(box); } if (nodes && nodes.length > 0) { const node = nodes.sort(sortByDistance)[0]; const closestSegment = node.segment; let vertex = closestOnSegmentData(pixelCoordinate, node, projection); const vertexPixel = map.getPixelFromCoordinate(vertex); let dist = distance(pixel, vertexPixel); if (hitPointGeometry || dist <= this.pixelTolerance_) { const vertexSegments = {}; vertexSegments[getUid(closestSegment)] = true; if (!this.snapToPointer_) { this.delta_[0] = vertex[0] - pixelCoordinate[0]; this.delta_[1] = vertex[1] - pixelCoordinate[1]; } if (node.geometry.getType() === "Circle" && node.index === CIRCLE_CIRCUMFERENCE_INDEX) { this.snappedToVertex_ = true; this.createOrUpdateVertexFeature_( vertex, [node.feature], [node.geometry], this.snappedToVertex_ ); } else { const pixel1 = map.getPixelFromCoordinate(closestSegment[0]); const pixel2 = map.getPixelFromCoordinate(closestSegment[1]); const squaredDist1 = squaredDistance(vertexPixel, pixel1); const squaredDist2 = squaredDistance(vertexPixel, pixel2); dist = Math.sqrt(Math.min(squaredDist1, squaredDist2)); this.snappedToVertex_ = dist <= this.pixelTolerance_; if (!this.snappedToVertex_ && !this.insertVertexCondition_(this.lastPointerEvent_)) { if (this.vertexFeature_) { this.overlay_.getSource().removeFeature(this.vertexFeature_); this.vertexFeature_ = null; } return; } if (this.snappedToVertex_) { vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0]; } this.createOrUpdateVertexFeature_( vertex, [node.feature], [node.geometry], this.snappedToVertex_ ); const geometries = {}; geometries[getUid(node.geometry)] = true; for (let i = 1, ii = nodes.length; i < ii; ++i) { const segment = nodes[i].segment; if (equals2(closestSegment[0], segment[0]) && equals2(closestSegment[1], segment[1]) || equals2(closestSegment[0], segment[1]) && equals2(closestSegment[1], segment[0])) { const geometryUid = getUid(nodes[i].geometry); if (!(geometryUid in geometries)) { geometries[geometryUid] = true; vertexSegments[getUid(segment)] = true; } } else { break; } } } this.vertexSegments_ = vertexSegments; return; } } if (this.vertexFeature_) { this.overlay_.getSource().removeFeature(this.vertexFeature_); this.vertexFeature_ = null; } } /** * @param {SegmentData} segmentData Segment data. * @param {import("../coordinate.js").Coordinate} vertex Vertex. * @return {boolean} A vertex was inserted. * @private */ insertVertex_(segmentData, vertex) { const segment = segmentData.segment; const feature = segmentData.feature; const geometry = segmentData.geometry; const depth = segmentData.depth; const index = segmentData.index; let coordinates; while (vertex.length < geometry.getStride()) { vertex.push(0); } switch (geometry.getType()) { case "MultiLineString": coordinates = geometry.getCoordinates(); coordinates[depth[0]].splice(index + 1, 0, vertex); break; case "Polygon": coordinates = geometry.getCoordinates(); coordinates[depth[0]].splice(index + 1, 0, vertex); break; case "MultiPolygon": coordinates = geometry.getCoordinates(); coordinates[depth[1]][depth[0]].splice(index + 1, 0, vertex); break; case "LineString": coordinates = geometry.getCoordinates(); coordinates.splice(index + 1, 0, vertex); break; default: return false; } this.setGeometryCoordinates_(geometry, coordinates); const rTree = this.rBush_; rTree.remove(segmentData); this.updateSegmentIndices_(geometry, index, depth, 1); const newSegmentData = { segment: [segment[0], vertex], feature, geometry, depth, index }; rTree.insert(boundingExtent(newSegmentData.segment), newSegmentData); this.dragSegments_.push([newSegmentData, 1]); const newSegmentData2 = { segment: [vertex, segment[1]], feature, geometry, depth, index: index + 1 }; rTree.insert(boundingExtent(newSegmentData2.segment), newSegmentData2); this.dragSegments_.push([newSegmentData2, 0]); return true; } /** * @param {import("../coordinate.js").Coordinate} coordinate The coordinate. * @return {import("../coordinate.js").Coordinate} The updated pointer coordinate. * @private */ updatePointer_(coordinate) { var _a; if (coordinate) { this.findInsertVerticesAndUpdateDragSegments_(coordinate); } return (_a = this.vertexFeature_) == null ? void 0 : _a.getGeometry().getCoordinates(); } /** * Get the current pointer position. * @return {import("../coordinate.js").Coordinate | null} The current pointer coordinate. */ getPoint() { var _a; const coordinate = (_a = this.vertexFeature_) == null ? void 0 : _a.getGeometry().getCoordinates(); if (!coordinate) { return null; } return toUserCoordinate( coordinate, this.getMap().getView().getProjection() ); } /** * Check if a point can be removed from the current linestring or polygon at the current * pointer position. * @return {boolean} A point can be deleted at the current pointer position. * @api */ canRemovePoint() { if (!this.vertexFeature_) { return false; } if (this.vertexFeature_.get("geometries").every( (geometry) => geometry.getType() === "Circle" || geometry.getType().endsWith("Point") )) { return false; } const coordinate = this.vertexFeature_.getGeometry().getCoordinates(); const segments = this.rBush_.getInExtent(boundingExtent([coordinate])); return segments.some( ({ segment }) => equals2(segment[0], coordinate) || equals2(segment[1], coordinate) ); } /** * Removes the vertex currently being pointed from the current linestring or polygon. * @param {import('../coordinate.js').Coordinate} [coordinate] If provided, the pointer * will be set to the provided coordinate. If not, the current pointer coordinate will be used. * @return {boolean} True when a vertex was removed. * @api */ removePoint(coordinate) { if (coordinate) { coordinate = fromUserCoordinate( coordinate, this.getMap().getView().getProjection() ); this.updatePointer_(coordinate); } if (!this.lastPointerEvent_ || this.lastPointerEvent_ && this.lastPointerEvent_.type != MapBrowserEventType_default.POINTERDRAG) { const evt = this.lastPointerEvent_; this.willModifyFeatures_( evt, this.dragSegments_.map(([segment]) => segment) ); const removed = this.removeVertex_(); if (this.featuresBeingModified_) { this.dispatchEvent( new ModifyEvent( ModifyEventType.MODIFYEND, this.featuresBeingModified_, evt ) ); } this.featuresBeingModified_ = null; return removed; } return false; } /** * Removes a vertex from all matching features. * @return {boolean} True when a vertex was removed. * @private */ removeVertex_() { const dragSegments = this.dragSegments_; const segmentsByFeature = {}; let deleted = false; let component, coordinates, dragSegment, geometry, i, index, left; let newIndex, right, segmentData, uid; for (i = dragSegments.length - 1; i >= 0; --i) { dragSegment = dragSegments[i]; segmentData = dragSegment[0]; uid = getUid(segmentData.feature); if (segmentData.depth) { uid += "-" + segmentData.depth.join("-"); } if (!(uid in segmentsByFeature)) { segmentsByFeature[uid] = {}; } if (dragSegment[1] === 0) { segmentsByFeature[uid].right = segmentData; segmentsByFeature[uid].index = segmentData.index; } else if (dragSegment[1] == 1) { segmentsByFeature[uid].left = segmentData; segmentsByFeature[uid].index = segmentData.index + 1; } } for (uid in segmentsByFeature) { right = segmentsByFeature[uid].right; left = segmentsByFeature[uid].left; index = segmentsByFeature[uid].index; newIndex = index - 1; if (left !== void 0) { segmentData = left; } else { segmentData = right; } if (newIndex < 0) { newIndex = 0; } geometry = segmentData.geometry; coordinates = geometry.getCoordinates(); component = coordinates; deleted = false; switch (geometry.getType()) { case "MultiLineString": if (coordinates[segmentData.depth[0]].length > 2) { coordinates[segmentData.depth[0]].splice(index, 1); deleted = true; } break; case "LineString": if (coordinates.length > 2) { coordinates.splice(index, 1); deleted = true; } break; case "MultiPolygon": component = component[segmentData.depth[1]]; /* falls through */ case "Polygon": component = component[segmentData.depth[0]]; if (component.length > 4) { if (index == component.length - 1) { index = 0; } component.splice(index, 1); deleted = true; if (index === 0) { component.pop(); component.push(component[0]); newIndex = component.length - 1; } } break; default: } if (deleted) { this.setGeometryCoordinates_(geometry, coordinates); const segments = []; if (left !== void 0) { this.rBush_.remove(left); segments.push(left.segment[0]); } if (right !== void 0) { this.rBush_.remove(right); segments.push(right.segment[1]); } if (left !== void 0 && right !== void 0) { const newSegmentData = { depth: segmentData.depth, feature: segmentData.feature, geometry: segmentData.geometry, index: newIndex, segment: segments }; this.rBush_.insert( boundingExtent(newSegmentData.segment), newSegmentData ); } this.updateSegmentIndices_(geometry, index, segmentData.depth, -1); if (this.vertexFeature_) { this.overlay_.getSource().removeFeature(this.vertexFeature_); this.vertexFeature_ = null; } dragSegments.length = 0; } } return deleted; } /** * Check if a point can be inserted to the current linestring or polygon at the current * pointer position. * @return {boolean} A point can be inserted at the current pointer position. * @api */ canInsertPoint() { if (!this.vertexFeature_) { return false; } if (this.vertexFeature_.get("geometries").every( (geometry) => geometry.getType() === "Circle" || geometry.getType().endsWith("Point") )) { return false; } const coordinate = this.vertexFeature_.getGeometry().getCoordinates(); const segments = this.rBush_.getInExtent(boundingExtent([coordinate])); return segments.some( ({ segment }) => !(equals2(segment[0], coordinate) || equals2(segment[1], coordinate)) ); } /** * Inserts the vertex currently being pointed to the current linestring or polygon. * @param {import('../coordinate.js').Coordinate} [coordinate] If provided, the pointer * will be set to the provided coordinate. If not, the current pointer coordinate will be used. * @return {boolean} A vertex was inserted. * @api */ insertPoint(coordinate) { var _a; const pixelCoordinate = coordinate ? fromUserCoordinate(coordinate, this.getMap().getView().getProjection()) : (_a = this.vertexFeature_) == null ? void 0 : _a.getGeometry().getCoordinates(); if (!pixelCoordinate) { return false; } const insertVertices = this.findInsertVerticesAndUpdateDragSegments_(pixelCoordinate); return insertVertices.reduce( (prev, segmentData) => prev || this.insertVertex_(segmentData, pixelCoordinate), false ); } /** * @param {import("../geom/SimpleGeometry.js").default} geometry Geometry. * @param {Array} coordinates Coordinates. * @private */ setGeometryCoordinates_(geometry, coordinates) { this.changingFeature_ = true; geometry.setCoordinates(coordinates); this.changingFeature_ = false; } /** * @param {import("../geom/SimpleGeometry.js").default} geometry Geometry. * @param {number} index Index. * @param {Array|undefined} depth Depth. * @param {number} delta Delta (1 or -1). * @private */ updateSegmentIndices_(geometry, index, depth, delta) { this.rBush_.forEachInExtent( geometry.getExtent(), function(segmentDataMatch) { if (segmentDataMatch.geometry === geometry && (depth === void 0 || segmentDataMatch.depth === void 0 || equals(segmentDataMatch.depth, depth)) && segmentDataMatch.index > index) { segmentDataMatch.index += delta; } } ); } }; function compareIndexes(a, b) { return a.index - b.index; } function projectedDistanceToSegmentDataSquared(pointCoordinates, segmentData, projection) { const geometry = segmentData.geometry; if (geometry.getType() === "Circle") { let circleGeometry = ( /** @type {import("../geom/Circle.js").default} */ geometry ); if (segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) { const userProjection = getUserProjection(); if (userProjection) { circleGeometry = circleGeometry.clone().transform(userProjection, projection); } const distanceToCenterSquared = squaredDistance( circleGeometry.getCenter(), fromUserCoordinate(pointCoordinates, projection) ); const distanceToCircumference = Math.sqrt(distanceToCenterSquared) - circleGeometry.getRadius(); return distanceToCircumference * distanceToCircumference; } } const coordinate = fromUserCoordinate(pointCoordinates, projection); tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection); tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection); return squaredDistanceToSegment(coordinate, tempSegment); } function closestOnSegmentData(pointCoordinates, segmentData, projection) { const geometry = segmentData.geometry; if (geometry.getType() === "Circle" && segmentData.index === CIRCLE_CIRCUMFERENCE_INDEX) { let circleGeometry = ( /** @type {import("../geom/Circle.js").default} */ geometry ); const userProjection = getUserProjection(); if (userProjection) { circleGeometry = circleGeometry.clone().transform(userProjection, projection); } return toUserCoordinate( circleGeometry.getClosestPoint( fromUserCoordinate(pointCoordinates, projection) ), projection ); } const coordinate = fromUserCoordinate(pointCoordinates, projection); tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection); tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection); return toUserCoordinate( closestOnSegment(coordinate, tempSegment), projection ); } function getDefaultStyleFunction() { const style = createEditingStyle(); return function(feature, resolution) { return style["Point"]; }; } var Modify_default = Modify; // node_modules/ol/events/SnapEvent.js var SnapEventType = { /** * Triggered upon snapping to vertex or edge * @event SnapEvent#snap * @api */ SNAP: "snap", /** * Triggered if no longer snapped * @event SnapEvent#unsnap * @api */ UNSNAP: "unsnap" }; var SnapEvent = class extends Event_default { /** * @param {SnapEventType} type Type. * @param {Object} options Options. * @param {import("../coordinate.js").Coordinate} options.vertex The snapped vertex. * @param {import("../coordinate.js").Coordinate} options.vertexPixel The pixel of the snapped vertex. * @param {import("../Feature.js").default} options.feature The feature being snapped. * @param {Array|null} options.segment Segment, or `null` if snapped to a vertex. */ constructor(type, options) { super(type); this.vertex = options.vertex; this.vertexPixel = options.vertexPixel; this.feature = options.feature; this.segment = options.segment; } }; // node_modules/ol/interaction/Snap.js var GEOMETRY_SEGMENTERS = { /** * @param {import("../geom/Circle.js").default} geometry Geometry. * @param {import("../proj/Projection.js").default} projection Projection. * @return {Array} Segments */ Circle(geometry, projection) { let circleGeometry = geometry; const userProjection = getUserProjection(); if (userProjection) { circleGeometry = circleGeometry.clone().transform(userProjection, projection); } const polygon = fromCircle(circleGeometry); if (userProjection) { polygon.transform(projection, userProjection); } return GEOMETRY_SEGMENTERS.Polygon(polygon); }, /** * @param {import("../geom/GeometryCollection.js").default} geometry Geometry. * @param {import("../proj/Projection.js").default} projection Projection. * @return {Array} Segments */ GeometryCollection(geometry, projection) { const segments = []; const geometries = geometry.getGeometriesArray(); for (let i = 0; i < geometries.length; ++i) { const segmenter = this[geometries[i].getType()]; if (segmenter) { segments.push(segmenter(geometries[i], projection)); } } return segments.flat(); }, /** * @param {import("../geom/LineString.js").default} geometry Geometry. * @return {Array} Segments */ LineString(geometry) { const segments = []; const coordinates = geometry.getFlatCoordinates(); const stride = geometry.getStride(); for (let i = 0, ii = coordinates.length - stride; i < ii; i += stride) { segments.push([ coordinates.slice(i, i + 2), coordinates.slice(i + stride, i + stride + 2) ]); } return segments; }, /** * @param {import("../geom/MultiLineString.js").default} geometry Geometry. * @return {Array} Segments */ MultiLineString(geometry) { const segments = []; const coordinates = geometry.getFlatCoordinates(); const stride = geometry.getStride(); const ends = geometry.getEnds(); let offset = 0; for (let i = 0, ii = ends.length; i < ii; ++i) { const end = ends[i]; for (let j = offset, jj = end - stride; j < jj; j += stride) { segments.push([ coordinates.slice(j, j + 2), coordinates.slice(j + stride, j + stride + 2) ]); } offset = end; } return segments; }, /** * @param {import("../geom/MultiPoint.js").default} geometry Geometry. * @return {Array} Segments */ MultiPoint(geometry) { const segments = []; const coordinates = geometry.getFlatCoordinates(); const stride = geometry.getStride(); for (let i = 0, ii = coordinates.length; i < ii; i += stride) { segments.push([coordinates.slice(i, i + 2)]); } return segments; }, /** * @param {import("../geom/MultiPolygon.js").default} geometry Geometry. * @return {Array} Segments */ MultiPolygon(geometry) { const segments = []; const coordinates = geometry.getFlatCoordinates(); const stride = geometry.getStride(); const endss = geometry.getEndss(); let offset = 0; for (let i = 0, ii = endss.length; i < ii; ++i) { const ends = endss[i]; for (let j = 0, jj = ends.length; j < jj; ++j) { const end = ends[j]; for (let k = offset, kk = end - stride; k < kk; k += stride) { segments.push([ coordinates.slice(k, k + 2), coordinates.slice(k + stride, k + stride + 2) ]); } offset = end; } } return segments; }, /** * @param {import("../geom/Point.js").default} geometry Geometry. * @return {Array} Segments */ Point(geometry) { return [[geometry.getFlatCoordinates().slice(0, 2)]]; }, /** * @param {import("../geom/Polygon.js").default} geometry Geometry. * @return {Array} Segments */ Polygon(geometry) { const segments = []; const coordinates = geometry.getFlatCoordinates(); const stride = geometry.getStride(); const ends = geometry.getEnds(); let offset = 0; for (let i = 0, ii = ends.length; i < ii; ++i) { const end = ends[i]; for (let j = offset, jj = end - stride; j < jj; j += stride) { segments.push([ coordinates.slice(j, j + 2), coordinates.slice(j + stride, j + stride + 2) ]); } offset = end; } return segments; } }; function getFeatureFromEvent(evt) { if ( /** @type {import("../source/Vector.js").VectorSourceEvent} */ evt.feature ) { return ( /** @type {import("../source/Vector.js").VectorSourceEvent} */ evt.feature ); } if ( /** @type {import("../Collection.js").CollectionEvent} */ evt.element ) { return ( /** @type {import("../Collection.js").CollectionEvent} */ evt.element ); } return null; } var tempSegment2 = []; var tempExtents = []; var tempSegmentData = []; var Snap = class extends Pointer_default { /** * @param {Options} [options] Options. */ constructor(options) { options = options ? options : {}; super({ handleDownEvent: TRUE, stopDown: FALSE }); this.on; this.once; this.un; this.source_ = options.source ? options.source : null; this.vertex_ = options.vertex !== void 0 ? options.vertex : true; this.edge_ = options.edge !== void 0 ? options.edge : true; this.intersection_ = options.intersection !== void 0 ? options.intersection : false; this.features_ = options.features ? options.features : null; this.featuresListenerKeys_ = []; this.featureChangeListenerKeys_ = {}; this.indexedFeaturesExtents_ = {}; this.pendingFeatures_ = {}; this.pixelTolerance_ = options.pixelTolerance !== void 0 ? options.pixelTolerance : 10; this.rBush_ = new RBush_default(); this.snapped_ = null; this.segmenters_ = Object.assign( {}, GEOMETRY_SEGMENTERS, options.segmenters ); } /** * Add a feature to the collection of features that we may snap to. * @param {import("../Feature.js").default} feature Feature. * @param {boolean} [register] Whether to listen to the feature change or not * Defaults to `true`. * @api */ addFeature(feature, register) { register = register !== void 0 ? register : true; const feature_uid = getUid(feature); const geometry = feature.getGeometry(); if (geometry) { const segmenter = this.segmenters_[geometry.getType()]; if (segmenter) { this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent(createEmpty()); const segments = segmenter.call( this.segmenters_, geometry, this.getMap().getView().getProjection() ); let segmentCount = segments.length; for (let i = 0; i < segmentCount; ++i) { const segment = segments[i]; tempExtents[i] = boundingExtent(segment); tempSegmentData[i] = { feature, segment }; } if (this.intersection_) { for (let j = 0, jj = segments.length; j < jj; ++j) { const segment = segments[j]; if (segment.length === 1) { continue; } const extent = tempExtents[j]; for (let k = 0, kk = j - 1; k < kk; ++k) { const otherSegment = segments[k]; if (!intersects(extent, tempExtents[k])) { continue; } const intersection = getIntersectionPoint(segment, otherSegment); if (!intersection) { continue; } const intersectionSegment = [intersection]; tempExtents[segmentCount] = boundingExtent(intersectionSegment); tempSegmentData[segmentCount++] = { feature, intersectionFeature: feature, segment: intersectionSegment }; } const otherSegments = this.rBush_.getInExtent(tempExtents[j]); for (let k = 0, kk = otherSegments.length; k < kk; ++k) { const otherSegment = otherSegments[k].segment; if (otherSegment.length === 1) { continue; } const intersection = getIntersectionPoint(segment, otherSegment); if (!intersection) { continue; } const intersectionSegment = [intersection]; tempExtents[segmentCount] = boundingExtent(intersectionSegment); tempSegmentData[segmentCount++] = { feature, intersectionFeature: otherSegments[k].feature, segment: intersectionSegment }; } } } if (segmentCount === 1) { this.rBush_.insert(tempExtents[0], tempSegmentData[0]); } else { tempExtents.length = segmentCount; tempSegmentData.length = segmentCount; this.rBush_.load(tempExtents, tempSegmentData); } } } if (register) { if (this.featureChangeListenerKeys_[feature_uid]) { unlistenByKey(this.featureChangeListenerKeys_[feature_uid]); } this.featureChangeListenerKeys_[feature_uid] = listen( feature, EventType_default.CHANGE, this.handleFeatureChange_, this ); } } /** * @return {import("../Collection.js").default|Array} Features. * @private */ getFeatures_() { let features; if (this.features_) { features = this.features_; } else if (this.source_) { features = this.source_.getFeatures(); } return features; } /** * Checks if two snap data sets are equal. * Compares the segment and the feature. * * @param {SnappedInfo} data1 The first snap data set. * @param {SnappedInfo} data2 The second snap data set. * @return {boolean} `true` if the data sets are equal, otherwise `false`. * @private */ areSnapDataEqual_(data1, data2) { return data1.segment === data2.segment && data1.feature === data2.feature; } /** * @param {import("../MapBrowserEvent.js").default} evt Map browser event. * @return {boolean} `false` to stop event propagation. * @api * @override */ handleEvent(evt) { const result = this.snapTo(evt.pixel, evt.coordinate, evt.map); if (result) { evt.coordinate = result.vertex.slice(0, 2); evt.pixel = result.vertexPixel; if (this.snapped_ && !this.areSnapDataEqual_(this.snapped_, result)) { this.dispatchEvent(new SnapEvent(SnapEventType.UNSNAP, this.snapped_)); } this.snapped_ = { vertex: evt.coordinate, vertexPixel: evt.pixel, feature: result.feature, segment: result.segment }; this.dispatchEvent(new SnapEvent(SnapEventType.SNAP, this.snapped_)); } else if (this.snapped_) { this.dispatchEvent(new SnapEvent(SnapEventType.UNSNAP, this.snapped_)); this.snapped_ = null; } return super.handleEvent(evt); } /** * @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent} evt Event. * @private */ handleFeatureAdd_(evt) { const feature = getFeatureFromEvent(evt); if (feature) { this.addFeature(feature); } } /** * @param {import("../source/Vector.js").VectorSourceEvent|import("../Collection.js").CollectionEvent} evt Event. * @private */ handleFeatureRemove_(evt) { const feature = getFeatureFromEvent(evt); if (feature) { this.removeFeature(feature); delete this.pendingFeatures_[getUid(feature)]; } } /** * @param {import("../events/Event.js").default} evt Event. * @private */ handleFeatureChange_(evt) { const feature = ( /** @type {import("../Feature.js").default} */ evt.target ); if (this.handlingDownUpSequence) { this.pendingFeatures_[getUid(feature)] = feature; } else { this.updateFeature_(feature); } } /** * Handle pointer up events. * @param {import("../MapBrowserEvent.js").default} evt Event. * @return {boolean} If the event was consumed. * @override */ handleUpEvent(evt) { const featuresToUpdate = Object.values(this.pendingFeatures_); if (featuresToUpdate.length) { for (const feature of featuresToUpdate) { this.updateFeature_(feature); } clear(this.pendingFeatures_); } return false; } /** * Remove a feature from the collection of features that we may snap to. * @param {import("../Feature.js").default} feature Feature * @param {boolean} [unlisten] Whether to unlisten to the feature change * or not. Defaults to `true`. * @api */ removeFeature(feature, unlisten) { const unregister = unlisten !== void 0 ? unlisten : true; const feature_uid = getUid(feature); const extent = this.indexedFeaturesExtents_[feature_uid]; if (extent) { const rBush = this.rBush_; rBush.getInExtent(extent).forEach((node) => { if (feature === node.feature || feature === node.intersectionFeature) { rBush.remove(node); } }); } if (unregister) { unlistenByKey(this.featureChangeListenerKeys_[feature_uid]); delete this.featureChangeListenerKeys_[feature_uid]; } } /** * Remove the interaction from its current map and attach it to the new map. * Subclasses may set up event handlers to get notified about changes to * the map here. * @param {import("../Map.js").default} map Map. * @override */ setMap(map) { const currentMap = this.getMap(); const keys = this.featuresListenerKeys_; let features = this.getFeatures_(); if (!Array.isArray(features)) { features = features.getArray(); } if (currentMap) { keys.forEach(unlistenByKey); keys.length = 0; this.rBush_.clear(); Object.values(this.featureChangeListenerKeys_).forEach(unlistenByKey); this.featureChangeListenerKeys_ = {}; } super.setMap(map); if (map) { if (this.features_) { keys.push( listen( this.features_, CollectionEventType_default.ADD, this.handleFeatureAdd_, this ), listen( this.features_, CollectionEventType_default.REMOVE, this.handleFeatureRemove_, this ) ); } else if (this.source_) { keys.push( listen( this.source_, VectorEventType_default.ADDFEATURE, this.handleFeatureAdd_, this ), listen( this.source_, VectorEventType_default.REMOVEFEATURE, this.handleFeatureRemove_, this ) ); } for (const feature of features) { this.addFeature(feature); } } } /** * @param {import("../pixel.js").Pixel} pixel Pixel * @param {import("../coordinate.js").Coordinate} pixelCoordinate Coordinate * @param {import("../Map.js").default} map Map. * @return {SnappedInfo|null} Snap result */ snapTo(pixel, pixelCoordinate, map) { const projection = map.getView().getProjection(); const projectedCoordinate = fromUserCoordinate(pixelCoordinate, projection); const box = toUserExtent( buffer( boundingExtent([projectedCoordinate]), map.getView().getResolution() * this.pixelTolerance_ ), projection ); const segments = this.rBush_.getInExtent(box); const segmentsLength = segments.length; if (segmentsLength === 0) { return null; } let closestVertex; let minSquaredDistance = Infinity; let closestFeature; let closestSegment = null; const squaredPixelTolerance = this.pixelTolerance_ * this.pixelTolerance_; const getResult = () => { if (!closestVertex) { return null; } const vertexPixel = map.getPixelFromCoordinate(closestVertex); const squaredPixelDistance = squaredDistance(pixel, vertexPixel); if (squaredPixelDistance > squaredPixelTolerance) { return null; } return { vertex: closestVertex, vertexPixel: [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])], feature: closestFeature, segment: closestSegment }; }; if (this.vertex_ || this.intersection_) { for (let i = 0; i < segmentsLength; ++i) { const segmentData = segments[i]; if (segmentData.feature.getGeometry().getType() !== "Circle") { for (const vertex of segmentData.segment) { const tempVertexCoord = fromUserCoordinate(vertex, projection); const delta = squaredDistance(projectedCoordinate, tempVertexCoord); if (delta < minSquaredDistance && (this.intersection_ && segmentData.intersectionFeature || this.vertex_ && !segmentData.intersectionFeature)) { closestVertex = vertex; minSquaredDistance = delta; closestFeature = segmentData.feature; } } } } const result = getResult(); if (result) { return result; } } if (this.edge_) { for (let i = 0; i < segmentsLength; ++i) { let vertex = null; const segmentData = segments[i]; if (segmentData.feature.getGeometry().getType() === "Circle") { let circleGeometry = segmentData.feature.getGeometry(); const userProjection = getUserProjection(); if (userProjection) { circleGeometry = circleGeometry.clone().transform(userProjection, projection); } vertex = closestOnCircle( projectedCoordinate, /** @type {import("../geom/Circle.js").default} */ circleGeometry ); } else { const [segmentStart, segmentEnd] = segmentData.segment; if (segmentEnd) { tempSegment2[0] = fromUserCoordinate(segmentStart, projection); tempSegment2[1] = fromUserCoordinate(segmentEnd, projection); vertex = closestOnSegment(projectedCoordinate, tempSegment2); } } if (vertex) { const delta = squaredDistance(projectedCoordinate, vertex); if (delta < minSquaredDistance) { closestVertex = toUserCoordinate(vertex, projection); closestSegment = segmentData.feature.getGeometry().getType() === "Circle" ? null : segmentData.segment; minSquaredDistance = delta; closestFeature = segmentData.feature; } } } const result = getResult(); if (result) { return result; } } return null; } /** * @param {import("../Feature.js").default} feature Feature * @private */ updateFeature_(feature) { this.removeFeature(feature, false); this.addFeature(feature, false); } }; var Snap_default = Snap; // node_modules/ol/interaction/Translate.js var TranslateEventType = { /** * Triggered upon feature translation start. * @event TranslateEvent#translatestart * @api */ TRANSLATESTART: "translatestart", /** * Triggered upon feature translation. * @event TranslateEvent#translating * @api */ TRANSLATING: "translating", /** * Triggered upon feature translation end. * @event TranslateEvent#translateend * @api */ TRANSLATEEND: "translateend" }; var TranslateEvent = class extends Event_default { /** * @param {TranslateEventType} type Type. * @param {Collection} features The features translated. * @param {import("../coordinate.js").Coordinate} coordinate The event coordinate. * @param {import("../coordinate.js").Coordinate} startCoordinate The original coordinates before.translation started * @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event. */ constructor(type, features, coordinate, startCoordinate, mapBrowserEvent) { super(type); this.features = features; this.coordinate = coordinate; this.startCoordinate = startCoordinate; this.mapBrowserEvent = mapBrowserEvent; } }; var Translate = class extends Pointer_default { /** * @param {Options} [options] Options. */ constructor(options) { options = options ? options : {}; super( /** @type {import("./Pointer.js").Options} */ options ); this.on; this.once; this.un; this.lastCoordinate_ = null; this.startCoordinate_ = null; this.features_ = options.features !== void 0 ? options.features : null; let layerFilter; if (options.layers && !this.features_) { if (typeof options.layers === "function") { layerFilter = options.layers; } else { const layers = options.layers; layerFilter = function(layer) { return layers.includes(layer); }; } } else { layerFilter = TRUE; } this.layerFilter_ = layerFilter; this.filter_ = options.filter && !this.features_ ? options.filter : TRUE; this.hitTolerance_ = options.hitTolerance ? options.hitTolerance : 0; this.condition_ = options.condition ? options.condition : always; this.lastFeature_ = null; this.addChangeListener( Property_default.ACTIVE, this.handleActiveChanged_ ); } /** * Handle pointer down events. * @param {import("../MapBrowserEvent.js").default} event Event. * @return {boolean} If the event was consumed. * @override */ handleDownEvent(event) { if (!event.originalEvent || !this.condition_(event)) { return false; } this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map); if (!this.lastCoordinate_ && this.lastFeature_) { this.startCoordinate_ = event.coordinate; this.lastCoordinate_ = event.coordinate; this.handleMoveEvent(event); const features = this.features_ || new Collection_default([this.lastFeature_]); this.dispatchEvent( new TranslateEvent( TranslateEventType.TRANSLATESTART, features, event.coordinate, this.startCoordinate_, event ) ); return true; } return false; } /** * Handle pointer up events. * @param {import("../MapBrowserEvent.js").default} event Event. * @return {boolean} If the event was consumed. * @override */ handleUpEvent(event) { if (this.lastCoordinate_) { this.lastCoordinate_ = null; this.handleMoveEvent(event); const features = this.features_ || new Collection_default([this.lastFeature_]); this.dispatchEvent( new TranslateEvent( TranslateEventType.TRANSLATEEND, features, event.coordinate, this.startCoordinate_, event ) ); this.startCoordinate_ = null; return true; } return false; } /** * Handle pointer drag events. * @param {import("../MapBrowserEvent.js").default} event Event. * @override */ handleDragEvent(event) { if (this.lastCoordinate_) { const newCoordinate = event.coordinate; const projection = event.map.getView().getProjection(); const newViewCoordinate = fromUserCoordinate(newCoordinate, projection); const lastViewCoordinate = fromUserCoordinate( this.lastCoordinate_, projection ); const deltaX = newViewCoordinate[0] - lastViewCoordinate[0]; const deltaY = newViewCoordinate[1] - lastViewCoordinate[1]; const features = this.features_ || new Collection_default([this.lastFeature_]); const userProjection = getUserProjection(); features.forEach(function(feature) { const geom = feature.getGeometry(); if (userProjection) { geom.transform(userProjection, projection); geom.translate(deltaX, deltaY); geom.transform(projection, userProjection); } else { geom.translate(deltaX, deltaY); } feature.setGeometry(geom); }); this.lastCoordinate_ = newCoordinate; this.dispatchEvent( new TranslateEvent( TranslateEventType.TRANSLATING, features, newCoordinate, this.startCoordinate_, event ) ); } } /** * Handle pointer move events. * @param {import("../MapBrowserEvent.js").default} event Event. * @override */ handleMoveEvent(event) { const elem = event.map.getViewport(); if (this.featuresAtPixel_(event.pixel, event.map)) { elem.classList.remove(this.lastCoordinate_ ? "ol-grab" : "ol-grabbing"); elem.classList.add(this.lastCoordinate_ ? "ol-grabbing" : "ol-grab"); } else { elem.classList.remove("ol-grab", "ol-grabbing"); } } /** * Tests to see if the given coordinates intersects any of our selected * features. * @param {import("../pixel.js").Pixel} pixel Pixel coordinate to test for intersection. * @param {import("../Map.js").default} map Map to test the intersection on. * @return {Feature} Returns the feature found at the specified pixel * coordinates. * @private */ featuresAtPixel_(pixel, map) { return map.forEachFeatureAtPixel( pixel, (feature, layer) => { if (!(feature instanceof Feature_default) || !this.filter_(feature, layer)) { return void 0; } if (this.features_ && !this.features_.getArray().includes(feature)) { return void 0; } return feature; }, { layerFilter: this.layerFilter_, hitTolerance: this.hitTolerance_ } ); } /** * Returns the Hit-detection tolerance. * @return {number} Hit tolerance in pixels. * @api */ getHitTolerance() { return this.hitTolerance_; } /** * Hit-detection tolerance. Pixels inside the radius around the given position * will be checked for features. * @param {number} hitTolerance Hit tolerance in pixels. * @api */ setHitTolerance(hitTolerance) { this.hitTolerance_ = hitTolerance; } /** * Remove the interaction from its current map and attach it to the new map. * Subclasses may set up event handlers to get notified about changes to * the map here. * @param {import("../Map.js").default} map Map. * @override */ setMap(map) { const oldMap = this.getMap(); super.setMap(map); this.updateState_(oldMap); } /** * @private */ handleActiveChanged_() { this.updateState_(null); } /** * @param {import("../Map.js").default} oldMap Old map. * @private */ updateState_(oldMap) { let map = this.getMap(); const active = this.getActive(); if (!map || !active) { map = map || oldMap; if (map) { const elem = map.getViewport(); elem.classList.remove("ol-grab", "ol-grabbing"); } } } }; var Translate_default = Translate; export { DblClickDragZoom_default as DblClickDragZoom, DoubleClickZoom_default as DoubleClickZoom, DragAndDrop_default as DragAndDrop, DragBox_default as DragBox, DragPan_default as DragPan, DragRotate_default as DragRotate, DragRotateAndZoom_default as DragRotateAndZoom, DragZoom_default as DragZoom, Draw_default as Draw, Extent_default as Extent, Interaction_default as Interaction, KeyboardPan_default as KeyboardPan, KeyboardZoom_default as KeyboardZoom, Link_default as Link, Modify_default as Modify, MouseWheelZoom_default as MouseWheelZoom, PinchRotate_default as PinchRotate, PinchZoom_default as PinchZoom, Pointer_default as Pointer, Select_default as Select, Snap_default as Snap, Translate_default as Translate, defaults }; //# sourceMappingURL=ol_interaction.js.map