From 086b1946e0c19dfa4d384ad50dc7a85a0d0bc907 Mon Sep 17 00:00:00 2001
From: ctw <1051735452@qq.com>
Date: Mon, 2 Feb 2026 11:04:57 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=AF=94=E4=BE=8B=E5=B0=BA?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
ruoyi-ui/src/views/cesiumMap/index.vue | 194 ++++++++++++++++++++++++++++++---
1 file changed, 176 insertions(+), 18 deletions(-)
diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue
index 3ffe8d4..aa41e97 100644
--- a/ruoyi-ui/src/views/cesiumMap/index.vue
+++ b/ruoyi-ui/src/views/cesiumMap/index.vue
@@ -35,9 +35,18 @@
@delete="deleteEntityFromContextMenu"
@update-property="updateEntityProperty"
/>
-
-
- {{ coordinatesText }}
+
+
+
+
{{ scaleBarText }}
+
+
+
+
+
+
+ {{ coordinatesText }}
+
@@ -85,7 +94,6 @@ export default {
data() {
return {
viewer: null,
- scaleBar: null,
// 绘制相关
drawingMode: null, // 'point', 'line', 'polygon', 'rectangle', 'circle'
drawingHandler: null,
@@ -127,7 +135,10 @@ export default {
image: { width: 150, height: 150 }
},
// 鼠标经纬度
- coordinatesText: '经度: --, 纬度: --'
+ coordinatesText: '经度: --, 纬度: --',
+ // 比例尺(高德风格)
+ scaleBarText: '--',
+ scaleBarWidthPx: 80
}
},
components: {
@@ -2558,7 +2569,101 @@ export default {
})
},
initScaleBar() {
- // ... 原有的比例尺代码保持不变
+ const that = this
+ const update = () => {
+ that.updateScaleBar()
+ }
+ update()
+ this.viewer.camera.changed.addEventListener(update)
+ this.viewer.camera.moveEnd.addEventListener(update)
+ this.scaleBarCleanup = () => {
+ that.viewer.camera.changed.removeEventListener(update)
+ that.viewer.camera.moveEnd.removeEventListener(update)
+ }
+ },
+ /** 根据当前视口计算比例尺(兼容 2D/WebMercator,多位置尝试 pick + 视口宽度备用) */
+ getScaleBarInfo() {
+ if (!this.viewer || !this.viewer.scene.canvas) return null
+ const canvas = this.viewer.scene.canvas
+ const w = canvas.clientWidth
+ const h = canvas.clientHeight
+ if (w <= 0 || h <= 0) return null
+ const ellipsoid = this.viewer.scene.globe.ellipsoid
+ const camera = this.viewer.camera
+ const barPx = 80
+ const centerX = w / 2
+ // 多组参考点尝试(2D 下 pickEllipsoid 可能只在部分区域有效)
+ const tryPoints = [
+ [centerX - barPx / 2, h - 50],
+ [centerX + barPx / 2, h - 50]
+ ].concat([
+ [centerX - barPx / 2, h / 2],
+ [centerX + barPx / 2, h / 2]
+ ])
+ let leftCartesian = null
+ let rightCartesian = null
+ leftCartesian = camera.pickEllipsoid(new Cesium.Cartesian2(tryPoints[0][0], tryPoints[0][1]), ellipsoid)
+ rightCartesian = camera.pickEllipsoid(new Cesium.Cartesian2(tryPoints[1][0], tryPoints[1][1]), ellipsoid)
+ if (!leftCartesian || !rightCartesian) {
+ leftCartesian = camera.pickEllipsoid(new Cesium.Cartesian2(tryPoints[2][0], tryPoints[2][1]), ellipsoid)
+ rightCartesian = camera.pickEllipsoid(new Cesium.Cartesian2(tryPoints[3][0], tryPoints[3][1]), ellipsoid)
+ }
+ if (leftCartesian && rightCartesian) {
+ const rawMeters = Cesium.Cartesian3.distance(leftCartesian, rightCartesian)
+ if (rawMeters > 0) {
+ const niceMeters = this.niceScaleValue(rawMeters)
+ const widthPx = Math.round((niceMeters / rawMeters) * barPx)
+ const text = niceMeters >= 1000 ? `${(niceMeters / 1000).toFixed(0)} 公里` : `${Math.round(niceMeters)} 米`
+ return { text, widthPx, niceMeters }
+ }
+ }
+ // 2D/WebMercator 备用:用整屏宽度对应的地理范围计算(四角 pick 得到视口矩形)
+ const leftBottom = camera.pickEllipsoid(new Cesium.Cartesian2(0, h - 20), ellipsoid)
+ const rightBottom = camera.pickEllipsoid(new Cesium.Cartesian2(w, h - 20), ellipsoid)
+ if (leftBottom && rightBottom) {
+ const widthMeters = Cesium.Cartesian3.distance(leftBottom, rightBottom)
+ if (widthMeters > 0) {
+ const metersPerPx = widthMeters / w
+ const rawMeters = metersPerPx * barPx
+ const niceMeters = this.niceScaleValue(rawMeters)
+ const widthPx = Math.round(niceMeters / metersPerPx)
+ const text = niceMeters >= 1000 ? `${(niceMeters / 1000).toFixed(0)} 公里` : `${Math.round(niceMeters)} 米`
+ return { text, widthPx: Math.min(120, Math.max(40, widthPx)), niceMeters }
+ }
+ }
+ // 最后备用:从 2D 相机视锥估算(正交宽度 -> 米)
+ if (this.viewer.scene.mode === Cesium.SceneMode.SCENE2D && camera.frustum && camera.frustum.right !== undefined) {
+ const frustumWidth = camera.frustum.right - camera.frustum.left
+ if (frustumWidth > 0) {
+ const metersPerPx = frustumWidth / w
+ const rawMeters = metersPerPx * barPx
+ const niceMeters = this.niceScaleValue(rawMeters)
+ const widthPx = Math.round(niceMeters / metersPerPx)
+ const text = niceMeters >= 1000 ? `${(niceMeters / 1000).toFixed(0)} 公里` : `${Math.round(niceMeters)} 米`
+ return { text, widthPx: Math.min(120, Math.max(40, widthPx)), niceMeters }
+ }
+ }
+ return null
+ },
+ /** 将实际距离圆整为易读的刻度值(米) */
+ niceScaleValue(meters) {
+ const candidates = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000]
+ let best = candidates[0]
+ for (let i = 0; i < candidates.length; i++) {
+ if (candidates[i] <= meters * 1.5) best = candidates[i]
+ }
+ return best
+ },
+ updateScaleBar() {
+ const info = this.getScaleBarInfo()
+ if (info) {
+ this.scaleBarText = info.text
+ this.scaleBarWidthPx = Math.min(120, Math.max(40, info.widthPx))
+ } else {
+ this.scaleBarText = '--'
+ this.scaleBarWidthPx = 80
+ }
+ this.$nextTick()
},
initPointMovement() {
// 创建屏幕空间事件处理器
@@ -2657,10 +2762,6 @@ export default {
}, Cesium.ScreenSpaceEventType.LEFT_UP)
},
- updateScaleBar() {
- // ... 原有的比例尺更新代码保持不变
- },
-
// 初始化鼠标经纬度显示
initMouseCoordinates() {
// 创建屏幕空间事件处理器
@@ -2697,6 +2798,11 @@ export default {
this.mouseCoordinatesHandler = null
}
+ if (typeof this.scaleBarCleanup === 'function') {
+ this.scaleBarCleanup()
+ this.scaleBarCleanup = null
+ }
+
if (this.viewer) {
this.viewer.destroy()
this.viewer = null
@@ -2737,20 +2843,72 @@ export default {
display: none !important;
}
-/* 鼠标经纬度显示样式 */
-.coordinates-display {
+/* 地图右下角信息面板:比例尺在上、经纬度在下,整体略下移减少遮挡 */
+.map-info-panel {
position: absolute;
- bottom: 20px;
- right: 20px;
+ bottom: 10px;
+ right: 12px;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 6px;
+ z-index: 1000;
+ pointer-events: none;
+}
+
+/* 比例尺:高德风格,浅色底、圆角、刻度线 */
+.scale-bar {
+ background: rgba(255, 255, 255, 0.65);
+ color: #333;
+ padding: 4px 8px 6px;
+ border-radius: 4px;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ min-width: 60px;
+}
+.scale-bar-text {
+ font-size: 12px;
+ font-family: 'Microsoft YaHei', 'PingFang SC', sans-serif;
+ margin-bottom: 4px;
+ color: #555;
+}
+.scale-bar-line {
+ height: 2px;
+ background: #555;
+ position: relative;
+ flex-shrink: 0;
+}
+.scale-bar-tick {
+ position: absolute;
+ top: 0;
+ width: 2px;
+ height: 6px;
+ background: #555;
+}
+.scale-bar-tick-left {
+ left: 0;
+ top: -4px;
+}
+.scale-bar-tick-right {
+ right: 0;
+ left: auto;
+ top: -4px;
+}
+
+/* 经纬度显示(在比例尺下方) */
+.map-info-panel .coordinates-display {
+ position: static;
+ bottom: auto;
+ right: auto;
background-color: rgba(0, 0, 0, 0.7);
color: white;
- padding: 8px 12px;
+ padding: 6px 10px;
border-radius: 4px;
- font-size: 14px;
+ font-size: 13px;
font-family: Arial, sans-serif;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
- z-index: 1000;
- pointer-events: none;
min-width: 200px;
text-align: right;
}