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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/409292.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【STM32】看门狗

看门狗&#xff0c;还没有别的地方用上&#xff0c;暂时还不清楚在实际应用中最多的场景是什么&#xff0c;我感觉是用来强制重启系统。 大部分图片来源&#xff1a;正点原子HAL库教程 专栏目录&#xff1a;记录自己的嵌入式学习之路-CSDN博客 目录 1 应用场景 1.1 解决…

Langchain Memory组件深度剖析:从对话基础到高级链式应用

文章目录 前言一、Langchain memory 记忆1.Memory 组件基本介绍2.Memory 组件的类型1.ChatMessageHistory2.ConversationBufferMemory3.ConversationBufferWindowMemory4.ConversationEntityMemory5.ConversationKGMemory6.ConversationSummaryMemory 二、长时记忆1.简单介绍2.…

解决ubuntu22.04无法识别CH340/CH341和vscode espidf插件无法选择串口设备节点问题

文章目录 解决ubuntu22.04无法识别CH340/CH341和vscode espidf插件无法选择串口设备节点问题不识别CH340/CH341报错解决办法升级驱动编译安装 卸载brltty程序 vscode espidf插件无法选择串口设备节点问题解决办法编译安装 解决ubuntu22.04无法识别CH340/CH341和vscode espidf插…

C#开发中ImageComboBox控件数据源实时变换

在C#开发中&#xff0c;我们如何将控件的数据源实时变换&#xff0c;当然我们可以在窗口实例化的时候指定固定的数据源&#xff0c;但是这样对于用户来说数据源永远固定&#xff0c;并不利于我们对于用户的数据存储&#xff0c;优化用户的操作&#xff0c;遇到这种问题&#xf…

Flutter ListView滑动

在Flutter中&#xff0c;ScrollController可以精确地控制和管理滚动行为。通过ScrollController&#xff0c;可以监听滚动的位置、速度&#xff0c;甚至可以在用户滚动时触发自定义的动作。此外&#xff0c;ScrollController还提供了对滚动位置的直接控制&#xff0c;可以编程地…

DRF——请求的封装与版本管理

文章目录 django restframework1. 快速上手2. 请求数据的封装3. 版本管理3.1 URL的GET参数传递&#xff08;*&#xff09;3.2 URL路径传递&#xff08;*&#xff09;3.3 请求头传递3.4 二级域名传递3.5 路由的namespace传递 小结 django restframework 快速上手请求的封装版本…

科大讯飞刘聪:大模型加持,人形机器人将跨越三大瓶颈

2024年&#xff0c;AI大模型成为机器人产业新的加速器。 今年3月&#xff0c;ChatGPT4加持的机器人Figure01向外界展示了大模型赋能人形机器人的巨大潜力。Figure01能理解周围环境&#xff0c;流畅地与人类交谈&#xff0c;理解人类的需求并完成具体行动&#xff0c;包括给人类…

虚幻5|AI视力系统,听力系统,预测系统(2)听力系统

虚幻5|AI视力系统&#xff0c;听力系统&#xff0c;预测系统&#xff08;1&#xff09;视力系统-CSDN博客 一&#xff0c;把之前的听力系统&#xff0c;折叠成函数&#xff0c;复制粘贴一份改名为听力系统 1.小个体修改如下&#xff0c;把之前的视力系统改成听力系统 2.整体修…

隐私指纹浏览器产品系列 —— 浏览器指纹 中(三)

1.引言 在上一篇文章中&#xff0c;我们聊到了最老牌的浏览器指纹检测站——BrowserLeaks。BrowserLeaks曾经是浏览器指纹检测的权威&#xff0c;但它似乎更像是一本老旧的工具书&#xff0c;只能呆板告诉你浏览器的指纹值&#xff0c;并对比不同浏览器的指纹差异。 今天&…

C语言 之 浮点数在内存中的存储 详细讲解

文章目录 浮点数浮点数的存储浮点数的存储浮点数的读取例题 浮点数 常见的浮点数&#xff1a;3.14159、1E10&#xff08;表示1*10^10&#xff09;等 浮点数家族包括&#xff1a; float、double、long double 类型。 浮点数表示的范围在float.h 中有定义 浮点数的存储 浮点数…

C++研发笔记1——github注册文档

1、第一步&#xff1a;登录网站 GitHub: Let’s build from here GitHub 最新跳转页面如下&#xff1a; 2、选择“sign up”进行注册&#xff0c;并填写设置账户信息 3、创建账户成功之后需要进行再次登录 4、根据实际情况填写个人状态信息 登录完成后页面网站&#xff1a; 5…

手写SpringAOP

一、非注解式简易版AOP 整体流程 1.1 代码 public class Test {public static void main(String[] args){// Aop代理工厂DefaultAopProxyFactory factory new DefaultAopProxyFactory();// 测试对象AOPDemoImpl demo new AOPDemoImpl();// 支撑类&#xff1a;用于存放目标…

配置策略路由实战 附带基础网络知识

背景 作为一个软件开发人员&#xff0c;不可能做到只负责业务开发工作&#xff0c;一旦功能上线或者系统切换就会遇到非常多考验开发人员个人能力的场景&#xff0c;网络调整就是非常重要的一个方面&#xff0c;如果你在系统上线的过程中无法处理一些简单的网络问题或者听不懂…

文件包含漏洞(1)

目录 PHP伪协议 php://input Example 1&#xff1a; 造成任意代码执行 Example 2&#xff1a; 文件内容绕过 php://filer zip:// PHP伪协议 php://input Example 1&#xff1a; 造成任意代码执行 搭建环境 <meta charset"utf8"> <?php error_repo…

Modern C++——不准确“类型声明”引发的非必要性能损耗

大纲 案例代码地址 C是一种强类型语言。我们在编码时就需要明确指出每个变量的类型&#xff0c;进而让编译器可以正确的编译。看似C编译器比其他弱类型语言的编译器要死板&#xff0c;实则它也做了很多“隐藏”的操作。它会在尝试针对一些非预期类型进行相应转换&#xff0c;以…

QT Quick QML 网络助手——TCP客户端

GitHub 源码: QmlLearningPro &#xff0c;选择子工程 Nettools.pro QML 其它文章请点击这里: QT QUICK QML 学习笔记 ● 运行效果&#xff1a; 左侧为常用的网络调试工具&#xff0c;右侧为本项目 UI 效果&#xff0c;前端使用 QML &#xff0c;后端使用C &#xff…

【文档智能 RAG】浅看开源的同质化的文档解析框架-Docling

前言 RAG的兴起&#xff0c;越来越多的人开始关注文档结构化解析的效果&#xff0c;这个赛道变得非常的同质化。 关于文档智能解析过程中的每个技术环节的技术点&#xff0c;前期文章详细介绍了很多内容&#xff1a; 下面我们简单的看看Docling这个PDF文档解析框架里面都有什…

GPIO(通用输入/输出)、中断(hal库)

目录 GPIO&#xff08;通用输入/输出)&#xff08;hal库&#xff09; GPIO工作模式 推挽输出&#xff08;Push-Pull Output&#xff09; 开漏输出&#xff08;Open-Drain Output&#xff09; 复用推挽输出&#xff08;Alternate Function Push-Pull Output&#xff09; 复…

在Ubuntu 22.04测试ebpf-go入门例子

文章目录 1、eBPF-Go依赖1.1 Ubuntu安装ssh server1.2 安装go1.3 安装llvm和clang1.4 安装libbpf和Linux kernel headers 2 编写eBPF C程序3 使用bpf2go编译eBPF C程序4 编写Go程序5 编译运行Go应用程序 eBPF-Go是一个使用eBPF的Go库。它不依赖于C、libbpf或除标准库之外的任何…

Windows单机安装配置mongodb+hadoop+spark+pyspark用于大数据分析

目录 版本选择安装配置Java环境配置Hadoop配置Spark配置 安装pyspark使用Jupyter Notebook进行Spark MongoDB测试参考 版本选择 根据Spark Connector&#xff1a;org.mongodb.spark:mongo-spark-connector_2.13:10.3.0 的前提要求 这里选择使用最新的MongoDB 7.0.12社区版 ht…