UNPKG

resium

Version:

React components for Cesium

287 lines (252 loc) 8.16 kB
import { ScreenSpaceEventType, ScreenSpaceEventHandler, Scene, Cartesian2, Primitive, Entity, PrimitiveCollection, Cesium3DTileFeature, PointPrimitiveCollection, LabelCollection, BillboardCollection, PolylineCollection, PointPrimitive, Label, Billboard, Polyline, TimeDynamicPointCloud, ModelMesh, ModelNode, GroundPolylinePrimitive, GroundPrimitive, } from "cesium"; import { entries, includes } from "./util"; export const eventManagerContextKey = "__RESIUM_EVENT_MANAGER"; export type EventType = keyof RootEventProps; export type RootEventTarget = | Cesium3DTileFeature | { collection?: | PrimitiveCollection | PointPrimitiveCollection | LabelCollection | BillboardCollection | PolylineCollection; id?: Entity | string; mesh?: ModelMesh; node?: ModelNode; primitive?: | Primitive | PointPrimitive | Label | Billboard | Polyline | TimeDynamicPointCloud | GroundPolylinePrimitive | GroundPrimitive; }; export type EventProps<T> = { onClick?: (movement: CesiumMovementEvent, target: T) => void; onDoubleClick?: (movement: CesiumMovementEvent, target: T) => void; onMouseDown?: (movement: CesiumMovementEvent, target: T) => void; onMouseUp?: (movement: CesiumMovementEvent, target: T) => void; onMiddleClick?: (movement: CesiumMovementEvent, target: T) => void; onMiddleDown?: (movement: CesiumMovementEvent, target: T) => void; onMiddleUp?: (movement: CesiumMovementEvent, target: T) => void; onMouseMove?: (movement: CesiumMovementEvent, target: T) => void; onPinchEnd?: (movement: CesiumMovementEvent, target: T) => void; onPinchMove?: (movement: CesiumMovementEvent, target: T) => void; onPinchStart?: (movement: CesiumMovementEvent, target: T) => void; onRightClick?: (movement: CesiumMovementEvent, target: T) => void; onRightDown?: (movement: CesiumMovementEvent, target: T) => void; onRightUp?: (movement: CesiumMovementEvent, target: T) => void; onMouseEnter?: (movement: CesiumMovementEvent, target: T) => void; onMouseLeave?: (movement: CesiumMovementEvent, target: T) => void; }; export type RootEventProps = EventProps<RootEventTarget> & { onWheel?: (delta: number) => void; }; type EventMap<T> = { [k in EventType]: T }; export type CesiumMovementEvent = { position?: Cartesian2; startPosition?: Cartesian2; endPosition?: Cartesian2; }; export type Callback<T = any> = (e: CesiumMovementEvent, source: T) => void; export const eventNames: EventType[] = [ "onClick", "onDoubleClick", "onMouseDown", "onMouseUp", "onMiddleClick", "onMiddleDown", "onMiddleUp", "onMouseMove", "onPinchEnd", "onPinchMove", "onPinchStart", "onRightClick", "onRightDown", "onRightUp", "onWheel", "onMouseEnter", "onMouseLeave", ]; export class EventManager { private static eventTypeMap: EventMap<ScreenSpaceEventType> = { onClick: ScreenSpaceEventType.LEFT_CLICK, onDoubleClick: ScreenSpaceEventType.LEFT_DOUBLE_CLICK, onMouseDown: ScreenSpaceEventType.LEFT_DOWN, onMouseUp: ScreenSpaceEventType.LEFT_UP, onMiddleClick: ScreenSpaceEventType.MIDDLE_CLICK, onMiddleDown: ScreenSpaceEventType.MIDDLE_DOWN, onMiddleUp: ScreenSpaceEventType.MIDDLE_UP, onMouseMove: ScreenSpaceEventType.MOUSE_MOVE, onPinchEnd: ScreenSpaceEventType.PINCH_END, onPinchMove: ScreenSpaceEventType.PINCH_MOVE, onPinchStart: ScreenSpaceEventType.PINCH_START, onRightClick: ScreenSpaceEventType.RIGHT_CLICK, onRightDown: ScreenSpaceEventType.RIGHT_DOWN, onRightUp: ScreenSpaceEventType.RIGHT_UP, onWheel: ScreenSpaceEventType.WHEEL, onMouseEnter: ScreenSpaceEventType.MOUSE_MOVE, onMouseLeave: ScreenSpaceEventType.MOUSE_MOVE, }; private scene: Scene | undefined; private sshe: ScreenSpaceEventHandler; private events: EventMap<Map<any, Callback>> = { onClick: new Map(), onDoubleClick: new Map(), onMouseDown: new Map(), onMouseUp: new Map(), onMiddleClick: new Map(), onMiddleDown: new Map(), onMiddleUp: new Map(), onMouseMove: new Map(), onPinchEnd: new Map(), onPinchMove: new Map(), onPinchStart: new Map(), onRightClick: new Map(), onRightDown: new Map(), onRightUp: new Map(), onWheel: new Map(), onMouseEnter: new Map(), onMouseLeave: new Map(), }; private hovered: any = undefined; public constructor(scene?: Scene) { this.scene = scene; this.sshe = new ScreenSpaceEventHandler(scene?.canvas); } public destroy() { this.hovered = undefined; if (!this.sshe.isDestroyed()) { this.sshe.destroy(); } } public isDestroyed() { return this.sshe.isDestroyed(); } public on(element: any, type: EventType, cb: Callback) { if (element && type === "onWheel") return; this.events[type].set(element, cb); } public off(element: any, type: EventType) { this.events[type].delete(element); if (this.hovered === element) { this.hovered = undefined; } } public setEvents(element: any, props: any) { entries(props).forEach(([k, v]) => { const et = k as EventType; if (includes(eventNames, et)) { if (v) { this.on(element, et, v); } else { this.off(element, et); } } }); this.commit(); } public clearEvents(element: any) { this.hovered = undefined; eventNames.forEach(et => { this.off(element, et); }); this.commit(); } public commit() { const sshe = this.sshe; const destroyed = this.sshe.isDestroyed(); if (!destroyed) { if ( this.events.onMouseEnter.size === 0 && this.events.onMouseLeave.size === 0 && this.events.onMouseMove.size === 0 ) { this.sshe.removeInputAction(ScreenSpaceEventType.MOUSE_MOVE); } else if (!this.sshe.getInputAction(ScreenSpaceEventType.MOUSE_MOVE)) { this.sshe.setInputAction(this.onMouseMove, ScreenSpaceEventType.MOUSE_MOVE); } } entries(this.events).forEach(([et, m]) => { if (et === "onMouseEnter" || et === "onMouseLeave" || et === "onMouseMove") { return; } const cesiumEventType = EventManager.eventTypeMap[et]; if (!destroyed) { if (m.size === 0) { sshe.removeInputAction(cesiumEventType); } else if (!sshe.getInputAction(cesiumEventType)) { sshe.setInputAction(this.eventCallback(et), cesiumEventType); } } }); } public getScreenSpaceEventHandler() { return this.sshe; } private getEventCallback(type: EventType, picked: any) { return picked === null ? this.events[type].get(null) : this.events[type].get(picked.id) || // Entity this.events[type].get(picked.id?.entityCollection?.owner) || // Entity in DataSource this.events[type].get(picked.primitive) || // Primitive this.events[type].get(picked.tileset); // Cesium3DTileFeature } private onMouseMove = (e: CesiumMovementEvent) => { const picked = this.pick(e.endPosition); if (this.hovered !== picked) { if (this.hovered) { this.getEventCallback("onMouseLeave", this.hovered)?.(e, this.hovered); this.getEventCallback("onMouseLeave", null)?.(e, this.hovered); } if (picked) { this.getEventCallback("onMouseEnter", picked)?.(e, picked); this.getEventCallback("onMouseEnter", null)?.(e, picked); } } if (picked) { this.getEventCallback("onMouseMove", picked)?.(e, picked); } this.getEventCallback("onMouseMove", null)?.(e, picked); this.hovered = picked; }; private eventCallback = (et: EventType) => { return (e: any) => { const picked = this.pick(e?.position); if (picked) { this.getEventCallback(et, picked)?.(e, picked); } this.getEventCallback(et, null)?.(e, picked); }; }; private pick(pos?: Cartesian2): any | undefined { if (!pos) return undefined; return this.scene?.pick(pos); } } export default EventManager;