import { easeOut, inAndOut } from "./chunk-LMC3RO5P.js"; import { DEFAULT_TILE_SIZE } from "./chunk-FM44FOIC.js"; import { fromExtent } from "./chunk-RBA5LKAR.js"; import { METERS_PER_UNIT, createProjection, disableCoordinateWarning, fromUserCoordinate, fromUserExtent, getUserProjection, toUserCoordinate, toUserExtent } from "./chunk-XZU4LSFD.js"; import { add, equals, rotate } from "./chunk-3JZANJYE.js"; import { clamp, modulo, toRadians } from "./chunk-54BTDBAD.js"; import { getCenter, getForViewAndSize, getHeight, getWidth, intersects, isEmpty } from "./chunk-CKDBVGKM.js"; import { assert } from "./chunk-QFCIXVZ3.js"; import { Object_default, abstract } from "./chunk-H47PV7W6.js"; import { EventType_default, Event_default, VOID, listen, unlistenByKey } from "./chunk-KJXIHBKT.js"; import { linearFindNearest } from "./chunk-FQY6EMA7.js"; // node_modules/ol/ViewHint.js var ViewHint_default = { ANIMATING: 0, INTERACTING: 1 }; // node_modules/ol/ViewProperty.js var ViewProperty_default = { CENTER: "center", RESOLUTION: "resolution", ROTATION: "rotation" }; // node_modules/ol/centerconstraint.js function createExtent(extent, onlyCenter, smooth) { return ( /** * @param {import("./coordinate.js").Coordinate|undefined} center Center. * @param {number|undefined} resolution Resolution. * @param {import("./size.js").Size} size Viewport size; unused if `onlyCenter` was specified. * @param {boolean} [isMoving] True if an interaction or animation is in progress. * @param {Array} [centerShift] Shift between map center and viewport center. * @return {import("./coordinate.js").Coordinate|undefined} Center. */ (function(center, resolution, size, isMoving, centerShift) { if (!center) { return void 0; } if (!resolution && !onlyCenter) { return center; } const viewWidth = onlyCenter ? 0 : size[0] * resolution; const viewHeight = onlyCenter ? 0 : size[1] * resolution; const shiftX = centerShift ? centerShift[0] : 0; const shiftY = centerShift ? centerShift[1] : 0; let minX = extent[0] + viewWidth / 2 + shiftX; let maxX = extent[2] - viewWidth / 2 + shiftX; let minY = extent[1] + viewHeight / 2 + shiftY; let maxY = extent[3] - viewHeight / 2 + shiftY; if (minX > maxX) { minX = (maxX + minX) / 2; maxX = minX; } if (minY > maxY) { minY = (maxY + minY) / 2; maxY = minY; } let x = clamp(center[0], minX, maxX); let y = clamp(center[1], minY, maxY); if (isMoving && smooth && resolution) { const ratio = 30 * resolution; x += -ratio * Math.log(1 + Math.max(0, minX - center[0]) / ratio) + ratio * Math.log(1 + Math.max(0, center[0] - maxX) / ratio); y += -ratio * Math.log(1 + Math.max(0, minY - center[1]) / ratio) + ratio * Math.log(1 + Math.max(0, center[1] - maxY) / ratio); } return [x, y]; }) ); } function none(center) { return center; } // node_modules/ol/resolutionconstraint.js function getViewportClampedResolution(resolution, maxExtent, viewportSize, showFullExtent) { const xResolution = getWidth(maxExtent) / viewportSize[0]; const yResolution = getHeight(maxExtent) / viewportSize[1]; if (showFullExtent) { return Math.min(resolution, Math.max(xResolution, yResolution)); } return Math.min(resolution, Math.min(xResolution, yResolution)); } function getSmoothClampedResolution(resolution, maxResolution, minResolution) { let result = Math.min(resolution, maxResolution); const ratio = 50; result *= Math.log(1 + ratio * Math.max(0, resolution / maxResolution - 1)) / ratio + 1; if (minResolution) { result = Math.max(result, minResolution); result /= Math.log(1 + ratio * Math.max(0, minResolution / resolution - 1)) / ratio + 1; } return clamp(result, minResolution / 2, maxResolution * 2); } function createSnapToResolutions(resolutions, smooth, maxExtent, showFullExtent) { smooth = smooth !== void 0 ? smooth : true; return ( /** * @param {number|undefined} resolution Resolution. * @param {number} direction Direction. * @param {import("./size.js").Size} size Viewport size. * @param {boolean} [isMoving] True if an interaction or animation is in progress. * @return {number|undefined} Resolution. */ (function(resolution, direction, size, isMoving) { if (resolution !== void 0) { const maxResolution = resolutions[0]; const minResolution = resolutions[resolutions.length - 1]; const cappedMaxRes = maxExtent ? getViewportClampedResolution( maxResolution, maxExtent, size, showFullExtent ) : maxResolution; if (isMoving) { if (!smooth) { return clamp(resolution, minResolution, cappedMaxRes); } return getSmoothClampedResolution( resolution, cappedMaxRes, minResolution ); } const capped = Math.min(cappedMaxRes, resolution); const z = Math.floor(linearFindNearest(resolutions, capped, direction)); if (resolutions[z] > cappedMaxRes && z < resolutions.length - 1) { return resolutions[z + 1]; } return resolutions[z]; } return void 0; }) ); } function createSnapToPower(power, maxResolution, minResolution, smooth, maxExtent, showFullExtent) { smooth = smooth !== void 0 ? smooth : true; minResolution = minResolution !== void 0 ? minResolution : 0; return ( /** * @param {number|undefined} resolution Resolution. * @param {number} direction Direction. * @param {import("./size.js").Size} size Viewport size. * @param {boolean} [isMoving] True if an interaction or animation is in progress. * @return {number|undefined} Resolution. */ (function(resolution, direction, size, isMoving) { if (resolution !== void 0) { const cappedMaxRes = maxExtent ? getViewportClampedResolution( maxResolution, maxExtent, size, showFullExtent ) : maxResolution; if (isMoving) { if (!smooth) { return clamp(resolution, minResolution, cappedMaxRes); } return getSmoothClampedResolution( resolution, cappedMaxRes, minResolution ); } const tolerance = 1e-9; const minZoomLevel = Math.ceil( Math.log(maxResolution / cappedMaxRes) / Math.log(power) - tolerance ); const offset = -direction * (0.5 - tolerance) + 0.5; const capped = Math.min(cappedMaxRes, resolution); const cappedZoomLevel = Math.floor( Math.log(maxResolution / capped) / Math.log(power) + offset ); const zoomLevel = Math.max(minZoomLevel, cappedZoomLevel); const newResolution = maxResolution / Math.pow(power, zoomLevel); return clamp(newResolution, minResolution, cappedMaxRes); } return void 0; }) ); } function createMinMaxResolution(maxResolution, minResolution, smooth, maxExtent, showFullExtent) { smooth = smooth !== void 0 ? smooth : true; return ( /** * @param {number|undefined} resolution Resolution. * @param {number} direction Direction. * @param {import("./size.js").Size} size Viewport size. * @param {boolean} [isMoving] True if an interaction or animation is in progress. * @return {number|undefined} Resolution. */ (function(resolution, direction, size, isMoving) { if (resolution !== void 0) { const cappedMaxRes = maxExtent ? getViewportClampedResolution( maxResolution, maxExtent, size, showFullExtent ) : maxResolution; if (!smooth || !isMoving) { return clamp(resolution, minResolution, cappedMaxRes); } return getSmoothClampedResolution( resolution, cappedMaxRes, minResolution ); } return void 0; }) ); } // node_modules/ol/rotationconstraint.js function disable(rotation) { if (rotation !== void 0) { return 0; } return void 0; } function none2(rotation) { if (rotation !== void 0) { return rotation; } return void 0; } function createSnapToN(n) { const theta = 2 * Math.PI / n; return ( /** * @param {number|undefined} rotation Rotation. * @param {boolean} [isMoving] True if an interaction or animation is in progress. * @return {number|undefined} Rotation. */ (function(rotation, isMoving) { if (isMoving) { return rotation; } if (rotation !== void 0) { rotation = Math.floor(rotation / theta + 0.5) * theta; return rotation; } return void 0; }) ); } function createSnapToZero(tolerance) { const t = tolerance === void 0 ? toRadians(5) : tolerance; return ( /** * @param {number|undefined} rotation Rotation. * @param {boolean} [isMoving] True if an interaction or animation is in progress. * @return {number|undefined} Rotation. */ (function(rotation, isMoving) { if (isMoving || rotation === void 0) { return rotation; } if (Math.abs(rotation) <= t) { return 0; } return rotation; }) ); } // node_modules/ol/View.js var DEFAULT_MIN_ZOOM = 0; var View = class extends Object_default { /** * @param {ViewOptions} [options] View options. */ constructor(options) { super(); this.on; this.once; this.un; options = Object.assign({}, options); this.hints_ = [0, 0]; this.animations_ = []; this.updateAnimationKey_; this.projection_ = createProjection(options.projection, "EPSG:3857"); this.viewportSize_ = [100, 100]; this.targetCenter_ = null; this.targetResolution_; this.targetRotation_; this.nextCenter_ = null; this.nextResolution_; this.nextRotation_; this.cancelAnchor_ = void 0; if (options.projection) { disableCoordinateWarning(); } if (options.center) { options.center = fromUserCoordinate(options.center, this.projection_); } if (options.extent) { options.extent = fromUserExtent(options.extent, this.projection_); } this.applyOptions_(options); } /** * Set up the view with the given options. * @param {ViewOptions} options View options. */ applyOptions_(options) { const properties = Object.assign({}, options); for (const key in ViewProperty_default) { delete properties[key]; } this.setProperties(properties, true); const resolutionConstraintInfo = createResolutionConstraint(options); this.maxResolution_ = resolutionConstraintInfo.maxResolution; this.minResolution_ = resolutionConstraintInfo.minResolution; this.zoomFactor_ = resolutionConstraintInfo.zoomFactor; this.resolutions_ = options.resolutions; this.padding_ = options.padding; this.minZoom_ = resolutionConstraintInfo.minZoom; const centerConstraint = createCenterConstraint(options); const resolutionConstraint = resolutionConstraintInfo.constraint; const rotationConstraint = createRotationConstraint(options); this.constraints_ = { center: centerConstraint, resolution: resolutionConstraint, rotation: rotationConstraint }; this.setRotation(options.rotation !== void 0 ? options.rotation : 0); this.setCenterInternal( options.center !== void 0 ? options.center : null ); if (options.resolution !== void 0) { this.setResolution(options.resolution); } else if (options.zoom !== void 0) { this.setZoom(options.zoom); } } /** * Padding (in css pixels). * If the map viewport is partially covered with other content (overlays) along * its edges, this setting allows to shift the center of the viewport away from that * content. The order of the values in the array is top, right, bottom, left. * The default is no padding, which is equivalent to `[0, 0, 0, 0]`. * @type {Array|undefined} * @api */ get padding() { return this.padding_; } set padding(padding) { let oldPadding = this.padding_; this.padding_ = padding; const center = this.getCenterInternal(); if (center) { const newPadding = padding || [0, 0, 0, 0]; oldPadding = oldPadding || [0, 0, 0, 0]; const resolution = this.getResolution(); const offsetX = resolution / 2 * (newPadding[3] - oldPadding[3] + oldPadding[1] - newPadding[1]); const offsetY = resolution / 2 * (newPadding[0] - oldPadding[0] + oldPadding[2] - newPadding[2]); this.setCenterInternal([center[0] + offsetX, center[1] - offsetY]); } } /** * Get an updated version of the view options used to construct the view. The * current resolution (or zoom), center, and rotation are applied to any stored * options. The provided options can be used to apply new min/max zoom or * resolution limits. * @param {ViewOptions} newOptions New options to be applied. * @return {ViewOptions} New options updated with the current view state. */ getUpdatedOptions_(newOptions) { const options = this.getProperties(); if (options.resolution !== void 0) { options.resolution = this.getResolution(); } else { options.zoom = this.getZoom(); } options.center = this.getCenterInternal(); options.rotation = this.getRotation(); return Object.assign({}, options, newOptions); } /** * Animate the view. The view's center, zoom (or resolution), and rotation * can be animated for smooth transitions between view states. For example, * to animate the view to a new zoom level: * * view.animate({zoom: view.getZoom() + 1}); * * By default, the animation lasts one second and uses in-and-out easing. You * can customize this behavior by including `duration` (in milliseconds) and * `easing` options (see {@link module:ol/easing}). * * To chain together multiple animations, call the method with multiple * animation objects. For example, to first zoom and then pan: * * view.animate({zoom: 10}, {center: [0, 0]}); * * If you provide a function as the last argument to the animate method, it * will get called at the end of an animation series. The callback will be * called with `true` if the animation series completed on its own or `false` * if it was cancelled. * * Animations are cancelled by user interactions (e.g. dragging the map) or by * calling `view.setCenter()`, `view.setResolution()`, or `view.setRotation()` * (or another method that calls one of these). * * @param {...(AnimationOptions|function(boolean): void)} var_args Animation * options. Multiple animations can be run in series by passing multiple * options objects. To run multiple animations in parallel, call the method * multiple times. An optional callback can be provided as a final * argument. The callback will be called with a boolean indicating whether * the animation completed without being cancelled. * @api */ animate(var_args) { if (this.isDef() && !this.getAnimating()) { this.resolveConstraints(0); } const args = new Array(arguments.length); for (let i = 0; i < args.length; ++i) { let options = arguments[i]; if (options.center) { options = Object.assign({}, options); options.center = fromUserCoordinate( options.center, this.getProjection() ); } if (options.anchor) { options = Object.assign({}, options); options.anchor = fromUserCoordinate( options.anchor, this.getProjection() ); } args[i] = options; } this.animateInternal.apply(this, args); } /** * @param {...(AnimationOptions|function(boolean): void)} var_args Animation options. */ animateInternal(var_args) { let animationCount = arguments.length; let callback; if (animationCount > 1 && typeof arguments[animationCount - 1] === "function") { callback = arguments[animationCount - 1]; --animationCount; } let i = 0; for (; i < animationCount && !this.isDef(); ++i) { const state = arguments[i]; if (state.center) { this.setCenterInternal(state.center); } if (state.zoom !== void 0) { this.setZoom(state.zoom); } else if (state.resolution) { this.setResolution(state.resolution); } if (state.rotation !== void 0) { this.setRotation(state.rotation); } } if (i === animationCount) { if (callback) { animationCallback(callback, true); } return; } let start = Date.now(); let center = this.targetCenter_.slice(); let resolution = this.targetResolution_; let rotation = this.targetRotation_; const series = []; for (; i < animationCount; ++i) { const options = ( /** @type {AnimationOptions} */ arguments[i] ); const animation = { start, complete: false, anchor: options.anchor, duration: options.duration !== void 0 ? options.duration : 1e3, easing: options.easing || inAndOut, callback }; if (options.center) { animation.sourceCenter = center; animation.targetCenter = options.center.slice(); center = animation.targetCenter; } if (options.zoom !== void 0) { animation.sourceResolution = resolution; animation.targetResolution = this.getResolutionForZoom(options.zoom); resolution = animation.targetResolution; } else if (options.resolution) { animation.sourceResolution = resolution; animation.targetResolution = options.resolution; resolution = animation.targetResolution; } if (options.rotation !== void 0) { animation.sourceRotation = rotation; const delta = modulo(options.rotation - rotation + Math.PI, 2 * Math.PI) - Math.PI; animation.targetRotation = rotation + delta; rotation = animation.targetRotation; } if (isNoopAnimation(animation)) { animation.complete = true; } else { start += animation.duration; } series.push(animation); } this.animations_.push(series); this.setHint(ViewHint_default.ANIMATING, 1); this.updateAnimations_(); } /** * Determine if the view is being animated. * @return {boolean} The view is being animated. * @api */ getAnimating() { return this.hints_[ViewHint_default.ANIMATING] > 0; } /** * Determine if the user is interacting with the view, such as panning or zooming. * @return {boolean} The view is being interacted with. * @api */ getInteracting() { return this.hints_[ViewHint_default.INTERACTING] > 0; } /** * Cancel any ongoing animations. * @api */ cancelAnimations() { this.setHint(ViewHint_default.ANIMATING, -this.hints_[ViewHint_default.ANIMATING]); let anchor; for (let i = 0, ii = this.animations_.length; i < ii; ++i) { const series = this.animations_[i]; if (series[0].callback) { animationCallback(series[0].callback, false); } if (!anchor) { for (let j = 0, jj = series.length; j < jj; ++j) { const animation = series[j]; if (!animation.complete) { anchor = animation.anchor; break; } } } } this.animations_.length = 0; this.cancelAnchor_ = anchor; this.nextCenter_ = null; this.nextResolution_ = NaN; this.nextRotation_ = NaN; } /** * Update all animations. */ updateAnimations_() { if (this.updateAnimationKey_ !== void 0) { cancelAnimationFrame(this.updateAnimationKey_); this.updateAnimationKey_ = void 0; } if (!this.getAnimating()) { return; } const now = Date.now(); let more = false; for (let i = this.animations_.length - 1; i >= 0; --i) { const series = this.animations_[i]; let seriesComplete = true; for (let j = 0, jj = series.length; j < jj; ++j) { const animation = series[j]; if (animation.complete) { continue; } const elapsed = now - animation.start; let fraction = animation.duration > 0 ? elapsed / animation.duration : 1; if (fraction >= 1) { animation.complete = true; fraction = 1; } else { seriesComplete = false; } const progress = animation.easing(fraction); if (animation.sourceCenter) { const x0 = animation.sourceCenter[0]; const y0 = animation.sourceCenter[1]; const x1 = animation.targetCenter[0]; const y1 = animation.targetCenter[1]; this.nextCenter_ = animation.targetCenter; const x = x0 + progress * (x1 - x0); const y = y0 + progress * (y1 - y0); this.targetCenter_ = [x, y]; } if (animation.sourceResolution && animation.targetResolution) { const resolution = progress === 1 ? animation.targetResolution : animation.sourceResolution + progress * (animation.targetResolution - animation.sourceResolution); if (animation.anchor) { const size = this.getViewportSize_(this.getRotation()); const constrainedResolution = this.constraints_.resolution( resolution, 0, size, true ); this.targetCenter_ = this.calculateCenterZoom( constrainedResolution, animation.anchor ); } this.nextResolution_ = animation.targetResolution; this.targetResolution_ = resolution; this.applyTargetState_(true); } if (animation.sourceRotation !== void 0 && animation.targetRotation !== void 0) { const rotation = progress === 1 ? modulo(animation.targetRotation + Math.PI, 2 * Math.PI) - Math.PI : animation.sourceRotation + progress * (animation.targetRotation - animation.sourceRotation); if (animation.anchor) { const constrainedRotation = this.constraints_.rotation( rotation, true ); this.targetCenter_ = this.calculateCenterRotate( constrainedRotation, animation.anchor ); } this.nextRotation_ = animation.targetRotation; this.targetRotation_ = rotation; } this.applyTargetState_(true); more = true; if (!animation.complete) { break; } } if (seriesComplete) { this.animations_[i] = null; this.setHint(ViewHint_default.ANIMATING, -1); this.nextCenter_ = null; this.nextResolution_ = NaN; this.nextRotation_ = NaN; const callback = series[0].callback; if (callback) { animationCallback(callback, true); } } } this.animations_ = this.animations_.filter(Boolean); if (more && this.updateAnimationKey_ === void 0) { this.updateAnimationKey_ = requestAnimationFrame( this.updateAnimations_.bind(this) ); } } /** * @param {number} rotation Target rotation. * @param {import("./coordinate.js").Coordinate} anchor Rotation anchor. * @return {import("./coordinate.js").Coordinate|undefined} Center for rotation and anchor. */ calculateCenterRotate(rotation, anchor) { let center; const currentCenter = this.getCenterInternal(); if (currentCenter !== void 0) { center = [currentCenter[0] - anchor[0], currentCenter[1] - anchor[1]]; rotate(center, rotation - this.getRotation()); add(center, anchor); } return center; } /** * @param {number} resolution Target resolution. * @param {import("./coordinate.js").Coordinate} anchor Zoom anchor. * @return {import("./coordinate.js").Coordinate|undefined} Center for resolution and anchor. */ calculateCenterZoom(resolution, anchor) { let center; const currentCenter = this.getCenterInternal(); const currentResolution = this.getResolution(); if (currentCenter !== void 0 && currentResolution !== void 0) { const x = anchor[0] - resolution * (anchor[0] - currentCenter[0]) / currentResolution; const y = anchor[1] - resolution * (anchor[1] - currentCenter[1]) / currentResolution; center = [x, y]; } return center; } /** * Returns the current viewport size. * @private * @param {number} [rotation] Take into account the rotation of the viewport when giving the size * @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found. */ getViewportSize_(rotation) { const size = this.viewportSize_; if (rotation) { const w = size[0]; const h = size[1]; return [ Math.abs(w * Math.cos(rotation)) + Math.abs(h * Math.sin(rotation)), Math.abs(w * Math.sin(rotation)) + Math.abs(h * Math.cos(rotation)) ]; } return size; } /** * Stores the viewport size on the view. The viewport size is not read every time from the DOM * to avoid performance hit and layout reflow. * This should be done on map size change. * Note: the constraints are not resolved during an animation to avoid stopping it * @param {import("./size.js").Size} [size] Viewport size; if undefined, [100, 100] is assumed */ setViewportSize(size) { this.viewportSize_ = Array.isArray(size) ? size.slice() : [100, 100]; if (!this.getAnimating()) { this.resolveConstraints(0); } } /** * Get the view center. * @return {import("./coordinate.js").Coordinate|undefined} The center of the view. * @observable * @api */ getCenter() { const center = this.getCenterInternal(); if (!center) { return center; } return toUserCoordinate(center, this.getProjection()); } /** * Get the view center without transforming to user projection. * @return {import("./coordinate.js").Coordinate|undefined} The center of the view. */ getCenterInternal() { return ( /** @type {import("./coordinate.js").Coordinate|undefined} */ this.get(ViewProperty_default.CENTER) ); } /** * @return {Constraints} Constraints. */ getConstraints() { return this.constraints_; } /** * @return {boolean} Resolution constraint is set */ getConstrainResolution() { return this.get("constrainResolution"); } /** * @param {Array} [hints] Destination array. * @return {Array} Hint. */ getHints(hints) { if (hints !== void 0) { hints[0] = this.hints_[0]; hints[1] = this.hints_[1]; return hints; } return this.hints_.slice(); } /** * Calculate the extent for the current view state and the passed box size. * @param {import("./size.js").Size} [size] The pixel dimensions of the box * into which the calculated extent should fit. Defaults to the size of the * map the view is associated with. * If no map or multiple maps are connected to the view, provide the desired * box size (e.g. `map.getSize()`). * @return {import("./extent.js").Extent} Extent. * @api */ calculateExtent(size) { const extent = this.calculateExtentInternal(size); return toUserExtent(extent, this.getProjection()); } /** * @param {import("./size.js").Size} [size] Box pixel size. If not provided, * the map's last known viewport size will be used. * @return {import("./extent.js").Extent} Extent. */ calculateExtentInternal(size) { size = size || this.getViewportSizeMinusPadding_(); const center = ( /** @type {!import("./coordinate.js").Coordinate} */ this.getCenterInternal() ); assert(center, "The view center is not defined"); const resolution = ( /** @type {!number} */ this.getResolution() ); assert(resolution !== void 0, "The view resolution is not defined"); const rotation = ( /** @type {!number} */ this.getRotation() ); assert(rotation !== void 0, "The view rotation is not defined"); return getForViewAndSize(center, resolution, rotation, size); } /** * Get the maximum resolution of the view. * @return {number} The maximum resolution of the view. * @api */ getMaxResolution() { return this.maxResolution_; } /** * Get the minimum resolution of the view. * @return {number} The minimum resolution of the view. * @api */ getMinResolution() { return this.minResolution_; } /** * Get the maximum zoom level for the view. * @return {number} The maximum zoom level. * @api */ getMaxZoom() { return ( /** @type {number} */ this.getZoomForResolution(this.minResolution_) ); } /** * Set a new maximum zoom level for the view. * @param {number} zoom The maximum zoom level. * @api */ setMaxZoom(zoom) { this.applyOptions_(this.getUpdatedOptions_({ maxZoom: zoom })); } /** * Get the minimum zoom level for the view. * @return {number} The minimum zoom level. * @api */ getMinZoom() { return ( /** @type {number} */ this.getZoomForResolution(this.maxResolution_) ); } /** * Set a new minimum zoom level for the view. * @param {number} zoom The minimum zoom level. * @api */ setMinZoom(zoom) { this.applyOptions_(this.getUpdatedOptions_({ minZoom: zoom })); } /** * Set whether the view should allow intermediary zoom levels. * @param {boolean} enabled Whether the resolution is constrained. * @api */ setConstrainResolution(enabled) { this.applyOptions_(this.getUpdatedOptions_({ constrainResolution: enabled })); } /** * Get the view projection. * @return {import("./proj/Projection.js").default} The projection of the view. * @api */ getProjection() { return this.projection_; } /** * Get the view resolution. * @return {number|undefined} The resolution of the view. * @observable * @api */ getResolution() { return ( /** @type {number|undefined} */ this.get(ViewProperty_default.RESOLUTION) ); } /** * Get the resolutions for the view. This returns the array of resolutions * passed to the constructor of the View, or undefined if none were given. * @return {Array|undefined} The resolutions of the view. * @api */ getResolutions() { return this.resolutions_; } /** * Get the resolution for a provided extent (in map units) and size (in pixels). * @param {import("./extent.js").Extent} extent Extent. * @param {import("./size.js").Size} [size] Box pixel size. * @return {number} The resolution at which the provided extent will render at * the given size. * @api */ getResolutionForExtent(extent, size) { return this.getResolutionForExtentInternal( fromUserExtent(extent, this.getProjection()), size ); } /** * Get the resolution for a provided extent (in map units) and size (in pixels). * @param {import("./extent.js").Extent} extent Extent. * @param {import("./size.js").Size} [size] Box pixel size. * @return {number} The resolution at which the provided extent will render at * the given size. */ getResolutionForExtentInternal(extent, size) { size = size || this.getViewportSizeMinusPadding_(); const xResolution = getWidth(extent) / size[0]; const yResolution = getHeight(extent) / size[1]; return Math.max(xResolution, yResolution); } /** * Return a function that returns a value between 0 and 1 for a * resolution. Exponential scaling is assumed. * @param {number} [power] Power. * @return {function(number): number} Resolution for value function. */ getResolutionForValueFunction(power) { power = power || 2; const maxResolution = this.getConstrainedResolution(this.maxResolution_); const minResolution = this.minResolution_; const max = Math.log(maxResolution / minResolution) / Math.log(power); return ( /** * @param {number} value Value. * @return {number} Resolution. */ (function(value) { const resolution = maxResolution / Math.pow(power, value * max); return resolution; }) ); } /** * Get the view rotation. * @return {number} The rotation of the view in radians. * @observable * @api */ getRotation() { return ( /** @type {number} */ this.get(ViewProperty_default.ROTATION) ); } /** * Return a function that returns a resolution for a value between * 0 and 1. Exponential scaling is assumed. * @param {number} [power] Power. * @return {function(number): number} Value for resolution function. */ getValueForResolutionFunction(power) { const logPower = Math.log(power || 2); const maxResolution = this.getConstrainedResolution(this.maxResolution_); const minResolution = this.minResolution_; const max = Math.log(maxResolution / minResolution) / logPower; return ( /** * @param {number} resolution Resolution. * @return {number} Value. */ (function(resolution) { const value = Math.log(maxResolution / resolution) / logPower / max; return value; }) ); } /** * Returns the size of the viewport minus padding. * @private * @param {number} [rotation] Take into account the rotation of the viewport when giving the size * @return {import("./size.js").Size} Viewport size reduced by the padding. */ getViewportSizeMinusPadding_(rotation) { let size = this.getViewportSize_(rotation); const padding = this.padding_; if (padding) { size = [ size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2] ]; } return size; } /** * @return {State} View state. */ getState() { const projection = this.getProjection(); const resolution = this.getResolution(); const rotation = this.getRotation(); let center = ( /** @type {import("./coordinate.js").Coordinate} */ this.getCenterInternal() ); const padding = this.padding_; if (padding) { const reducedSize = this.getViewportSizeMinusPadding_(); center = calculateCenterOn( center, this.getViewportSize_(), [reducedSize[0] / 2 + padding[3], reducedSize[1] / 2 + padding[0]], resolution, rotation ); } return { center: center.slice(0), projection: projection !== void 0 ? projection : null, resolution, nextCenter: this.nextCenter_, nextResolution: this.nextResolution_, nextRotation: this.nextRotation_, rotation, zoom: this.getZoom() }; } /** * @return {ViewStateLayerStateExtent} Like `FrameState`, but just `viewState` and `extent`. */ getViewStateAndExtent() { return { viewState: this.getState(), extent: this.calculateExtent() }; } /** * Get the current zoom level. This method may return non-integer zoom levels * if the view does not constrain the resolution, or if an interaction or * animation is underway. * @return {number|undefined} Zoom. * @api */ getZoom() { let zoom; const resolution = this.getResolution(); if (resolution !== void 0) { zoom = this.getZoomForResolution(resolution); } return zoom; } /** * Get the zoom level for a resolution. * @param {number} resolution The resolution. * @return {number|undefined} The zoom level for the provided resolution. * @api */ getZoomForResolution(resolution) { let offset = this.minZoom_ || 0; let max, zoomFactor; if (this.resolutions_) { const nearest = linearFindNearest(this.resolutions_, resolution, 1); offset = nearest; max = this.resolutions_[nearest]; if (nearest == this.resolutions_.length - 1) { zoomFactor = 2; } else { zoomFactor = max / this.resolutions_[nearest + 1]; } } else { max = this.maxResolution_; zoomFactor = this.zoomFactor_; } return offset + Math.log(max / resolution) / Math.log(zoomFactor); } /** * Get the resolution for a zoom level. * @param {number} zoom Zoom level. * @return {number} The view resolution for the provided zoom level. * @api */ getResolutionForZoom(zoom) { var _a; if ((_a = this.resolutions_) == null ? void 0 : _a.length) { if (this.resolutions_.length === 1) { return this.resolutions_[0]; } const baseLevel = clamp( Math.floor(zoom), 0, this.resolutions_.length - 2 ); const zoomFactor = this.resolutions_[baseLevel] / this.resolutions_[baseLevel + 1]; return this.resolutions_[baseLevel] / Math.pow(zoomFactor, clamp(zoom - baseLevel, 0, 1)); } return this.maxResolution_ / Math.pow(this.zoomFactor_, zoom - this.minZoom_); } /** * Fit the given geometry or extent based on the given map size and border. * The size is pixel dimensions of the box to fit the extent into. * In most cases you will want to use the map size, that is `map.getSize()`. * Takes care of the map angle. * @param {import("./geom/SimpleGeometry.js").default|import("./extent.js").Extent} geometryOrExtent The geometry or * extent to fit the view to. * @param {FitOptions} [options] Options. * @api */ fit(geometryOrExtent, options) { let geometry; assert( Array.isArray(geometryOrExtent) || typeof /** @type {?} */ geometryOrExtent.getSimplifiedGeometry === "function", "Invalid extent or geometry provided as `geometry`" ); if (Array.isArray(geometryOrExtent)) { assert( !isEmpty(geometryOrExtent), "Cannot fit empty extent provided as `geometry`" ); const extent = fromUserExtent(geometryOrExtent, this.getProjection()); geometry = fromExtent(extent); } else if (geometryOrExtent.getType() === "Circle") { const extent = fromUserExtent( geometryOrExtent.getExtent(), this.getProjection() ); geometry = fromExtent(extent); geometry.rotate(this.getRotation(), getCenter(extent)); } else { const userProjection = getUserProjection(); if (userProjection) { geometry = /** @type {import("./geom/SimpleGeometry.js").default} */ geometryOrExtent.clone().transform(userProjection, this.getProjection()); } else { geometry = geometryOrExtent; } } this.fitInternal(geometry, options); } /** * Calculate rotated extent * @param {import("./geom/SimpleGeometry.js").default} geometry The geometry. * @return {import("./extent").Extent} The rotated extent for the geometry. */ rotatedExtentForGeometry(geometry) { const rotation = this.getRotation(); const cosAngle = Math.cos(rotation); const sinAngle = Math.sin(-rotation); const coords = geometry.getFlatCoordinates(); const stride = geometry.getStride(); let minRotX = Infinity; let minRotY = Infinity; let maxRotX = -Infinity; let maxRotY = -Infinity; for (let i = 0, ii = coords.length; i < ii; i += stride) { const rotX = coords[i] * cosAngle - coords[i + 1] * sinAngle; const rotY = coords[i] * sinAngle + coords[i + 1] * cosAngle; minRotX = Math.min(minRotX, rotX); minRotY = Math.min(minRotY, rotY); maxRotX = Math.max(maxRotX, rotX); maxRotY = Math.max(maxRotY, rotY); } return [minRotX, minRotY, maxRotX, maxRotY]; } /** * @param {import("./geom/SimpleGeometry.js").default} geometry The geometry. * @param {FitOptions} [options] Options. */ fitInternal(geometry, options) { options = options || {}; let size = options.size; if (!size) { size = this.getViewportSizeMinusPadding_(); } const padding = options.padding !== void 0 ? options.padding : [0, 0, 0, 0]; const nearest = options.nearest !== void 0 ? options.nearest : false; let minResolution; if (options.minResolution !== void 0) { minResolution = options.minResolution; } else if (options.maxZoom !== void 0) { minResolution = this.getResolutionForZoom(options.maxZoom); } else { minResolution = 0; } const rotatedExtent = this.rotatedExtentForGeometry(geometry); let resolution = this.getResolutionForExtentInternal(rotatedExtent, [ size[0] - padding[1] - padding[3], size[1] - padding[0] - padding[2] ]); resolution = isNaN(resolution) ? minResolution : Math.max(resolution, minResolution); resolution = this.getConstrainedResolution(resolution, nearest ? 0 : 1); const rotation = this.getRotation(); const sinAngle = Math.sin(rotation); const cosAngle = Math.cos(rotation); const centerRot = getCenter(rotatedExtent); centerRot[0] += (padding[1] - padding[3]) / 2 * resolution; centerRot[1] += (padding[0] - padding[2]) / 2 * resolution; const centerX = centerRot[0] * cosAngle - centerRot[1] * sinAngle; const centerY = centerRot[1] * cosAngle + centerRot[0] * sinAngle; const center = this.getConstrainedCenter([centerX, centerY], resolution); const callback = options.callback ? options.callback : VOID; if (options.duration !== void 0) { this.animateInternal( { resolution, center, duration: options.duration, easing: options.easing }, callback ); } else { this.targetResolution_ = resolution; this.targetCenter_ = center; this.applyTargetState_(false, true); animationCallback(callback, true); } } /** * Center on coordinate and view position. * @param {import("./coordinate.js").Coordinate} coordinate Coordinate. * @param {import("./size.js").Size} size Box pixel size. * @param {import("./pixel.js").Pixel} position Position on the view to center on. * @api */ centerOn(coordinate, size, position) { this.centerOnInternal( fromUserCoordinate(coordinate, this.getProjection()), size, position ); } /** * @param {import("./coordinate.js").Coordinate} coordinate Coordinate. * @param {import("./size.js").Size} size Box pixel size. * @param {import("./pixel.js").Pixel} position Position on the view to center on. */ centerOnInternal(coordinate, size, position) { this.setCenterInternal( calculateCenterOn( coordinate, size, position, this.getResolution(), this.getRotation() ) ); } /** * Calculates the shift between map and viewport center. * @param {import("./coordinate.js").Coordinate} center Center. * @param {number} resolution Resolution. * @param {number} rotation Rotation. * @param {import("./size.js").Size} size Size. * @return {Array|undefined} Center shift. */ calculateCenterShift(center, resolution, rotation, size) { let centerShift; const padding = this.padding_; if (padding && center) { const reducedSize = this.getViewportSizeMinusPadding_(-rotation); const shiftedCenter = calculateCenterOn( center, size, [reducedSize[0] / 2 + padding[3], reducedSize[1] / 2 + padding[0]], resolution, rotation ); centerShift = [ center[0] - shiftedCenter[0], center[1] - shiftedCenter[1] ]; } return centerShift; } /** * @return {boolean} Is defined. */ isDef() { return !!this.getCenterInternal() && this.getResolution() !== void 0; } /** * Adds relative coordinates to the center of the view. Any extent constraint will apply. * @param {import("./coordinate.js").Coordinate} deltaCoordinates Relative value to add. * @api */ adjustCenter(deltaCoordinates) { const center = toUserCoordinate(this.targetCenter_, this.getProjection()); this.setCenter([ center[0] + deltaCoordinates[0], center[1] + deltaCoordinates[1] ]); } /** * Adds relative coordinates to the center of the view. Any extent constraint will apply. * @param {import("./coordinate.js").Coordinate} deltaCoordinates Relative value to add. */ adjustCenterInternal(deltaCoordinates) { const center = this.targetCenter_; this.setCenterInternal([ center[0] + deltaCoordinates[0], center[1] + deltaCoordinates[1] ]); } /** * Multiply the view resolution by a ratio, optionally using an anchor. Any resolution * constraint will apply. * @param {number} ratio The ratio to apply on the view resolution. * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. * @api */ adjustResolution(ratio, anchor) { anchor = anchor && fromUserCoordinate(anchor, this.getProjection()); this.adjustResolutionInternal(ratio, anchor); } /** * Multiply the view resolution by a ratio, optionally using an anchor. Any resolution * constraint will apply. * @param {number} ratio The ratio to apply on the view resolution. * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. */ adjustResolutionInternal(ratio, anchor) { const isMoving = this.getAnimating() || this.getInteracting(); const size = this.getViewportSize_(this.getRotation()); const newResolution = this.constraints_.resolution( this.targetResolution_ * ratio, 0, size, isMoving ); if (anchor) { this.targetCenter_ = this.calculateCenterZoom(newResolution, anchor); } this.targetResolution_ *= ratio; this.applyTargetState_(); } /** * Adds a value to the view zoom level, optionally using an anchor. Any resolution * constraint will apply. * @param {number} delta Relative value to add to the zoom level. * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. * @api */ adjustZoom(delta, anchor) { this.adjustResolution(Math.pow(this.zoomFactor_, -delta), anchor); } /** * Adds a value to the view rotation, optionally using an anchor. Any rotation * constraint will apply. * @param {number} delta Relative value to add to the zoom rotation, in radians. * @param {import("./coordinate.js").Coordinate} [anchor] The rotation center. * @api */ adjustRotation(delta, anchor) { if (anchor) { anchor = fromUserCoordinate(anchor, this.getProjection()); } this.adjustRotationInternal(delta, anchor); } /** * @param {number} delta Relative value to add to the zoom rotation, in radians. * @param {import("./coordinate.js").Coordinate} [anchor] The rotation center. */ adjustRotationInternal(delta, anchor) { const isMoving = this.getAnimating() || this.getInteracting(); const newRotation = this.constraints_.rotation( this.targetRotation_ + delta, isMoving ); if (anchor) { this.targetCenter_ = this.calculateCenterRotate(newRotation, anchor); } this.targetRotation_ += delta; this.applyTargetState_(); } /** * Set the center of the current view. Any extent constraint will apply. * @param {import("./coordinate.js").Coordinate|undefined} center The center of the view. * @observable * @api */ setCenter(center) { this.setCenterInternal( center ? fromUserCoordinate(center, this.getProjection()) : center ); } /** * Set the center using the view projection (not the user projection). * @param {import("./coordinate.js").Coordinate|undefined} center The center of the view. */ setCenterInternal(center) { this.targetCenter_ = center; this.applyTargetState_(); } /** * @param {import("./ViewHint.js").default} hint Hint. * @param {number} delta Delta. * @return {number} New value. */ setHint(hint, delta) { this.hints_[hint] += delta; this.changed(); return this.hints_[hint]; } /** * Set the resolution for this view. Any resolution constraint will apply. * @param {number|undefined} resolution The resolution of the view. * @observable * @api */ setResolution(resolution) { this.targetResolution_ = resolution; this.applyTargetState_(); } /** * Set the rotation for this view. Any rotation constraint will apply. * @param {number} rotation The rotation of the view in radians. * @observable * @api */ setRotation(rotation) { this.targetRotation_ = rotation; this.applyTargetState_(); } /** * Zoom to a specific zoom level. Any resolution constrain will apply. * @param {number} zoom Zoom level. * @api */ setZoom(zoom) { this.setResolution(this.getResolutionForZoom(zoom)); } /** * Recompute rotation/resolution/center based on target values. * Note: we have to compute rotation first, then resolution and center considering that * parameters can influence one another in case a view extent constraint is present. * @param {boolean} [doNotCancelAnims] Do not cancel animations. * @param {boolean} [forceMoving] Apply constraints as if the view is moving. * @private */ applyTargetState_(doNotCancelAnims, forceMoving) { const isMoving = this.getAnimating() || this.getInteracting() || forceMoving; const newRotation = this.constraints_.rotation( this.targetRotation_, isMoving ); const size = this.getViewportSize_(newRotation); const newResolution = this.constraints_.resolution( this.targetResolution_, 0, size, isMoving ); const newCenter = this.constraints_.center( this.targetCenter_, newResolution, size, isMoving, this.calculateCenterShift( this.targetCenter_, newResolution, newRotation, size ) ); if (this.get(ViewProperty_default.ROTATION) !== newRotation) { this.set(ViewProperty_default.ROTATION, newRotation); } if (this.get(ViewProperty_default.RESOLUTION) !== newResolution) { this.set(ViewProperty_default.RESOLUTION, newResolution); this.set("zoom", this.getZoom(), true); } if (!newCenter || !this.get(ViewProperty_default.CENTER) || !equals(this.get(ViewProperty_default.CENTER), newCenter)) { this.set(ViewProperty_default.CENTER, newCenter); } if (this.getAnimating() && !doNotCancelAnims) { this.cancelAnimations(); } this.cancelAnchor_ = void 0; } /** * If any constraints need to be applied, an animation will be triggered. * This is typically done on interaction end. * Note: calling this with a duration of 0 will apply the constrained values straight away, * without animation. * @param {number} [duration] The animation duration in ms. * @param {number} [resolutionDirection] Which direction to zoom. * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. */ resolveConstraints(duration, resolutionDirection, anchor) { duration = duration !== void 0 ? duration : 200; const direction = resolutionDirection || 0; const newRotation = this.constraints_.rotation(this.targetRotation_); const size = this.getViewportSize_(newRotation); const newResolution = this.constraints_.resolution( this.targetResolution_, direction, size ); const newCenter = this.constraints_.center( this.targetCenter_, newResolution, size, false, this.calculateCenterShift( this.targetCenter_, newResolution, newRotation, size ) ); if (duration === 0 && !this.cancelAnchor_) { this.targetResolution_ = newResolution; this.targetRotation_ = newRotation; this.targetCenter_ = newCenter; this.applyTargetState_(); return; } anchor = anchor || (duration === 0 ? this.cancelAnchor_ : void 0); this.cancelAnchor_ = void 0; if (this.getResolution() !== newResolution || this.getRotation() !== newRotation || !this.getCenterInternal() || !equals(this.getCenterInternal(), newCenter)) { if (this.getAnimating()) { this.cancelAnimations(); } this.animateInternal({ rotation: newRotation, center: newCenter, resolution: newResolution, duration, easing: easeOut, anchor }); } } /** * Notify the View that an interaction has started. * The view state will be resolved to a stable one if needed * (depending on its constraints). * @api */ beginInteraction() { this.resolveConstraints(0); this.setHint(ViewHint_default.INTERACTING, 1); } /** * Notify the View that an interaction has ended. The view state will be resolved * to a stable one if needed (depending on its constraints). * @param {number} [duration] Animation duration in ms. * @param {number} [resolutionDirection] Which direction to zoom. * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. * @api */ endInteraction(duration, resolutionDirection, anchor) { anchor = anchor && fromUserCoordinate(anchor, this.getProjection()); this.endInteractionInternal(duration, resolutionDirection, anchor); } /** * Notify the View that an interaction has ended. The view state will be resolved * to a stable one if needed (depending on its constraints). * @param {number} [duration] Animation duration in ms. * @param {number} [resolutionDirection] Which direction to zoom. * @param {import("./coordinate.js").Coordinate} [anchor] The origin of the transformation. */ endInteractionInternal(duration, resolutionDirection, anchor) { if (!this.getInteracting()) { return; } this.setHint(ViewHint_default.INTERACTING, -1); this.resolveConstraints(duration, resolutionDirection, anchor); } /** * Get a valid position for the view center according to the current constraints. * @param {import("./coordinate.js").Coordinate|undefined} targetCenter Target center position. * @param {number} [targetResolution] Target resolution. If not supplied, the current one will be used. * This is useful to guess a valid center position at a different zoom level. * @return {import("./coordinate.js").Coordinate|undefined} Valid center position. */ getConstrainedCenter(targetCenter, targetResolution) { const size = this.getViewportSize_(this.getRotation()); return this.constraints_.center( targetCenter, targetResolution || this.getResolution(), size ); } /** * Get a valid zoom level according to the current view constraints. * @param {number|undefined} targetZoom Target zoom. * @param {number} [direction] Indicate which resolution should be used * by a renderer if the view resolution does not match any resolution of the tile source. * If 0, the nearest resolution will be used. If 1, the nearest lower resolution * will be used. If -1, the nearest higher resolution will be used. * @return {number|undefined} Valid zoom level. */ getConstrainedZoom(targetZoom, direction) { const targetRes = this.getResolutionForZoom(targetZoom); return this.getZoomForResolution( this.getConstrainedResolution(targetRes, direction) ); } /** * Get a valid resolution according to the current view constraints. * @param {number|undefined} targetResolution Target resolution. * @param {number} [direction] Indicate which resolution should be used * by a renderer if the view resolution does not match any resolution of the tile source. * If 0, the nearest resolution will be used. If 1, the nearest lower resolution * will be used. If -1, the nearest higher resolution will be used. * @return {number|undefined} Valid resolution. */ getConstrainedResolution(targetResolution, direction) { direction = direction || 0; const size = this.getViewportSize_(this.getRotation()); return this.constraints_.resolution(targetResolution, direction, size); } }; function animationCallback(callback, returnValue) { setTimeout(function() { callback(returnValue); }, 0); } function createCenterConstraint(options) { if (options.extent !== void 0) { const smooth = options.smoothExtentConstraint !== void 0 ? options.smoothExtentConstraint : true; return createExtent(options.extent, options.constrainOnlyCenter, smooth); } const projection = createProjection(options.projection, "EPSG:3857"); if (options.multiWorld !== true && projection.isGlobal()) { const extent = projection.getExtent().slice(); extent[0] = -Infinity; extent[2] = Infinity; return createExtent(extent, false, false); } return none; } function createResolutionConstraint(options) { let resolutionConstraint; let maxResolution; let minResolution; const defaultMaxZoom = 28; const defaultZoomFactor = 2; let minZoom = options.minZoom !== void 0 ? options.minZoom : DEFAULT_MIN_ZOOM; let maxZoom = options.maxZoom !== void 0 ? options.maxZoom : defaultMaxZoom; const zoomFactor = options.zoomFactor !== void 0 ? options.zoomFactor : defaultZoomFactor; const multiWorld = options.multiWorld !== void 0 ? options.multiWorld : false; const smooth = options.smoothResolutionConstraint !== void 0 ? options.smoothResolutionConstraint : true; const showFullExtent = options.showFullExtent !== void 0 ? options.showFullExtent : false; const projection = createProjection(options.projection, "EPSG:3857"); const projExtent = projection.getExtent(); let constrainOnlyCenter = options.constrainOnlyCenter; let extent = options.extent; if (!multiWorld && !extent && projection.isGlobal()) { constrainOnlyCenter = false; extent = projExtent; } if (options.resolutions !== void 0) { const resolutions = options.resolutions; maxResolution = resolutions[minZoom]; minResolution = resolutions[maxZoom] !== void 0 ? resolutions[maxZoom] : resolutions[resolutions.length - 1]; if (options.constrainResolution) { resolutionConstraint = createSnapToResolutions( resolutions, smooth, !constrainOnlyCenter && extent, showFullExtent ); } else { resolutionConstraint = createMinMaxResolution( maxResolution, minResolution, smooth, !constrainOnlyCenter && extent, showFullExtent ); } } else { const size = !projExtent ? ( // use an extent that can fit the whole world if need be 360 * METERS_PER_UNIT.degrees / projection.getMetersPerUnit() ) : Math.max(getWidth(projExtent), getHeight(projExtent)); const defaultMaxResolution = size / DEFAULT_TILE_SIZE / Math.pow(defaultZoomFactor, DEFAULT_MIN_ZOOM); const defaultMinResolution = defaultMaxResolution / Math.pow(defaultZoomFactor, defaultMaxZoom - DEFAULT_MIN_ZOOM); maxResolution = options.maxResolution; if (maxResolution !== void 0) { minZoom = 0; } else { maxResolution = defaultMaxResolution / Math.pow(zoomFactor, minZoom); } minResolution = options.minResolution; if (minResolution === void 0) { if (options.maxZoom !== void 0) { if (options.maxResolution !== void 0) { minResolution = maxResolution / Math.pow(zoomFactor, maxZoom); } else { minResolution = defaultMaxResolution / Math.pow(zoomFactor, maxZoom); } } else { minResolution = defaultMinResolution; } } maxZoom = minZoom + Math.floor( Math.log(maxResolution / minResolution) / Math.log(zoomFactor) ); minResolution = maxResolution / Math.pow(zoomFactor, maxZoom - minZoom); if (options.constrainResolution) { resolutionConstraint = createSnapToPower( zoomFactor, maxResolution, minResolution, smooth, !constrainOnlyCenter && extent, showFullExtent ); } else { resolutionConstraint = createMinMaxResolution( maxResolution, minResolution, smooth, !constrainOnlyCenter && extent, showFullExtent ); } } return { constraint: resolutionConstraint, maxResolution, minResolution, minZoom, zoomFactor }; } function createRotationConstraint(options) { const enableRotation = options.enableRotation !== void 0 ? options.enableRotation : true; if (enableRotation) { const constrainRotation = options.constrainRotation; if (constrainRotation === void 0 || constrainRotation === true) { return createSnapToZero(); } if (constrainRotation === false) { return none2; } if (typeof constrainRotation === "number") { return createSnapToN(constrainRotation); } return none2; } return disable; } function isNoopAnimation(animation) { if (animation.sourceCenter && animation.targetCenter) { if (!equals(animation.sourceCenter, animation.targetCenter)) { return false; } } if (animation.sourceResolution !== animation.targetResolution) { return false; } if (animation.sourceRotation !== animation.targetRotation) { return false; } return true; } function calculateCenterOn(coordinate, size, position, resolution, rotation) { const cosAngle = Math.cos(-rotation); let sinAngle = Math.sin(-rotation); let rotX = coordinate[0] * cosAngle - coordinate[1] * sinAngle; let rotY = coordinate[1] * cosAngle + coordinate[0] * sinAngle; rotX += (size[0] / 2 - position[0]) * resolution; rotY += (position[1] - size[1] / 2) * resolution; sinAngle = -sinAngle; const centerX = rotX * cosAngle - rotY * sinAngle; const centerY = rotY * cosAngle + rotX * sinAngle; return [centerX, centerY]; } var View_default = View; // node_modules/ol/layer/Property.js var Property_default = { OPACITY: "opacity", VISIBLE: "visible", EXTENT: "extent", Z_INDEX: "zIndex", MAX_RESOLUTION: "maxResolution", MIN_RESOLUTION: "minResolution", MAX_ZOOM: "maxZoom", MIN_ZOOM: "minZoom", SOURCE: "source", MAP: "map" }; // node_modules/ol/render/EventType.js var EventType_default2 = { /** * Triggered before a layer is rendered. * @event module:ol/render/Event~RenderEvent#prerender * @api */ PRERENDER: "prerender", /** * Triggered after a layer is rendered. * @event module:ol/render/Event~RenderEvent#postrender * @api */ POSTRENDER: "postrender", /** * Triggered before layers are composed. When dispatched by the map, the event object will not have * a `context` set. When dispatched by a layer, the event object will have a `context` set. Only * WebGL layers currently dispatch this event. * @event module:ol/render/Event~RenderEvent#precompose * @api */ PRECOMPOSE: "precompose", /** * Triggered after layers are composed. When dispatched by the map, the event object will not have * a `context` set. When dispatched by a layer, the event object will have a `context` set. Only * WebGL layers currently dispatch this event. * @event module:ol/render/Event~RenderEvent#postcompose * @api */ POSTCOMPOSE: "postcompose", /** * Triggered when rendering is complete, i.e. all sources and tiles have * finished loading for the current viewport, and all tiles are faded in. * The event object will not have a `context` set. * @event module:ol/render/Event~RenderEvent#rendercomplete * @api */ RENDERCOMPLETE: "rendercomplete" }; // node_modules/ol/layer/Base.js var BaseLayer = class extends Object_default { /** * @param {Options} options Layer options. */ constructor(options) { super(); this.on; this.once; this.un; this.background_ = options.background; const properties = Object.assign({}, options); if (typeof options.properties === "object") { delete properties.properties; Object.assign(properties, options.properties); } properties[Property_default.OPACITY] = options.opacity !== void 0 ? options.opacity : 1; assert( typeof properties[Property_default.OPACITY] === "number", "Layer opacity must be a number" ); properties[Property_default.VISIBLE] = options.visible !== void 0 ? options.visible : true; properties[Property_default.Z_INDEX] = options.zIndex; properties[Property_default.MAX_RESOLUTION] = options.maxResolution !== void 0 ? options.maxResolution : Infinity; properties[Property_default.MIN_RESOLUTION] = options.minResolution !== void 0 ? options.minResolution : 0; properties[Property_default.MIN_ZOOM] = options.minZoom !== void 0 ? options.minZoom : -Infinity; properties[Property_default.MAX_ZOOM] = options.maxZoom !== void 0 ? options.maxZoom : Infinity; this.className_ = properties.className !== void 0 ? properties.className : "ol-layer"; delete properties.className; this.setProperties(properties); this.state_ = null; } /** * Get the background for this layer. * @return {BackgroundColor|false} Layer background. */ getBackground() { return this.background_; } /** * @return {string} CSS class name. */ getClassName() { return this.className_; } /** * This method is not meant to be called by layers or layer renderers because the state * is incorrect if the layer is included in a layer group. * * @param {boolean} [managed] Layer is managed. * @return {import("./Layer.js").State} Layer state. */ getLayerState(managed) { const state = this.state_ || /** @type {?} */ { layer: this, managed: managed === void 0 ? true : managed }; const zIndex = this.getZIndex(); state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1); state.visible = this.getVisible(); state.extent = this.getExtent(); state.zIndex = zIndex === void 0 && !state.managed ? Infinity : zIndex; state.maxResolution = this.getMaxResolution(); state.minResolution = Math.max(this.getMinResolution(), 0); state.minZoom = this.getMinZoom(); state.maxZoom = this.getMaxZoom(); this.state_ = state; return state; } /** * @abstract * @param {Array} [array] Array of layers (to be * modified in place). * @return {Array} Array of layers. */ getLayersArray(array) { return abstract(); } /** * @abstract * @param {Array} [states] Optional list of layer * states (to be modified in place). * @return {Array} List of layer states. */ getLayerStatesArray(states) { return abstract(); } /** * Return the {@link module:ol/extent~Extent extent} of the layer or `undefined` if it * will be visible regardless of extent. * @return {import("../extent.js").Extent|undefined} The layer extent. * @observable * @api */ getExtent() { return ( /** @type {import("../extent.js").Extent|undefined} */ this.get(Property_default.EXTENT) ); } /** * Return the maximum resolution of the layer. Returns Infinity if * the layer has no maximum resolution set. * @return {number} The maximum resolution of the layer. * @observable * @api */ getMaxResolution() { return ( /** @type {number} */ this.get(Property_default.MAX_RESOLUTION) ); } /** * Return the minimum resolution of the layer. Returns 0 if * the layer has no minimum resolution set. * @return {number} The minimum resolution of the layer. * @observable * @api */ getMinResolution() { return ( /** @type {number} */ this.get(Property_default.MIN_RESOLUTION) ); } /** * Return the minimum zoom level of the layer. Returns -Infinity if * the layer has no minimum zoom set. * @return {number} The minimum zoom level of the layer. * @observable * @api */ getMinZoom() { return ( /** @type {number} */ this.get(Property_default.MIN_ZOOM) ); } /** * Return the maximum zoom level of the layer. Returns Infinity if * the layer has no maximum zoom set. * @return {number} The maximum zoom level of the layer. * @observable * @api */ getMaxZoom() { return ( /** @type {number} */ this.get(Property_default.MAX_ZOOM) ); } /** * Return the opacity of the layer (between 0 and 1). * @return {number} The opacity of the layer. * @observable * @api */ getOpacity() { return ( /** @type {number} */ this.get(Property_default.OPACITY) ); } /** * @abstract * @return {import("../source/Source.js").State} Source state. */ getSourceState() { return abstract(); } /** * Return the value of this layer's `visible` property. To find out whether the layer * is visible on a map, use `isVisible()` instead. * @return {boolean} The value of the `visible` property of the layer. * @observable * @api */ getVisible() { return ( /** @type {boolean} */ this.get(Property_default.VISIBLE) ); } /** * Return the Z-index of the layer, which is used to order layers before * rendering. Returns undefined if the layer is unmanaged. * @return {number|undefined} The Z-index of the layer. * @observable * @api */ getZIndex() { return ( /** @type {number|undefined} */ this.get(Property_default.Z_INDEX) ); } /** * Sets the background color. * @param {BackgroundColor} [background] Background color. */ setBackground(background) { this.background_ = background; this.changed(); } /** * Set the extent at which the layer is visible. If `undefined`, the layer * will be visible at all extents. * @param {import("../extent.js").Extent|undefined} extent The extent of the layer. * @observable * @api */ setExtent(extent) { this.set(Property_default.EXTENT, extent); } /** * Set the maximum resolution at which the layer is visible. * @param {number} maxResolution The maximum resolution of the layer. * @observable * @api */ setMaxResolution(maxResolution) { this.set(Property_default.MAX_RESOLUTION, maxResolution); } /** * Set the minimum resolution at which the layer is visible. * @param {number} minResolution The minimum resolution of the layer. * @observable * @api */ setMinResolution(minResolution) { this.set(Property_default.MIN_RESOLUTION, minResolution); } /** * Set the maximum zoom (exclusive) at which the layer is visible. * Note that the zoom levels for layer visibility are based on the * view zoom level, which may be different from a tile source zoom level. * @param {number} maxZoom The maximum zoom of the layer. * @observable * @api */ setMaxZoom(maxZoom) { this.set(Property_default.MAX_ZOOM, maxZoom); } /** * Set the minimum zoom (inclusive) at which the layer is visible. * Note that the zoom levels for layer visibility are based on the * view zoom level, which may be different from a tile source zoom level. * @param {number} minZoom The minimum zoom of the layer. * @observable * @api */ setMinZoom(minZoom) { this.set(Property_default.MIN_ZOOM, minZoom); } /** * Set the opacity of the layer, allowed values range from 0 to 1. * @param {number} opacity The opacity of the layer. * @observable * @api */ setOpacity(opacity) { assert(typeof opacity === "number", "Layer opacity must be a number"); this.set(Property_default.OPACITY, opacity); } /** * Set the visibility of the layer (`true` or `false`). * @param {boolean} visible The visibility of the layer. * @observable * @api */ setVisible(visible) { this.set(Property_default.VISIBLE, visible); } /** * Set Z-index of the layer, which is used to order layers before rendering. * The default Z-index is 0. * @param {number} zindex The z-index of the layer. * @observable * @api */ setZIndex(zindex) { this.set(Property_default.Z_INDEX, zindex); } /** * Clean up. * @override */ disposeInternal() { if (this.state_) { this.state_.layer = null; this.state_ = null; } super.disposeInternal(); } }; var Base_default = BaseLayer; // node_modules/ol/layer/Layer.js var Layer = class extends Base_default { /** * @param {Options} options Layer options. */ constructor(options) { const baseOptions = Object.assign({}, options); delete baseOptions.source; super(baseOptions); this.on; this.once; this.un; this.mapPrecomposeKey_ = null; this.mapRenderKey_ = null; this.sourceChangeKey_ = null; this.renderer_ = null; this.sourceReady_ = false; this.rendered = false; if (options.render) { this.render = options.render; } if (options.map) { this.setMap(options.map); } this.addChangeListener( Property_default.SOURCE, this.handleSourcePropertyChange_ ); const source = options.source ? ( /** @type {SourceType} */ options.source ) : null; this.setSource(source); } /** * @param {Array} [array] Array of layers (to be modified in place). * @return {Array} Array of layers. * @override */ getLayersArray(array) { array = array ? array : []; array.push(this); return array; } /** * @param {Array} [states] Optional list of layer states (to be modified in place). * @return {Array} List of layer states. * @override */ getLayerStatesArray(states) { states = states ? states : []; states.push(this.getLayerState()); return states; } /** * Get the layer source. * @return {SourceType|null} The layer source (or `null` if not yet set). * @observable * @api */ getSource() { return ( /** @type {SourceType} */ this.get(Property_default.SOURCE) || null ); } /** * @return {SourceType|null} The source being rendered. */ getRenderSource() { return this.getSource(); } /** * @return {import("../source/Source.js").State} Source state. * @override */ getSourceState() { const source = this.getSource(); return !source ? "undefined" : source.getState(); } /** * @private */ handleSourceChange_() { this.changed(); if (this.sourceReady_ || this.getSource().getState() !== "ready") { return; } this.sourceReady_ = true; this.dispatchEvent("sourceready"); } /** * @private */ handleSourcePropertyChange_() { if (this.sourceChangeKey_) { unlistenByKey(this.sourceChangeKey_); this.sourceChangeKey_ = null; } this.sourceReady_ = false; const source = this.getSource(); if (source) { this.sourceChangeKey_ = listen( source, EventType_default.CHANGE, this.handleSourceChange_, this ); if (source.getState() === "ready") { this.sourceReady_ = true; setTimeout(() => { this.dispatchEvent("sourceready"); }, 0); } } this.changed(); } /** * @param {import("../pixel").Pixel} pixel Pixel. * @return {Promise>} Promise that resolves with * an array of features. */ getFeatures(pixel) { if (!this.renderer_) { return Promise.resolve([]); } return this.renderer_.getFeatures(pixel); } /** * @param {import("../pixel").Pixel} pixel Pixel. * @return {Uint8ClampedArray|Uint8Array|Float32Array|DataView|null} Pixel data. */ getData(pixel) { if (!this.renderer_ || !this.rendered) { return null; } return this.renderer_.getData(pixel); } /** * The layer is visible on the map view, i.e. within its min/max resolution or zoom and * extent, not set to `visible: false`, and not inside a layer group that is set * to `visible: false`. * @param {View|import("../View.js").ViewStateLayerStateExtent} [view] View or {@link import("../Map.js").FrameState}. * Only required when the layer is not added to a map. * @return {boolean} The layer is visible in the map view. * @api */ isVisible(view) { let frameState; const map = this.getMapInternal(); if (!view && map) { view = map.getView(); } if (view instanceof View_default) { frameState = { viewState: view.getState(), extent: view.calculateExtent() }; } else { frameState = view; } if (!frameState.layerStatesArray && map) { frameState.layerStatesArray = map.getLayerGroup().getLayerStatesArray(); } let layerState; if (frameState.layerStatesArray) { layerState = frameState.layerStatesArray.find( (layerState2) => layerState2.layer === this ); if (!layerState) { return false; } } else { layerState = this.getLayerState(); } const layerExtent = this.getExtent(); return inView(layerState, frameState.viewState) && (!layerExtent || intersects(layerExtent, frameState.extent)); } /** * Get the attributions of the source of this layer for the given view. * @param {View|import("../View.js").ViewStateLayerStateExtent} [view] View or {@link import("../Map.js").FrameState}. * Only required when the layer is not added to a map. * @return {Array} Attributions for this layer at the given view. * @api */ getAttributions(view) { var _a; if (!this.isVisible(view)) { return []; } const getAttributions = (_a = this.getSource()) == null ? void 0 : _a.getAttributions(); if (!getAttributions) { return []; } const frameState = view instanceof View_default ? view.getViewStateAndExtent() : view; let attributions = getAttributions(frameState); if (!Array.isArray(attributions)) { attributions = [attributions]; } return attributions; } /** * In charge to manage the rendering of the layer. One layer type is * bounded with one layer renderer. * @param {?import("../Map.js").FrameState} frameState Frame state. * @param {HTMLElement} target Target which the renderer may (but need not) use * for rendering its content. * @return {HTMLElement|null} The rendered element. */ render(frameState, target) { const layerRenderer = this.getRenderer(); if (layerRenderer.prepareFrame(frameState)) { this.rendered = true; return layerRenderer.renderFrame(frameState, target); } return null; } /** * Called when a layer is not visible during a map render. */ unrender() { this.rendered = false; } /** @return {string} Declutter */ getDeclutter() { return void 0; } /** * @param {import("../Map.js").FrameState} frameState Frame state. * @param {import("../layer/Layer.js").State} layerState Layer state. */ renderDeclutter(frameState, layerState) { } /** * When the renderer follows a layout -> render approach, do the final rendering here. * @param {import('../Map.js').FrameState} frameState Frame state */ renderDeferred(frameState) { const layerRenderer = this.getRenderer(); if (!layerRenderer) { return; } layerRenderer.renderDeferred(frameState); } /** * For use inside the library only. * @param {import("../Map.js").default|null} map Map. */ setMapInternal(map) { if (!map) { this.unrender(); } this.set(Property_default.MAP, map); } /** * For use inside the library only. * @return {import("../Map.js").default|null} Map. */ getMapInternal() { return this.get(Property_default.MAP); } /** * Sets the layer to be rendered on top of other layers on a map. The map will * not manage this layer in its layers collection. This * is useful for temporary layers. To remove an unmanaged layer from the map, * use `#setMap(null)`. * * To add the layer to a map and have it managed by the map, use * {@link module:ol/Map~Map#addLayer} instead. * @param {import("../Map.js").default|null} map Map. * @api */ setMap(map) { if (this.mapPrecomposeKey_) { unlistenByKey(this.mapPrecomposeKey_); this.mapPrecomposeKey_ = null; } if (!map) { this.changed(); } if (this.mapRenderKey_) { unlistenByKey(this.mapRenderKey_); this.mapRenderKey_ = null; } if (map) { this.mapPrecomposeKey_ = listen( map, EventType_default2.PRECOMPOSE, this.handlePrecompose_, this ); this.mapRenderKey_ = listen(this, EventType_default.CHANGE, map.render, map); this.changed(); } } /** * @param {import("../events/Event.js").default} renderEvent Render event * @private */ handlePrecompose_(renderEvent) { const layerStatesArray = ( /** @type {import("../render/Event.js").default} */ renderEvent.frameState.layerStatesArray ); const layerState = this.getLayerState(false); assert( !layerStatesArray.some( (arrayLayerState) => arrayLayerState.layer === layerState.layer ), "A layer can only be added to the map once. Use either `layer.setMap()` or `map.addLayer()`, not both." ); layerStatesArray.push(layerState); } /** * Set the layer source. * @param {SourceType|null} source The layer source. * @observable * @api */ setSource(source) { this.set(Property_default.SOURCE, source); } /** * Get the renderer for this layer. * @return {RendererType|null} The layer renderer. */ getRenderer() { if (!this.renderer_) { this.renderer_ = this.createRenderer(); } return this.renderer_; } /** * @return {boolean} The layer has a renderer. */ hasRenderer() { return !!this.renderer_; } /** * Create a renderer for this layer. * @return {RendererType} A layer renderer. * @protected */ createRenderer() { return null; } /** * This will clear the renderer so that a new one can be created next time it is needed */ clearRenderer() { if (this.renderer_) { this.renderer_.dispose(); delete this.renderer_; } } /** * Clean up. * @override */ disposeInternal() { this.clearRenderer(); this.setSource(null); super.disposeInternal(); } }; function inView(layerState, viewState) { if (!layerState.visible) { return false; } const resolution = viewState.resolution; if (resolution < layerState.minResolution || resolution >= layerState.maxResolution) { return false; } const zoom = viewState.zoom; return zoom > layerState.minZoom && zoom <= layerState.maxZoom; } var Layer_default = Layer; // node_modules/ol/render/Event.js var RenderEvent = class extends Event_default { /** * @param {import("./EventType.js").default} type Type. * @param {import("../transform.js").Transform} [inversePixelTransform] Transform for * CSS pixels to rendered pixels. * @param {import("../Map.js").FrameState} [frameState] Frame state. * @param {?(CanvasRenderingContext2D|WebGLRenderingContext)} [context] Context. */ constructor(type, inversePixelTransform, frameState, context) { super(type); this.inversePixelTransform = inversePixelTransform; this.frameState = frameState; this.context = context; } }; var Event_default2 = RenderEvent; export { EventType_default2 as EventType_default, ViewHint_default, Event_default2 as Event_default, ViewProperty_default, disable, View_default, Property_default, Base_default, inView, Layer_default }; //# sourceMappingURL=chunk-S5OMZ56B.js.map