UNPKG

@web-map-service/map2d

Version:

基于openlayer的2D地图服务

1,777 lines 729 kB
var jh = Object.defineProperty; var Kh = (s, t, e) => t in s ? jh(s, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : s[t] = e; var Wo = (s, t, e) => Kh(s, typeof t != "symbol" ? t + "" : t, e); const st = { /** * Triggered when an item is added to the collection. * @event module:ol/Collection.CollectionEvent#add * @api */ ADD: "add", /** * Triggered when an item is removed from the collection. * @event module:ol/Collection.CollectionEvent#remove * @api */ REMOVE: "remove" }, _i = { /** * Triggered when a property is changed. * @event module:ol/Object.ObjectEvent#propertychange * @api */ PROPERTYCHANGE: "propertychange" }, F = { /** * Generic change event. Triggered when the revision counter is increased. * @event module:ol/events/Event~BaseEvent#change * @api */ CHANGE: "change", CONTEXTMENU: "contextmenu", CLICK: "click", DBLCLICK: "dblclick", KEYDOWN: "keydown", KEYPRESS: "keypress", TOUCHMOVE: "touchmove", WHEEL: "wheel" }; class Nr { constructor() { this.disposed = !1; } /** * Clean up. */ dispose() { this.disposed || (this.disposed = !0, this.disposeInternal()); } /** * Extension point for disposable objects. * @protected */ disposeInternal() { } } function Uh(s, t, e) { let i, n; e = e || ze; let r = 0, o = s.length, a = !1; for (; r < o; ) i = r + (o - r >> 1), n = +e(s[i], t), n < 0 ? r = i + 1 : (o = i, a = !n); return a ? r : ~r; } function ze(s, t) { return s > t ? 1 : s < t ? -1 : 0; } function Hh(s, t) { return s < t ? 1 : s > t ? -1 : 0; } function Gr(s, t, e) { if (s[0] <= t) return 0; const i = s.length; if (t <= s[i - 1]) return i - 1; if (typeof e == "function") { for (let n = 1; n < i; ++n) { const r = s[n]; if (r === t) return n; if (r < t) return e(t, s[n - 1], r) > 0 ? n - 1 : n; } return i - 1; } if (e > 0) { for (let n = 1; n < i; ++n) if (s[n] < t) return n - 1; return i - 1; } if (e < 0) { for (let n = 1; n < i; ++n) if (s[n] <= t) return n; return i - 1; } for (let n = 1; n < i; ++n) { if (s[n] == t) return n; if (s[n] < t) return s[n - 1] - t < t - s[n] ? n - 1 : n; } return i - 1; } function Zh(s, t, e) { for (; t < e; ) { const i = s[t]; s[t] = s[e], s[e] = i, ++t, --e; } } function kt(s, t) { const e = Array.isArray(t) ? t : [t], i = e.length; for (let n = 0; n < i; n++) s[s.length] = e[n]; } function pe(s, t) { const e = s.length; if (e !== t.length) return !1; for (let i = 0; i < e; i++) if (s[i] !== t[i]) return !1; return !0; } function ee() { return !0; } function vi() { return !1; } function en() { } function Ja(s) { let t, e, i; return function() { const n = Array.prototype.slice.call(arguments); return (!e || this !== i || !pe(n, e)) && (i = this, e = n, t = s.apply(this, arguments)), t; }; } function Qa(s) { function t() { let e; try { e = s(); } catch (i) { return Promise.reject(i); } return e instanceof Promise ? e : Promise.resolve(e); } return t(); } function Ri(s) { for (const t in s) delete s[t]; } function mi(s) { let t; for (t in s) return !1; return !t; } class Lt { /** * @param {string} type Type. */ constructor(t) { this.propagationStopped, this.defaultPrevented, this.type = t, this.target = null; } /** * Prevent default. This means that no emulated `click`, `singleclick` or `doubleclick` events * will be fired. * @api */ preventDefault() { this.defaultPrevented = !0; } /** * Stop event propagation. * @api */ stopPropagation() { this.propagationStopped = !0; } } class ds extends Nr { /** * @param {*} [target] Default event target for dispatched events. */ constructor(t) { super(), this.eventTarget_ = t, this.pendingRemovals_ = null, this.dispatching_ = null, this.listeners_ = null; } /** * @param {string} type Type. * @param {import("../events.js").Listener} listener Listener. */ addEventListener(t, e) { if (!t || !e) return; const i = this.listeners_ || (this.listeners_ = {}), n = i[t] || (i[t] = []); n.includes(e) || n.push(e); } /** * Dispatches an event and calls all listeners listening for events * of this type. The event parameter can either be a string or an * Object with a `type` property. * * @param {import("./Event.js").default|string} event Event object. * @return {boolean|undefined} `false` if anyone called preventDefault on the * event object or if any of the listeners returned false. * @api */ dispatchEvent(t) { const e = typeof t == "string", i = e ? t : t.type, n = this.listeners_ && this.listeners_[i]; if (!n) return; const r = e ? new Lt(t) : ( /** @type {Event} */ t ); r.target || (r.target = this.eventTarget_ || this); const o = this.dispatching_ || (this.dispatching_ = {}), a = this.pendingRemovals_ || (this.pendingRemovals_ = {}); i in o || (o[i] = 0, a[i] = 0), ++o[i]; let l; for (let c = 0, h = n.length; c < h; ++c) if ("handleEvent" in n[c] ? l = /** @type {import("../events.js").ListenerObject} */ n[c].handleEvent(r) : l = /** @type {import("../events.js").ListenerFunction} */ n[c].call(this, r), l === !1 || r.propagationStopped) { l = !1; break; } if (--o[i] === 0) { let c = a[i]; for (delete a[i]; c--; ) this.removeEventListener(i, en); delete o[i]; } return l; } /** * Clean up. * @override */ disposeInternal() { this.listeners_ && Ri(this.listeners_); } /** * Get the listeners for a specified event type. Listeners are returned in the * order that they will be called in. * * @param {string} type Type. * @return {Array<import("../events.js").Listener>|undefined} Listeners. */ getListeners(t) { return this.listeners_ && this.listeners_[t] || void 0; } /** * @param {string} [type] Type. If not provided, * `true` will be returned if this event target has any listeners. * @return {boolean} Has listeners. */ hasListener(t) { return this.listeners_ ? t ? t in this.listeners_ : Object.keys(this.listeners_).length > 0 : !1; } /** * @param {string} type Type. * @param {import("../events.js").Listener} listener Listener. */ removeEventListener(t, e) { if (!this.listeners_) return; const i = this.listeners_[t]; if (!i) return; const n = i.indexOf(e); n !== -1 && (this.pendingRemovals_ && t in this.pendingRemovals_ ? (i[n] = en, ++this.pendingRemovals_[t]) : (i.splice(n, 1), i.length === 0 && delete this.listeners_[t])); } } function z(s, t, e, i, n) { if (n) { const o = e; e = function(a) { return s.removeEventListener(t, e), o.call(i ?? this, a); }; } else i && i !== s && (e = e.bind(i)); const r = { target: s, type: t, listener: e }; return s.addEventListener(t, e), r; } function Bo(s, t, e, i) { return z(s, t, e, i, !0); } function tt(s) { s && s.target && (s.target.removeEventListener(s.type, s.listener), Ri(s)); } class En extends ds { constructor() { super(), this.on = /** @type {ObservableOnSignature<import("./events").EventsKey>} */ this.onInternal, this.once = /** @type {ObservableOnSignature<import("./events").EventsKey>} */ this.onceInternal, this.un = /** @type {ObservableOnSignature<void>} */ this.unInternal, this.revision_ = 0; } /** * Increases the revision counter and dispatches a 'change' event. * @api */ changed() { ++this.revision_, this.dispatchEvent(F.CHANGE); } /** * Get the version number for this object. Each time the object is modified, * its version number will be incremented. * @return {number} Revision. * @api */ getRevision() { return this.revision_; } /** * @param {string|Array<string>} type Type. * @param {function((Event|import("./events/Event").default)): ?} listener Listener. * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Event key. * @protected */ onInternal(t, e) { if (Array.isArray(t)) { const i = t.length, n = new Array(i); for (let r = 0; r < i; ++r) n[r] = z(this, t[r], e); return n; } return z( this, /** @type {string} */ t, e ); } /** * @param {string|Array<string>} type Type. * @param {function((Event|import("./events/Event").default)): ?} listener Listener. * @return {import("./events.js").EventsKey|Array<import("./events.js").EventsKey>} Event key. * @protected */ onceInternal(t, e) { let i; if (Array.isArray(t)) { const n = t.length; i = new Array(n); for (let r = 0; r < n; ++r) i[r] = Bo(this, t[r], e); } else i = Bo( this, /** @type {string} */ t, e ); return e.ol_key = i, i; } /** * Unlisten for a certain type of event. * @param {string|Array<string>} type Type. * @param {function((Event|import("./events/Event").default)): ?} listener Listener. * @protected */ unInternal(t, e) { const i = ( /** @type {Object} */ e.ol_key ); if (i) yr(i); else if (Array.isArray(t)) for (let n = 0, r = t.length; n < r; ++n) this.removeEventListener(t[n], e); else this.removeEventListener(t, e); } } En.prototype.on; En.prototype.once; En.prototype.un; function yr(s) { if (Array.isArray(s)) for (let t = 0, e = s.length; t < e; ++t) tt(s[t]); else tt( /** @type {import("./events.js").EventsKey} */ s ); } function K() { throw new Error("Unimplemented abstract method."); } let qh = 0; function Y(s) { return s.ol_uid || (s.ol_uid = String(++qh)); } class Xo extends Lt { /** * @param {string} type The event type. * @param {string} key The property name. * @param {*} oldValue The old value for `key`. */ constructor(t, e, i) { super(t), this.key = e, this.oldValue = i; } } class Ht extends En { /** * @param {Object<string, *>} [values] An object with key-value pairs. */ constructor(t) { super(), this.on, this.once, this.un, Y(this), this.values_ = null, t !== void 0 && this.setProperties(t); } /** * Gets a value. * @param {string} key Key name. * @return {*} Value. * @api */ get(t) { let e; return this.values_ && this.values_.hasOwnProperty(t) && (e = this.values_[t]), e; } /** * Get a list of object property names. * @return {Array<string>} List of property names. * @api */ getKeys() { return this.values_ && Object.keys(this.values_) || []; } /** * Get an object of all property names and values. * @return {Object<string, *>} Object. * @api */ getProperties() { return this.values_ && Object.assign({}, this.values_) || {}; } /** * Get an object of all property names and values. * @return {Object<string, *>?} Object. */ getPropertiesInternal() { return this.values_; } /** * @return {boolean} The object has properties. */ hasProperties() { return !!this.values_; } /** * @param {string} key Key name. * @param {*} oldValue Old value. */ notify(t, e) { let i; i = `change:${t}`, this.hasListener(i) && this.dispatchEvent(new Xo(i, t, e)), i = _i.PROPERTYCHANGE, this.hasListener(i) && this.dispatchEvent(new Xo(i, t, e)); } /** * @param {string} key Key name. * @param {import("./events.js").Listener} listener Listener. */ addChangeListener(t, e) { this.addEventListener(`change:${t}`, e); } /** * @param {string} key Key name. * @param {import("./events.js").Listener} listener Listener. */ removeChangeListener(t, e) { this.removeEventListener(`change:${t}`, e); } /** * Sets a value. * @param {string} key Key name. * @param {*} value Value. * @param {boolean} [silent] Update without triggering an event. * @api */ set(t, e, i) { const n = this.values_ || (this.values_ = {}); if (i) n[t] = e; else { const r = n[t]; n[t] = e, r !== e && this.notify(t, r); } } /** * Sets a collection of key-value pairs. Note that this changes any existing * properties and adds new ones (it does not remove any existing properties). * @param {Object<string, *>} values Values. * @param {boolean} [silent] Update without triggering an event. * @api */ setProperties(t, e) { for (const i in t) this.set(i, t[i], e); } /** * Apply any properties from another object without triggering events. * @param {BaseObject} source The source object. * @protected */ applyProperties(t) { t.values_ && Object.assign(this.values_ || (this.values_ = {}), t.values_); } /** * Unsets a property. * @param {string} key Key name. * @param {boolean} [silent] Unset without triggering an event. * @api */ unset(t, e) { if (this.values_ && t in this.values_) { const i = this.values_[t]; delete this.values_[t], mi(this.values_) && (this.values_ = null), e || this.notify(t, i); } } } const Vo = { LENGTH: "length" }; class Pn extends Lt { /** * @param {import("./CollectionEventType.js").default} type Type. * @param {T} element Element. * @param {number} index The index of the added or removed element. */ constructor(t, e, i) { super(t), this.element = e, this.index = i; } } class ot extends Ht { /** * @param {Array<T>} [array] Array. * @param {Options} [options] Collection options. */ constructor(t, e) { if (super(), this.on, this.once, this.un, e = e || {}, this.unique_ = !!e.unique, this.array_ = t || [], this.unique_) for (let i = 0, n = this.array_.length; i < n; ++i) this.assertUnique_(this.array_[i], i); this.updateLength_(); } /** * Remove all elements from the collection. * @api */ clear() { for (; this.getLength() > 0; ) this.pop(); } /** * Add elements to the collection. This pushes each item in the provided array * to the end of the collection. * @param {!Array<T>} arr Array. * @return {Collection<T>} This collection. * @api */ extend(t) { for (let e = 0, i = t.length; e < i; ++e) this.push(t[e]); return this; } /** * Iterate over each element, calling the provided callback. * @param {function(T, number, Array<T>): *} f The function to call * for every element. This function takes 3 arguments (the element, the * index and the array). The return value is ignored. * @api */ forEach(t) { const e = this.array_; for (let i = 0, n = e.length; i < n; ++i) t(e[i], i, e); } /** * Get a reference to the underlying Array object. Warning: if the array * is mutated, no events will be dispatched by the collection, and the * collection's "length" property won't be in sync with the actual length * of the array. * @return {!Array<T>} Array. * @api */ getArray() { return this.array_; } /** * Get the element at the provided index. * @param {number} index Index. * @return {T} Element. * @api */ item(t) { return this.array_[t]; } /** * Get the length of this collection. * @return {number} The length of the array. * @observable * @api */ getLength() { return this.get(Vo.LENGTH); } /** * Insert an element at the provided index. * @param {number} index Index. * @param {T} elem Element. * @api */ insertAt(t, e) { if (t < 0 || t > this.getLength()) throw new Error("Index out of bounds: " + t); this.unique_ && this.assertUnique_(e), this.array_.splice(t, 0, e), this.updateLength_(), this.dispatchEvent( new Pn(st.ADD, e, t) ); } /** * Remove the last element of the collection and return it. * Return `undefined` if the collection is empty. * @return {T|undefined} Element. * @api */ pop() { return this.removeAt(this.getLength() - 1); } /** * Insert the provided element at the end of the collection. * @param {T} elem Element. * @return {number} New length of the collection. * @api */ push(t) { this.unique_ && this.assertUnique_(t); const e = this.getLength(); return this.insertAt(e, t), this.getLength(); } /** * Remove the first occurrence of an element from the collection. * @param {T} elem Element. * @return {T|undefined} The removed element or undefined if none found. * @api */ remove(t) { const e = this.array_; for (let i = 0, n = e.length; i < n; ++i) if (e[i] === t) return this.removeAt(i); } /** * Remove the element at the provided index and return it. * Return `undefined` if the collection does not contain this index. * @param {number} index Index. * @return {T|undefined} Value. * @api */ removeAt(t) { if (t < 0 || t >= this.getLength()) return; const e = this.array_[t]; return this.array_.splice(t, 1), this.updateLength_(), this.dispatchEvent( /** @type {CollectionEvent<T>} */ new Pn(st.REMOVE, e, t) ), e; } /** * Set the element at the provided index. * @param {number} index Index. * @param {T} elem Element. * @api */ setAt(t, e) { const i = this.getLength(); if (t >= i) { this.insertAt(t, e); return; } if (t < 0) throw new Error("Index out of bounds: " + t); this.unique_ && this.assertUnique_(e, t); const n = this.array_[t]; this.array_[t] = e, this.dispatchEvent( /** @type {CollectionEvent<T>} */ new Pn(st.REMOVE, n, t) ), this.dispatchEvent( /** @type {CollectionEvent<T>} */ new Pn(st.ADD, e, t) ); } /** * @private */ updateLength_() { this.set(Vo.LENGTH, this.array_.length); } /** * @private * @param {T} elem Element. * @param {number} [except] Optional index to ignore. */ assertUnique_(t, e) { for (let i = 0, n = this.array_.length; i < n; ++i) if (this.array_[i] === t && i !== e) throw new Error("Duplicate item added to a unique collection"); } } class si extends Lt { /** * @param {string} type Event type. * @param {import("./Map.js").default} map Map. * @param {?import("./Map.js").FrameState} [frameState] Frame state. */ constructor(t, e, i) { super(t), this.map = e, this.frameState = i !== void 0 ? i : null; } } class ce extends si { /** * @param {string} type Event type. * @param {import("./Map.js").default} map Map. * @param {EVENT} originalEvent Original event. * @param {boolean} [dragging] Is the map currently being dragged? * @param {import("./Map.js").FrameState} [frameState] Frame state. * @param {Array<PointerEvent>} [activePointers] Active pointers. */ constructor(t, e, i, n, r, o) { super(t, e, r), this.originalEvent = i, this.pixel_ = null, this.coordinate_ = null, this.dragging = n !== void 0 ? n : !1, this.activePointers = o; } /** * The map pixel relative to the viewport corresponding to the original event. * @type {import("./pixel.js").Pixel} * @api */ get pixel() { return this.pixel_ || (this.pixel_ = this.map.getEventPixel(this.originalEvent)), this.pixel_; } set pixel(t) { this.pixel_ = t; } /** * The coordinate corresponding to the original browser event. This will be in the user * projection if one is set. Otherwise it will be in the view projection. * @type {import("./coordinate.js").Coordinate} * @api */ get coordinate() { return this.coordinate_ || (this.coordinate_ = this.map.getCoordinateFromPixel(this.pixel)), this.coordinate_; } set coordinate(t) { this.coordinate_ = t; } /** * Prevents the default browser action. * See https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault. * @api * @override */ preventDefault() { super.preventDefault(), "preventDefault" in this.originalEvent && this.originalEvent.preventDefault(); } /** * Prevents further propagation of the current event. * See https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation. * @api * @override */ stopPropagation() { super.stopPropagation(), "stopPropagation" in this.originalEvent && this.originalEvent.stopPropagation(); } } const X = { /** * A true single click with no dragging and no double click. Note that this * event is delayed by 250 ms to ensure that it is not a double click. * @event module:ol/MapBrowserEvent~MapBrowserEvent#singleclick * @api */ SINGLECLICK: "singleclick", /** * A click with no dragging. A double click will fire two of this. * @event module:ol/MapBrowserEvent~MapBrowserEvent#click * @api */ CLICK: F.CLICK, /** * A true double click, with no dragging. * @event module:ol/MapBrowserEvent~MapBrowserEvent#dblclick * @api */ DBLCLICK: F.DBLCLICK, /** * Triggered when a pointer is dragged. * @event module:ol/MapBrowserEvent~MapBrowserEvent#pointerdrag * @api */ POINTERDRAG: "pointerdrag", /** * Triggered when a pointer is moved. Note that on touch devices this is * triggered when the map is panned, so is not the same as mousemove. * @event module:ol/MapBrowserEvent~MapBrowserEvent#pointermove * @api */ POINTERMOVE: "pointermove", POINTERDOWN: "pointerdown", POINTERUP: "pointerup", POINTEROVER: "pointerover", POINTEROUT: "pointerout", POINTERENTER: "pointerenter", POINTERLEAVE: "pointerleave", POINTERCANCEL: "pointercancel" }, Ye = typeof navigator < "u" && typeof navigator.userAgent < "u" ? navigator.userAgent.toLowerCase() : "", $h = Ye.includes("safari") && !Ye.includes("chrom"); $h && (Ye.includes("version/15.4") || /cpu (os|iphone os) 15_4 like mac os x/.test(Ye)); const Jh = Ye.includes("webkit") && !Ye.includes("edge"), Wr = Ye.includes("macintosh"), Qh = typeof devicePixelRatio < "u" ? devicePixelRatio : 1, tl = typeof WorkerGlobalScope < "u" && typeof OffscreenCanvas < "u" && self instanceof WorkerGlobalScope, el = typeof Image < "u" && Image.prototype.decode, il = typeof createImageBitmap == "function", nl = function() { let s = !1; try { const t = Object.defineProperty({}, "passive", { get: function() { s = !0; } }); window.addEventListener("_", null, t), window.removeEventListener("_", null, t); } catch { } return s; }(), pr = { POINTERMOVE: "pointermove", POINTERDOWN: "pointerdown" }; class tc extends ds { /** * @param {import("./Map.js").default} map The map with the viewport to listen to events on. * @param {number} [moveTolerance] The minimal distance the pointer must travel to trigger a move. */ constructor(t, e) { super(t), this.map_ = t, this.clickTimeoutId_, this.emulateClicks_ = !1, this.dragging_ = !1, this.dragListenerKeys_ = [], this.moveTolerance_ = e === void 0 ? 1 : e, this.down_ = null; const i = this.map_.getViewport(); this.activePointers_ = [], this.trackedTouches_ = {}, this.element_ = i, this.pointerdownListenerKey_ = z( i, pr.POINTERDOWN, this.handlePointerDown_, this ), this.originalPointerMoveEvent_, this.relayedListenerKey_ = z( i, pr.POINTERMOVE, this.relayMoveEvent_, this ), this.boundHandleTouchMove_ = this.handleTouchMove_.bind(this), this.element_.addEventListener( F.TOUCHMOVE, this.boundHandleTouchMove_, nl ? { passive: !1 } : !1 ); } /** * @param {PointerEvent} pointerEvent Pointer * event. * @private */ emulateClick_(t) { let e = new ce( X.CLICK, this.map_, t ); this.dispatchEvent(e), this.clickTimeoutId_ !== void 0 ? (clearTimeout(this.clickTimeoutId_), this.clickTimeoutId_ = void 0, e = new ce( X.DBLCLICK, this.map_, t ), this.dispatchEvent(e)) : this.clickTimeoutId_ = setTimeout(() => { this.clickTimeoutId_ = void 0; const i = new ce( X.SINGLECLICK, this.map_, t ); this.dispatchEvent(i); }, 250); } /** * Keeps track on how many pointers are currently active. * * @param {PointerEvent} pointerEvent Pointer * event. * @private */ updateActivePointers_(t) { const e = t, i = e.pointerId; if (e.type == X.POINTERUP || e.type == X.POINTERCANCEL) { delete this.trackedTouches_[i]; for (const n in this.trackedTouches_) if (this.trackedTouches_[n].target !== e.target) { delete this.trackedTouches_[n]; break; } } else (e.type == X.POINTERDOWN || e.type == X.POINTERMOVE) && (this.trackedTouches_[i] = e); this.activePointers_ = Object.values(this.trackedTouches_); } /** * @param {PointerEvent} pointerEvent Pointer * event. * @private */ handlePointerUp_(t) { this.updateActivePointers_(t); const e = new ce( X.POINTERUP, this.map_, t, void 0, void 0, this.activePointers_ ); this.dispatchEvent(e), this.emulateClicks_ && !e.defaultPrevented && !this.dragging_ && this.isMouseActionButton_(t) && this.emulateClick_(this.down_), this.activePointers_.length === 0 && (this.dragListenerKeys_.forEach(tt), this.dragListenerKeys_.length = 0, this.dragging_ = !1, this.down_ = null); } /** * @param {PointerEvent} pointerEvent Pointer * event. * @return {boolean} If the left mouse button was pressed. * @private */ isMouseActionButton_(t) { return t.button === 0; } /** * @param {PointerEvent} pointerEvent Pointer * event. * @private */ handlePointerDown_(t) { this.emulateClicks_ = this.activePointers_.length === 0, this.updateActivePointers_(t); const e = new ce( X.POINTERDOWN, this.map_, t, void 0, void 0, this.activePointers_ ); if (this.dispatchEvent(e), this.down_ = new PointerEvent(t.type, t), Object.defineProperty(this.down_, "target", { writable: !1, value: t.target }), this.dragListenerKeys_.length === 0) { const i = this.map_.getOwnerDocument(); this.dragListenerKeys_.push( z( i, X.POINTERMOVE, this.handlePointerMove_, this ), z(i, X.POINTERUP, this.handlePointerUp_, this), /* Note that the listener for `pointercancel is set up on * `pointerEventHandler_` and not `documentPointerEventHandler_` like * the `pointerup` and `pointermove` listeners. * * The reason for this is the following: `TouchSource.vacuumTouches_()` * issues `pointercancel` events, when there was no `touchend` for a * `touchstart`. Now, let's say a first `touchstart` is registered on * `pointerEventHandler_`. The `documentPointerEventHandler_` is set up. * But `documentPointerEventHandler_` doesn't know about the first * `touchstart`. If there is no `touchend` for the `touchstart`, we can * only receive a `touchcancel` from `pointerEventHandler_`, because it is * only registered there. */ z( this.element_, X.POINTERCANCEL, this.handlePointerUp_, this ) ), this.element_.getRootNode && this.element_.getRootNode() !== i && this.dragListenerKeys_.push( z( this.element_.getRootNode(), X.POINTERUP, this.handlePointerUp_, this ) ); } } /** * @param {PointerEvent} pointerEvent Pointer * event. * @private */ handlePointerMove_(t) { if (this.isMoving_(t)) { this.updateActivePointers_(t), this.dragging_ = !0; const e = new ce( X.POINTERDRAG, this.map_, t, this.dragging_, void 0, this.activePointers_ ); this.dispatchEvent(e); } } /** * Wrap and relay a pointermove event. * @param {PointerEvent} pointerEvent Pointer * event. * @private */ relayMoveEvent_(t) { this.originalPointerMoveEvent_ = t; const e = !!(this.down_ && this.isMoving_(t)); this.dispatchEvent( new ce( X.POINTERMOVE, this.map_, t, e ) ); } /** * Flexible handling of a `touch-action: none` css equivalent: because calling * `preventDefault()` on a `pointermove` event does not stop native page scrolling * and zooming, we also listen for `touchmove` and call `preventDefault()` on it * when an interaction (currently `DragPan` handles the event. * @param {TouchEvent} event Event. * @private */ handleTouchMove_(t) { const e = this.originalPointerMoveEvent_; (!e || e.defaultPrevented) && (typeof t.cancelable != "boolean" || t.cancelable === !0) && t.preventDefault(); } /** * @param {PointerEvent} pointerEvent Pointer * event. * @return {boolean} Is moving. * @private */ isMoving_(t) { return this.dragging_ || Math.abs(t.clientX - this.down_.clientX) > this.moveTolerance_ || Math.abs(t.clientY - this.down_.clientY) > this.moveTolerance_; } /** * Clean up. * @override */ disposeInternal() { this.relayedListenerKey_ && (tt(this.relayedListenerKey_), this.relayedListenerKey_ = null), this.element_.removeEventListener( F.TOUCHMOVE, this.boundHandleTouchMove_ ), this.pointerdownListenerKey_ && (tt(this.pointerdownListenerKey_), this.pointerdownListenerKey_ = null), this.dragListenerKeys_.forEach(tt), this.dragListenerKeys_.length = 0, this.element_ = null, super.disposeInternal(); } } const ue = { /** * Triggered after a map frame is rendered. * @event module:ol/MapEvent~MapEvent#postrender * @api */ POSTRENDER: "postrender", /** * Triggered when the map starts moving. * @event module:ol/MapEvent~MapEvent#movestart * @api */ MOVESTART: "movestart", /** * Triggered after the map is moved. * @event module:ol/MapEvent~MapEvent#moveend * @api */ MOVEEND: "moveend", /** * Triggered when loading of additional map data (tiles, images, features) starts. * @event module:ol/MapEvent~MapEvent#loadstart * @api */ LOADSTART: "loadstart", /** * Triggered when loading of additional map data has completed. * @event module:ol/MapEvent~MapEvent#loadend * @api */ LOADEND: "loadend" }, _t = { LAYERGROUP: "layergroup", SIZE: "size", TARGET: "target", VIEW: "view" }, Gi = { IDLE: 0, LOADED: 2, /** * Indicates that tile loading failed * @type {number} */ ERROR: 3, EMPTY: 4 }; function it(s, t) { if (!s) throw new Error(t); } const qn = 1 / 0; class ec { /** * @param {function(T): number} priorityFunction Priority function. * @param {function(T): string} keyFunction Key function. */ constructor(t, e) { this.priorityFunction_ = t, this.keyFunction_ = e, this.elements_ = [], this.priorities_ = [], this.queuedElements_ = {}; } /** * FIXME empty description for jsdoc */ clear() { this.elements_.length = 0, this.priorities_.length = 0, Ri(this.queuedElements_); } /** * Remove and return the highest-priority element. O(log N). * @return {T} Element. */ dequeue() { const t = this.elements_, e = this.priorities_, i = t[0]; t.length == 1 ? (t.length = 0, e.length = 0) : (t[0] = /** @type {T} */ t.pop(), e[0] = /** @type {number} */ e.pop(), this.siftUp_(0)); const n = this.keyFunction_(i); return delete this.queuedElements_[n], i; } /** * Enqueue an element. O(log N). * @param {T} element Element. * @return {boolean} The element was added to the queue. */ enqueue(t) { it( !(this.keyFunction_(t) in this.queuedElements_), "Tried to enqueue an `element` that was already added to the queue" ); const e = this.priorityFunction_(t); return e != qn ? (this.elements_.push(t), this.priorities_.push(e), this.queuedElements_[this.keyFunction_(t)] = !0, this.siftDown_(0, this.elements_.length - 1), !0) : !1; } /** * @return {number} Count. */ getCount() { return this.elements_.length; } /** * Gets the index of the left child of the node at the given index. * @param {number} index The index of the node to get the left child for. * @return {number} The index of the left child. * @private */ getLeftChildIndex_(t) { return t * 2 + 1; } /** * Gets the index of the right child of the node at the given index. * @param {number} index The index of the node to get the right child for. * @return {number} The index of the right child. * @private */ getRightChildIndex_(t) { return t * 2 + 2; } /** * Gets the index of the parent of the node at the given index. * @param {number} index The index of the node to get the parent for. * @return {number} The index of the parent. * @private */ getParentIndex_(t) { return t - 1 >> 1; } /** * Make this a heap. O(N). * @private */ heapify_() { let t; for (t = (this.elements_.length >> 1) - 1; t >= 0; t--) this.siftUp_(t); } /** * @return {boolean} Is empty. */ isEmpty() { return this.elements_.length === 0; } /** * @param {string} key Key. * @return {boolean} Is key queued. */ isKeyQueued(t) { return t in this.queuedElements_; } /** * @param {T} element Element. * @return {boolean} Is queued. */ isQueued(t) { return this.isKeyQueued(this.keyFunction_(t)); } /** * @param {number} index The index of the node to move down. * @private */ siftUp_(t) { const e = this.elements_, i = this.priorities_, n = e.length, r = e[t], o = i[t], a = t; for (; t < n >> 1; ) { const l = this.getLeftChildIndex_(t), c = this.getRightChildIndex_(t), h = c < n && i[c] < i[l] ? c : l; e[t] = e[h], i[t] = i[h], t = h; } e[t] = r, i[t] = o, this.siftDown_(a, t); } /** * @param {number} startIndex The index of the root. * @param {number} index The index of the node to move up. * @private */ siftDown_(t, e) { const i = this.elements_, n = this.priorities_, r = i[e], o = n[e]; for (; e > t; ) { const a = this.getParentIndex_(e); if (n[a] > o) i[e] = i[a], n[e] = n[a], e = a; else break; } i[e] = r, n[e] = o; } /** * FIXME empty description for jsdoc */ reprioritize() { const t = this.priorityFunction_, e = this.elements_, i = this.priorities_; let n = 0; const r = e.length; let o, a, l; for (a = 0; a < r; ++a) o = e[a], l = t(o), l == qn ? delete this.queuedElements_[this.keyFunction_(o)] : (i[n] = l, e[n++] = o); e.length = n, i.length = n, this.heapify_(); } } class ic extends ec { /** * @param {PriorityFunction} tilePriorityFunction Tile priority function. * @param {function(): ?} tileChangeCallback Function called on each tile change event. */ constructor(t, e) { super( (i) => t.apply(null, i), (i) => i[0].getKey() ), this.boundHandleTileChange_ = this.handleTileChange.bind(this), this.tileChangeCallback_ = e, this.tilesLoading_ = 0, this.tilesLoadingKeys_ = {}; } /** * @param {TileQueueElement} element Element. * @return {boolean} The element was added to the queue. * @override */ enqueue(t) { const e = super.enqueue(t); return e && t[0].addEventListener(F.CHANGE, this.boundHandleTileChange_), e; } /** * @return {number} Number of tiles loading. */ getTilesLoading() { return this.tilesLoading_; } /** * @param {import("./events/Event.js").default} event Event. * @protected */ handleTileChange(t) { const e = ( /** @type {import("./Tile.js").default} */ t.target ), i = e.getState(); if (i === Gi.LOADED || i === Gi.ERROR || i === Gi.EMPTY) { i !== Gi.ERROR && e.removeEventListener(F.CHANGE, this.boundHandleTileChange_); const n = e.getKey(); n in this.tilesLoadingKeys_ && (delete this.tilesLoadingKeys_[n], --this.tilesLoading_), this.tileChangeCallback_(); } } /** * @param {number} maxTotalLoading Maximum number tiles to load simultaneously. * @param {number} maxNewLoads Maximum number of new tiles to load. */ loadMoreTiles(t, e) { let i = 0; for (; this.tilesLoading_ < t && i < e && this.getCount() > 0; ) { const n = this.dequeue()[0], r = n.getKey(); n.getState() === Gi.IDLE && !(r in this.tilesLoadingKeys_) && (this.tilesLoadingKeys_[r] = !0, ++this.tilesLoading_, ++i, n.load()); } } } function nc(s, t, e, i, n) { if (!s || !(e in s.wantedTiles) || !s.wantedTiles[e][t.getKey()]) return qn; const r = s.viewState.center, o = i[0] - r[0], a = i[1] - r[1]; return 65536 * Math.log(n) + Math.sqrt(o * o + a * a) / n; } const lt = { ANIMATING: 0, INTERACTING: 1 }, Xt = { CENTER: "center", RESOLUTION: "resolution", ROTATION: "rotation" }; function nt(s, t, e) { return Math.min(Math.max(s, t), e); } function sc(s, t, e, i, n, r) { const o = n - e, a = r - i; if (o !== 0 || a !== 0) { const l = ((s - e) * o + (t - i) * a) / (o * o + a * a); l > 1 ? (e = n, i = r) : l > 0 && (e += o * l, i += a * l); } return ge(s, t, e, i); } function ge(s, t, e, i) { const n = e - s, r = i - t; return n * n + r * r; } function rc(s) { const t = s.length; for (let i = 0; i < t; i++) { let n = i, r = Math.abs(s[i][i]); for (let a = i + 1; a < t; a++) { const l = Math.abs(s[a][i]); l > r && (r = l, n = a); } if (r === 0) return null; const o = s[n]; s[n] = s[i], s[i] = o; for (let a = i + 1; a < t; a++) { const l = -s[a][i] / s[i][i]; for (let c = i; c < t + 1; c++) i == c ? s[a][c] = 0 : s[a][c] += l * s[i][c]; } } const e = new Array(t); for (let i = t - 1; i >= 0; i--) { e[i] = s[i][t] / s[i][i]; for (let n = i - 1; n >= 0; n--) s[n][t] -= s[n][i] * e[i]; } return e; } function zo(s) { return s * 180 / Math.PI; } function Yt(s) { return s * Math.PI / 180; } function Zi(s, t) { const e = s % t; return e * t < 0 ? e + t : e; } function St(s, t, e) { return s + e * (t - s); } function fs(s, t) { const e = Math.pow(10, t); return Math.round(s * e) / e; } function bn(s, t) { return Math.ceil(fs(s, t)); } function Er(s, t, e) { if (s >= t && s < e) return s; const i = e - t; return ((s - t) % i + i) % i + t; } function Yo(s, t, e) { 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<number>} [centerShift] Shift between map center and viewport center. * @return {import("./coordinate.js").Coordinate|undefined} Center. */ function(i, n, r, o, a) { if (!i) return; if (!n && !t) return i; const l = t ? 0 : r[0] * n, c = t ? 0 : r[1] * n, h = a ? a[0] : 0, u = a ? a[1] : 0; let d = s[0] + l / 2 + h, f = s[2] - l / 2 + h, g = s[1] + c / 2 + u, _ = s[3] - c / 2 + u; d > f && (d = (f + d) / 2, f = d), g > _ && (g = (_ + g) / 2, _ = g); let m = nt(i[0], d, f), y = nt(i[1], g, _); if (o && e && n) { const p = 30 * n; m += -p * Math.log(1 + Math.max(0, d - i[0]) / p) + p * Math.log(1 + Math.max(0, i[0] - f) / p), y += -p * Math.log(1 + Math.max(0, g - i[1]) / p) + p * Math.log(1 + Math.max(0, i[1] - _) / p); } return [m, y]; } ); } function oc(s) { return s; } const at = { UNKNOWN: 0, INTERSECTING: 1, ABOVE: 2, RIGHT: 4, BELOW: 8, LEFT: 16 }; function Et(s) { const t = Kt(); for (let e = 0, i = s.length; e < i; ++e) $i(t, s[e]); return t; } function gs(s, t, e) { return e ? (e[0] = s[0] - t, e[1] = s[1] - t, e[2] = s[2] + t, e[3] = s[3] + t, e) : [ s[0] - t, s[1] - t, s[2] + t, s[3] + t ]; } function sl(s, t) { return t ? (t[0] = s[0], t[1] = s[1], t[2] = s[2], t[3] = s[3], t) : s.slice(); } function qe(s, t, e) { let i, n; return t < s[0] ? i = s[0] - t : s[2] < t ? i = t - s[2] : i = 0, e < s[1] ? n = s[1] - e : s[3] < e ? n = e - s[3] : n = 0, i * i + n * n; } function nn(s, t) { return Br(s, t[0], t[1]); } function fe(s, t) { return s[0] <= t[0] && t[2] <= s[2] && s[1] <= t[1] && t[3] <= s[3]; } function Br(s, t, e) { return s[0] <= t && t <= s[2] && s[1] <= e && e <= s[3]; } function xr(s, t) { const e = s[0], i = s[1], n = s[2], r = s[3], o = t[0], a = t[1]; let l = at.UNKNOWN; return o < e ? l = l | at.LEFT : o > n && (l = l | at.RIGHT), a < i ? l = l | at.BELOW : a > r && (l = l | at.ABOVE), l === at.UNKNOWN && (l = at.INTERSECTING), l; } function Kt() { return [1 / 0, 1 / 0, -1 / 0, -1 / 0]; } function je(s, t, e, i, n) { return n ? (n[0] = s, n[1] = t, n[2] = e, n[3] = i, n) : [s, t, e, i]; } function xn(s) { return je(1 / 0, 1 / 0, -1 / 0, -1 / 0, s); } function qi(s, t) { const e = s[0], i = s[1]; return je(e, i, e, i, t); } function Xr(s, t, e, i, n) { const r = xn(n); return ol(r, s, t, e, i); } function sn(s, t) { return s[0] == t[0] && s[2] == t[2] && s[1] == t[1] && s[3] == t[3]; } function rl(s, t) { return t[0] < s[0] && (s[0] = t[0]), t[2] > s[2] && (s[2] = t[2]), t[1] < s[1] && (s[1] = t[1]), t[3] > s[3] && (s[3] = t[3]), s; } function $i(s, t) { t[0] < s[0] && (s[0] = t[0]), t[0] > s[2] && (s[2] = t[0]), t[1] < s[1] && (s[1] = t[1]), t[1] > s[3] && (s[3] = t[1]); } function ol(s, t, e, i, n) { for (; e < i; e += n) ac(s, t[e], t[e + 1]); return s; } function ac(s, t, e) { s[0] = Math.min(s[0], t), s[1] = Math.min(s[1], e), s[2] = Math.max(s[2], t), s[3] = Math.max(s[3], e); } function al(s, t) { let e; return e = t(rn(s)), e || (e = t(_s(s)), e) || (e = t(ms(s)), e) || (e = t(Cn(s)), e) ? e : !1; } function lc(s) { let t = 0; return Si(s) || (t = U(s) * ht(s)), t; } function rn(s) { return [s[0], s[1]]; } function _s(s) { return [s[2], s[1]]; } function ie(s) { return [(s[0] + s[2]) / 2, (s[1] + s[3]) / 2]; } function $n(s, t, e, i, n) { const [r, o, a, l, c, h, u, d] = hc( s, t, e, i ); return je( Math.min(r, a, c, u), Math.min(o, l, h, d), Math.max(r, a, c, u), Math.max(o, l, h, d), n ); } function hc(s, t, e, i) { const n = t * i[0] / 2, r = t * i[1] / 2, o = Math.cos(e), a = Math.sin(e), l = n * o, c = n * a, h = r * o, u = r * a, d = s[0], f = s[1]; return [ d - l + u, f - c - h, d - l - u, f - c + h, d + l - u, f + c + h, d + l + u, f + c - h, d - l + u, f - c - h ]; } function ht(s) { return s[3] - s[1]; } function Vr(s, t, e) { const i = e || Kt(); return mt(s, t) ? (s[0] > t[0] ? i[0] = s[0] : i[0] = t[0], s[1] > t[1] ? i[1] = s[1] : i[1] = t[1], s[2] < t[2] ? i[2] = s[2] : i[2] = t[2], s[3] < t[3] ? i[3] = s[3] : i[3] = t[3]) : xn(i), i; } function Cn(s) { return [s[0], s[3]]; } function ms(s) { return [s[2], s[3]]; } function U(s) { return s[2] - s[0]; } function mt(s, t) { return s[0] <= t[2] && s[2] >= t[0] && s[1] <= t[3] && s[3] >= t[1]; } function Si(s) { return s[2] < s[0] || s[3] < s[1]; } function cc(s, t) { return t ? (t[0] = s[0], t[1] = s[1], t[2] = s[2], t[3] = s[3], t) : s; } function uc(s, t, e) { let i = !1; const n = xr(s, t), r = xr(s, e); if (n === at.INTERSECTING || r === at.INTERSECTING) i = !0; else { const o = s[0], a = s[1], l = s[2], c = s[3], h = t[0], u = t[1], d = e[0], f = e[1], g = (f - u) / (d - h); let _, m; r & at.ABOVE && !(n & at.ABOVE) && (_ = d - (f - c) / g, i = _ >= o && _ <= l), !i && r & at.RIGHT && !(n & at.RIGHT) && (m = f - (d - l) * g, i = m >= a && m <= c), !i && r & at.BELOW && !(n & at.BELOW) && (_ = d - (f - a) / g, i = _ >= o && _ <= l), !i && r & at.LEFT && !(n & at.LEFT) && (m = f - (d - o) * g, i = m >= a && m <= c); } return i; } function ll(s, t) { const e = t.getExtent(), i = ie(s); if (t.canWrapX() && (i[0] < e[0] || i[0] >= e[2])) { const n = U(e), o = Math.floor( (i[0] - e[0]) / n ) * n; s[0] -= o, s[2] -= o; } return s; } function dc(s, t, e) { if (t.canWrapX()) { const i = t.getExtent(); if (!isFinite(s[0]) || !isFinite(s[2])) return [[i[0], s[1], i[2], s[3]]]; ll(s, t); const n = U(i); if (U(s) > n) return [[i[0], s[1], i[2], s[3]]]; if (s[0] < i[0]) return [ [s[0] + n, s[1], i[2], s[3]], [i[0], s[1], s[2], s[3]] ]; if (s[2] > i[2]) return [ [s[0], s[1], i[2], s[3]], [i[0], s[1], s[2] - n, s[3]] ]; } return [s]; } function fc(s, t) { return s[0] += +t[0], s[1] += +t[1], s; } function hl(s, t) { const e = s[0], i = s[1], n = t[0], r = t[1], o = n[0], a = n[1], l = r[0], c = r[1], h = l - o, u = c - a, d = h === 0 && u === 0 ? 0 : (h * (e - o) + u * (i - a)) / (h * h + u * u || 0); let f, g; return d <= 0 ? (f = o, g = a) : d >= 1 ? (f = l, g = c) : (f = o + d * h, g = a + d * u), [f, g]; } function xt(s, t) { let e = !0; for (let i = s.length - 1; i >= 0; --i) if (s[i] != t[i]) { e = !1; break; } return e; } function zr(s, t) { const e = Math.cos(t), i = Math.sin(t), n = s[0] * e - s[1] * i, r = s[1] * e + s[0] * i; return s[0] = n, s[1] = r, s; } function gc(s, t) { return s[0] *= t, s[1] *= t, s; } function yi(s, t) { const e = s[0] - t[0], i = s[1] - t[1]; return e * e + i * i; } function Jn(s, t) { return Math.sqrt(yi(s, t)); } function _c(s, t) { return yi(s, hl(s, t)); } function cl(s, t) { if (t.canWrapX()) { const e = U(t.getExtent()), i = mc(s, t, e); i && (s[0] -= i * e); } return s; } function mc(s, t, e) { const i = t.getExtent(); let n = 0; return t.canWrapX() && (s[0] < i[0] || s[0] > i[2]) && (e = e || U(i), n = Math.floor( (s[0] - i[0]) / e )), n; } function yc(s) { return Math.pow(s, 3); } function Ti(s) { return 1 - yc(1 - s); } function pc(s) { return 3 * s * s - 2 * s * s * s; } function Ec(s) { return s; } const Yr = 63710088e-1; function Cr(s, t, e) { e = e || Yr; const i = Yt(s[1]), n = Yt(t[1]), r = (n - i) / 2, o = Yt(t[0] - s[0]) / 2, a = Math.sin(r) * Math.sin(r) + Math.sin(o) * Math.sin(o) * Math.cos(i) * Math.cos(n); return 2 * e * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); } function Gs(s, t) { let e = 0; for (let i = 0, n = s.length; i < n - 1; ++i) e += Cr(s[i], s[i + 1], t); return e; } function ul(s, t) { t = t || {}; const e = t.radius || Yr, i = t.projection || "EPSG:3857", n = s.getType(); n !== "GeometryCollection" && (s = s.clone().transform(i, "EPSG:4326")); let r = 0, o, a, l, c, h, u; switch (n) { case "Point": case "MultiPoint": break; case "LineString": case "LinearRing": { o = /** @type {import("./geom/SimpleGeometry.js").default} */ s.getCoordinates(), r = Gs(o, e); break; } case "MultiLineString": case "Polygon": { for (o = /** @type {import("./geom/SimpleGeometry.js").default} */ s.getCoordinates(), l = 0, c = o.length; l < c; ++l) r += Gs(o[l], e); break; } case "MultiPolygon": { for (o = /** @type {import("./geom/SimpleGeometry.js").default} */ s.getCoordinates(), l = 0, c = o.length; l < c; ++l) for (a = o[l], h = 0, u = a.length; h < u; ++h) r += Gs(a[h], e); break; } case "GeometryCollection": { const d = ( /** @type {import("./geom/GeometryCollection.js").default} */ s.getGeometries() ); for (l = 0, c = d.length; l < c; ++l) r += ul(d[l], t); break; } default: throw new Error("Unsupported geometry type: " + n); } return r; } function Dn(s, t) { let e = 0; const i = s.length; let n = s[i - 1][0], r = s[i - 1][1]; for (let o = 0; o < i; o++) { const a = s[o][0], l = s[o][1]; e += Yt(a - n) * (2 + Math.sin(Yt(r)) + Math.sin(Yt(l))), n = a, r = l; } return e * t * t / 2; } function dl(s, t) { t = t || {}; const e = t.radius || Yr, i = t.projection || "EPSG:3857", n = s.getType(); n !== "GeometryCollection" && (s = s.clone().transform(i, "EPSG:4326")); let r = 0, o, a, l, c, h, u; switch (n) { case "Point": case "MultiPoint": case "LineString": case "MultiLineString": case "LinearRing": break; case "Polygon": { for (o = /** @type {import("./geom/Polygon.js").default} */ s.getCoordinates(), r = Math.abs(Dn(o[0], e)), l = 1, c = o.length; l < c; ++l) r -= Math.abs(Dn(o[l], e)); break; } case "MultiPolygon": { for (o = /** @type {import("./geom/SimpleGeometry.js").default} */ s.getCoordinates(), l = 0, c = o.length; l < c; ++l) for (a = o[l], r += Math.abs(Dn(a[0], e)), h = 1, u = a.length; h < u; ++h) r -= Math.abs(Dn(a[h], e)); break; } case "GeometryCollection": { const d = ( /** @type {import("./geom/GeometryCollection.js").default} */ s.getGeometries() ); for (l = 0, c = d.length; l < c; ++l) r += dl(d[l], t); break; } default: throw new Error("Unsupported geometry type: " + n); } return r; } function fl(...s) { console.warn(...s); } const gl = { // use the radius of the Normal