Vue3加vite使用Cesium绘制图形
1、项目开发准备
Node版本:16.20.2
1.1创建一个新的工程:my-cesium-app
npm create vite@latest my-cesium-app – --template vue
1.2 安装Element Plus
npm install element-plus --save
// main.js
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
const app = createApp(App)
//字体图标注册
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {app.component(key, component)
}
1.3安装cesium
npm i cesium@1.99 vite-plugin-cesium
// main.js
import * as Cesium from 'cesium';
const app = createApp(App)
app.use(Cesium)//vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import cesium from 'vite-plugin-cesium'
export default defineConfig({ plugins: [ vue(),cesium()]})
1.4注册Cesium
首先需要去注册一个免费的Cesium ion账户
打开https://ion.cesium.com/ 然后注册一个新的账户。
点击”Access Token”,跳转到Access Tokens page页面。
选择Default默认的access token拷贝到contents中。
2、使用Draw.js绘制对应图形
2.1基础参数
constructor(viewer, config) {this.viewer = viewer;this.config = config || {borderColor: Cesium.Color.BLUE,borderWidth: 2,material: Cesium.Color.GREEN.withAlpha(0.5),};this.infoDetail = { point: [], line: [], rectangle: [], circle: [], planeSelf: [], sector: [] };//判断是否右键销毁this.isDestroy = false//是否是销毁状态this.isRemove = falsethis.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);}
2.2 绘制点
drawPoint () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isDestroy = falsethis.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((click) => {let cartesian = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid, new Cesium.Cartographic());let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);let id = new Date().getTime();this.viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(lng, lat, 0),name: 'point',id: id,point: {color: this.config.material,pixelSize: 12,outlineColor: this.config.borderColor,outlineWidth: this.config.borderWidth,},});this.infoDetail.point.push({ id: id, position: [lng, lat] });}, Cesium.ScreenSpaceEventType.LEFT_CLICK);this.handler.setInputAction((click) => {if (this.handler) {this.isDestroy = truethis.handler.destroy();//重新点击进行绘制this.drawPoint()}}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}
2.3绘制矩形区域
/******* * @function: function* @description: 绘制矩形区域*/drawRectangle () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = falsethis.isDestroy = falselet westSouthEastNorth = [];let id = null;this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((click) => {let cartesian = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid, new Cesium.Cartographic());let lng1 = Cesium.Math.toDegrees(cartographic.longitude);let lat1 = Cesium.Math.toDegrees(cartographic.latitude);westSouthEastNorth = [lng1, lat1];id = new Date().getTime();if (westSouthEastNorth) {this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);}let polygons = this.viewer.entities.add({name: 'rectangle',id: id,polygon: {hierarchy: new Cesium.CallbackProperty(function () {return {positions: Cesium.Cartesian3.fromDegreesArray(westSouthEastNorth),};}, false),height: 0,material: this.config.material,fill: true,show: true,},polyline: {positions: new Cesium.CallbackProperty(function () { return Cesium.Cartesian3.fromDegreesArray(westSouthEastNorth); }, false),material: this.config.borderColor,width: this.config.borderWidth,zIndex: 1,},});this.handler.setInputAction((move) => {let cartesian = this.viewer.camera.pickEllipsoid(move.endPosition, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid, new Cesium.Cartographic());let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);westSouthEastNorth = [lng1, lat1, lng1, lat, lng, lat, lng, lat1, lng1, lat1];}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);//右键完成绘制this.handler.setInputAction(() => {if (this.handler) {this.isDestroy = truethis.handler.destroy();//重新点击进行绘制this.drawRectangle()}this.infoDetail.rectangle.push({ id: id, position: westSouthEastNorth });}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}
2.4绘制圆形区域,并计算面积和周长
drawCircle() {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = false;this.isDestroy = false;let id = null;let radius = 0;let lngLat = [];let circleEntity = null;this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((click) => {id = new Date().getTime();let cartesian = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);lngLat = [lng, lat];circleEntity = this.viewer.entities.add({position: new Cesium.CallbackProperty(function () { return Cesium.Cartesian3.fromDegrees(...lngLat, 0); }, false),name: 'circle',id: id,ellipse: {height: 0,outline: true,material: this.config.material,outlineColor: this.config.borderColor,outlineWidth: this.config.borderWidth,semiMajorAxis: new Cesium.CallbackProperty(function () { return radius; }, false),semiMinorAxis: new Cesium.CallbackProperty(function () { return radius; }, false),},});this.handler.setInputAction((move) => {let cartesian2 = this.viewer.camera.pickEllipsoid(move.endPosition, this.viewer.scene.globe.ellipsoid);radius = Cesium.Cartesian3.distance(cartesian, cartesian2);}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);this.handler.setInputAction(() => {// 计算面积(πr²)和周长(2πr)let area = Math.PI * Math.pow(radius, 2); // 单位:平方米let circumference = 2 * Math.PI * radius; // 单位:米this.infoDetail.circle.push({id: id,center: lngLat,radius: radius,area: area, // 保存面积circumference: circumference // 保存周长});if (this.handler) {this.isDestroy = true;this.handler.destroy();this.drawCircle();//this.enableCircleDragging(circleEntity, id); // 启用拖动功能}}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);}
2.5绘制自定义区域,并计算面积
drawPlane() {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = false;this.isDestroy = false;let id = new Date().getTime();let positions = [];let codeInfo = [];let polygon = new Cesium.PolygonHierarchy();let _polygonEntity = new Cesium.Entity();let polyObj = null;this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((movement) => {let cartesian = this.viewer.camera.pickEllipsoid(movement.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);if (cartesian && cartesian.x) {if (positions.length == 0) {positions.push(cartesian.clone());}codeInfo.push([lng, lat]);positions.push(cartesian.clone());polygon.positions.push(cartesian.clone());if (!polyObj) {_polygonEntity.polyline = {width: this.config.borderWidth,material: this.config.borderColor,clampToGround: false,};_polygonEntity.polyline.positions = new Cesium.CallbackProperty(function () {return positions;}, false);_polygonEntity.polygon = {hierarchy: new Cesium.CallbackProperty(function () {return polygon;}, false),material: this.config.material,clampToGround: false,};_polygonEntity.name = 'planeSelf';_polygonEntity._id = id;polyObj = this.viewer.entities.add(_polygonEntity);}}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);this.handler.setInputAction((movement) => {let cartesian = this.viewer.camera.pickEllipsoid(movement.endPosition, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);if (positions.length >= 0) {if (cartesian && cartesian.x) {positions.pop();positions.push(cartesian);polygon.positions.pop();polygon.positions.push(cartesian);codeInfo.pop();codeInfo.push([lng, lat]);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 右键完成绘制this.handler.setInputAction((movement) => {// 计算多边形面积let area = this.calculatePolygonArea(positions);this.infoDetail.planeSelf.push({id: id,positions: codeInfo,area: area // 保存面积});if (this.handler) {this.isDestroy = true;this.handler.destroy();this.drawPlane();//this.enablePolygonDragging(polyObj, id); // 启用拖动功能}positions.push(positions[0]);}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}
2.6绘制线段并计算其长度
drawLine () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = false;this.isDestroy = false;let id = null;let positions = [];let codeInfo = [];let polyObj = null;this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((movement) => {id = new Date().getTime();let cartesian = this.viewer.camera.pickEllipsoid(movement.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);if (cartesian && cartesian.x) {if (positions.length == 0) {positions.push(cartesian.clone());}codeInfo.push([lng, lat]);positions.push(cartesian.clone());if (!polyObj) {polyObj = this.viewer.entities.add({polyline: {positions: new Cesium.CallbackProperty(() => positions, false),width: this.config.borderWidth,material: this.config.borderColor,clampToGround: false,},name: 'line',id: id,});}}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);this.handler.setInputAction((movement) => {let cartesian = this.viewer.camera.pickEllipsoid(movement.endPosition, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);if (positions.length >= 0) {if (cartesian && cartesian.x) {positions.pop();positions.push(cartesian);codeInfo.pop();codeInfo.push([lng, lat]);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 右键完成绘制this.handler.setInputAction(() => {// 计算线段长度let length = this.calculateLineLength(positions);this.infoDetail.line.push({id: id,positions: codeInfo,length: length // 保存线段长度});if (this.handler) {this.isDestroy = true;this.handler.destroy();this.drawLine(); // 重新启用绘制功能}}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}/******* * @function: function* @description: 计算线段的总长度*/calculateLineLength (positions) {let totalLength = 0;for (let i = 0; i < positions.length - 1; i++) {let startCartographic = Cesium.Cartographic.fromCartesian(positions[i]);let endCartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);let startPos = Cesium.Cartesian3.fromRadians(startCartographic.longitude,startCartographic.latitude);let endPos = Cesium.Cartesian3.fromRadians(endCartographic.longitude,endCartographic.latitude);let segmentLength = Cesium.Cartesian3.distance(startPos, endPos);totalLength += segmentLength;}return totalLength; // 返回线段总长度,单位:米}
2.7绘制扇形,并计算面积和弧长
drawSector () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = false;this.isDestroy = false;let id = null;let center = null;let radius = 0;let startAngle = 0;let endAngle = 0;let positions = [];this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);// 第一次点击确定中心点this.handler.setInputAction((click) => {id = new Date().getTime();center = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);if (!center) return;const cartographic = Cesium.Cartographic.fromCartesian(center);const lng = Cesium.Math.toDegrees(cartographic.longitude);const lat = Cesium.Math.toDegrees(cartographic.latitude);let entity = this.viewer.entities.add({id: id,position: center,polygon: {hierarchy: new Cesium.CallbackProperty(() => new Cesium.PolygonHierarchy(positions), false),material: this.config.material,outline: true,outlineColor: this.config.borderColor,outlineWidth: this.config.borderWidth,},});this.handler.setInputAction((move) => {const movePosition = this.viewer.camera.pickEllipsoid(move.endPosition, this.viewer.scene.globe.ellipsoid);if (!movePosition) return;radius = Cesium.Cartesian3.distance(center, movePosition);const cartographicMove = Cesium.Cartographic.fromCartesian(movePosition);const lngMove = Cesium.Math.toDegrees(cartographicMove.longitude);const latMove = Cesium.Math.toDegrees(cartographicMove.latitude);endAngle = Math.atan2(latMove - lat, lngMove - lng);// 动态计算扇形边界点positions = this.computeSectorPositions(center, radius, startAngle, endAngle);}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 设置起始角度this.handler.setInputAction((click) => {const startCartesian = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);if (!startCartesian) return;const cartographicStart = Cesium.Cartographic.fromCartesian(startCartesian);const lngStart = Cesium.Math.toDegrees(cartographicStart.longitude);const latStart = Cesium.Math.toDegrees(cartographicStart.latitude);startAngle = Math.atan2(latStart - lat, lngStart - lng);this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);// 右键完成绘制this.handler.setInputAction(() => {// 计算扇形的面积和弧长let area = this.calculateSectorArea(radius, startAngle, endAngle);let arcLength = this.calculateArcLength(radius, startAngle, endAngle);this.infoDetail.sector.push({id: id,center: Cesium.Cartographic.fromCartesian(center),radius: radius,startAngle: startAngle,endAngle: endAngle,area: area, // 保存面积arcLength: arcLength // 保存弧长});if (this.handler) {this.isDestroy = true;this.handler.destroy();// 重新启用绘制功能this.drawSector();}}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}/******* * @function: function* @description: 计算扇形的面积*/calculateSectorArea (radius, startAngle, endAngle) {let angleDiff = endAngle - startAngle;if (angleDiff < 0) {angleDiff += 2 * Math.PI; // 确保角度差为正}return 0.5 * Math.pow(radius, 2) * angleDiff;}
2.8移除绘制对象,获取绘制对象的数据
/******* * @function: function* @description: 移除绘制对象*/removeEntity () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = truethis.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((move) => {let pick = this.viewer.scene.pick(move.endPosition);if (pick && pick.id && pick.id.id && this.isRemove) {document.body.style.cursor = 'pointer';this.handler.setInputAction((click) => {let newPoint;switch (pick.id.name) {case 'point':newPoint = this.infoDetail.point.filter((item) => item.id != pick.id._id);this.infoDetail.point = newPoint;break;case 'line':newPoint = this.infoDetail.line.filter((item) => item.id != pick.id._id);this.infoDetail.line = newPoint;break;case 'rectangle':newPoint = this.infoDetail.rectangle.filter((item) => item.id != pick.id._id);this.infoDetail.rectangle = newPoint;break;case 'planeSelf':newPoint = this.infoDetail.planeSelf.filter((item) => item.id != pick.id._id);this.infoDetail.planeSelf = newPoint;break;case 'circle':newPoint = this.infoDetail.circle.filter((item) => item.id != pick.id._id);this.infoDetail.circle = newPoint;break;case 'sector':newPoint = this.infoDetail.sector.filter((item) => item.id != pick.id._id);this.infoDetail.sector = newPoint;break;default:break;}this.viewer.entities.remove(pick.id);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);} else {document.body.style = 'cursor: default;';}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);}/******* * @function: function* @description: 获取绘制对象*/backInfoDetail () {return this.infoDetail;}
3、页面代码
<template><div class="map"><div class="flex-items search"><el-radio-group v-model="btnType"size="large"@change="changeBtn"><!-- <el-radio-button label="绘制点"value="drawPoint" /> --><!-- <el-radio-button label="绘制矩形"value="drawRectangle" /> --><el-radio-button label="绘制线段"value="drawLine" /><el-radio-button label="绘制多边形"value="drawPlane" /><el-radio-button label="绘制圆形"value="drawCircle" /><el-radio-button label="扇形"value="drawSector" /><el-radio-button label="移除绘制对象"value="removeEntity" /></el-radio-group><div class="flex-items"><!--输入框形式--><!-- <el-input v-model="coordinates"style="width: 240px":rows="2"type="textarea"placeholder="请输入坐标集" /> --><el-dropdown @command="addDraw"><el-button type="primary"style="margin-right: 10px;">生成图形<el-icon class="el-icon--right"><arrow-down /></el-icon></el-button><template #dropdown><el-dropdown-menu><el-dropdown-item command="drawLineFromCoordinates">生成线段</el-dropdown-item><el-dropdown-item command="drawPlaneFromCoordinates">生成多边形</el-dropdown-item><el-dropdown-item command="drawCircleFromCoordinates">生成圆形</el-dropdown-item><el-dropdown-item command="drawSectorFromCoordinates">生成扇形</el-dropdown-item></el-dropdown-menu></template></el-dropdown><el-button type="success"@click="getData()">获取图形数据</el-button></div></div></div><el-dialog v-model="drawVisible"title="生成图形"width="680"><template v-if="drawInfo.key=='drawCircleFromCoordinates'"><el-row :gutter="20"><el-col :span="8"><div>lng</div></el-col><el-col :span="8"><div>lat</div></el-col><el-col :span="8"><div>半径(米)</div></el-col><div class="flex-items draw-item"v-for="(item,index) in drawInfo.coordinates":key="index"><el-col :span="8"><el-input v-model="item.lng"placeholder="请输入lng" /></el-col><el-col :span="8"><el-input v-model="item.lat"placeholder="请输入lat" /> </el-col><el-col :span="8"><el-input v-model="item.radius"placeholder="请输入半径"></el-input></el-col></div></el-row></template><template v-else-if="drawInfo.key=='drawSectorFromCoordinates'"><el-row :gutter="20"><el-col :span="6"><div>lng</div></el-col><el-col :span="6"><div>lat</div></el-col><el-col :span="4"><div>半径(米)</div></el-col><el-col :span="4"><div>起始角度</div></el-col><el-col :span="4"><div>结束角度</div></el-col><div class="flex-items draw-item"v-for="(item,index) in drawInfo.coordinates":key="index"><el-col :span="6"><el-input v-model="item.lng"placeholder="请输入lng" /></el-col><el-col :span="6"><el-input v-model="item.lat"placeholder="请输入lat" /></el-col><el-col :span="4"><el-input v-model="item.radius"placeholder="请输入半径"></el-input></el-col><el-col :span="4"><el-input v-model="item.startAngle"placeholder="请输入"></el-input></el-col><el-col :span="4"><el-input v-model="item.endAngle"placeholder="请输入"></el-input></el-col></div></el-row></template><template v-else><el-row :gutter="20"><el-col :span="10"><div>lng</div></el-col><el-col :span="10"><div>lat</div></el-col><el-col :span="4"><div>操作</div></el-col><div class="flex-items draw-item"v-for="(item,index) in drawInfo.coordinates":key="index"><el-col :span="10"><el-input v-model="item.lng"placeholder="请输入lng" /></el-col><el-col :span="10"><el-input v-model="item.lat"placeholder="请输入lat" /></el-col><el-col :span="4"><el-button type="danger"circlev-if="drawInfo.coordinates.length>1"@click="delItem(index)"><el-icon><delete /></el-icon></el-button></el-col></div></el-row><el-button type="primary"@click="addItem">添加坐标</el-button></template><template #footer><div class="dialog-footer"><el-button @click="drawVisible = false">取消</el-button><el-button type="primary"@click="createDraw()">确认生成</el-button></div></template></el-dialog><div id="cesiumContainer"ref="cesiumContainer"></div></template><script>
import { onMounted, ref } from 'vue'
import * as Cesium from 'cesium'
import Draw from './Draw' // 确保路径正确
import { ArrowDown, Delete } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'export default {name: 'CesiumMap',setup() {const btnType = ref('')const cesiumContainer = ref(null)const coordinates = ref('')const drawVisible = ref(false)const drawInfo = ref({key: '',coordinates: [{ lng: '', lat: '', radius: 0, startAngle: 0, endAngle: 90 },],center: [],radius: 0,})let viewerlet drawonMounted(() => {// 初始化地球Cesium.Ion.defaultAccessToken = '注册的token'viewer = new Cesium.Viewer(cesiumContainer.value, {geocoder: true,homeButton: true, //是否显示首页位置工具sceneModePicker: true, //是否显示视角模式切换工具baseLayerPicker: true, //是否显示默认图层选择工具navigationHelpButton: false, //是否显示导航帮助工具animation: false, //是否显示动画工具timeline: false, //是否显示时间轴工具fullscreenButton: true, //是否显示全屏按钮工具})//初始化绘制方法draw = new Draw(viewer, {borderColor: Cesium.Color.RED,borderWidth: 2,material: Cesium.Color.BLUE.withAlpha(0.5),})})//点击不同的类型按钮,触发不同的绘制效果function changeBtn(val) {draw[val]()}//获取绘制的图形信息function getData() {console.log(draw.backInfoDetail())}//添加生成图形中的坐标对象const addItem = () => {drawInfo.value.coordinates.push({lng: '',lat: '',radius: 0,startAngle: 0,endAngle: 90,})}//删除生成图形中的坐标对象const delItem = (index) => {drawInfo.value.coordinates.splice(index, 1)}//弹窗形式,逐个添加坐标对象const addDraw = (command) => {drawVisible.value = truedrawInfo.value.key = commanddrawInfo.value.coordinates = [{ lng: '', lat: '', radius: 0, startAngle: 0, endAngle: 90 },]}//生成图形const createDraw = () => {let isEmpty = falsedrawInfo.value.coordinates.forEach((item) => {if (item.lng === '' || item.lat === '') {isEmpty = true}})if (isEmpty) {ElMessage({message: '坐标内容不能为空!',type: 'warning',})return}if (drawInfo.value.key == 'drawCircleFromCoordinates') {draw[drawInfo.value.key]([Number(drawInfo.value.coordinates[0].lng),Number(drawInfo.value.coordinates[0].lat),],Number(drawInfo.value.coordinates[0].radius))} else if (drawInfo.value.key == 'drawSectorFromCoordinates') {const startAngle = Cesium.Math.toRadians(Number(drawInfo.value.coordinates[0].startAngle)) // 起始角度,0度(东向)const endAngle = Cesium.Math.toRadians(Number(drawInfo.value.coordinates[0].endAngle)) // 结束角度,90度(北向)draw[drawInfo.value.key]([Number(drawInfo.value.coordinates[0].lng),Number(drawInfo.value.coordinates[0].lat),],Number(drawInfo.value.coordinates[0].radius),startAngle,endAngle)} else {let coordinates = []drawInfo.value.coordinates.forEach((item) => {coordinates.push([Number(item.lng), Number(item.lat)])})draw[drawInfo.value.key](coordinates)}drawVisible.value = false}//输入框形式,直接输入坐标集,生成图形const handleCommand = (command) => {if (command == 'drawCircleFromCoordinates') {const center = [-84.89521051429298, 47.804323372822424] // 圆心的经纬度const radius = 944831.9687022993 // 半径,单位:米draw[command](center, radius)} else if (command == 'drawSectorFromCoordinates') {const startAngle = Cesium.Math.toRadians(Number(0)) // 起始角度,0度(东向)const endAngle = Cesium.Math.toRadians(Number(90)) // 结束角度,90度(北向)const center = [116.391193, 39.907776] // 圆心的经纬度const radius = 944831.9687022993 // 半径,单位:米draw[command](center, radius, startAngle, endAngle)} else {// 清理输入字符串let cleanedInput = coordinates.value.trim()if (!cleanedInput) {ElMessage({message: '坐标集不能为空!',type: 'warning',})return}let parsedArray = null// 修复尾随逗号cleanedInput = cleanedInput.replace(/,\s*([}\]])/g, '$1')// 处理其他常见问题// 替换单引号为双引号cleanedInput = cleanedInput.replace(/'/g, '"')// 尝试解析 JSONtry {// 解析字符串为数组parsedArray = JSON.parse(cleanedInput)draw[command](parsedArray)} catch (error) {ElMessage.error(error)}}}return {handleCommand,changeBtn,getData,addItem,createDraw,delItem,addDraw,cesiumContainer,btnType,coordinates,drawInfo,drawVisible,}},
}
</script><style scoped>
#cesiumContainer {width: 100%;height: calc(100vh - 120px);
}
.flex-items {display: flex;align-items: center;
}
.search {margin-bottom: 10px;justify-content: space-between;
}
.draw-item {margin: 10px 0;width: 100%;
}
</style>
4页面效果图
除了绘制图形之外,还新增了使用通过输入坐标点集合生成上述图形(WGS84 坐标) ,以及圆形、线段、多边形的拖拽,但是拖拽效果不是很理想,只能当做参考
5、完整的Draw.js
// Draw.js 绘制方法
import * as Cesium from 'cesium'
export default class Draw {constructor(viewer, config) {this.viewer = viewer;this.config = config || {borderColor: Cesium.Color.BLUE,borderWidth: 2,material: Cesium.Color.GREEN.withAlpha(0.5),};this.infoDetail = { point: [], line: [], rectangle: [], circle: [], planeSelf: [], sector: [] };//判断是否右键销毁this.isDestroy = false//是否是销毁状态this.isRemove = falsethis.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);}/******* * @function: function* @description: 绘制点*/drawPoint () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isDestroy = falsethis.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((click) => {let cartesian = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid, new Cesium.Cartographic());let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);let id = new Date().getTime();this.viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(lng, lat, 0),name: 'point',id: id,point: {color: this.config.material,pixelSize: 12,outlineColor: this.config.borderColor,outlineWidth: this.config.borderWidth,},});this.infoDetail.point.push({ id: id, position: [lng, lat] });}, Cesium.ScreenSpaceEventType.LEFT_CLICK);this.handler.setInputAction((click) => {if (this.handler) {this.isDestroy = truethis.handler.destroy();//重新点击进行绘制this.drawPoint()}}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}/******* * @function: function* @description: 绘制矩形区域*/drawRectangle () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = falsethis.isDestroy = falselet westSouthEastNorth = [];let id = null;this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((click) => {let cartesian = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid, new Cesium.Cartographic());let lng1 = Cesium.Math.toDegrees(cartographic.longitude);let lat1 = Cesium.Math.toDegrees(cartographic.latitude);westSouthEastNorth = [lng1, lat1];id = new Date().getTime();if (westSouthEastNorth) {this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);}let polygons = this.viewer.entities.add({name: 'rectangle',id: id,polygon: {hierarchy: new Cesium.CallbackProperty(function () {return {positions: Cesium.Cartesian3.fromDegreesArray(westSouthEastNorth),};}, false),height: 0,material: this.config.material,fill: true,show: true,},polyline: {positions: new Cesium.CallbackProperty(function () { return Cesium.Cartesian3.fromDegreesArray(westSouthEastNorth); }, false),material: this.config.borderColor,width: this.config.borderWidth,zIndex: 1,},});this.handler.setInputAction((move) => {let cartesian = this.viewer.camera.pickEllipsoid(move.endPosition, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid, new Cesium.Cartographic());let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);westSouthEastNorth = [lng1, lat1, lng1, lat, lng, lat, lng, lat1, lng1, lat1];}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);//右键完成绘制this.handler.setInputAction(() => {if (this.handler) {this.isDestroy = truethis.handler.destroy();//重新点击进行绘制this.drawRectangle()}this.infoDetail.rectangle.push({ id: id, position: westSouthEastNorth });}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}/******* * @function: function* @description: 绘制圆形区域,并计算面积和周长,同时支持拖动*/drawCircle() {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = false;this.isDestroy = false;let id = null;let radius = 0;let lngLat = [];let circleEntity = null;this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((click) => {id = new Date().getTime();let cartesian = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);lngLat = [lng, lat];circleEntity = this.viewer.entities.add({position: new Cesium.CallbackProperty(function () { return Cesium.Cartesian3.fromDegrees(...lngLat, 0); }, false),name: 'circle',id: id,ellipse: {height: 0,outline: true,material: this.config.material,outlineColor: this.config.borderColor,outlineWidth: this.config.borderWidth,semiMajorAxis: new Cesium.CallbackProperty(function () { return radius; }, false),semiMinorAxis: new Cesium.CallbackProperty(function () { return radius; }, false),},});this.handler.setInputAction((move) => {let cartesian2 = this.viewer.camera.pickEllipsoid(move.endPosition, this.viewer.scene.globe.ellipsoid);radius = Cesium.Cartesian3.distance(cartesian, cartesian2);}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 完成圆形绘制后,允许拖动this.handler.setInputAction(() => {// 计算面积(πr²)和周长(2πr)let area = Math.PI * Math.pow(radius, 2); // 单位:平方米let circumference = 2 * Math.PI * radius; // 单位:米this.infoDetail.circle.push({id: id,center: lngLat,radius: radius,area: area, // 保存面积circumference: circumference // 保存周长});if (this.handler) {this.isDestroy = true;this.handler.destroy();this.drawCircle();this.enableCircleDragging(circleEntity, id); // 启用拖动功能}}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);}/******* * @function: function* @description: 绘制自定义区域,并计算面积,同时支持拖动*/drawPlane() {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = false;this.isDestroy = false;let id = new Date().getTime();let positions = [];let codeInfo = [];let polygon = new Cesium.PolygonHierarchy();let _polygonEntity = new Cesium.Entity();let polyObj = null;this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((movement) => {let cartesian = this.viewer.camera.pickEllipsoid(movement.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);if (cartesian && cartesian.x) {if (positions.length == 0) {positions.push(cartesian.clone());}codeInfo.push([lng, lat]);positions.push(cartesian.clone());polygon.positions.push(cartesian.clone());if (!polyObj) {_polygonEntity.polyline = {width: this.config.borderWidth,material: this.config.borderColor,clampToGround: false,};_polygonEntity.polyline.positions = new Cesium.CallbackProperty(function () {return positions;}, false);_polygonEntity.polygon = {hierarchy: new Cesium.CallbackProperty(function () {return polygon;}, false),material: this.config.material,clampToGround: false,};_polygonEntity.name = 'planeSelf';_polygonEntity._id = id;polyObj = this.viewer.entities.add(_polygonEntity);}}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);this.handler.setInputAction((movement) => {let cartesian = this.viewer.camera.pickEllipsoid(movement.endPosition, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);if (positions.length >= 0) {if (cartesian && cartesian.x) {positions.pop();positions.push(cartesian);polygon.positions.pop();polygon.positions.push(cartesian);codeInfo.pop();codeInfo.push([lng, lat]);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 右键完成绘制this.handler.setInputAction((movement) => {// 计算多边形面积let area = this.calculatePolygonArea(positions);this.infoDetail.planeSelf.push({id: id,positions: codeInfo,area: area // 保存面积});if (this.handler) {this.isDestroy = true;this.handler.destroy();this.drawPlane();this.enablePolygonDragging(polyObj, id); // 启用拖动功能}positions.push(positions[0]);}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}/******* * @function: function* @description: 绘制线段并计算其长度*/drawLine () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = false;this.isDestroy = false;let id = null;let positions = [];let codeInfo = [];let polyObj = null;this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((movement) => {id = new Date().getTime();let cartesian = this.viewer.camera.pickEllipsoid(movement.position, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);if (cartesian && cartesian.x) {if (positions.length == 0) {positions.push(cartesian.clone());}codeInfo.push([lng, lat]);positions.push(cartesian.clone());if (!polyObj) {polyObj = this.viewer.entities.add({polyline: {positions: new Cesium.CallbackProperty(() => positions, false),width: this.config.borderWidth,material: this.config.borderColor,clampToGround: false,},name: 'line',id: id,});}}}, Cesium.ScreenSpaceEventType.LEFT_CLICK);this.handler.setInputAction((movement) => {let cartesian = this.viewer.camera.pickEllipsoid(movement.endPosition, this.viewer.scene.globe.ellipsoid);let cartographic = Cesium.Cartographic.fromCartesian(cartesian, this.viewer.scene.globe.ellipsoid);let lng = Cesium.Math.toDegrees(cartographic.longitude);let lat = Cesium.Math.toDegrees(cartographic.latitude);if (positions.length >= 0) {if (cartesian && cartesian.x) {positions.pop();positions.push(cartesian);codeInfo.pop();codeInfo.push([lng, lat]);}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 右键完成绘制this.handler.setInputAction(() => {// 计算线段长度let length = this.calculateLineLength(positions);this.infoDetail.line.push({id: id,positions: codeInfo,length: length // 保存线段长度});if (this.handler) {this.isDestroy = true;this.handler.destroy();this.drawLine(); // 重新启用绘制功能}}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}/******* * @function: function* @description: 计算扇形的面积*/calculateSectorArea (radius, startAngle, endAngle) {let angleDiff = endAngle - startAngle;if (angleDiff < 0) {angleDiff += 2 * Math.PI; // 确保角度差为正}return 0.5 * Math.pow(radius, 2) * angleDiff;}/******* * @function: function* @description: 计算扇形的弧长*/calculateArcLength (radius, startAngle, endAngle) {let angleDiff = endAngle - startAngle;return radius * angleDiff; // 单位:米}/******* * @function: function* @description: 计算扇形的边界点*/computeSectorPositions (center, radius, startAngle, endAngle) {const positions = [];const numPoints = 50; // 调整为更平滑或更粗糙的扇形const angleDiff = endAngle - startAngle;for (let i = 0; i <= numPoints; i++) {const angle = startAngle + (i * angleDiff) / numPoints;const x = center.x + radius * Math.cos(angle);const y = center.y + radius * Math.sin(angle);positions.push(new Cesium.Cartesian3(x, y, center.z));}positions.push(center);return positions;}/******* * @function: function* @description: 绘制扇形,并计算面积和弧长*/drawSector () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = false;this.isDestroy = false;let id = null;let center = null;let radius = 0;let startAngle = 0;let endAngle = 0;let positions = [];this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);// 第一次点击确定中心点this.handler.setInputAction((click) => {id = new Date().getTime();center = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);if (!center) return;const cartographic = Cesium.Cartographic.fromCartesian(center);const lng = Cesium.Math.toDegrees(cartographic.longitude);const lat = Cesium.Math.toDegrees(cartographic.latitude);let entity = this.viewer.entities.add({id: id,position: center,polygon: {hierarchy: new Cesium.CallbackProperty(() => new Cesium.PolygonHierarchy(positions), false),material: this.config.material,outline: true,outlineColor: this.config.borderColor,outlineWidth: this.config.borderWidth,},});this.handler.setInputAction((move) => {const movePosition = this.viewer.camera.pickEllipsoid(move.endPosition, this.viewer.scene.globe.ellipsoid);if (!movePosition) return;radius = Cesium.Cartesian3.distance(center, movePosition);const cartographicMove = Cesium.Cartographic.fromCartesian(movePosition);const lngMove = Cesium.Math.toDegrees(cartographicMove.longitude);const latMove = Cesium.Math.toDegrees(cartographicMove.latitude);endAngle = Math.atan2(latMove - lat, lngMove - lng);// 动态计算扇形边界点positions = this.computeSectorPositions(center, radius, startAngle, endAngle);}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);// 设置起始角度this.handler.setInputAction((click) => {const startCartesian = this.viewer.camera.pickEllipsoid(click.position, this.viewer.scene.globe.ellipsoid);if (!startCartesian) return;const cartographicStart = Cesium.Cartographic.fromCartesian(startCartesian);const lngStart = Cesium.Math.toDegrees(cartographicStart.longitude);const latStart = Cesium.Math.toDegrees(cartographicStart.latitude);startAngle = Math.atan2(latStart - lat, lngStart - lng);this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);// 右键完成绘制this.handler.setInputAction(() => {// 计算扇形的面积和弧长let area = this.calculateSectorArea(radius, startAngle, endAngle);let arcLength = this.calculateArcLength(radius, startAngle, endAngle);this.infoDetail.sector.push({id: id,center: Cesium.Cartographic.fromCartesian(center),radius: radius,startAngle: startAngle,endAngle: endAngle,area: area, // 保存面积arcLength: arcLength // 保存弧长});if (this.handler) {this.isDestroy = true;this.handler.destroy();// 重新启用绘制功能this.drawSector();}}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);}/******* * @function: function* @description: 通过坐标数组生成线段并计算长度*/drawLineFromCoordinates (coordinates) {let id = new Date().getTime();let positions = coordinates.map(coord => {return Cesium.Cartesian3.fromDegrees(coord[0], coord[1]);});// 计算线段长度let length = this.calculateLineLength(positions);this.infoDetail.line.push({id: id,positions: coordinates,length: length // 保存线段长度});let _polygonEntity = new Cesium.Entity();_polygonEntity.polyline = {width: this.config.borderWidth,material: this.config.borderColor,clampToGround: false,positions: positions,};_polygonEntity.name = 'line';_polygonEntity._id = id;this.viewer.entities.add(_polygonEntity);} /******* * @function: function* @description: 计算线段的总长度*/calculateLineLength (positions) {let totalLength = 0;for (let i = 0; i < positions.length - 1; i++) {let startCartographic = Cesium.Cartographic.fromCartesian(positions[i]);let endCartographic = Cesium.Cartographic.fromCartesian(positions[i + 1]);let startPos = Cesium.Cartesian3.fromRadians(startCartographic.longitude,startCartographic.latitude);let endPos = Cesium.Cartesian3.fromRadians(endCartographic.longitude,endCartographic.latitude);let segmentLength = Cesium.Cartesian3.distance(startPos, endPos);totalLength += segmentLength;}return totalLength; // 返回线段总长度,单位:米}/******* /******* * @function: function* @description: 通过坐标数组生成自定义区域,并计算面积*/drawPlaneFromCoordinates (coordinates) {let id = new Date().getTime();let positions = coordinates.map(coord => {return Cesium.Cartesian3.fromDegrees(coord[0], coord[1]);});// 关闭区域,用第一个点作为最后一个点positions.push(positions[0]);// 计算多边形面积let area = this.calculatePolygonArea(positions);this.infoDetail.planeSelf.push({id: id,positions: coordinates,area: area // 保存面积});let polygonHierarchy = new Cesium.PolygonHierarchy(positions);let _polygonEntity = new Cesium.Entity();_polygonEntity.polyline = {width: this.config.borderWidth,material: this.config.borderColor,clampToGround: false,positions: positions,};_polygonEntity.polygon = {hierarchy: polygonHierarchy,material: this.config.material,clampToGround: false,};_polygonEntity.name = 'planeSelf';_polygonEntity._id = id;this.viewer.entities.add(_polygonEntity);this.enablePolygonDragging(_polygonEntity, id); // 启用拖动功能}/******* * @function: function* @description: 启用多边形的拖动功能*/enablePolygonDragging(polygonEntity, id) {this.dragHandler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);let isDragging = false;let originalPositions = null;this.dragHandler.setInputAction((click) => {const pickedObject = this.viewer.scene.pick(click.position);if (Cesium.defined(pickedObject) && pickedObject.id === polygonEntity) {isDragging = true;originalPositions = pickedObject.id.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions;}}, Cesium.ScreenSpaceEventType.LEFT_DOWN);this.dragHandler.setInputAction((movement) => {if (isDragging && polygonEntity) {const newCartesian = this.viewer.camera.pickEllipsoid(movement.endPosition, this.viewer.scene.globe.ellipsoid);if (newCartesian) {const deltaX = newCartesian.x - originalPositions[0].x;const deltaY = newCartesian.y - originalPositions[0].y;const deltaZ = newCartesian.z - originalPositions[0].z;const newPositions = originalPositions.map((position) => {return new Cesium.Cartesian3(position.x + deltaX,position.y + deltaY,position.z + deltaZ);});// 更新多边形和折线的位置信息polygonEntity.polygon.hierarchy = new Cesium.CallbackProperty(() => {return new Cesium.PolygonHierarchy(newPositions);}, false);polygonEntity.polyline.positions = new Cesium.CallbackProperty(() => {return newPositions;}, false);// 实时更新 infoDetail 中多边形的位置const polygonInfo = this.infoDetail.planeSelf.find(plane => plane.id === id);if (polygonInfo) {polygonInfo.positions = newPositions.map(pos => {const cartographic = Cesium.Cartographic.fromCartesian(pos);return [Cesium.Math.toDegrees(cartographic.longitude),Cesium.Math.toDegrees(cartographic.latitude)];});}}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);this.dragHandler.setInputAction(() => {isDragging = false;}, Cesium.ScreenSpaceEventType.LEFT_UP);}/******* * @function: function* @description: 启用圆形的拖动功能*/enableCircleDragging(circleEntity, id) {this.dragHandler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);let isDragging = false;let originalPosition = null;this.dragHandler.setInputAction((click) => {const pickedObject = this.viewer.scene.pick(click.position);if (Cesium.defined(pickedObject) && pickedObject.id === circleEntity) {isDragging = true;originalPosition = pickedObject.id.position.getValue(Cesium.JulianDate.now());}}, Cesium.ScreenSpaceEventType.LEFT_DOWN);this.dragHandler.setInputAction((movement) => {if (isDragging && circleEntity) {const newCartesian = this.viewer.camera.pickEllipsoid(movement.endPosition, this.viewer.scene.globe.ellipsoid);if (newCartesian) {circleEntity.position = new Cesium.CallbackProperty(() => newCartesian, false);const newCartographic = Cesium.Cartographic.fromCartesian(newCartesian);const newLngLat = [Cesium.Math.toDegrees(newCartographic.longitude),Cesium.Math.toDegrees(newCartographic.latitude)];// 实时更新 infoDetail 中圆形的位置const circleInfo = this.infoDetail.circle.find(circle => circle.id === id);if (circleInfo) {circleInfo.center = newLngLat;}}}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);this.dragHandler.setInputAction(() => {if (isDragging && circleEntity) {const finalPosition = circleEntity.position.getValue(Cesium.JulianDate.now());const finalCartographic = Cesium.Cartographic.fromCartesian(finalPosition);const finalLngLat = [Cesium.Math.toDegrees(finalCartographic.longitude),Cesium.Math.toDegrees(finalCartographic.latitude)];// 结束拖动后,更新 infoDetail 中的圆心坐标const circleInfo = this.infoDetail.circle.find(circle => circle.id === id);if (circleInfo) {circleInfo.center = finalLngLat;}}isDragging = false;}, Cesium.ScreenSpaceEventType.LEFT_UP);}/******* * @function: function* @description: 通过坐标和半径生成圆形区域,并计算面积和周长*/drawCircleFromCoordinates (center, radius) {let id = new Date().getTime();// 将中心点转换为 Cartesian3 坐标let centerCartesian = Cesium.Cartesian3.fromDegrees(center[0], center[1]);// 计算面积(πr²)和周长(2πr)let area = Math.PI * Math.pow(radius, 2); // 单位:平方米let circumference = 2 * Math.PI * radius; // 单位:米this.infoDetail.circle.push({id: id,center: center,radius: radius,area: area, // 保存面积circumference: circumference // 保存周长});let entity = this.viewer.entities.add({position: centerCartesian,name: 'circle',id: id,ellipse: {semiMajorAxis: radius,semiMinorAxis: radius,height: 0,outline: true,material: this.config.material,outlineColor: this.config.borderColor,outlineWidth: this.config.borderWidth,},});// 启用拖动功能this.enableCircleDragging(entity, id);}/******* * @function: function* @description: 通过坐标、半径、起始角度和结束角度生成扇形,并计算面积和弧长*/drawSectorFromCoordinates (center, radius, startAngle, endAngle) {let id = new Date().getTime();// 将中心点转换为 Cartesian3 坐标let centerCartesian = Cesium.Cartesian3.fromDegrees(center[0], center[1]);// 计算扇形的边界点let positions = this.computeSectorPositions(centerCartesian, radius, startAngle, endAngle);// 计算扇形的面积和弧长let area = this.calculateSectorArea(radius, startAngle, endAngle);let arcLength = this.calculateArcLength(radius, startAngle, endAngle);this.infoDetail.sector.push({id: id,center: center,radius: radius,startAngle: startAngle,endAngle: endAngle,area: area, // 保存面积arcLength: arcLength // 保存弧长});let entity = this.viewer.entities.add({polygon: {hierarchy: new Cesium.PolygonHierarchy(positions),material: this.config.material,outline: true,outlineColor: this.config.borderColor,outlineWidth: this.config.borderWidth,},name: 'sector',id: id,});}/******* * @function: function* @description: 移除绘制对象*/removeEntity () {if (this.handler && !this.isDestroy) {this.handler.destroy();}this.isRemove = truethis.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);this.handler.setInputAction((move) => {let pick = this.viewer.scene.pick(move.endPosition);if (pick && pick.id && pick.id.id && this.isRemove) {document.body.style.cursor = 'pointer';this.handler.setInputAction((click) => {let newPoint;switch (pick.id.name) {case 'point':newPoint = this.infoDetail.point.filter((item) => item.id != pick.id._id);this.infoDetail.point = newPoint;break;case 'line':newPoint = this.infoDetail.line.filter((item) => item.id != pick.id._id);this.infoDetail.line = newPoint;break;case 'rectangle':newPoint = this.infoDetail.rectangle.filter((item) => item.id != pick.id._id);this.infoDetail.rectangle = newPoint;break;case 'planeSelf':newPoint = this.infoDetail.planeSelf.filter((item) => item.id != pick.id._id);this.infoDetail.planeSelf = newPoint;break;case 'circle':newPoint = this.infoDetail.circle.filter((item) => item.id != pick.id._id);this.infoDetail.circle = newPoint;break;case 'sector':newPoint = this.infoDetail.sector.filter((item) => item.id != pick.id._id);this.infoDetail.sector = newPoint;break;default:break;}this.viewer.entities.remove(pick.id);}, Cesium.ScreenSpaceEventType.LEFT_CLICK);} else {document.body.style = 'cursor: default;';}}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);}backInfoDetail () {return this.infoDetail;}
}