vesium
Version:
Core Vue composition hooks for Cesium
1 lines • 103 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","names":["Viewer","Cartesian2","ScreenSpaceEventHandler","ScreenSpaceEventType","ScreenSpaceEventType","ScreenSpaceEventType","Cartesian2","EllipsoidGeodesic"],"sources":["../createViewer/index.ts","../toPromiseValue/index.ts","../useCesiumEventListener/index.ts","../useViewer/index.ts","../useCameraState/index.ts","../useCesiumFps/index.ts","../useCollectionScope/index.ts","../useDataSource/index.ts","../useDataSourceScope/index.ts","../useElementOverlay/index.ts","../useEntity/index.ts","../useEntityScope/index.ts","../useScenePick/index.ts","../useScreenSpaceEventHandler/index.ts","../useGraphicEvent/useDrag.ts","../useGraphicEvent/useHover.ts","../useGraphicEvent/usePositioned.ts","../useGraphicEvent/index.ts","../useImageryLayer/index.ts","../useImageryLayerScope/index.ts","../usePostProcessStage/index.ts","../usePostProcessStageScope/index.ts","../usePrimitive/index.ts","../usePrimitiveScope/index.ts","../useScaleBar/index.ts","../useSceneDrillPick/index.ts"],"sourcesContent":["import type { MaybeComputedElementRef } from '@vueuse/core';\nimport type { EffectScope, InjectionKey, MaybeRef, ShallowRef } from 'vue';\nimport { tryOnScopeDispose, unrefElement, useMutationObserver } from '@vueuse/core';\nimport { Viewer } from 'cesium';\nimport { computed, getCurrentScope, markRaw, provide, shallowReadonly, shallowRef, toRaw, toValue, watchEffect } from 'vue';\n\n/**\n * @internal\n */\nexport const CREATE_VIEWER_INJECTION_KEY: InjectionKey<Readonly<ShallowRef<Viewer | undefined>>> = Symbol('CREATE_VIEWER_INJECTION_KEY');\n\n/**\n * @internal\n */\nexport const CREATE_VIEWER_COLLECTION = new WeakMap<EffectScope, Readonly<ShallowRef<Viewer | undefined>>>();\n\n/**\n * Pass in an existing Viewer instance,\n * which can be accessed by the current component and its descendant components using {@link useViewer}\n *\n * When the Viewer instance referenced by this overloaded function becomes invalid, it will not trigger destruction.\n * @param viewer - Existing viewer instance\n * @returns The Viewer instance\n */\nexport function createViewer(\n viewer: MaybeRef<Viewer | undefined>,\n): Readonly<ShallowRef<Viewer | undefined>>;\n\n/**\n * Initialize a Viewer instance, which can be accessed by the\n * current component and its descendant components using {@link useViewer}.\n *\n * The Viewer instance created by this overloaded function will automatically be destroyed when it becomes invalid.\n *\n * @param element - The DOM element or ID that will contain the widget\n * @param options - see `Viewer.ConstructorOptions`\n * @returns The Viewer instance\n */\nexport function createViewer(\n element: MaybeComputedElementRef,\n options?: Viewer.ConstructorOptions,\n): Readonly<ShallowRef<Viewer | undefined>>;\n\n/**\n * @internal\n */\nexport function createViewer(\n arg1?: MaybeRef<Viewer | undefined> | MaybeComputedElementRef,\n arg2?: Viewer.ConstructorOptions,\n): Readonly<ShallowRef<Viewer | undefined>> {\n const viewer = shallowRef<Viewer>();\n const readonlyViewer = shallowReadonly(viewer);\n\n provide(CREATE_VIEWER_INJECTION_KEY, readonlyViewer);\n\n const scope = getCurrentScope();\n if (scope) {\n CREATE_VIEWER_COLLECTION.set(scope, readonlyViewer);\n }\n\n const canvas = computed(() => viewer.value?.canvas);\n const body = typeof document !== 'undefined' ? document.body : undefined;\n\n // Watch for the canvas being removed from the DOM\n if (body) {\n useMutationObserver(body, () => {\n if (canvas.value && !body.contains(canvas.value)) {\n viewer.value = undefined;\n }\n }, {\n childList: true,\n subtree: true,\n });\n }\n\n watchEffect((onCleanup) => {\n const value = toRaw(toValue(arg1));\n if (value instanceof Viewer) {\n viewer.value = markRaw(value);\n }\n else if (value) {\n const element = unrefElement(value);\n viewer.value = new Viewer(element, arg2);\n onCleanup(() => !viewer.value?.isDestroyed() && viewer.value?.destroy());\n }\n else {\n viewer.value = undefined;\n }\n });\n\n tryOnScopeDispose(() => {\n viewer.value = undefined;\n });\n\n return computed(() => {\n return viewer.value?.isDestroyed() ? undefined : viewer.value;\n });\n}\n","import type { MaybeRef } from 'vue';\nimport { isFunction, isPromise } from '@vesium/shared';\nimport { toRaw, toValue } from 'vue';\n\nexport type OnAsyncGetterCancel = (onCancel: () => void) => void;\n\nexport type MaybeAsyncGetter<T> = () => (Promise<T> | T);\nexport type MaybeRefOrAsyncGetter<T> = MaybeRef<T> | MaybeAsyncGetter<T>;\n\nexport interface ToPromiseValueOptions {\n /**\n * Determines whether the source should be unwrapped to its raw value.\n * @default true\n */\n raw?: boolean;\n}\n\n/**\n * Similar to Vue's built-in `toValue`, but capable of handling asynchronous functions, thus returning a `await value`.\n *\n * Used in conjunction with VueUse's `computedAsync`.\n *\n * @param source The source value, which can be a reactive reference or an asynchronous getter.\n * @param options Conversion options\n * @returns The converted value.\n *\n * @example\n * ```ts\n *\n * const data = computedAsync(async ()=> {\n * return await toPromiseValue(promiseRef)\n * })\n *\n * ```\n */\nexport async function toPromiseValue<T>(source: MaybeRefOrAsyncGetter<T>, options: ToPromiseValueOptions = {}): Promise<T> {\n const { raw = true } = options;\n let value: T;\n\n if (isFunction(source)) {\n value = await source();\n }\n else {\n const result = toValue(source);\n value = isPromise(result) ? await result : result;\n }\n return raw ? toRaw(value) : value;\n}\n","import type { Arrayable, FunctionArgs } from '@vueuse/core';\nimport type { Event } from 'cesium';\nimport type { MaybeRefOrGetter, WatchStopHandle } from 'vue';\nimport { tryOnScopeDispose } from '@vueuse/core';\nimport { toRef, toValue, watchEffect } from 'vue';\n\nexport interface UseCesiumEventListenerOptions {\n /**\n * Whether to active the event listener.\n * @default true\n */\n isActive?: MaybeRefOrGetter<boolean>;\n}\n\n/**\n * Easily use the `addEventListener` in `Cesium.Event` instances,\n * when the dependent data changes or the component is unmounted,\n * the listener function will automatically reload or destroy.\n *\n * @param event The Cesium.Event instance\n * @param listener The listener function\n * @param options additional options\n * @returns A function that can be called to remove the event listener\n */\nexport function useCesiumEventListener<FN extends FunctionArgs<any[]>>(\n event: Arrayable<Event<FN> | undefined> | Arrayable<MaybeRefOrGetter<Event<FN> | undefined>> | MaybeRefOrGetter<Arrayable<Event<FN> | undefined>>,\n listener: FN,\n options: UseCesiumEventListenerOptions = {},\n): WatchStopHandle {\n const isActive = toRef(options.isActive ?? true);\n\n const cleanup = watchEffect((onCleanup) => {\n const _event = toValue(event);\n const events = Array.isArray(_event) ? _event : [_event];\n if (events) {\n if (events.length && isActive.value) {\n const stopFns = events.map((event) => {\n const e = toValue(event);\n return e?.addEventListener(listener, e);\n });\n onCleanup(() => stopFns.forEach(stop => stop?.()));\n }\n }\n });\n\n tryOnScopeDispose(cleanup.stop);\n return cleanup.stop;\n}\n","import type { Viewer } from 'cesium';\nimport type { ShallowRef } from 'vue';\nimport { getCurrentScope, inject } from 'vue';\nimport { CREATE_VIEWER_COLLECTION, CREATE_VIEWER_INJECTION_KEY } from '../createViewer';\n\n/**\n * Obtain the `Viewer` instance injected through `createViewer` in the current component or its ancestor components.\n *\n * note:\n * - If `createViewer` and `useViewer` are called in the same component, the `Viewer` instance injected by `createViewer` will be used preferentially.\n * - When calling `createViewer` and `useViewer` in the same component, `createViewer` should be called before `useViewer`.\n */\nexport function useViewer(): Readonly<ShallowRef<Viewer | undefined>> {\n const scope = getCurrentScope();\n const instanceViewer = scope ? CREATE_VIEWER_COLLECTION.get(scope) : undefined;\n if (instanceViewer) {\n return instanceViewer;\n }\n else {\n const injectViewer = inject(CREATE_VIEWER_INJECTION_KEY);\n if (!injectViewer) {\n throw new Error(\n 'The `Viewer` instance injected by `createViewer` '\n + 'was not found in the current component or its '\n + 'ancestor components. Have you called `createViewer`?',\n );\n }\n return injectViewer;\n }\n}\n","import type { Camera, Cartesian3, Cartographic, Rectangle } from 'cesium';\nimport type { ComputedRef, MaybeRefOrGetter } from 'vue';\nimport { refThrottled } from '@vueuse/core';\nimport { computed, shallowRef, toValue, watch } from 'vue';\nimport { useCesiumEventListener } from '../useCesiumEventListener';\nimport { useViewer } from '../useViewer';\n\nexport interface UseCameraStateOptions {\n /**\n * The camera to use\n * @default useViewer().value.scene.camera\n */\n camera?: MaybeRefOrGetter<Camera | undefined>;\n\n /**\n * Camera event type to watch\n * @default `changed`\n */\n event?: MaybeRefOrGetter<'changed' | 'moveStart' | 'moveEnd'>;\n\n /**\n * Throttled delay duration (ms)\n * @default 8\n */\n delay?: number;\n}\n\nexport interface UseCameraStateReturn {\n /**\n * The camera\n */\n camera: ComputedRef<Camera | undefined>;\n\n /**\n * The position of the camera\n */\n position: ComputedRef<Cartesian3 | undefined>;\n\n /**\n * The view direction of the camera\n */\n direction: ComputedRef<Cartesian3 | undefined>;\n\n /**\n * The up direction of the camera\n */\n up: ComputedRef<Cartesian3 | undefined>;\n\n /**\n * The right direction of the camera\n */\n right: ComputedRef<Cartesian3 | undefined>;\n\n /**\n * Gets the {@link Cartographic} position of the camera, with longitude and latitude\n * expressed in radians and height in meters. In 2D and Columbus View, it is possible\n * for the returned longitude and latitude to be outside the range of valid longitudes\n * and latitudes when the camera is outside the map.\n */\n positionCartographic: ComputedRef<Cartographic | undefined>;\n\n /**\n * Gets the position of the camera in world coordinates\n */\n positionWC: ComputedRef<Cartesian3 | undefined>;\n\n /**\n * Gets the view direction of the camera in world coordinates\n */\n directionWC: ComputedRef<Cartesian3 | undefined>;\n\n /**\n * Gets the up direction of the camera in world coordinates\n */\n upWC: ComputedRef<Cartesian3 | undefined>;\n\n /**\n * Gets the right direction of the camera in world coordinates\n */\n rightWC: ComputedRef<Cartesian3 | undefined>;\n\n /**\n * Computes the approximate visible rectangle on the ellipsoid\n */\n viewRectangle: ComputedRef<Rectangle | undefined>;\n\n /**\n * Gets the camera heading in radians\n */\n heading: ComputedRef<number | undefined>;\n\n /**\n * Gets the camera pitch in radians\n */\n pitch: ComputedRef<number | undefined>;\n\n /**\n * Gets the camera roll in radians\n */\n roll: ComputedRef<number | undefined>;\n\n /**\n * Gets the camera center hierarchy level\n */\n level: ComputedRef<number | undefined>;\n\n}\n\n/**\n * Reactive Cesium Camera state\n * @param options options\n * @returns Reactive camera states\n */\nexport function useCameraState(options: UseCameraStateOptions = {}): UseCameraStateReturn {\n let getCamera = options.camera;\n if (!getCamera) {\n const viewer = useViewer();\n getCamera = () => viewer.value?.scene.camera;\n }\n\n const camera = computed(() => toValue(getCamera));\n\n const event = computed(() => {\n const eventField = toValue(options.event) || 'changed';\n return camera.value?.[eventField];\n });\n\n const changedSymbol = refThrottled(\n shallowRef(Symbol('camera change')),\n options.delay ?? 8,\n true,\n false,\n );\n\n const setChangedSymbol = () => {\n changedSymbol.value = Symbol('camera change');\n };\n\n watch(camera, () => setChangedSymbol());\n useCesiumEventListener(event, () => setChangedSymbol());\n\n return {\n camera,\n position: computed(() => changedSymbol.value ? camera.value?.position?.clone() : undefined),\n direction: computed(() => changedSymbol.value ? camera.value?.direction?.clone() : undefined),\n up: computed(() => changedSymbol.value ? camera.value?.up?.clone() : undefined),\n right: computed(() => changedSymbol.value ? camera.value?.right?.clone() : undefined),\n positionCartographic: computed(() => changedSymbol.value ? camera.value?.positionCartographic?.clone() : undefined),\n positionWC: computed(() => changedSymbol.value ? camera.value?.positionWC?.clone() : undefined),\n directionWC: computed(() => changedSymbol.value ? camera.value?.directionWC?.clone() : undefined),\n upWC: computed(() => changedSymbol.value ? camera.value?.upWC?.clone() : undefined),\n rightWC: computed(() => changedSymbol.value ? camera.value?.rightWC?.clone() : undefined),\n viewRectangle: computed(() => changedSymbol.value ? camera.value?.computeViewRectangle() : undefined),\n heading: computed(() => changedSymbol.value ? camera.value?.heading : undefined),\n pitch: computed(() => changedSymbol.value ? camera.value?.pitch : undefined),\n roll: computed(() => changedSymbol.value ? camera.value?.roll : undefined),\n level: computed(() =>\n (changedSymbol.value && camera.value?.positionCartographic?.height !== undefined)\n ? computeLevel(camera.value.positionCartographic.height)\n : undefined),\n };\n}\n\nconst A = 40487.57;\nconst B = 0.00007096758;\nconst C = 91610.74;\nconst D = -40467.74;\n\n/**\n * Compute the camera level at a given height.\n */\nfunction computeLevel(height: number): number {\n return D + (A - D) / (1 + (height / C) ** B);\n}\n","import type { Ref } from 'vue';\nimport { watchThrottled } from '@vueuse/core';\nimport { computed, readonly, ref, shallowRef } from 'vue';\nimport { useCesiumEventListener } from '../useCesiumEventListener';\nimport { useViewer } from '../useViewer';\n\nexport interface UseCesiumFpsOptions {\n /**\n * Throttled sampling (ms)\n * @default 100\n */\n delay?: number;\n}\n\nexport interface UseCesiumFpsReturn {\n /**\n * Inter-frame Interval (ms)\n */\n interval: Readonly<Ref<number>>;\n\n /**\n * Frames Per Second\n */\n fps: Readonly<Ref<number>>;\n}\n\n/**\n * Reactive get the frame rate of Cesium\n * @param options options\n * @returns Reactive fps states\n */\nexport function useCesiumFps(options: UseCesiumFpsOptions = {}): UseCesiumFpsReturn {\n const { delay = 100 } = options;\n\n const viewer = useViewer();\n const p = shallowRef(performance.now());\n\n useCesiumEventListener(\n () => viewer.value?.scene.postRender,\n () => p.value = performance.now(),\n );\n\n const interval = ref(0);\n\n watchThrottled(p, (value, oldValue) => {\n interval.value = value - oldValue;\n }, {\n throttle: delay,\n });\n\n const fps = computed(() => {\n return 1000 / interval.value;\n });\n\n return {\n interval: readonly(interval),\n fps,\n };\n}\n","import type { ShallowReactive } from 'vue';\nimport { isPromise } from '@vesium/shared';\nimport { tryOnScopeDispose } from '@vueuse/core';\nimport { shallowReactive, shallowReadonly } from 'vue';\n\nexport type EffcetRemovePredicate<T> = (instance: T) => boolean;\n\nexport interface UseCollectionScopeOptions<\n T,\n AddArgs extends any[] = any[],\n RemoveArgs extends any[] = [],\n RemoveReturn = any,\n> {\n /**\n * add SideEffect function. e.g. `entities.add`\n */\n addEffect: (instance: T | Promise<T>, ...args: AddArgs) => T | Promise<T>;\n\n /**\n * Clean SideEffect function. eg.`entities.remove`\n */\n removeEffect: (instance: T, ...args: RemoveArgs) => RemoveReturn;\n\n /**\n * The parameters to pass for `removeScope` triggered when the component is unmounted\n */\n removeScopeArgs?: RemoveArgs;\n}\n\nexport interface UseCollectionScopeReturn<\n T,\n AddArgs extends any[],\n RemoveArgs extends any[],\n RemoveReturn = any,\n> {\n /**\n * A `Set` for storing SideEffect instance,\n * which is encapsulated using `ShallowReactive` to provide Vue's reactive functionality\n */\n scope: Readonly<ShallowReactive<Set<T>>>;\n\n /**\n * Add SideEffect instance\n */\n add: <R extends T | Promise<T>>(instance: R, ...args: AddArgs) => R extends Promise<infer U> ? Promise<U> : T;\n\n /**\n * Remove specified SideEffect instance\n */\n remove: (instance: T, ...args: RemoveArgs) => RemoveReturn;\n\n /**\n * Remove all SideEffect instance that meets the specified criteria\n */\n removeWhere: (predicate: EffcetRemovePredicate<T>, ...args: RemoveArgs) => void;\n\n /**\n * Remove all SideEffect instance within current scope\n */\n removeScope: (...args: RemoveArgs) => void;\n}\n\n/**\n * Scope the SideEffects of Cesium-related `Collection` and automatically remove them when unmounted.\n * - note: This is a basic function that is intended to be called by other lower-level function\n * @returns Contains side effect addition and removal functions\n */\nexport function useCollectionScope<\n T,\n AddArgs extends any[] = any[],\n RemoveArgs extends any[] = [],\n RemoveReturn = any,\n>(\n options: UseCollectionScopeOptions<T, AddArgs, RemoveArgs, RemoveReturn>,\n): UseCollectionScopeReturn<T, AddArgs, RemoveArgs, RemoveReturn> {\n const { addEffect, removeEffect, removeScopeArgs } = options;\n const scope = shallowReactive(new Set<T>());\n const add = (instance: T | Promise<T>, ...args: AddArgs) => {\n const result = addEffect(instance, ...args);\n // 可能为promise 如dataSource\n if (isPromise(result)) {\n return new Promise<T>((resolve, reject) => {\n result.then((i: T) => {\n scope.add(i);\n resolve(i);\n }).catch(error => reject(error));\n });\n }\n else {\n scope.add(result as T);\n return result;\n }\n };\n\n const remove: typeof removeEffect = (instance, ...args) => {\n scope.delete(instance);\n return removeEffect(instance, ...args);\n };\n\n const removeWhere = (predicate: EffcetRemovePredicate<T>, ...args: RemoveArgs) => {\n for (const instance of Array.from(scope)) {\n if (predicate(instance)) {\n remove(instance, ...args);\n }\n }\n };\n\n const removeScope = (...args: RemoveArgs) => {\n for (const instance of Array.from(scope)) {\n remove(instance, ...args);\n }\n };\n\n tryOnScopeDispose(() => removeScope(...(removeScopeArgs ?? [] as RemoveArgs)));\n\n return {\n scope: shallowReadonly(scope),\n add: add as UseCollectionScopeReturn<T, AddArgs, RemoveArgs, RemoveReturn>['add'],\n remove,\n removeWhere,\n removeScope,\n };\n}\n","import type { CesiumDataSource } from '@vesium/shared';\nimport type { Arrayable } from '@vueuse/core';\nimport type { DataSourceCollection } from 'cesium';\nimport type { ComputedRef, MaybeRefOrGetter, Ref } from 'vue';\nimport type { MaybeRefOrAsyncGetter } from '../toPromiseValue';\nimport { computedAsync } from '@vueuse/core';\nimport { toValue, watchEffect } from 'vue';\nimport { toPromiseValue } from '../toPromiseValue';\nimport { useViewer } from '../useViewer';\n\nexport interface UseDataSourceOptions {\n /**\n * The collection of DataSource to be added\n * @default useViewer().value.dataSources\n */\n collection?: DataSourceCollection;\n\n /**\n * default value of `isActive`\n * @default true\n */\n isActive?: MaybeRefOrGetter<boolean>;\n\n /**\n * Ref passed to receive the updated of async evaluation\n */\n evaluating?: Ref<boolean>;\n\n /**\n * The second parameter passed to the `remove` function\n *\n * `dataSources.remove(dataSource,destroyOnRemove)`\n */\n destroyOnRemove?: MaybeRefOrGetter<boolean>;\n\n}\n\n/**\n * Add `DataSource` to the `DataSourceCollection`, automatically update when the data changes, and destroy the side effects caused by the previous `DataSource`.\n *\n * Overload 1: Parameter supports passing in a single value.\n *\n * @param dataSource The `DataSource` to added\n * @param options additional options\n *\n * @returns computedRef of the `DataSource`\n *\n * @overload\n */\nexport function useDataSource<T extends CesiumDataSource = CesiumDataSource>(\n dataSource?: MaybeRefOrAsyncGetter<T | undefined>,\n options?: UseDataSourceOptions,\n): ComputedRef<T | undefined>;\n\n/**\n * Add `DataSource` to the `DataSourceCollection`, automatically update when the data changes, and destroy the side effects caused by the previous `DataSource`.\n *\n * Overload 2: Parameter supports passing in an array.\n *\n * @param dataSources The list of `DataSource` to added\n * @param options additional options\n *\n * @returns computedRef of the `DataSource`\n *\n * @overload\n */\nexport function useDataSource<T extends CesiumDataSource = CesiumDataSource>(\n dataSources?: MaybeRefOrAsyncGetter<T[] | undefined>,\n options?: UseDataSourceOptions,\n): ComputedRef<T[] | undefined>;\n\nexport function useDataSource<T extends CesiumDataSource>(\n dataSources?: MaybeRefOrAsyncGetter<Arrayable<T | undefined>>,\n options: UseDataSourceOptions = {},\n) {\n const {\n destroyOnRemove,\n collection,\n isActive = true,\n evaluating,\n } = options;\n\n const result = computedAsync(\n () => toPromiseValue(dataSources),\n undefined,\n {\n evaluating,\n },\n );\n\n const viewer = useViewer();\n\n watchEffect((onCleanup) => {\n const _isActive = toValue(isActive);\n if (_isActive) {\n const list = Array.isArray(result.value) ? [...result.value] : [result.value];\n const _collection = collection ?? viewer.value?.dataSources;\n list.forEach(item => (item && _collection?.add(item)));\n onCleanup(() => {\n const destroy = toValue(destroyOnRemove);\n !_collection?.isDestroyed() && list.forEach(dataSource => dataSource && _collection?.remove(dataSource, destroy));\n });\n }\n });\n\n return result;\n}\n","import type { CesiumDataSource } from '@vesium/shared';\nimport type { DataSourceCollection } from 'cesium';\nimport type { MaybeRefOrGetter } from 'vue';\nimport { isPromise } from '@vesium/shared';\nimport { computed, toValue } from 'vue';\nimport { useCollectionScope } from '../useCollectionScope';\nimport { useViewer } from '../useViewer';\n\nexport interface UseDataSourceScopeOptions {\n /**\n * The collection of DataSource to be added\n * @default useViewer().value.dataSources\n */\n collection?: MaybeRefOrGetter<DataSourceCollection | undefined>;\n\n /**\n * The second parameter passed to the `remove` function\n *\n * `dataSources.remove(dataSource,destroyOnRemove)`\n */\n destroyOnRemove?: boolean;\n}\n\n/**\n * Scope the SideEffects of `DataSourceCollection` operations and automatically remove them when unmounted\n */\nexport function useDataSourceScope(options: UseDataSourceScopeOptions = {}) {\n const { collection: _collection, destroyOnRemove } = options;\n const viewer = useViewer();\n\n const collection = computed(() => {\n return toValue(_collection) ?? viewer.value?.dataSources;\n });\n\n return useCollectionScope<CesiumDataSource, [], [destroy?: boolean], boolean>({\n addEffect(instance) {\n if (!collection.value) {\n throw new Error('collection is not defined');\n }\n\n if (isPromise(instance)) {\n return new Promise<CesiumDataSource>((resolve, reject) => {\n instance.then((i) => {\n try {\n collection.value!.add(i);\n resolve(i);\n }\n catch (error) {\n reject(error);\n }\n }).catch(error => reject(error));\n });\n }\n else {\n collection.value.add(instance);\n return instance;\n }\n },\n removeEffect(instance, destroy) {\n return !!collection.value?.remove(instance, destroy);\n },\n removeScopeArgs: [destroyOnRemove],\n });\n}\n","import type { CommonCoord } from '@vesium/shared';\nimport type { MaybeComputedElementRef } from '@vueuse/core';\nimport type { ComputedRef, MaybeRefOrGetter } from 'vue';\nimport { cartesianToCanvasCoord, toCartesian3 } from '@vesium/shared';\nimport { unrefElement, useElementBounding, useElementSize } from '@vueuse/core';\nimport { Cartesian2 } from 'cesium';\nimport { computed, shallowRef, toValue, watchEffect } from 'vue';\nimport { useCesiumEventListener } from '../useCesiumEventListener';\nimport { useViewer } from '../useViewer';\n\nexport interface UseElementOverlayOptions {\n /**\n * Horizontal origin of the target element\n * @default `center`\n */\n horizontal?: MaybeRefOrGetter<'center' | 'left' | 'right' | undefined>;\n\n /**\n * Vertical origin of the target element\n * @default `bottom`\n */\n vertical?: MaybeRefOrGetter<'center' | 'bottom' | 'top' | undefined>;\n\n /**\n * Pixel offset presented by the target element\n * @default {x:0,y:0}\n */\n offset?: MaybeRefOrGetter<{ x?: number; y?: number } | undefined>;\n\n /**\n * The reference element for calculating the position of the target element\n * - `true` refer to the browser viewport\n * - `false` refer to the Cesium canvas\n */\n referenceWindow?: MaybeRefOrGetter<boolean>;\n\n /**\n * Whether to apply style to the target element\n * @default true\n */\n applyStyle?: MaybeRefOrGetter<boolean>;\n\n /**\n * The position will be clamped to the ground\n *\n */\n clampToGround?: MaybeRefOrGetter<boolean>;\n}\n\nexport interface UseElementOverlayReturn {\n /**\n * Calculation result of the target element's horizontal direction\n */\n x: ComputedRef<number>;\n\n /**\n * Calculation result of the target element's vertical direction\n */\n y: ComputedRef<number>;\n\n /**\n * Calculation `css` of the target element\n */\n style: ComputedRef<string | undefined>;\n}\n\n/**\n * Cesium HTMLElement Overlay\n */\nexport function useElementOverlay(\n target?: MaybeComputedElementRef,\n position?: MaybeRefOrGetter<CommonCoord | undefined>,\n options: UseElementOverlayOptions = {},\n): UseElementOverlayReturn {\n const {\n referenceWindow,\n horizontal = 'center',\n vertical = 'bottom',\n clampToGround,\n offset = { x: 0, y: 0 },\n } = options;\n\n const viewer = useViewer();\n\n const cartesian3 = computed(() => {\n const positionValue = toValue(position);\n if (!positionValue) {\n return undefined;\n }\n return toCartesian3(positionValue);\n });\n\n const coord = shallowRef<Cartesian2>();\n\n useCesiumEventListener(\n () => viewer.value?.scene.postUpdate,\n () => {\n const scene = viewer.value?.scene;\n if (!scene || !cartesian3.value) {\n coord.value = undefined;\n return;\n }\n\n let finalPosition = toValue(clampToGround) ? scene.clampToHeight(cartesian3.value) : cartesian3.value;\n finalPosition ??= cartesian3.value;\n const result = cartesianToCanvasCoord(finalPosition, scene);\n if (result) {\n result.x = +result.x.toFixed(1);\n result.y = +result.y.toFixed(1);\n coord.value = !Cartesian2.equals(result, coord.value) ? result : coord.value;\n }\n },\n );\n\n const canvasBounding = useElementBounding(() => viewer.value?.canvas.parentElement);\n const targetSize = useElementSize(target, undefined, { box: 'border-box' });\n\n const finalOffset = computed(() => {\n const _offset = toValue(offset);\n let x = _offset?.x ?? 0;\n const _horizontal = toValue(horizontal);\n if (_horizontal === 'center') {\n x -= targetSize.width.value / 2;\n }\n else if (_horizontal === 'right') {\n x -= targetSize.width.value;\n }\n\n let y = _offset?.y ?? 0;\n const _vertical = toValue(vertical);\n if (_vertical === 'center') {\n y -= targetSize.height.value / 2;\n }\n else if (_vertical === 'bottom') {\n y -= targetSize.height.value;\n }\n\n return {\n x,\n y,\n };\n });\n\n const x = computed(() => {\n let v = coord.value?.x ?? 0;\n if (toValue(referenceWindow)) {\n v += canvasBounding.x.value;\n }\n return +(v + finalOffset.value.x).toFixed(1);\n });\n\n const y = computed(() => {\n let v = coord.value?.y ?? 0;\n if (toValue(referenceWindow)) {\n v += canvasBounding.y.value;\n }\n return +(v + finalOffset.value.y).toFixed(1);\n });\n\n const style = computed(() => `left:${x.value}px;top:${y.value}px;`);\n\n watchEffect(() => {\n const applyStyle = toValue(options.applyStyle ?? true);\n if (!applyStyle) {\n return;\n }\n const element = unrefElement(target);\n if (element && applyStyle) {\n element.style?.setProperty?.('left', `${x.value}px`);\n element.style?.setProperty?.('top', `${y.value}px`);\n }\n }, {\n flush: 'post',\n });\n\n return {\n x,\n y,\n style,\n };\n}\n","import type { Arrayable } from '@vueuse/core';\nimport type { Entity, EntityCollection } from 'cesium';\nimport type { ComputedRef, MaybeRefOrGetter, Ref } from 'vue';\nimport type { MaybeRefOrAsyncGetter } from '../toPromiseValue';\nimport { computedAsync } from '@vueuse/core';\nimport { toValue, watchEffect } from 'vue';\nimport { toPromiseValue } from '../toPromiseValue';\nimport { useViewer } from '../useViewer';\n\nexport interface UseEntityOptions {\n /**\n * The collection of Entity to be added\n * @default useViewer().value.entities\n */\n collection?: EntityCollection;\n\n /**\n * default value of `isActive`\n * @default true\n */\n isActive?: MaybeRefOrGetter<boolean>;\n\n /**\n * Ref passed to receive the updated of async evaluation\n */\n evaluating?: Ref<boolean>;\n}\n\n/**\n * Add `Entity` to the `EntityCollection`, automatically update when the data changes, and destroy the side effects caused by the previous `Entity`.\n *\n * Overload 1: Parameter supports passing in a single value.\n */\nexport function useEntity<T extends Entity = Entity>(\n entity?: MaybeRefOrAsyncGetter<T | undefined>,\n options?: UseEntityOptions,\n): ComputedRef<T | undefined>;\n\n/**\n * Add `Entity` to the `EntityCollection`, automatically update when the data changes, and destroy the side effects caused by the previous `Entity`.\n *\n * Overload 2: Parameter supports passing in an array.\n */\nexport function useEntity<T extends Entity = Entity>(\n entities?: MaybeRefOrAsyncGetter<Array<T | undefined> | undefined>,\n options?: UseEntityOptions,\n): ComputedRef<T[] | undefined>;\n\nexport function useEntity<T extends Entity>(\n data?: MaybeRefOrAsyncGetter<Arrayable<T | undefined>>,\n options: UseEntityOptions = {},\n) {\n const { collection, isActive = true, evaluating } = options;\n\n const result = computedAsync(\n () => toPromiseValue(data),\n [],\n {\n evaluating,\n },\n );\n\n const viewer = useViewer();\n\n watchEffect((onCleanup) => {\n const _isActive = toValue(isActive);\n if (_isActive) {\n const list = Array.isArray(result.value) ? [...result.value] : [result.value];\n const _collection = collection ?? viewer.value?.entities;\n list.forEach(item => (item && _collection?.add(item)));\n onCleanup(() => {\n list.forEach(item => item && _collection?.remove(item));\n });\n }\n });\n\n return result;\n}\n","import type { Entity, EntityCollection } from 'cesium';\nimport type { MaybeRefOrGetter } from 'vue';\nimport { isPromise } from '@vesium/shared';\nimport { computed, toValue } from 'vue';\nimport { useCollectionScope } from '../useCollectionScope';\nimport { useViewer } from '../useViewer';\n\nexport interface UseEntityScopeOptions {\n /**\n * The collection of Entity to be added\n * @default useViewer().value.entities\n */\n collection?: MaybeRefOrGetter<EntityCollection | undefined>;\n}\n\n/**\n * Make `add` and `remove` operations of `EntityCollection` scoped,\n * automatically remove `Entity` instance when component is unmounted.\n */\nexport function useEntityScope(options: UseEntityScopeOptions = {}) {\n const { collection: _collection } = options;\n const viewer = useViewer();\n\n const collection = computed(() => {\n return toValue(_collection) ?? viewer.value?.entities;\n });\n\n return useCollectionScope<Entity>({\n addEffect(instance) {\n if (!collection.value) {\n throw new Error('collection is not defined');\n }\n\n if (isPromise(instance)) {\n return new Promise<Entity>((resolve, reject) => {\n instance.then((i) => {\n collection.value.add(i);\n resolve(i);\n }).catch(error => reject(error));\n });\n }\n else {\n collection.value.add(instance);\n return instance;\n }\n },\n removeEffect(instance) {\n return !!collection.value?.remove(instance);\n },\n removeScopeArgs: [],\n });\n}\n","import type { ScenePickResult } from '@vesium/shared';\nimport type { Cartesian2, Viewer } from 'cesium';\nimport type { MaybeRefOrGetter, ShallowRef } from 'vue';\nimport { refThrottled } from '@vueuse/core';\nimport { computed, shallowRef, toRef, toValue, watchEffect } from 'vue';\nimport { useViewer } from '../useViewer';\n\nexport interface UseScenePickOptions {\n /**\n * Whether to active the event listener.\n * @default true\n */\n isActive?: MaybeRefOrGetter<boolean>;\n /**\n * Throttled sampling (ms)\n * @default 8\n */\n throttled?: number;\n\n /**\n * The width of the pick rectangle.\n * @default 3\n */\n width?: MaybeRefOrGetter<number | undefined>;\n\n /**\n * The height of the pick rectangle.\n * @default 3\n */\n height?: MaybeRefOrGetter<number | undefined>;\n\n}\n\ninterface PickCacheEntry {\n position: Cartesian2;\n width: number | undefined;\n height: number | undefined;\n pick: ScenePickResult | undefined;\n}\n\n// Cache the most recent pick for the same viewer/position/size tuple so throttled cursor updates\n// do not keep calling scene.pick while the screen inputs are unchanged.\nconst pickCache = new WeakMap<Viewer, PickCacheEntry>();\n\n/**\n * Uses the `scene.pick` function in Cesium's Scene object to perform screen point picking,\n * return a computed property containing the pick result, or undefined if no object is picked.\n *\n * @param windowPosition The screen coordinates of the pick point.\n */\nexport function useScenePick(\n windowPosition: MaybeRefOrGetter<Cartesian2 | undefined>,\n options: UseScenePickOptions = {},\n): Readonly<ShallowRef<ScenePickResult | undefined>> {\n const { width = 3, height = 3, throttled = 8 } = options;\n\n const isActive = toRef(options.isActive ?? true);\n\n const viewer = useViewer();\n\n const position = refThrottled(computed(() => toValue(windowPosition)?.clone()), throttled, false, true);\n\n const pick = shallowRef<ScenePickResult | undefined>();\n watchEffect(() => {\n if (viewer.value && position.value && isActive.value) {\n const widthValue = toValue(width);\n const heightValue = toValue(height);\n const cache = pickCache.get(viewer.value);\n if (cache && cache.position.equals(position.value) && cache.width === widthValue && cache.height === heightValue) {\n pick.value = cache.pick;\n }\n else {\n try {\n const nextPick = viewer.value?.scene.pick(\n position.value,\n widthValue,\n heightValue,\n );\n pick.value = nextPick;\n pickCache.set(viewer.value, {\n position: position.value.clone(),\n width: widthValue,\n height: heightValue,\n pick: nextPick,\n });\n }\n catch (error) {\n console.error('[useScenePick] Error during pick:', error);\n pick.value = undefined;\n }\n }\n }\n else {\n pick.value = undefined;\n }\n });\n return pick;\n}\n","import type { KeyboardEventModifier, ScreenSpaceEventType } from 'cesium';\nimport type { MaybeRefOrGetter, WatchStopHandle } from 'vue';\nimport { isDef } from '@vesium/shared';\nimport { tryOnScopeDispose } from '@vueuse/core';\nimport { ScreenSpaceEventHandler } from 'cesium';\nimport { computed, toRef, toValue, watch, watchEffect } from 'vue';\nimport { useViewer } from '../useViewer';\n\nexport type ScreenSpaceEvent<T extends ScreenSpaceEventType> = {\n [ScreenSpaceEventType.LEFT_DOWN]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.LEFT_UP]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.LEFT_CLICK]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.LEFT_DOUBLE_CLICK]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.RIGHT_DOWN]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.RIGHT_UP]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.RIGHT_CLICK]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.MIDDLE_DOWN]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.MIDDLE_UP]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.MIDDLE_CLICK]: ScreenSpaceEventHandler.PositionedEvent;\n [ScreenSpaceEventType.MOUSE_MOVE]: ScreenSpaceEventHandler.MotionEvent;\n [ScreenSpaceEventType.WHEEL]: number;\n [ScreenSpaceEventType.PINCH_START]: ScreenSpaceEventHandler.TwoPointEvent;\n [ScreenSpaceEventType.PINCH_END]: ScreenSpaceEventHandler.TwoPointEvent;\n [ScreenSpaceEventType.PINCH_MOVE]: ScreenSpaceEventHandler.TwoPointMotionEvent;\n}[T];\n\nexport interface UseScreenSpaceEventHandlerOptions {\n /**\n * Modifier key forwarded to Cesium.\n */\n modifier?: MaybeRefOrGetter<KeyboardEventModifier | undefined>;\n\n /**\n * Whether to activate the event listener without tearing down the composable.\n * @default true\n */\n isActive?: MaybeRefOrGetter<boolean>;\n}\n\n/**\n * Easily use the `ScreenSpaceEventHandler`,\n * when the dependent data changes or the component is unmounted,\n * the listener function will automatically reload or destroy.\n *\n * @param type Types of mouse event\n * @param inputAction Callback function for listening\n */\nexport function useScreenSpaceEventHandler<T extends ScreenSpaceEventType>(\n type?: MaybeRefOrGetter<T | undefined>,\n inputAction?: (event: ScreenSpaceEvent<T>) => any,\n options: UseScreenSpaceEventHandlerOptions = {},\n): WatchStopHandle {\n const { modifier } = options;\n const viewer = useViewer();\n const isActive = toRef(options.isActive ?? true);\n // Keep a strong reference to the latest handler so scope disposal can destroy it even if the\n // computed ref has already been cleared by a viewer/canvas change.\n let currentHandler: ScreenSpaceEventHandler | undefined;\n\n // Recreate the handler whenever the canvas becomes available or changes.\n const handler = computed(() => {\n if (viewer.value?.cesiumWidget?.canvas) {\n return new ScreenSpaceEventHandler(viewer.value.cesiumWidget.canvas);\n }\n });\n\n const cleanup1 = watch(handler, (_value, previous) => {\n previous?.destroy();\n currentHandler = _value;\n });\n\n const cleanup2 = watchEffect((onCleanup) => {\n const typeValue = toValue(type);\n const modifierValue = toValue(modifier);\n const handlerValue = toValue(handler);\n currentHandler = handlerValue;\n if (!handlerValue || !isActive.value || !inputAction) {\n return;\n }\n if (isDef(typeValue)) {\n handlerValue.setInputAction(inputAction as any, typeValue, modifierValue);\n onCleanup(() => handlerValue!.removeInputAction(typeValue, modifierValue));\n }\n });\n\n const stop = () => {\n cleanup1();\n cleanup2();\n // Destroy the active instance after stopping the watchers; the computed ref may already\n // have been reset by the time stop() runs.\n currentHandler?.destroy();\n currentHandler = undefined;\n };\n\n tryOnScopeDispose(stop);\n\n return stop;\n}\n","import type { ScenePickResult } from '@vesium/shared';\nimport type { Cartesian2, ScreenSpaceEventHandler } from 'cesium';\nimport type { WatchStopHandle } from 'vue';\nimport { throttle } from '@vesium/shared';\nimport { tryOnScopeDispose } from '@vueuse/core';\nimport { ScreenSpaceEventType } from 'cesium';\nimport { nextTick, ref, shallowRef, watch } from 'vue';\nimport { useScenePick } from '../useScenePick';\nimport { useScreenSpaceEventHandler } from '../useScreenSpaceEventHandler';\nimport { useViewer } from '../useViewer';\n\n/**\n * Parameters for graphic drag events\n */\nexport interface GraphicDragEvent {\n /**\n * Event of the motion event\n */\n event: ScreenSpaceEventHandler.MotionEvent;\n\n /**\n * The graphic object picked by `scene.pick`\n */\n pick: ScenePickResult;\n\n /**\n * Whether the graphic is currently being dragged.\n */\n dragging: boolean;\n\n /**\n * Whether to lock the camera, Will automatically resume when you end dragging.\n */\n lockCamera: () => void;\n}\n\n/**\n * Use graphic drag events with ease, and remove listener automatically on unmounted.\n */\nexport function useDrag(\n listener: (params: GraphicDragEvent) => void,\n): WatchStopHandle {\n const position = shallowRef<Cartesian2>();\n const pick = useScenePick(position);\n const motionEvent = shallowRef<ScreenSpaceEventHandler.MotionEvent>();\n const dragging = ref(false);\n\n const viewer = useViewer();\n\n const cameraLocked = ref(false);\n\n watch(cameraLocked, (locked) => {\n viewer.value && (viewer.value.scene.screenSpaceCameraController.enableRotate = !locked);\n });\n\n const lockCamera = () => {\n cameraLocked.value = true;\n };\n\n const execute = (pickedValue: ScenePickResult, startPosition: Cartesian2, endPosition: Cartesian2) => {\n listener({\n event: {\n startPosition: startPosition.clone(),\n endPosition: endPosition.clone(),\n },\n pick: pickedValue,\n dragging: dragging.value,\n lockCamera,\n });\n // reset lockCamera\n nextTick(() => {\n if (!dragging.value && cameraLocked.value) {\n cameraLocked.value = false;\n }\n });\n };\n\n const stopLeftDownWatch = useScreenSpaceEventHandler(\n ScreenSpaceEventType.LEFT_DOWN,\n (event) => {\n dragging.value = true;\n position.value = event.position.clone();\n },\n );\n\n const stopMouseMoveWatch = useScreenSpaceEventHandler(\n ScreenSpaceEventType.MOUSE_MOVE,\n throttle(({ startPosition, endPosition }) => {\n motionEvent.value = {\n startPosition: motionEvent.value?.endPosition.clone() || startPosition.clone(),\n endPosition: endPosition.clone(),\n };\n }, 8, false, true),\n );\n\n // dragging\n watch([pick, motionEvent], ([pickValue, motionValue]) => {\n if (pickValue && motionValue) {\n const { startPosition, endPosition } = motionValue;\n dragging.value && execute(pickValue, startPosition, endPosition);\n }\n });\n\n // drag end\n const stopLeftUpWatch = useScreenSpaceEventHandler(\n ScreenSpaceEventType.LEFT_UP,\n (event) => {\n dragging.value = false;\n\n if (pick.value && motionEvent.value) {\n execute(pick.value, motionEvent.value.endPosition, event.position);\n }\n position.value = undefined;\n motionEvent.value = undefined;\n },\n );\n\n const stop = () => {\n stopLeftDownWatch();\n stopMouseMoveWatch();\n stopLeftUpWatch();\n };\n\n tryOnScopeDispose(stop);\n\n return stop;\n}\n","import type { ScenePickResult } from '@vesium/shared';\nimport type { Cartesian2, ScreenSpaceEventHandler } from 'cesium';\nimport { ScreenSpaceEventType } from 'cesium';\nimport { shallowRef, watch } from 'vue';\nimport { useScenePick } from '../useScenePick';\nimport { useScreenSpaceEventHandler } from '../useScreenSpaceEventHandler';\n\n/**\n * Parameters for graphic hover events\n */\nexport interface GraphicHoverEvent {\n /**\n * Event of the motion event\n */\n event: ScreenSpaceEventHandler.MotionEvent;\n\n /**\n * The graphic object picked by `scene.pick`\n */\n pick: ScenePickResult;\n\n /**\n * Whether the graphic is currently being hoverged. Returns `true` continuously while hoverging, and `false` once it ends.\n */\n hovering: boolean;\n\n}\n\n/**\n * Use graphic hover events with ease, and remove listener automatically on unmounted.\n */\nexport function useHover(\n listener: (params: GraphicHoverEvent) => void,\n) {\n const motionEvent = shallowRef<ScreenSpaceEventHandler.MotionEvent>();\n const pick = useScenePick(() => motionEvent.value?.endPosition);\n\n const execute = (pickedValue: ScenePickResult, startPosition: Cartesian2, endPosition: Cartesian2, hovering: boolean) => {\n listener({\n event: {\n startPosition: startPosition.clone(),\n endPosition: endPosition.clone(),\n },\n pick: pickedValue,\n hovering,\n });\n };\n\n useScreenSpaceEventHandler(\n ScreenSpaceEventType.MOUSE_MOVE,\n ({ startPosition, endPosition }) => {\n const prevStart = motionEvent.value?.startPosition;\n const prevEnd = motionEvent.value?.endPosition;\n if (!prevStart || !prevEnd || !startPosition.equals(prevStart) || !endPosition.equals(prevEnd)) {\n motionEvent.value = { startPosition: startPosition.clone(), endPosition: endPosition.clone() };\n }\n },\n );\n\n // hovering\n watch([pick, motionEvent], ([pickValue, motionValue]) => {\n if (pickValue && motionValue) {\n const { startPosition, endPosition } = motionValue;\n execute(pickValue, startPosition, endPosition, true);\n }\n });\n\n // hover end\n watch(pick, (pickValue, prevPick) => {\n if (prevPick && motionEvent.value) {\n const { startPosition, endPosition } = motionEvent.value;\n execute(prevPick, startPosition, endPosition, false);\n }\n });\n}\n","import type { ScenePickResult } from '@vesium/shared';\nimport type { ScreenSpaceEventHandler } from 'cesium';\nimport { ScreenSpaceEventType } from 'cesium';\nimport { useScreenSpaceEventHandler } from '../useScreenSpaceEventHandler';\nimport { useViewer } from '../useViewer';\n\nexport type PositionedEventType = 'LEFT_DOWN' | 'LEFT_UP' | 'LEFT_CLICK' | 'LEFT_DOUBLE_CLICK' | 'RIGHT_DOWN' | 'RIGHT_UP' | 'RIGHT_CLICK' | 'MIDDLE_DOWN' | 'MIDDLE_UP' | 'MIDDLE_CLICK';\n\ntype PositionedScreenSpaceEventType\n = ScreenSpaceEventType.LEFT_DOWN\n | ScreenSpaceEventType.LEFT_UP\n | ScreenSpaceEventType.LEFT_CLICK\n | ScreenSpaceEventType.LEFT_DOUBLE_CLICK\n | ScreenSpaceEventType.RIGHT_DOWN\n | ScreenSpaceEventType.RIGHT_UP\n | ScreenSpaceEventType.RIGHT_CLICK\n | ScreenSpaceEventType.MIDDLE_DOWN\n | ScreenSpaceEventType.MIDDLE_UP\n | ScreenSpaceEventType.MIDDLE_CLICK;\n\n/**\n * @internal\n */\nconst EVENT_TYPE_RECORD: Record<PositionedEventType, PositionedScreenSpaceEventType> = {\n LEFT_DOWN: ScreenSpaceEventType.LEFT_DOWN,\n LEFT_UP: ScreenSpaceEventType.LEFT_UP,\n LEFT_CLICK: ScreenSpaceEventType.LEFT_CLICK,\n LEFT_DOUBLE_CLICK: ScreenSpaceEventType.LEFT_DOUBLE_CLICK,\n RIGHT_DOWN: ScreenSpaceEventType.RIGHT_DOWN,\n RIGHT_UP: ScreenSpaceEventType.RIGHT_UP,\n RIGHT_CLICK: ScreenSpaceEventType.RIGHT_CLICK,\n MIDDLE_DOWN: ScreenSpaceEventType.MIDDLE_DOWN,\n MIDDLE_UP: ScreenSpaceEventType.MIDDLE_UP,\n MIDDLE_CLICK: ScreenSpaceEventType.MIDDLE_CLICK,\n};\n\n/**\n * Parameters for graphics click related events\n */\nexport interface GraphicPositionedEvent {\n /**\n * Event of the picked area\n */\n event: ScreenSpaceEventHandler.PositionedEvent;\n /**\n * The graphic object picked by `scene.pick`\n */\n pick: ScenePickResult;\n}\n\nexport function usePositioned(\n type: PositionedEventType,\n listener: (params: GraphicPositionedEvent) => void,\n) {\n const screenEvent = EVENT_TYPE_RECORD[type];\n const viewer = useViewer();\n useScreenSpaceEventHandler(screenEvent, (event) => {\n const position = event.position;\n const pick = viewer.value?.scene.pick(position);\n pick && position && listener({ event: { position }, pick: pick as ScenePickResult });\n });\n}\n","import type { AnyFn, Nullable } from '@vesium/shared';\nimport type { Entity } from 'cesium';\nimport type { GraphicDragEvent } from './useDrag';\nimport type { GraphicHoverEvent } from './useHover';\nimport type { GraphicPositionedEvent, PositionedEventType } from './usePositioned';\nimport { isDef, isFunction, resolvePick, tryRun } from '@vesium/shared';\nimport { ref } from 'vue';\nimport { useViewer } from '../useViewer';\nimport { useDrag } from './useDrag';\nimport { useHover } from './useHover';\nimport { usePositioned } from './usePositioned';\n\ntype GlobalGraphicSymbol = symbol;\n\nexport type CesiumGraphic = Entity | any;\n\nexport type GraphicEventType = PositionedEventType | 'HOVER' | 'DRAG';\n\nconst GLOBAL_GRAPHIC_SYMBOL: GlobalGraphicSymbol = Symbol('GLOBAL_GRAPHIC_SYMBOL');\n\nconst POSITIONED_EVENT_TYPES: PositionedEventType[] = [\n 'LEFT_DOWN',\n 'LEFT_UP',\n 'LEFT_CLICK',\n 'LEFT_DOUBLE_CLICK',\n 'RIGHT_DOWN',\n 'RIGHT_UP',\n 'RIGHT_CLICK',\n 'MIDDLE_DOWN',\n 'MIDDLE_UP',\n 'MIDDLE_CLICK',\n];\n\nexport type GraphicEventListener<T extends GraphicEventType>\n = T extends 'DRAG' ? (event: GraphicDragEvent) => void\n : T extends 'HOVER' ? (event: GraphicHoverEvent) => void\n : (event: GraphicPositionedEvent) => void;\n\nexport type removeFn = () => void;\n\nexport interface AddGraphicEventOptions {\n /**\n * The cursor style to use when the mouse is over the graphic.\n * @default 'pointer'\n */\n c