UNPKG

vesium

Version:

Core Vue composition hooks for Cesium

1,057 lines (1,056 loc) 40.2 kB
(function(exports, _vueuse_core, cesium, vue, _vesium_shared) { Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); //#region createViewer/index.ts /** * @internal */ const CREATE_VIEWER_INJECTION_KEY = Symbol("CREATE_VIEWER_INJECTION_KEY"); /** * @internal */ const CREATE_VIEWER_COLLECTION = /* @__PURE__ */ new WeakMap(); /** * @internal */ function createViewer(arg1, arg2) { const viewer = (0, vue.shallowRef)(); const readonlyViewer = (0, vue.shallowReadonly)(viewer); (0, vue.provide)(CREATE_VIEWER_INJECTION_KEY, readonlyViewer); const scope = (0, vue.getCurrentScope)(); if (scope) CREATE_VIEWER_COLLECTION.set(scope, readonlyViewer); const canvas = (0, vue.computed)(() => viewer.value?.canvas); const body = typeof document !== "undefined" ? document.body : void 0; if (body) (0, _vueuse_core.useMutationObserver)(body, () => { if (canvas.value && !body.contains(canvas.value)) viewer.value = void 0; }, { childList: true, subtree: true }); (0, vue.watchEffect)((onCleanup) => { const value = (0, vue.toRaw)((0, vue.toValue)(arg1)); if (value instanceof cesium.Viewer) viewer.value = (0, vue.markRaw)(value); else if (value) { viewer.value = new cesium.Viewer((0, _vueuse_core.unrefElement)(value), arg2); onCleanup(() => !viewer.value?.isDestroyed() && viewer.value?.destroy()); } else viewer.value = void 0; }); (0, _vueuse_core.tryOnScopeDispose)(() => { viewer.value = void 0; }); return (0, vue.computed)(() => { return viewer.value?.isDestroyed() ? void 0 : viewer.value; }); } //#endregion //#region toPromiseValue/index.ts /** * Similar to Vue's built-in `toValue`, but capable of handling asynchronous functions, thus returning a `await value`. * * Used in conjunction with VueUse's `computedAsync`. * * @param source The source value, which can be a reactive reference or an asynchronous getter. * @param options Conversion options * @returns The converted value. * * @example * ```ts * * const data = computedAsync(async ()=> { * return await toPromiseValue(promiseRef) * }) * * ``` */ async function toPromiseValue(source, options = {}) { const { raw = true } = options; let value; if ((0, _vesium_shared.isFunction)(source)) value = await source(); else { const result = (0, vue.toValue)(source); value = (0, _vesium_shared.isPromise)(result) ? await result : result; } return raw ? (0, vue.toRaw)(value) : value; } //#endregion //#region useCesiumEventListener/index.ts /** * Easily use the `addEventListener` in `Cesium.Event` instances, * when the dependent data changes or the component is unmounted, * the listener function will automatically reload or destroy. * * @param event The Cesium.Event instance * @param listener The listener function * @param options additional options * @returns A function that can be called to remove the event listener */ function useCesiumEventListener(event, listener, options = {}) { const isActive = (0, vue.toRef)(options.isActive ?? true); const cleanup = (0, vue.watchEffect)((onCleanup) => { const _event = (0, vue.toValue)(event); const events = Array.isArray(_event) ? _event : [_event]; if (events) { if (events.length && isActive.value) { const stopFns = events.map((event) => { const e = (0, vue.toValue)(event); return e?.addEventListener(listener, e); }); onCleanup(() => stopFns.forEach((stop) => stop?.())); } } }); (0, _vueuse_core.tryOnScopeDispose)(cleanup.stop); return cleanup.stop; } //#endregion //#region useViewer/index.ts /** * Obtain the `Viewer` instance injected through `createViewer` in the current component or its ancestor components. * * note: * - If `createViewer` and `useViewer` are called in the same component, the `Viewer` instance injected by `createViewer` will be used preferentially. * - When calling `createViewer` and `useViewer` in the same component, `createViewer` should be called before `useViewer`. */ function useViewer() { const scope = (0, vue.getCurrentScope)(); const instanceViewer = scope ? CREATE_VIEWER_COLLECTION.get(scope) : void 0; if (instanceViewer) return instanceViewer; else { const injectViewer = (0, vue.inject)(CREATE_VIEWER_INJECTION_KEY); if (!injectViewer) throw new Error("The `Viewer` instance injected by `createViewer` was not found in the current component or its ancestor components. Have you called `createViewer`?"); return injectViewer; } } //#endregion //#region useCameraState/index.ts /** * Reactive Cesium Camera state * @param options options * @returns Reactive camera states */ function useCameraState(options = {}) { let getCamera = options.camera; if (!getCamera) { const viewer = useViewer(); getCamera = () => viewer.value?.scene.camera; } const camera = (0, vue.computed)(() => (0, vue.toValue)(getCamera)); const event = (0, vue.computed)(() => { const eventField = (0, vue.toValue)(options.event) || "changed"; return camera.value?.[eventField]; }); const changedSymbol = (0, _vueuse_core.refThrottled)((0, vue.shallowRef)(Symbol("camera change")), options.delay ?? 8, true, false); const setChangedSymbol = () => { changedSymbol.value = Symbol("camera change"); }; (0, vue.watch)(camera, () => setChangedSymbol()); useCesiumEventListener(event, () => setChangedSymbol()); return { camera, position: (0, vue.computed)(() => changedSymbol.value ? camera.value?.position?.clone() : void 0), direction: (0, vue.computed)(() => changedSymbol.value ? camera.value?.direction?.clone() : void 0), up: (0, vue.computed)(() => changedSymbol.value ? camera.value?.up?.clone() : void 0), right: (0, vue.computed)(() => changedSymbol.value ? camera.value?.right?.clone() : void 0), positionCartographic: (0, vue.computed)(() => changedSymbol.value ? camera.value?.positionCartographic?.clone() : void 0), positionWC: (0, vue.computed)(() => changedSymbol.value ? camera.value?.positionWC?.clone() : void 0), directionWC: (0, vue.computed)(() => changedSymbol.value ? camera.value?.directionWC?.clone() : void 0), upWC: (0, vue.computed)(() => changedSymbol.value ? camera.value?.upWC?.clone() : void 0), rightWC: (0, vue.computed)(() => changedSymbol.value ? camera.value?.rightWC?.clone() : void 0), viewRectangle: (0, vue.computed)(() => changedSymbol.value ? camera.value?.computeViewRectangle() : void 0), heading: (0, vue.computed)(() => changedSymbol.value ? camera.value?.heading : void 0), pitch: (0, vue.computed)(() => changedSymbol.value ? camera.value?.pitch : void 0), roll: (0, vue.computed)(() => changedSymbol.value ? camera.value?.roll : void 0), level: (0, vue.computed)(() => changedSymbol.value && camera.value?.positionCartographic?.height !== void 0 ? computeLevel(camera.value.positionCartographic.height) : void 0) }; } const A = 40487.57; const B = 7096758e-11; const C = 91610.74; const D = -40467.74; /** * Compute the camera level at a given height. */ function computeLevel(height) { return D + (A - D) / (1 + (height / C) ** B); } //#endregion //#region useCesiumFps/index.ts /** * Reactive get the frame rate of Cesium * @param options options * @returns Reactive fps states */ function useCesiumFps(options = {}) { const { delay = 100 } = options; const viewer = useViewer(); const p = (0, vue.shallowRef)(performance.now()); useCesiumEventListener(() => viewer.value?.scene.postRender, () => p.value = performance.now()); const interval = (0, vue.ref)(0); (0, _vueuse_core.watchThrottled)(p, (value, oldValue) => { interval.value = value - oldValue; }, { throttle: delay }); const fps = (0, vue.computed)(() => { return 1e3 / interval.value; }); return { interval: (0, vue.readonly)(interval), fps }; } //#endregion //#region useCollectionScope/index.ts /** * Scope the SideEffects of Cesium-related `Collection` and automatically remove them when unmounted. * - note: This is a basic function that is intended to be called by other lower-level function * @returns Contains side effect addition and removal functions */ function useCollectionScope(options) { const { addEffect, removeEffect, removeScopeArgs } = options; const scope = (0, vue.shallowReactive)(/* @__PURE__ */ new Set()); const add = (instance, ...args) => { const result = addEffect(instance, ...args); if ((0, _vesium_shared.isPromise)(result)) return new Promise((resolve, reject) => { result.then((i) => { scope.add(i); resolve(i); }).catch((error) => reject(error)); }); else { scope.add(result); return result; } }; const remove = (instance, ...args) => { scope.delete(instance); return removeEffect(instance, ...args); }; const removeWhere = (predicate, ...args) => { for (const instance of Array.from(scope)) if (predicate(instance)) remove(instance, ...args); }; const removeScope = (...args) => { for (const instance of Array.from(scope)) remove(instance, ...args); }; (0, _vueuse_core.tryOnScopeDispose)(() => removeScope(...removeScopeArgs ?? [])); return { scope: (0, vue.shallowReadonly)(scope), add, remove, removeWhere, removeScope }; } //#endregion //#region useDataSource/index.ts function useDataSource(dataSources, options = {}) { const { destroyOnRemove, collection, isActive = true, evaluating } = options; const result = (0, _vueuse_core.computedAsync)(() => toPromiseValue(dataSources), void 0, { evaluating }); const viewer = useViewer(); (0, vue.watchEffect)((onCleanup) => { if ((0, vue.toValue)(isActive)) { const list = Array.isArray(result.value) ? [...result.value] : [result.value]; const _collection = collection ?? viewer.value?.dataSources; list.forEach((item) => item && _collection?.add(item)); onCleanup(() => { const destroy = (0, vue.toValue)(destroyOnRemove); !_collection?.isDestroyed() && list.forEach((dataSource) => dataSource && _collection?.remove(dataSource, destroy)); }); } }); return result; } //#endregion //#region useDataSourceScope/index.ts /** * Scope the SideEffects of `DataSourceCollection` operations and automatically remove them when unmounted */ function useDataSourceScope(options = {}) { const { collection: _collection, destroyOnRemove } = options; const viewer = useViewer(); const collection = (0, vue.computed)(() => { return (0, vue.toValue)(_collection) ?? viewer.value?.dataSources; }); return useCollectionScope({ addEffect(instance) { if (!collection.value) throw new Error("collection is not defined"); if ((0, _vesium_shared.isPromise)(instance)) return new Promise((resolve, reject) => { instance.then((i) => { try { collection.value.add(i); resolve(i); } catch (error) { reject(error); } }).catch((error) => reject(error)); }); else { collection.value.add(instance); return instance; } }, removeEffect(instance, destroy) { return !!collection.value?.remove(instance, destroy); }, removeScopeArgs: [destroyOnRemove] }); } //#endregion //#region useElementOverlay/index.ts /** * Cesium HTMLElement Overlay */ function useElementOverlay(target, position, options = {}) { const { referenceWindow, horizontal = "center", vertical = "bottom", clampToGround, offset = { x: 0, y: 0 } } = options; const viewer = useViewer(); const cartesian3 = (0, vue.computed)(() => { const positionValue = (0, vue.toValue)(position); if (!positionValue) return; return (0, _vesium_shared.toCartesian3)(positionValue); }); const coord = (0, vue.shallowRef)(); useCesiumEventListener(() => viewer.value?.scene.postUpdate, () => { const scene = viewer.value?.scene; if (!scene || !cartesian3.value) { coord.value = void 0; return; } let finalPosition = (0, vue.toValue)(clampToGround) ? scene.clampToHeight(cartesian3.value) : cartesian3.value; finalPosition ??= cartesian3.value; const result = (0, _vesium_shared.cartesianToCanvasCoord)(finalPosition, scene); if (result) { result.x = +result.x.toFixed(1); result.y = +result.y.toFixed(1); coord.value = !cesium.Cartesian2.equals(result, coord.value) ? result : coord.value; } }); const canvasBounding = (0, _vueuse_core.useElementBounding)(() => viewer.value?.canvas.parentElement); const targetSize = (0, _vueuse_core.useElementSize)(target, void 0, { box: "border-box" }); const finalOffset = (0, vue.computed)(() => { const _offset = (0, vue.toValue)(offset); let x = _offset?.x ?? 0; const _horizontal = (0, vue.toValue)(horizontal); if (_horizontal === "center") x -= targetSize.width.value / 2; else if (_horizontal === "right") x -= targetSize.width.value; let y = _offset?.y ?? 0; const _vertical = (0, vue.toValue)(vertical); if (_vertical === "center") y -= targetSize.height.value / 2; else if (_vertical === "bottom") y -= targetSize.height.value; return { x, y }; }); const x = (0, vue.computed)(() => { let v = coord.value?.x ?? 0; if ((0, vue.toValue)(referenceWindow)) v += canvasBounding.x.value; return +(v + finalOffset.value.x).toFixed(1); }); const y = (0, vue.computed)(() => { let v = coord.value?.y ?? 0; if ((0, vue.toValue)(referenceWindow)) v += canvasBounding.y.value; return +(v + finalOffset.value.y).toFixed(1); }); const style = (0, vue.computed)(() => `left:${x.value}px;top:${y.value}px;`); (0, vue.watchEffect)(() => { const applyStyle = (0, vue.toValue)(options.applyStyle ?? true); if (!applyStyle) return; const element = (0, _vueuse_core.unrefElement)(target); if (element && applyStyle) { element.style?.setProperty?.("left", `${x.value}px`); element.style?.setProperty?.("top", `${y.value}px`); } }, { flush: "post" }); return { x, y, style }; } //#endregion //#region useEntity/index.ts function useEntity(data, options = {}) { const { collection, isActive = true, evaluating } = options; const result = (0, _vueuse_core.computedAsync)(() => toPromiseValue(data), [], { evaluating }); const viewer = useViewer(); (0, vue.watchEffect)((onCleanup) => { if ((0, vue.toValue)(isActive)) { const list = Array.isArray(result.value) ? [...result.value] : [result.value]; const _collection = collection ?? viewer.value?.entities; list.forEach((item) => item && _collection?.add(item)); onCleanup(() => { list.forEach((item) => item && _collection?.remove(item)); }); } }); return result; } //#endregion //#region useEntityScope/index.ts /** * Make `add` and `remove` operations of `EntityCollection` scoped, * automatically remove `Entity` instance when component is unmounted. */ function useEntityScope(options = {}) { const { collection: _collection } = options; const viewer = useViewer(); const collection = (0, vue.computed)(() => { return (0, vue.toValue)(_collection) ?? viewer.value?.entities; }); return useCollectionScope({ addEffect(instance) { if (!collection.value) throw new Error("collection is not defined"); if ((0, _vesium_shared.isPromise)(instance)) return new Promise((resolve, reject) => { instance.then((i) => { collection.value.add(i); resolve(i); }).catch((error) => reject(error)); }); else { collection.value.add(instance); return instance; } }, removeEffect(instance) { return !!collection.value?.remove(instance); }, removeScopeArgs: [] }); } //#endregion //#region useScenePick/index.ts const pickCache = /* @__PURE__ */ new WeakMap(); /** * Uses the `scene.pick` function in Cesium's Scene object to perform screen point picking, * return a computed property containing the pick result, or undefined if no object is picked. * * @param windowPosition The screen coordinates of the pick point. */ function useScenePick(windowPosition, options = {}) { const { width = 3, height = 3, throttled = 8 } = options; const isActive = (0, vue.toRef)(options.isActive ?? true); const viewer = useViewer(); const position = (0, _vueuse_core.refThrottled)((0, vue.computed)(() => (0, vue.toValue)(windowPosition)?.clone()), throttled, false, true); const pick = (0, vue.shallowRef)(); (0, vue.watchEffect)(() => { if (viewer.value && position.value && isActive.value) { const widthValue = (0, vue.toValue)(width); const heightValue = (0, vue.toValue)(height); const cache = pickCache.get(viewer.value); if (cache && cache.position.equals(position.value) && cache.width === widthValue && cache.height === heightValue) pick.value = cache.pick; else try { const nextPick = viewer.value?.scene.pick(position.value, widthValue, heightValue); pick.value = nextPick; pickCache.set(viewer.value, { position: position.value.clone(), width: widthValue, height: heightValue, pick: nextPick }); } catch (error) { console.error("[useScenePick] Error during pick:", error); pick.value = void 0; } } else pick.value = void 0; }); return pick; } //#endregion //#region useScreenSpaceEventHandler/index.ts /** * Easily use the `ScreenSpaceEventHandler`, * when the dependent data changes or the component is unmounted, * the listener function will automatically reload or destroy. * * @param type Types of mouse event * @param inputAction Callback function for listening */ function useScreenSpaceEventHandler(type, inputAction, options = {}) { const { modifier } = options; const viewer = useViewer(); const isActive = (0, vue.toRef)(options.isActive ?? true); let currentHandler; const handler = (0, vue.computed)(() => { if (viewer.value?.cesiumWidget?.canvas) return new cesium.ScreenSpaceEventHandler(viewer.value.cesiumWidget.canvas); }); const cleanup1 = (0, vue.watch)(handler, (_value, previous) => { previous?.destroy(); currentHandler = _value; }); const cleanup2 = (0, vue.watchEffect)((onCleanup) => { const typeValue = (0, vue.toValue)(type); const modifierValue = (0, vue.toValue)(modifier); const handlerValue = (0, vue.toValue)(handler); currentHandler = handlerValue; if (!handlerValue || !isActive.value || !inputAction) return; if ((0, _vesium_shared.isDef)(typeValue)) { handlerValue.setInputAction(inputAction, typeValue, modifierValue); onCleanup(() => handlerValue.removeInputAction(typeValue, modifierValue)); } }); const stop = () => { cleanup1(); cleanup2(); currentHandler?.destroy(); currentHandler = void 0; }; (0, _vueuse_core.tryOnScopeDispose)(stop); return stop; } //#endregion //#region useGraphicEvent/useDrag.ts /** * Use graphic drag events with ease, and remove listener automatically on unmounted. */ function useDrag(listener) { const position = (0, vue.shallowRef)(); const pick = useScenePick(position); const motionEvent = (0, vue.shallowRef)(); const dragging = (0, vue.ref)(false); const viewer = useViewer(); const cameraLocked = (0, vue.ref)(false); (0, vue.watch)(cameraLocked, (locked) => { viewer.value && (viewer.value.scene.screenSpaceCameraController.enableRotate = !locked); }); const lockCamera = () => { cameraLocked.value = true; }; const execute = (pickedValue, startPosition, endPosition) => { listener({ event: { startPosition: startPosition.clone(), endPosition: endPosition.clone() }, pick: pickedValue, dragging: dragging.value, lockCamera }); (0, vue.nextTick)(() => { if (!dragging.value && cameraLocked.value) cameraLocked.value = false; }); }; const stopLeftDownWatch = useScreenSpaceEventHandler(cesium.ScreenSpaceEventType.LEFT_DOWN, (event) => { dragging.value = true; position.value = event.position.clone(); }); const stopMouseMoveWatch = useScreenSpaceEventHandler(cesium.ScreenSpaceEventType.MOUSE_MOVE, (0, _vesium_shared.throttle)(({ startPosition, endPosition }) => { motionEvent.value = { startPosition: motionEvent.value?.endPosition.clone() || startPosition.clone(), endPosition: endPosition.clone() }; }, 8, false, true)); (0, vue.watch)([pick, motionEvent], ([pickValue, motionValue]) => { if (pickValue && motionValue) { const { startPosition, endPosition } = motionValue; dragging.value && execute(pickValue, startPosition, endPosition); } }); const stopLeftUpWatch = useScreenSpaceEventHandler(cesium.ScreenSpaceEventType.LEFT_UP, (event) => { dragging.value = false; if (pick.value && motionEvent.value) execute(pick.value, motionEvent.value.endPosition, event.position); position.value = void 0; motionEvent.value = void 0; }); const stop = () => { stopLeftDownWatch(); stopMouseMoveWatch(); stopLeftUpWatch(); }; (0, _vueuse_core.tryOnScopeDispose)(stop); return stop; } //#endregion //#region useGraphicEvent/useHover.ts /** * Use graphic hover events with ease, and remove listener automatically on unmounted. */ function useHover(listener) { const motionEvent = (0, vue.shallowRef)(); const pick = useScenePick(() => motionEvent.value?.endPosition); const execute = (pickedValue, startPosition, endPosition, hovering) => { listener({ event: { startPosition: startPosition.clone(), endPosition: endPosition.clone() }, pick: pickedValue, hovering }); }; useScreenSpaceEventHandler(cesium.ScreenSpaceEventType.MOUSE_MOVE, ({ startPosition, endPosition }) => { const prevStart = motionEvent.value?.startPosition; const prevEnd = motionEvent.value?.endPosition; if (!prevStart || !prevEnd || !startPosition.equals(prevStart) || !endPosition.equals(prevEnd)) motionEvent.value = { startPosition: startPosition.clone(), endPosition: endPosition.clone() }; }); (0, vue.watch)([pick, motionEvent], ([pickValue, motionValue]) => { if (pickValue && motionValue) { const { startPosition, endPosition } = motionValue; execute(pickValue, startPosition, endPosition, true); } }); (0, vue.watch)(pick, (pickValue, prevPick) => { if (prevPick && motionEvent.value) { const { startPosition, endPosition } = motionEvent.value; execute(prevPick, startPosition, endPosition, false); } }); } //#endregion //#region useGraphicEvent/usePositioned.ts /** * @internal */ const EVENT_TYPE_RECORD = { LEFT_DOWN: cesium.ScreenSpaceEventType.LEFT_DOWN, LEFT_UP: cesium.ScreenSpaceEventType.LEFT_UP, LEFT_CLICK: cesium.ScreenSpaceEventType.LEFT_CLICK, LEFT_DOUBLE_CLICK: cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK, RIGHT_DOWN: cesium.ScreenSpaceEventType.RIGHT_DOWN, RIGHT_UP: cesium.ScreenSpaceEventType.RIGHT_UP, RIGHT_CLICK: cesium.ScreenSpaceEventType.RIGHT_CLICK, MIDDLE_DOWN: cesium.ScreenSpaceEventType.MIDDLE_DOWN, MIDDLE_UP: cesium.ScreenSpaceEventType.MIDDLE_UP, MIDDLE_CLICK: cesium.ScreenSpaceEventType.MIDDLE_CLICK }; function usePositioned(type, listener) { const screenEvent = EVENT_TYPE_RECORD[type]; const viewer = useViewer(); useScreenSpaceEventHandler(screenEvent, (event) => { const position = event.position; const pick = viewer.value?.scene.pick(position); pick && position && listener({ event: { position }, pick }); }); } //#endregion //#region useGraphicEvent/index.ts const GLOBAL_GRAPHIC_SYMBOL = Symbol("GLOBAL_GRAPHIC_SYMBOL"); const POSITIONED_EVENT_TYPES = [ "LEFT_DOWN", "LEFT_UP", "LEFT_CLICK", "LEFT_DOUBLE_CLICK", "RIGHT_DOWN", "RIGHT_UP", "RIGHT_CLICK", "MIDDLE_DOWN", "MIDDLE_UP", "MIDDLE_CLICK" ]; /** * Handle graphic event listeners and cursor styles for Cesium graphics. * You don't need to overly worry about memory leaks from the function, as it automatically cleans up internally. */ function useGraphicEvent() { const collection = /* @__PURE__ */ new WeakMap(); const cursorCollection = /* @__PURE__ */ new WeakMap(); const dragCursorCollection = /* @__PURE__ */ new WeakMap(); const remove = (graphic, type, listener) => { const _graphic = graphic === "global" ? GLOBAL_GRAPHIC_SYMBOL : graphic; collection?.get(_graphic)?.get(type)?.delete(listener); cursorCollection?.get(_graphic)?.get(type)?.delete(listener); if (collection?.get(_graphic)?.get(type)?.size === 0) collection.get(_graphic).delete(type); if (collection.get(_graphic)?.size === 0) collection.delete(_graphic); cursorCollection?.get(_graphic)?.get(type)?.delete(listener); if (cursorCollection?.get(_graphic)?.get(type)?.size === 0) cursorCollection?.get(_graphic)?.delete(type); if (cursorCollection?.get(_graphic)?.size === 0) cursorCollection?.delete(_graphic); dragCursorCollection?.get(_graphic)?.get(type)?.delete(listener); if (dragCursorCollection?.get(_graphic)?.get(type)?.size === 0) dragCursorCollection?.get(_graphic)?.delete(type); if (dragCursorCollection?.get(_graphic)?.size === 0) dragCursorCollection?.delete(_graphic); }; const add = (graphic, type, listener, options = {}) => { const _graphic = graphic === "global" ? GLOBAL_GRAPHIC_SYMBOL : graphic; collection.get(_graphic) ?? collection.set(_graphic, /* @__PURE__ */ new Map()); const eventTypeMap = collection.get(_graphic); eventTypeMap.get(type) ?? eventTypeMap.set(type, /* @__PURE__ */ new Set()); eventTypeMap.get(type).add(listener); let { cursor = "pointer", dragCursor } = options; if ((0, _vesium_shared.isDef)(cursor)) { const _cursor = (0, _vesium_shared.isFunction)(cursor) ? cursor : () => cursor; cursorCollection.get(_graphic) ?? cursorCollection.set(_graphic, /* @__PURE__ */ new Map()); cursorCollection.get(_graphic).get(type) ?? cursorCollection.get(_graphic).set(type, /* @__PURE__ */ new Map()); cursorCollection.get(_graphic).get(type).set(listener, _cursor); } if (type === "DRAG") dragCursor ??= ((event) => event?.dragging ? "crosshair" : void 0); if ((0, _vesium_shared.isDef)(dragCursor)) { const _dragCursor = (0, _vesium_shared.isFunction)(dragCursor) ? dragCursor : () => dragCursor; dragCursorCollection.get(_graphic) ?? dragCursorCollection.set(_graphic, /* @__PURE__ */ new Map()); dragCursorCollection.get(_graphic).get(type) ?? dragCursorCollection.get(_graphic).set(type, /* @__PURE__ */ new Map()); dragCursorCollection.get(_graphic).get(type).set(listener, _dragCursor); } return () => remove(graphic, type, listener); }; const clear = (graphic, type) => { const _graphic = graphic === "global" ? GLOBAL_GRAPHIC_SYMBOL : graphic; if (type === "all") { collection.delete(_graphic); cursorCollection.delete(_graphic); dragCursorCollection.delete(_graphic); return; } collection.get(_graphic)?.delete(type); if (collection.get(_graphic)?.size === 0) collection.delete(_graphic); cursorCollection?.get(_graphic)?.delete(type); dragCursorCollection?.get(_graphic)?.delete(type); if (cursorCollection?.get(_graphic)?.size === 0) cursorCollection?.delete(_graphic); if (dragCursorCollection?.get(_graphic)?.size === 0) dragCursorCollection?.delete(_graphic); }; for (const type of POSITIONED_EVENT_TYPES) usePositioned(type, (event) => { (0, _vesium_shared.resolvePick)(event.pick).concat(GLOBAL_GRAPHIC_SYMBOL).forEach((graphic) => { collection.get(graphic)?.get(type)?.forEach((fn) => (0, _vesium_shared.tryRun)(fn)?.(event)); }); }); const dragging = (0, vue.ref)(false); const viewer = useViewer(); useHover((event) => { (0, _vesium_shared.resolvePick)(event.pick).concat(GLOBAL_GRAPHIC_SYMBOL).forEach((graphic) => { collection.get(graphic)?.get("HOVER")?.forEach((fn) => (0, _vesium_shared.tryRun)(fn)?.(event)); if (!dragging.value) cursorCollection.get(graphic)?.forEach((map) => { map.forEach((fn) => { const cursor = event.hovering ? (0, _vesium_shared.tryRun)(fn)(event) : ""; viewer.value?.canvas.style?.setProperty("cursor", cursor); }); }); }); }); useDrag((event) => { const graphics = (0, _vesium_shared.resolvePick)(event.pick).concat(GLOBAL_GRAPHIC_SYMBOL); dragging.value = event.dragging; graphics.forEach((graphic) => { collection.get(graphic)?.get("DRAG")?.forEach((fn) => (0, _vesium_shared.tryRun)(fn)(event)); dragCursorCollection.get(graphic)?.forEach((map) => { map.forEach((fn) => { const cursor = event.dragging ? (0, _vesium_shared.tryRun)(fn)(event) : ""; viewer.value?.canvas.style?.setProperty("cursor", cursor); }); }); }); }); return { add, remove, clear }; } //#endregion //#region useImageryLayer/index.ts function useImageryLayer(data, options = {}) { const { destroyOnRemove, collection, isActive = true, evaluating, index } = options; const result = (0, _vueuse_core.computedAsync)(() => toPromiseValue(data), [], { evaluating }); const viewer = useViewer(); (0, vue.watchEffect)((onCleanup) => { if ((0, vue.toValue)(isActive)) { const list = Array.isArray(result.value) ? [...result.value] : [result.value]; const _collection = collection ?? viewer.value?.imageryLayers; const _index = (0, vue.toValue)(index); if (collection?.isDestroyed()) return; list.forEach((item) => { if (!item) return; if (item?.isDestroyed()) { console.warn("ImageryLayer is destroyed"); return; } _collection?.add(item, _index); }); onCleanup(() => { const destroy = (0, vue.toValue)(destroyOnRemove); list.forEach((item) => item && _collection?.remove(item, destroy)); }); } }); return result; } //#endregion //#region useImageryLayerScope/index.ts /** * Make `add` and `remove` operations of `ImageryLayerCollection` scoped, * automatically remove `ImageryLayer` instance when component is unmounted. */ function useImageryLayerScope(options = {}) { const { collection: _collection, destroyOnRemove } = options; const viewer = useViewer(); const collection = (0, vue.computed)(() => { return (0, vue.toValue)(_collection) ?? viewer.value?.imageryLayers; }); return useCollectionScope({ addEffect(instance, index) { if (!collection.value) throw new Error("collection is not defined"); if ((0, _vesium_shared.isPromise)(instance)) return new Promise((resolve, reject) => { instance.then((i) => { try { collection.value.add(i, index); resolve(i); } catch (error) { reject(error); } }).catch((error) => reject(error)); }); else { collection.value.add(instance, index); return instance; } }, removeEffect(instance, destroy) { return !!collection.value?.remove(instance, destroy); }, removeScopeArgs: [destroyOnRemove] }); } //#endregion //#region usePostProcessStage/index.ts function usePostProcessStage(data, options = {}) { const { collection, destroyOnRemove = true, isActive = true, evaluating } = options; const result = (0, _vueuse_core.computedAsync)(() => toPromiseValue(data), void 0, { evaluating }); const viewer = useViewer(); (0, vue.watchEffect)((onCleanup) => { if (!viewer.value) return; if ((0, vue.toValue)(isActive)) { const list = Array.isArray(result.value) ? [...result.value] : [result.value]; const _collection = collection ?? viewer.value.scene.postProcessStages; list.forEach((item) => item && _collection.add(item)); onCleanup(() => { list.forEach((item) => { if (item) { _collection.remove(item); if (destroyOnRemove && typeof item.destroy === "function" && !item.isDestroyed()) item.destroy(); } }); }); } }); return result; } //#endregion //#region usePostProcessStageScope/index.ts /** * Make `add` and `remove` operations of `PostProcessStageCollection` scoped, * automatically remove `PostProcessStage` instance when component is unmounted. */ function usePostProcessStageScope(options = {}) { const { collection: _collection, destroyOnRemove = true } = options; const viewer = useViewer(); const collection = (0, vue.computed)(() => { return (0, vue.toValue)(_collection) ?? viewer.value?.postProcessStages; }); return useCollectionScope({ addEffect(instance) { if (!collection.value) throw new Error("collection is not defined"); if ((0, _vesium_shared.isPromise)(instance)) return new Promise((resolve, reject) => { instance.then((resolvedInstance) => { collection.value.add(resolvedInstance); resolve(resolvedInstance); }).catch((error) => reject(error)); }); else return collection.value.add(instance); }, removeEffect(instance) { if (!collection.value) return false; const removed = collection.value.remove(instance); if (removed && destroyOnRemove && instance && typeof instance.destroy === "function" && !instance.isDestroyed()) instance.destroy(); return !!removed; }, removeScopeArgs: [] }); } //#endregion //#region usePrimitive/index.ts function usePrimitive(data, options = {}) { const { collection, destroyOnRemove = true, isActive = true, evaluating } = options; const result = (0, _vueuse_core.computedAsync)(() => toPromiseValue(data), void 0, { evaluating }); const viewer = useViewer(); (0, vue.watchEffect)((onCleanup) => { if (!viewer.value) return; if ((0, vue.toValue)(isActive)) { const list = Array.isArray(result.value) ? [...result.value] : [result.value]; const _collection = collection === "ground" ? viewer.value?.scene.groundPrimitives : collection ?? viewer.value?.scene.primitives; list.forEach((item) => item && _collection?.add(item)); onCleanup(() => { !_collection?.isDestroyed() && list.forEach((item) => { if (item) { _collection?.remove(item); if (destroyOnRemove && typeof item.destroy === "function" && !item.isDestroyed()) item.destroy(); } }); }); } }); return result; } //#endregion //#region usePrimitiveScope/index.ts /** * Make `add` and `remove` operations of `PrimitiveCollection` scoped, * automatically remove `Primitive` instance when component is unmounted. */ function usePrimitiveScope(options = {}) { const { collection: _collection, destroyOnRemove = true } = options; const viewer = useViewer(); const collection = (0, vue.computed)(() => { const value = (0, vue.toValue)(_collection); return value === "ground" ? viewer.value?.scene?.groundPrimitives : value || viewer.value?.scene.primitives; }); const { scope, add, remove, removeWhere, removeScope } = useCollectionScope({ addEffect(instance, ...args) { if (!collection.value) throw new Error("collection is not defined"); if ((0, _vesium_shared.isPromise)(instance)) return new Promise((resolve, reject) => { instance.then((instance) => resolve(collection.value.add(instance, ...args))).catch((error) => reject(error)); }); else return collection.value.add(instance, ...args); }, removeEffect(instance) { if (!collection.value) return false; const removed = collection.value.remove(instance); if (removed && destroyOnRemove && instance && typeof instance.destroy === "function" && !instance.isDestroyed()) instance.destroy(); return !!removed; }, removeScopeArgs: [] }); return { scope, add, remove, removeWhere, removeScope }; } //#endregion //#region useScaleBar/index.ts const distances = [ .01, .05, .1, .5, 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500, 1e3, 2e3, 3e3, 5e3, 1e4, 2e4, 3e4, 5e4, 1e5, 2e5, 3e5, 5e5, 1e6, 2e6, 3e6, 5e6, 1e7, 2e7, 3e7, 5e7 ].reverse(); /** * Reactive generation of scale bars */ function useScaleBar(options = {}) { const { maxPixel = 80, delay = 8 } = options; const maxPixelRef = (0, vue.computed)(() => (0, vue.toValue)(maxPixel)); const viewer = useViewer(); const canvasSize = (0, _vueuse_core.useElementSize)(() => viewer.value?.canvas); const pixelDistance = (0, vue.ref)(); const setPixelDistance = async () => { await (0, vue.nextTick)(); const scene = viewer.value?.scene; if (!scene) return; const left = scene.camera.getPickRay(new cesium.Cartesian2(Math.floor(canvasSize.width.value / 2), canvasSize.height.value - 1)); const right = scene.camera.getPickRay(new cesium.Cartesian2(Math.floor(1 + canvasSize.width.value / 2), canvasSize.height.value - 1)); if (!left || !right) return; const leftPosition = scene.globe.pick(left, scene); const rightPosition = scene.globe.pick(right, scene); if (!leftPosition || !rightPosition) return; pixelDistance.value = new cesium.EllipsoidGeodesic(scene.globe.ellipsoid.cartesianToCartographic(leftPosition), scene.globe.ellipsoid.cartesianToCartographic(rightPosition)).surfaceDistance; }; (0, vue.watch)([ viewer, () => canvasSize.width.value, () => canvasSize.height.value ], () => setPixelDistance(), { immediate: true }); useCesiumEventListener(() => viewer.value?.camera.changed, (0, _vesium_shared.throttle)(setPixelDistance, delay)); const distance = (0, vue.computed)(() => { if (pixelDistance.value) return distances.find((item) => pixelDistance.value * maxPixelRef.value > item); }); const width = (0, vue.computed)(() => { if (distance.value && pixelDistance.value) return distance.value / pixelDistance.value; return 0; }); const distanceText = (0, vue.computed)(() => { if (distance.value) return distance.value > 1e3 ? `${distance.value / 1e3 || 0}km` : `${distance.value || 0}m`; }); return { pixelDistance: (0, vue.readonly)(pixelDistance), width, distance, distanceText }; } //#endregion //#region useSceneDrillPick/index.ts /** * Uses the `scene.drillPick` function to perform screen point picking, * return a computed property containing the pick result, or undefined if no object is picked. * * @param windowPosition The screen coordinates of the pick point. */ function useSceneDrillPick(windowPosition, options = {}) { const { width = 3, height = 3, limit, throttled = 8, isActive = true } = options; const viewer = useViewer(); const position = (0, _vueuse_core.refThrottled)((0, vue.computed)(() => (0, vue.toValue)(windowPosition)), throttled, false, true); return (0, vue.computed)(() => { if (position.value && (0, vue.toValue)(isActive)) return viewer.value?.scene.drillPick(position.value, (0, vue.toValue)(limit), (0, vue.toValue)(width), (0, vue.toValue)(height)); }); } //#endregion exports.CREATE_VIEWER_COLLECTION = CREATE_VIEWER_COLLECTION; exports.CREATE_VIEWER_INJECTION_KEY = CREATE_VIEWER_INJECTION_KEY; exports.createViewer = createViewer; exports.toPromiseValue = toPromiseValue; exports.useCameraState = useCameraState; exports.useCesiumEventListener = useCesiumEventListener; exports.useCesiumFps = useCesiumFps; exports.useCollectionScope = useCollectionScope; exports.useDataSource = useDataSource; exports.useDataSourceScope = useDataSourceScope; exports.useElementOverlay = useElementOverlay; exports.useEntity = useEntity; exports.useEntityScope = useEntityScope; exports.useGraphicEvent = useGraphicEvent; exports.useImageryLayer = useImageryLayer; exports.useImageryLayerScope = useImageryLayerScope; exports.usePostProcessStage = usePostProcessStage; exports.usePostProcessStageScope = usePostProcessStageScope; exports.usePrimitive = usePrimitive; exports.usePrimitiveScope = usePrimitiveScope; exports.useScaleBar = useScaleBar; exports.useSceneDrillPick = useSceneDrillPick; exports.useScenePick = useScenePick; exports.useScreenSpaceEventHandler = useScreenSpaceEventHandler; exports.useViewer = useViewer; Object.keys(_vesium_shared).forEach(function(k) { if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, { enumerable: true, get: function() { return _vesium_shared[k]; } }); }); })(this.Vesium = this.Vesium || {}, VueUse, Cesium, Vue, Vesium); //# sourceMappingURL=index.iife.js.map