diff --git a/src/scene/CesiumGlobe.js b/src/scene/CesiumGlobe.js index 4460874..8536bb5 100644 --- a/src/scene/CesiumGlobe.js +++ b/src/scene/CesiumGlobe.js @@ -36,15 +36,16 @@ function sphericalAreaKm2(polys) { return area * R * R; } -// 生成便签 canvas:黄色圆角底 + 黑色加粗文字(整张图,背景与文字完美对齐) -function makeStickyNote(text, fontSize) { - const padX = 14, padY = 8, radius = 8, S = 2; // S: 2x 超采样,文字更清晰 +// 生成便签 canvas:黄底圆角 + 左侧箭头 + 黑色加粗文字(整张图,箭头尖端指向坐标) +function makeStickyNote(text, fontSize, selected = false) { + const padX = 14, padY = 8, radius = 8, arrowW = 12, arrowH = 16, S = 2; // S: 2x 超采样 const font = `bold ${fontSize}px "Noto Serif SC", "Songti SC", "STSong", "SimSun", Georgia, serif`; const m = document.createElement('canvas'); const mctx = m.getContext('2d'); mctx.font = font; const textW = mctx.measureText(text).width; - const w = Math.max(1, Math.ceil(textW + padX * 2)); + const bodyW = Math.max(1, Math.ceil(textW + padX * 2)); + const w = arrowW + bodyW; const h = Math.ceil(fontSize + padY * 2); const c = document.createElement('canvas'); c.width = w * S; @@ -52,20 +53,38 @@ function makeStickyNote(text, fontSize) { const ctx = c.getContext('2d'); ctx.scale(S, S); - // 黄色圆角底 + 阴影 + // 阴影 ctx.shadowColor = 'rgba(0, 0, 0, 0.20)'; ctx.shadowBlur = 5; ctx.shadowOffsetY = 2; + + // 箭头 + 圆角矩形一体化路径(箭头尖端在左侧 x=0,指向坐标) ctx.beginPath(); - ctx.moveTo(radius, 0); - ctx.arcTo(w, 0, w, h, radius); - ctx.arcTo(w, h, 0, h, radius); - ctx.arcTo(0, h, 0, 0, radius); - ctx.arcTo(0, 0, w, 0, radius); - ctx.closePath(); + ctx.moveTo(0, h / 2); // 箭头尖端 + ctx.lineTo(arrowW, h / 2 - arrowH / 2); // 箭头上沿 + ctx.lineTo(arrowW, radius); // 左边缘上部 + ctx.arcTo(arrowW, 0, arrowW + radius, 0, radius); // 左上圆角 + ctx.lineTo(w - radius, 0); // 上边 + ctx.arcTo(w, 0, w, radius, radius); // 右上圆角 + ctx.lineTo(w, h - radius); // 右边 + ctx.arcTo(w, h, w - radius, h, radius); // 右下圆角 + ctx.lineTo(arrowW + radius, h); // 底边 + ctx.arcTo(arrowW, h, arrowW, h - radius, radius); // 左下圆角 + ctx.lineTo(arrowW, h / 2 + arrowH / 2); // 左边缘下部 + ctx.closePath(); // 闭合回箭头尖端 ctx.fillStyle = '#FFF9A6'; ctx.fill(); + // 选中时加黑边 + if (selected) { + ctx.shadowColor = 'transparent'; + ctx.shadowBlur = 0; + ctx.shadowOffsetY = 0; + ctx.strokeStyle = '#14100d'; + ctx.lineWidth = 3; + ctx.stroke(); + } + // 黑色加粗文字(无阴影) ctx.shadowColor = 'transparent'; ctx.shadowBlur = 0; @@ -74,7 +93,7 @@ function makeStickyNote(text, fontSize) { ctx.font = font; ctx.textBaseline = 'middle'; ctx.textAlign = 'center'; - ctx.fillText(text, w / 2, h / 2 + 1); + ctx.fillText(text, arrowW + bodyW / 2, h / 2 + 1); return { canvas: c, scale: 1 / S }; } @@ -186,42 +205,28 @@ export class CesiumGlobe { _buildMarkers() { const viewer = this.viewer; - const gold = Cesium.Color.fromCssColorString('#e0c46a'); - const ink = Cesium.Color.fromCssColorString('#14100d'); ENTRIES.forEach((entry, i) => { + // 便签:黄底黑字 + 左侧箭头指向坐标(整张图) + const noteNormal = makeStickyNote(entry.name, 19, false); + const noteSelected = makeStickyNote(entry.name, 19, true); + const entity = viewer.entities.add({ - position: Cesium.Cartesian3.fromDegrees(entry.lng, entry.lat), - point: { - pixelSize: 10, // 标记宽一点 - color: gold, // 金色圆形 - outlineColor: ink, // 外侧 1px 黑边 - outlineWidth: 1, - heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, - disableDepthTestDistance: Number.POSITIVE_INFINITY, - distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1e7), - }, - }); - - entity.entryIndex = i; - - // 便签:黄底黑字(整张图,贴到圆点右侧) - const note = makeStickyNote(entry.name, 19); - const noteEntity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(entry.lng, entry.lat), billboard: { - image: note.canvas, - scale: note.scale, + image: noteNormal.canvas, + scale: noteNormal.scale, horizontalOrigin: Cesium.HorizontalOrigin.LEFT, verticalOrigin: Cesium.VerticalOrigin.CENTER, - pixelOffset: new Cesium.Cartesian2(12, 0), + pixelOffset: new Cesium.Cartesian2(0, 0), heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, disableDepthTestDistance: Number.POSITIVE_INFINITY, distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 1e7), }, }); + entity.entryIndex = i; - this.markers.push({ entity, index: i }); + this.markers.push({ entity, noteNormal, noteSelected, index: i }); }); } @@ -383,9 +388,9 @@ export class CesiumGlobe { setSelected(index) { this.selected = index; if (!this.viewer) return; - this.markers.forEach(({ entity, index: i }) => { + this.markers.forEach(({ entity, noteNormal, noteSelected, index: i }) => { const on = i === index; - entity.point.outlineWidth = on ? 3 : 1; // 选中加粗黑圈,不放大 + entity.billboard.image = on ? noteSelected.canvas : noteNormal.canvas; // 选中加黑边 }); this.viewer.scene.requestRender(); }