From b76509a1feb9511f6661de7a78c9396386bd84a2 Mon Sep 17 00:00:00 2001 From: cuitw <1051735452@qq.com> Date: Wed, 25 Feb 2026 08:39:30 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B9=B3=E5=8F=B0=E5=88=9D=E5=A7=8B=E9=A2=9C?= =?UTF-8?q?=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-ui/src/views/cesiumMap/index.vue | 50 ++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/ruoyi-ui/src/views/cesiumMap/index.vue b/ruoyi-ui/src/views/cesiumMap/index.vue index 62b986a..bddfa1a 100644 --- a/ruoyi-ui/src/views/cesiumMap/index.vue +++ b/ruoyi-ui/src/views/cesiumMap/index.vue @@ -1064,15 +1064,17 @@ export default { * @param {string} options.heading 航向值 * @param {number} options.fontSize 字号,默认 16 * @param {string} options.fontColor 属性值颜色,默认黑色 - * @returns {HTMLCanvasElement} + * @returns {{ canvas: HTMLCanvasElement, scale: number }} 高分屏下 scale 供 billboard.scale 使用以保持视觉尺寸 */ createRoundedLabelCanvas(options) { const { name, altitude, speed, heading, fontSize = 16, fontColor = '#000000' } = options; const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); + // 高分屏清晰度:按设备像素比放大绘制,再通过 billboard.scale 缩回,文字边缘更锐利 + const dpr = Math.min(2, window.devicePixelRatio || 1); - // 设置字体 + // 设置字体(先用于测量) const font = `${fontSize}px "Microsoft YaHei"`; ctx.font = font; @@ -1089,7 +1091,7 @@ export default { const textSpeed = speed + 'km/h'; const textHeading = Math.round(heading) + '°'; - // 计算各部分宽度 + // 计算各部分宽度(逻辑尺寸) const wName = ctx.measureText(name).width; const wLabelAlt = ctx.measureText(labelAlt).width; @@ -1101,9 +1103,7 @@ export default { const wLabelHeading = ctx.measureText(labelHeading).width; const wValHeading = ctx.measureText(textHeading).width; - // 总宽与总高 - // 第一行:名字居中 - // 第二行:高度 + 速度 + 航向 + // 总宽与总高(逻辑尺寸) const line1Width = wName; const line2Width = wLabelAlt + wValAlt + wLabelSpeed + wValSpeed + wLabelHeading + wValHeading; @@ -1113,9 +1113,10 @@ export default { const totalWidth = Math.max(line1Width, line2Width) + paddingX * 2; const totalHeight = lineHeight * 2 + paddingY * 2; - // 设置 Canvas 大小 (根据设备像素比优化清晰度,这里简单处理,Cesium Billboard 会自动缩放) - canvas.width = totalWidth; - canvas.height = totalHeight; + // Canvas 实际像素尺寸按 dpr 放大,绘制时用 scale 保持逻辑坐标 + canvas.width = Math.ceil(totalWidth * dpr); + canvas.height = Math.ceil(totalHeight * dpr); + ctx.scale(dpr, dpr); // 重新设置字体(因为重设 width 会重置 context) ctx.font = font; @@ -1179,7 +1180,8 @@ export default { ctx.fillStyle = colorValue; ctx.fillText(textHeading, currentX, line2Y); - return canvas; + // 返回 canvas 与显示缩放比,供 billboard 设置 scale 以保持视觉尺寸一致 + return { canvas, scale: 1 / dpr }; }, /** 伸缩框旋转手柄图标 SVG:蓝底、白边、白色弧形箭头 */ @@ -1619,7 +1621,7 @@ export default { image: fullUrl, width: 144, height: 144, - color: Cesium.Color.WHITE, // 初始颜色为白色(不染色) + color: Cesium.Color.BLACK, // 航线飞机默认黑色,可通过编辑飞机颜色功能修改 verticalOrigin: Cesium.VerticalOrigin.CENTER, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, scaleByDistance: new Cesium.NearFarScalar(500, 2.0, 200000, 0.4), @@ -1633,9 +1635,7 @@ export default { const target = this.viewer.entities.getById(platformBillboardId); if (target && target.billboard) { target.billboard.image = whiteImage; - // 注意:此时如果用户没有修改过颜色,target.billboard.color 默认为 WHITE,显示白图 - // 如果用户希望"未编辑时显示原图",这里可能会把黑图变成白图。 - // 但根据用户需求"一开始加入平台时将平台的颜色固定为白色",这正是想要的效果。 + // 此时 target.billboard.color 已在创建时设为 BLACK(航线飞机默认黑色),染色后显示为黑色图标 // 触发一次渲染刷新 if (this.viewer.scene.requestRenderMode) { @@ -1665,8 +1665,8 @@ export default { } const currentStyle = this.routeLabelStyles[routeId]; - // 使用 Canvas 生成圆角标牌 - const labelCanvas = this.createRoundedLabelCanvas({ + // 使用 Canvas 生成圆角标牌(高分屏下 scale 用于保持视觉尺寸) + const labelResult = this.createRoundedLabelCanvas({ name: (platform && platform.name) || '平台', altitude: firstAlt, speed: firstSpeed, @@ -1682,7 +1682,8 @@ export default { show: labelShow, properties: { routeId: routeId }, billboard: { - image: labelCanvas, // 使用 Canvas 作为图片 + image: labelResult.canvas, + scale: labelResult.scale, verticalOrigin: Cesium.VerticalOrigin.BOTTOM, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, pixelOffset: new Cesium.Cartesian2(0, -42), @@ -2358,7 +2359,7 @@ export default { return; } - const canvas = this.createRoundedLabelCanvas({ + const labelResult = this.createRoundedLabelCanvas({ name: displayData.name, altitude: displayData.altitude, speed: displayData.speed, @@ -2366,8 +2367,8 @@ export default { fontSize: style.fontSize, fontColor: style.fontColor }); - // 直接赋值 canvas,避免 ConstantProperty 包装可能带来的额外开销(Cesium 会自动处理) - labelEntity.billboard.image = canvas; + labelEntity.billboard.image = labelResult.canvas; + labelEntity.billboard.scale = labelResult.scale; // 记录本次渲染参数和时间 labelEntity._lastRenderParams = { @@ -2407,6 +2408,8 @@ export default { // 确保 Cesium 已加载 Cesium.buildModuleUrl.setBaseUrl(window.CESIUM_BASE_URL) Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjN2MzMmE5OS01NGU3LTQzOGQtYjdjZi1mNGIwZTFjZjQ0NmEiLCJpZCI6MTQ0MDc2LCJpYXQiOjE2ODU3NjY1OTN9.iCmFY-5WNdvyAT-EO2j-unrFm4ZN9J6aSuB2wElQZ-I' + // 使用设备像素比提升高分屏下字体与图形清晰度(上限 2 兼顾性能) + const resolutionScale = Math.min(2, window.devicePixelRatio || 1); this.viewer = new Cesium.Viewer('cesiumViewer', { animation: false, fullscreenButton: false, @@ -2424,6 +2427,7 @@ export default { imageryProvider: false, terrainProvider: new Cesium.EllipsoidTerrainProvider(), baseLayer: false, + resolutionScale, requestRenderMode: true, maximumRenderTimeChange: Infinity, contextOptions: { @@ -5320,7 +5324,7 @@ export default { if (labelEntity) { if (labelEntity.billboard) { const data = labelEntity.labelDataCache || { name: '平台', altitude: 0, speed: 0, headingDeg: 0 }; - const canvas = this.createRoundedLabelCanvas({ + const labelResult = this.createRoundedLabelCanvas({ name: data.name, altitude: data.altitude, speed: data.speed, @@ -5328,8 +5332,8 @@ export default { fontSize: fontSize, fontColor: fontColor }); - // 使用 ConstantProperty 确保更新 - labelEntity.billboard.image = new Cesium.ConstantProperty(canvas); + labelEntity.billboard.image = new Cesium.ConstantProperty(labelResult.canvas); + labelEntity.billboard.scale = labelResult.scale; } else if (labelEntity.label) { labelEntity.label.font = `${fontSize}px Microsoft YaHei` labelEntity.label.fillColor = Cesium.Color.fromCssColorString(fontColor)