vesium
Version:
Core Vue composition hooks for Cesium
1,057 lines (1,056 loc) • 40.2 kB
JavaScript
(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