diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue index d0a99ec..0f69877 100644 --- a/ruoyi-ui/src/views/cesiumMap/index.vue +++ b/ruoyi-ui/src/views/cesiumMap/index.vue @@ -69,6 +69,7 @@ export default { drawingPoints: [], drawingStartPoint: null, isDrawing: false, + activeCursorPosition: null, // 实时鼠标位置 // 实体管理 allEntities: [], // 所有绘制的实体 @@ -349,6 +350,7 @@ export default { this.drawingPoints = []; this.drawingStartPoint = null; this.isDrawing = false; + this.activeCursorPosition = null; this.viewer.scene.canvas.style.cursor = 'default'; }, @@ -368,8 +370,6 @@ export default { // 绘制线 startLineDrawing() { this.drawingPoints = []; - // 记录当前鼠标的实时位置 - let activeCursorPosition = null; // 清除可能存在的旧实体 if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); @@ -381,7 +381,7 @@ export default { this.drawingHandler.setInputAction((movement) => { const newPosition = this.getClickPosition(movement.endPosition); if (newPosition) { - activeCursorPosition = newPosition; + this.activeCursorPosition = newPosition; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); @@ -393,7 +393,7 @@ export default { // === 第一步:点击第一个点后,立即创建“动态虚线” === if (this.drawingPoints.length === 1) { - activeCursorPosition = position; // 初始化鼠标位置 + this.activeCursorPosition = position; // 初始化鼠标位置 // 创建预览虚线(只创建这一次,之后它会自动随数据更新) this.tempPreviewEntity = this.viewer.entities.add({ @@ -401,11 +401,11 @@ export default { // 关键:使用 CallbackProperty 动态获取位置 positions: new Cesium.CallbackProperty(() => { // 只有当有点且鼠标位置存在时才渲染 - if (this.drawingPoints.length > 0 && activeCursorPosition) { + if (this.drawingPoints.length > 0 && this.activeCursorPosition) { // 获取最后一个已确认的点 const lastPoint = this.drawingPoints[this.drawingPoints.length - 1]; // 返回 [最后一个点, 当前鼠标位置] - return [lastPoint, activeCursorPosition]; + return [lastPoint, this.activeCursorPosition]; } return []; }, false), @@ -451,8 +451,8 @@ export default { this.cancelDrawing(); } - // 重置局部变量 - activeCursorPosition = null; + // 重置鼠标位置 + this.activeCursorPosition = null; }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }, @@ -475,7 +475,9 @@ export default { type: 'line' }; - this.stopDrawing(); + // 重置绘制点数组,保持绘制状态以继续绘制 + this.drawingPoints = []; + this.tempEntity = null; return entity; } else { this.cancelDrawing(); @@ -486,7 +488,6 @@ export default { // 绘制多边形 startPolygonDrawing() { this.drawingPoints = []; - let activeCursorPosition = null; // 存储鼠标实时位置 // 1. 清理旧实体 // 移除之前可能遗留的实体,确保干净的画布 @@ -499,7 +500,7 @@ export default { this.drawingHandler.setInputAction((movement) => { const newPosition = this.getClickPosition(movement.endPosition); if (newPosition) { - activeCursorPosition = newPosition; + this.activeCursorPosition = newPosition; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); @@ -511,7 +512,7 @@ export default { // === 关键逻辑:点击第一个点时,创建唯一的“动态多边形” === if (this.drawingPoints.length === 1) { - activeCursorPosition = position; // 初始化鼠标位置 + this.activeCursorPosition = position; // 初始化鼠标位置 this.tempEntity = this.viewer.entities.add({ // --- 填充面配置 --- @@ -519,8 +520,8 @@ export default { // hierarchy 使用 CallbackProperty 实现动态填充 hierarchy: new Cesium.CallbackProperty(() => { // 组合:已确定的点 + 当前鼠标位置 - if (activeCursorPosition) { - return new Cesium.PolygonHierarchy([...this.drawingPoints, activeCursorPosition]); + if (this.activeCursorPosition) { + return new Cesium.PolygonHierarchy([...this.drawingPoints, this.activeCursorPosition]); } return new Cesium.PolygonHierarchy(this.drawingPoints); }, false), @@ -533,9 +534,9 @@ export default { polyline: { // positions 使用 CallbackProperty 实现动态闭合线 positions: new Cesium.CallbackProperty(() => { - if (activeCursorPosition) { + if (this.activeCursorPosition) { // 闭合回路:[所有点, 鼠标位置, 回到起点] - return [...this.drawingPoints, activeCursorPosition, this.drawingPoints[0]]; + return [...this.drawingPoints, this.activeCursorPosition, this.drawingPoints[0]]; } return this.drawingPoints; }, false), @@ -561,7 +562,7 @@ export default { } // 重置状态 - activeCursorPosition = null; + this.activeCursorPosition = null; }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }, @@ -576,15 +577,19 @@ export default { type: 'polygon' } - this.stopDrawing() + // 重置绘制点数组,保持绘制状态以继续绘制 + this.drawingPoints = [] + if (this.tempEntity) { + this.viewer.entities.remove(this.tempEntity) + this.tempEntity = null + } return entity }, // 绘制矩形(优化版:两点定矩形,实时预览) startRectangleDrawing() { + // 重置绘制状态 this.drawingPoints = []; // 存储起点和终点 - let activeCursorPosition = null; // 实时鼠标位置 - let startPoint = null; // 记录起点 // 1. 清理旧实体 if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); @@ -594,7 +599,7 @@ export default { this.drawingHandler.setInputAction((movement) => { const newPosition = this.getClickPosition(movement.endPosition); if (newPosition) { - activeCursorPosition = newPosition; + this.activeCursorPosition = newPosition; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); @@ -603,19 +608,18 @@ export default { const position = this.getClickPosition(click.position); if (position) { // --- 情况A:第一次点击(确定起点) --- - if (!startPoint) { - startPoint = position; - this.drawingPoints.push(startPoint); - activeCursorPosition = startPoint; // 初始化鼠标位置 + if (this.drawingPoints.length === 0) { + this.drawingPoints.push(position); + this.activeCursorPosition = position; // 初始化鼠标位置 // 创建动态预览矩形 this.tempEntity = this.viewer.entities.add({ rectangle: { // 关键:使用 CallbackProperty 动态计算矩形范围 coordinates: new Cesium.CallbackProperty(() => { - if (startPoint && activeCursorPosition) { + if (this.drawingPoints.length > 0 && this.activeCursorPosition) { // 使用 Cesium 内置工具,根据两个点(对角)自动计算矩形范围 - return Cesium.Rectangle.fromCartesianArray([startPoint, activeCursorPosition]); + return Cesium.Rectangle.fromCartesianArray([this.drawingPoints[0], this.activeCursorPosition]); } return Cesium.Rectangle.fromDegrees(0, 0, 0, 0); }, false), @@ -629,10 +633,10 @@ export default { }); } // --- 情况B:第二次点击(确定终点) --- - else { + else if (this.drawingPoints.length === 1) { this.drawingPoints.push(position); // 停止监听鼠标移动,因为形状已确定 - activeCursorPosition = null; + this.activeCursorPosition = null; // 调用完成逻辑 this.finishRectangleDrawing(); @@ -679,8 +683,8 @@ export default { type: 'rectangle' }; - // 6. 重置状态 - this.stopDrawing(); + // 6. 重置状态,保持绘制状态以继续绘制 + this.drawingPoints = []; }, // 计算矩形面积(辅助方法) @@ -718,73 +722,136 @@ export default { }, // 绘制圆形 startCircleDrawing() { + // 重置绘制状态 this.drawingPoints = []; // 存储圆心 - let activeCursorPosition = null; // 实时鼠标位置 - let centerPoint = null; // 圆心坐标 + this.activeCursorPosition = null; // 1. 清理旧实体 - if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); - this.tempEntity = null; + if (this.tempEntity) { + try { + this.viewer.entities.remove(this.tempEntity); + } catch (e) { + console.warn('Failed to remove temp entity:', e); + } + this.tempEntity = null; + } + if (this.tempPreviewEntity) { + try { + this.viewer.entities.remove(this.tempPreviewEntity); + } catch (e) { + console.warn('Failed to remove temp preview entity:', e); + } + this.tempPreviewEntity = null; + } - // 2. 鼠标移动事件 + // 2. 重置事件处理器 + this.drawingHandler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE); + this.drawingHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK); + this.drawingHandler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK); + + // 3. 鼠标移动事件 this.drawingHandler.setInputAction((movement) => { - const newPosition = this.getClickPosition(movement.endPosition); - if (newPosition) { - activeCursorPosition = newPosition; + try { + const newPosition = this.getClickPosition(movement.endPosition); + if (newPosition) { + this.activeCursorPosition = newPosition; + } + } catch (e) { + console.warn('Mouse move error:', e); } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); - // 3. 鼠标点击事件 + // 4. 鼠标点击事件 this.drawingHandler.setInputAction((click) => { - const position = this.getClickPosition(click.position); - if (position) { - // --- 情况A:第一次点击(确定圆心) --- - if (!centerPoint) { - centerPoint = position; - this.drawingPoints.push(centerPoint); - activeCursorPosition = centerPoint; + try { + const position = this.getClickPosition(click.position); + if (position) { + // --- 情况A:第一次点击(确定圆心) --- + if (this.drawingPoints.length === 0) { + this.drawingPoints.push(position); + this.activeCursorPosition = position; + + // 创建动态预览圆形 + if (this.tempEntity) { + try { + this.viewer.entities.remove(this.tempEntity); + } catch (e) { + console.warn('Failed to remove existing temp entity:', e); + } + this.tempEntity = null; + } - // 创建动态预览圆形 - this.tempEntity = this.viewer.entities.add({ - position: centerPoint, // 圆心固定 - ellipse: { - // 关键:使用 CallbackProperty 动态计算半径(半长轴和半短轴) - semiMajorAxis: new Cesium.CallbackProperty(() => { - if (centerPoint && activeCursorPosition) { - return Cesium.Cartesian3.distance(centerPoint, activeCursorPosition); - } - return 0; - }, false), - semiMinorAxis: new Cesium.CallbackProperty(() => { - if (centerPoint && activeCursorPosition) { - return Cesium.Cartesian3.distance(centerPoint, activeCursorPosition); + // 确保有有效的圆心位置 + if (position) { + // 先创建一个固定半径的临时圆,避免半径为0的情况 + const initialRadius = 100; // 初始半径设为100米 + + this.tempEntity = this.viewer.entities.add({ + position: position, // 直接使用确定的圆心位置 + ellipse: { + // 关键:使用 CallbackProperty 动态计算半径(半长轴和半短轴) + semiMajorAxis: new Cesium.CallbackProperty(() => { + try { + if (this.activeCursorPosition && this.drawingPoints.length > 0 && this.drawingPoints[0]) { + const center = this.drawingPoints[0]; + const edge = this.activeCursorPosition; + if (center && edge && typeof center.x === 'number' && typeof edge.x === 'number') { + const distance = Cesium.Cartesian3.distance(center, edge); + return isFinite(distance) && distance > 0 ? distance : initialRadius; + } + } + return initialRadius; + } catch (e) { + return initialRadius; + } + }, false), + semiMinorAxis: new Cesium.CallbackProperty(() => { + try { + if (this.activeCursorPosition && this.drawingPoints.length > 0 && this.drawingPoints[0]) { + const center = this.drawingPoints[0]; + const edge = this.activeCursorPosition; + if (center && edge && typeof center.x === 'number' && typeof edge.x === 'number') { + const distance = Cesium.Cartesian3.distance(center, edge); + return isFinite(distance) && distance > 0 ? distance : initialRadius; + } + } + return initialRadius; + } catch (e) { + return initialRadius; + } + }, false), + // 样式设置 + material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), + outline: true, + outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), + outlineWidth: 2, + // height: 0, // 如果需要贴地可开启或使用 heightReference } - return 0; - }, false), - // 样式设置 - material: Cesium.Color.fromCssColorString(this.defaultStyles.polygon.color).withAlpha(0.5), - outline: true, - outlineColor: Cesium.Color.fromCssColorString(this.defaultStyles.line.color), - outlineWidth: 2, - // height: 0, // 如果需要贴地可开启或使用 heightReference + }); } - }); - } - // --- 情况B:第二次点击(确定边缘/半径) --- - else { - // 记录边缘点(虽然圆只需要圆心和半径,但记录下来方便后续处理) - this.drawingPoints.push(position); - activeCursorPosition = null; // 停止动态更新 - - // 传递边缘点位置去结束绘制 - this.finishCircleDrawing(position); + } + // --- 情况B:第二次点击(确定边缘/半径) --- + else if (this.drawingPoints.length === 1) { + // 记录边缘点(虽然圆只需要圆心和半径,但记录下来方便后续处理) + this.drawingPoints.push(position); + this.activeCursorPosition = null; // 停止动态更新 + + // 传递边缘点位置去结束绘制 + this.finishCircleDrawing(position); + } } + } catch (e) { + console.warn('Mouse click error:', e); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); - // 4. 右键取消 + // 5. 右键取消 this.drawingHandler.setInputAction(() => { - this.cancelDrawing(); + try { + this.cancelDrawing(); + } catch (e) { + console.warn('Right click error:', e); + } }, Cesium.ScreenSpaceEventType.RIGHT_CLICK); }, @@ -827,17 +894,15 @@ export default { type: 'circle' }; - // 6. 结束绘制状态 - this.stopDrawing(); + // 6. 重置状态,保持绘制状态以继续绘制 + this.drawingPoints = []; + this.activeCursorPosition = null; }, // 绘制扇形 startSectorDrawing() { + // 重置绘制状态 this.drawingPoints = []; // 存储圆心、半径端点、角度端点 - let activeCursorPosition = null; // 实时鼠标位置 - let centerPoint = null; // 圆心坐标 - let radiusPoint = null; // 半径端点 - let radius = 0; // 半径长度 // 1. 清理旧实体 if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); @@ -849,7 +914,7 @@ export default { this.drawingHandler.setInputAction((movement) => { const newPosition = this.getClickPosition(movement.endPosition); if (newPosition) { - activeCursorPosition = newPosition; + this.activeCursorPosition = newPosition; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); @@ -858,17 +923,16 @@ export default { const position = this.getClickPosition(click.position); if (position) { // --- 情况A:第一次点击(确定圆心) --- - if (!centerPoint) { - centerPoint = position; - this.drawingPoints.push(centerPoint); - activeCursorPosition = centerPoint; + if (this.drawingPoints.length === 0) { + this.drawingPoints.push(position); + this.activeCursorPosition = position; // 创建动态预览半径线 this.tempPreviewEntity = this.viewer.entities.add({ polyline: { positions: new Cesium.CallbackProperty(() => { - if (centerPoint && activeCursorPosition) { - return [centerPoint, activeCursorPosition]; + if (this.drawingPoints.length > 0 && this.activeCursorPosition) { + return [this.drawingPoints[0], this.activeCursorPosition]; } return []; }, false), @@ -882,10 +946,12 @@ export default { }); } // --- 情况B:第二次点击(确定半径) --- - else if (!radiusPoint) { - radiusPoint = position; - this.drawingPoints.push(radiusPoint); - radius = Cesium.Cartesian3.distance(centerPoint, radiusPoint); + else if (this.drawingPoints.length === 1) { + this.drawingPoints.push(position); + this.activeCursorPosition = position; // 更新 activeCursorPosition 为实际点击位置 + const centerPoint = this.drawingPoints[0]; + const radiusPoint = this.drawingPoints[1]; + const fixedRadius = Cesium.Cartesian3.distance(centerPoint, radiusPoint); // 移除半径预览线 if (this.tempPreviewEntity) { @@ -897,11 +963,15 @@ export default { this.tempEntity = this.viewer.entities.add({ polygon: { hierarchy: new Cesium.CallbackProperty(() => { - if (centerPoint && activeCursorPosition) { - const currentRadius = Cesium.Cartesian3.distance(centerPoint, activeCursorPosition); + if (this.drawingPoints.length > 1 && this.activeCursorPosition) { + const centerPoint = this.drawingPoints[0]; + const radiusPoint = this.drawingPoints[1]; + if (!isFinite(fixedRadius) || fixedRadius === 0) { + return new Cesium.PolygonHierarchy([]); + } const startAngle = this.calculatePointAngle(centerPoint, radiusPoint); - const endAngle = this.calculatePointAngle(centerPoint, activeCursorPosition); - const positions = this.generateSectorPositions(centerPoint, currentRadius, startAngle, endAngle); + const endAngle = this.calculatePointAngle(centerPoint, this.activeCursorPosition); + const positions = this.generateSectorPositions(centerPoint, fixedRadius, startAngle, endAngle); return new Cesium.PolygonHierarchy(positions); } return new Cesium.PolygonHierarchy([]); @@ -914,13 +984,12 @@ export default { }); } // --- 情况C:第三次点击(确定角度) --- - else { - const anglePoint = position; - this.drawingPoints.push(anglePoint); - activeCursorPosition = null; // 停止动态更新 + else if (this.drawingPoints.length === 2) { + this.drawingPoints.push(position); + this.activeCursorPosition = null; // 停止动态更新 // 传递角度点位置去结束绘制 - this.finishSectorDrawing(centerPoint, radiusPoint, anglePoint); + this.finishSectorDrawing(this.drawingPoints[0], this.drawingPoints[1], this.drawingPoints[2]); } } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); @@ -933,7 +1002,7 @@ export default { // 完成扇形绘制 finishSectorDrawing(centerPoint, radiusPoint, anglePoint) { - const radius = Cesium.Cartesian3.distance(centerPoint, anglePoint); + const radius = Cesium.Cartesian3.distance(centerPoint, radiusPoint); const startAngle = this.calculatePointAngle(centerPoint, radiusPoint); const endAngle = this.calculatePointAngle(centerPoint, anglePoint); @@ -978,8 +1047,8 @@ export default { }; this.allEntities.push(entityData); - // 5. 结束绘制状态 - this.stopDrawing(); + // 5. 重置状态,保持绘制状态以继续绘制 + this.drawingPoints = []; }, // 计算角度 @@ -989,8 +1058,8 @@ export default { const centerLL = Cesium.Cartographic.fromCartesian(center); // 计算两点相对于圆心的角度 - const startAngle = Math.atan2(startLL.longitude - centerLL.longitude, startLL.latitude - centerLL.latitude); - const endAngle = Math.atan2(endLL.longitude - centerLL.longitude, endLL.latitude - centerLL.latitude); + const startAngle = Math.atan2(startLL.latitude - centerLL.latitude, startLL.longitude - centerLL.longitude); + const endAngle = Math.atan2(endLL.latitude - centerLL.latitude, endLL.longitude - centerLL.longitude); // 返回角度差 return endAngle - startAngle; @@ -1003,8 +1072,8 @@ export default { const centerLL = Cesium.Cartographic.fromCartesian(center); // 计算两点相对于圆心的角度 - const startAngle = Math.atan2(startLL.longitude - centerLL.longitude, startLL.latitude - centerLL.latitude); - const endAngle = Math.atan2(endLL.longitude - centerLL.longitude, endLL.latitude - centerLL.latitude); + const startAngle = Math.atan2(startLL.latitude - centerLL.latitude, startLL.longitude - centerLL.longitude); + const endAngle = Math.atan2(endLL.latitude - centerLL.latitude, endLL.longitude - centerLL.longitude); // 计算角度差(确保为正值) let angleDiff = endAngle - startAngle; @@ -1022,7 +1091,7 @@ export default { const centerLL = Cesium.Cartographic.fromCartesian(center); // 计算点相对于圆心的角度 - const angle = Math.atan2(pointLL.longitude - centerLL.longitude, pointLL.latitude - centerLL.latitude); + const angle = Math.atan2(pointLL.latitude - centerLL.latitude, pointLL.longitude - centerLL.longitude); return angle; }, @@ -1034,8 +1103,8 @@ export default { // 添加圆心 positions.push(center); - // 计算角度差 - let angleDiff = endAngle - startAngle; + // 计算角度差(顺时针方向) + let angleDiff = startAngle - endAngle; if (angleDiff < 0) { angleDiff += 2 * Math.PI; } @@ -1047,13 +1116,13 @@ export default { const numPoints = Math.max(5, Math.ceil(angleDiff * 180 / Math.PI / 10)); const angleStep = angleDiff / (numPoints - 1); - // 生成扇形的顶点 + // 生成扇形的顶点(顺时针方向) for (let i = 0; i < numPoints; i++) { - const currentAngle = startAngle + i * angleStep; + const currentAngle = startAngle - i * angleStep; const distance = radius / 6378137; // 转换为弧度 - const lat = centerLL.latitude + Math.cos(currentAngle) * distance; - const lng = centerLL.longitude + Math.sin(currentAngle) * distance / Math.cos(centerLL.latitude); + const lat = centerLL.latitude + Math.sin(currentAngle) * distance; + const lng = centerLL.longitude + Math.cos(currentAngle) * distance / Math.cos(centerLL.latitude); const position = Cesium.Cartesian3.fromRadians(lng, lat); positions.push(position); @@ -1065,6 +1134,8 @@ export default { return positions; }, + + // 计算两点之间的距离(米) calculateDistance(point1, point2) { return Cesium.Cartesian3.distance(point1, point2); @@ -1073,7 +1144,6 @@ export default { // 绘制箭头 startArrowDrawing() { this.drawingPoints = []; // 存储起点和终点 - let activeCursorPosition = null; // 实时鼠标位置 // 1. 清理旧实体 if (this.tempEntity) this.viewer.entities.remove(this.tempEntity); @@ -1085,7 +1155,7 @@ export default { this.drawingHandler.setInputAction((movement) => { const newPosition = this.getClickPosition(movement.endPosition); if (newPosition) { - activeCursorPosition = newPosition; + this.activeCursorPosition = newPosition; } }, Cesium.ScreenSpaceEventType.MOUSE_MOVE); @@ -1097,7 +1167,7 @@ export default { // --- 情况A:第一次点击(确定起点) --- if (this.drawingPoints.length === 1) { - activeCursorPosition = position; // 初始化鼠标位置 + this.activeCursorPosition = position; // 初始化鼠标位置 // 创建动态预览箭头 this.tempPreviewEntity = this.viewer.entities.add({ @@ -1105,11 +1175,11 @@ export default { // 使用 CallbackProperty 动态获取位置 positions: new Cesium.CallbackProperty(() => { // 只有当有点且鼠标位置存在时才渲染 - if (this.drawingPoints.length > 0 && activeCursorPosition) { + if (this.drawingPoints.length > 0 && this.activeCursorPosition) { // 获取最后一个已确认的点 const lastPoint = this.drawingPoints[this.drawingPoints.length - 1]; // 返回 [最后一个点, 当前鼠标位置] - return [lastPoint, activeCursorPosition]; + return [lastPoint, this.activeCursorPosition]; } return []; }, false), @@ -1126,7 +1196,7 @@ export default { // --- 情况B:第二次点击(确定终点) --- else { // 停止监听鼠标移动,因为形状已确定 - activeCursorPosition = null; + this.activeCursorPosition = null; // 调用完成逻辑 this.finishArrowDrawing(); @@ -1153,7 +1223,8 @@ export default { // 创建最终的箭头实体 const entity = this.addArrowEntity([...this.drawingPoints]); - this.stopDrawing(); + // 重置绘制点数组,保持绘制状态以继续绘制 + this.drawingPoints = []; return entity; } else { this.cancelDrawing();