import * as Cesium from 'cesium' import { MapTooltip } from '@ztzf/utils' import { ToolBase } from '../ToolBase' import { getBoundsFromCartesians, rectanglePositionsFromBounds } from '../shapeUtils' const DEFAULT_STYLE = { fill: Cesium.Color.fromBytes(45, 140, 240, 99), outline: Cesium.Color.fromBytes(45, 140, 240, 255), } const resolveStyle = style => ({ fill: style?.fill || DEFAULT_STYLE.fill, outline: style?.outline || DEFAULT_STYLE.outline, }) export class DrawRectangleTool extends ToolBase { constructor(viewer, options = {}) { super(viewer) this.tooltip = new MapTooltip(viewer) this.dataSource = null this.rectangleEntity = null this.outlineEntity = null this.startPosition = null this.endPosition = null this.isDrawing = false this.style = resolveStyle(options?.style) } start() { this.dataSource = new Cesium.CustomDataSource('draw-rectangle') this.viewer.dataSources.add(this.dataSource) this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas) this.handler.setInputAction(click => this.handleLeftClick(click), Cesium.ScreenSpaceEventType.LEFT_CLICK) this.handler.setInputAction(movement => this.handleMouseMove(movement), Cesium.ScreenSpaceEventType.MOUSE_MOVE) this.tooltip.hide() } handleLeftClick(click) { const position = this.getPositionFromScreen(click.position) if (!position) return if (!this.startPosition) { this.startPosition = position this.endPosition = position this.isDrawing = true this.createEntities() this.tooltip.show('单击结束绘制', click.position) return } if (this.isDrawing) { this.endPosition = position this.isDrawing = false const positions = this.getRectanglePositions() this.notify('getPolygonPositions', positions) this.tooltip.hide() this.clearPreviewEntities() } } handleMouseMove(movement) { const tipText = this.startPosition ? '单击结束绘制' : '单击设置起点' if (!this.tooltip?.isVisible) { this.tooltip.show(tipText, movement.endPosition) } else { this.tooltip.show(tipText) this.tooltip.move(movement.endPosition) } if (!this.isDrawing) return const position = this.getPositionFromScreen(movement.endPosition) if (!position) return this.endPosition = position } createEntities() { if (this.rectangleEntity) return const hierarchy = new Cesium.CallbackProperty(() => { const positions = this.getRectanglePositions() return new Cesium.PolygonHierarchy(positions) }, false) this.rectangleEntity = this.dataSource.entities.add({ polygon: { hierarchy, material: this.style.fill, outline: false, heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, }, }) this.outlineEntity = this.dataSource.entities.add({ polyline: { positions: new Cesium.CallbackProperty(() => { const positions = this.getRectanglePositions() return positions.length ? [...positions, positions[0]] : [] }, false), clampToGround: true, width: 2, material: this.style.outline, }, }) } getRectanglePositions() { if (!this.startPosition || !this.endPosition) return [] const bounds = getBoundsFromCartesians([this.startPosition, this.endPosition]) return rectanglePositionsFromBounds(bounds) } clearPreviewEntities() { if (!this.dataSource) return this.dataSource.entities.removeAll() this.rectangleEntity = null this.outlineEntity = null } getPositionFromScreen(screenPosition) { const scene = this.viewer.scene const ray = scene.camera.getPickRay(screenPosition) const cartesian = ray ? scene.globe.pick(ray, scene) : null if (cartesian) return cartesian return scene.camera.pickEllipsoid(screenPosition, scene.globe.ellipsoid) } setStyle(style) { this.style = resolveStyle(style) if (this.rectangleEntity?.polygon) { this.rectangleEntity.polygon.material = this.style.fill } if (this.outlineEntity?.polyline) { this.outlineEntity.polyline.material = this.style.outline } } destroy() { if (this.dataSource) { this.dataSource.entities.removeAll() this.viewer.dataSources.remove(this.dataSource) this.dataSource = null } if (this.handler) { this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE) this.handler.destroy() this.handler = null } this.tooltip?.destroy() this.tooltip = null this.startPosition = null this.endPosition = null this.isDrawing = false } }