Vue3加vite使用Cesium绘制图形

2024-08-26 15:36

本文主要是介绍Vue3加vite使用Cesium绘制图形,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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;}
}

这篇关于Vue3加vite使用Cesium绘制图形的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1108973

相关文章

Nginx中配置使用非默认80端口进行服务的完整指南

《Nginx中配置使用非默认80端口进行服务的完整指南》在实际生产环境中,我们经常需要将Nginx配置在其他端口上运行,本文将详细介绍如何在Nginx中配置使用非默认端口进行服务,希望对大家有所帮助... 目录一、为什么需要使用非默认端口二、配置Nginx使用非默认端口的基本方法2.1 修改listen指令

Python WebSockets 库从基础到实战使用举例

《PythonWebSockets库从基础到实战使用举例》WebSocket是一种全双工、持久化的网络通信协议,适用于需要低延迟的应用,如实时聊天、股票行情推送、在线协作、多人游戏等,本文给大家介... 目录1. 引言2. 为什么使用 WebSocket?3. 安装 WebSockets 库4. 使用 We

python中的显式声明类型参数使用方式

《python中的显式声明类型参数使用方式》文章探讨了Python3.10+版本中类型注解的使用,指出FastAPI官方示例强调显式声明参数类型,通过|操作符替代Union/Optional,可提升代... 目录背景python函数显式声明的类型汇总基本类型集合类型Optional and Union(py

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

使用SpringBoot+InfluxDB实现高效数据存储与查询

《使用SpringBoot+InfluxDB实现高效数据存储与查询》InfluxDB是一个开源的时间序列数据库,特别适合处理带有时间戳的监控数据、指标数据等,下面详细介绍如何在SpringBoot项目... 目录1、项目介绍2、 InfluxDB 介绍3、Spring Boot 配置 InfluxDB4、I

使用Java读取本地文件并转换为MultipartFile对象的方法

《使用Java读取本地文件并转换为MultipartFile对象的方法》在许多JavaWeb应用中,我们经常会遇到将本地文件上传至服务器或其他系统的需求,在这种场景下,MultipartFile对象非... 目录1. 基本需求2. 自定义 MultipartFile 类3. 实现代码4. 代码解析5. 自定

使用Python实现无损放大图片功能

《使用Python实现无损放大图片功能》本文介绍了如何使用Python的Pillow库进行无损图片放大,区分了JPEG和PNG格式在放大过程中的特点,并给出了示例代码,JPEG格式可能受压缩影响,需先... 目录一、什么是无损放大?二、实现方法步骤1:读取图片步骤2:无损放大图片步骤3:保存图片三、示php

使用Python实现一个简易计算器的新手指南

《使用Python实现一个简易计算器的新手指南》计算器是编程入门的经典项目,它涵盖了变量、输入输出、条件判断等核心编程概念,通过这个小项目,可以快速掌握Python的基础语法,并为后续更复杂的项目打下... 目录准备工作基础概念解析分步实现计算器第一步:获取用户输入第二步:实现基本运算第三步:显示计算结果进

python之uv使用详解

《python之uv使用详解》文章介绍uv在Ubuntu上用于Python项目管理,涵盖安装、初始化、依赖管理、运行调试及Docker应用,强调CI中使用--locked确保依赖一致性... 目录安装与更新standalonepip 安装创建php以及初始化项目依赖管理uv run直接在命令行运行pytho

C#使用Spire.XLS快速生成多表格Excel文件

《C#使用Spire.XLS快速生成多表格Excel文件》在日常开发中,我们经常需要将业务数据导出为结构清晰的Excel文件,本文将手把手教你使用Spire.XLS这个强大的.NET组件,只需几行C#... 目录一、Spire.XLS核心优势清单1.1 性能碾压:从3秒到0.5秒的质变1.2 批量操作的优雅