| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528 |
- <template>
- <div class="cesium-transition-wrapper">
- <div ref="cesiumContainer" class="cesium-container"></div>
- <div class="ui-layer">
- <div
- v-if="poi"
- ref="poiLabel"
- class="html-label"
- :style="{ color: poi.fontColor || '#00ffff', fontSize: (poi.fontSize || 20) + 'px', opacity: 0, display: 'none' }"
- >
- {{ poi.label }}
- </div>
- </div>
- </div>
- </template>
- <script>
- import CesiumPreloader from '@/utils/cesiumPreloader';
- const Cesium = window.Cesium;
- function createOuterRingTexture(color) {
- const size = 1024, cx = size / 2, cy = size / 2, radius = size / 2 - 20;
- const lineWidth = 16, baseColorStr = color.toCssColorString();
- const canvas = document.createElement('canvas'); canvas.width = size; canvas.height = size; const ctx = canvas.getContext('2d');
- const solidCanvas = document.createElement('canvas'); solidCanvas.width = size; solidCanvas.height = size; const solidCtx = solidCanvas.getContext('2d'); solidCtx.lineWidth = lineWidth; solidCtx.strokeStyle = baseColorStr; solidCtx.shadowBlur = 10; solidCtx.shadowColor = baseColorStr; solidCtx.beginPath(); solidCtx.arc(cx, cy, radius, 0, Math.PI * 2); solidCtx.stroke();
- const dashedCanvas = document.createElement('canvas'); dashedCanvas.width = size; dashedCanvas.height = size; const dashedCtx = dashedCanvas.getContext('2d'); dashedCtx.lineWidth = lineWidth; dashedCtx.strokeStyle = baseColorStr; dashedCtx.setLineDash([12, 12]); dashedCtx.shadowBlur = 10; dashedCtx.shadowColor = baseColorStr; dashedCtx.beginPath(); dashedCtx.arc(cx, cy, radius, 0, Math.PI * 2); dashedCtx.stroke();
- const solidMask = ctx.createConicGradient(0, cx, cy); solidMask.addColorStop(0.0, 'rgba(0,0,0,0)'); solidMask.addColorStop(0.10, 'rgba(0,0,0,0)'); solidMask.addColorStop(0.18, 'rgba(0,0,0,1)'); solidMask.addColorStop(0.48, 'rgba(0,0,0,1)'); solidMask.addColorStop(0.50, 'rgba(0,0,0,0)'); solidMask.addColorStop(0.60, 'rgba(0,0,0,0)'); solidMask.addColorStop(0.68, 'rgba(0,0,0,1)'); solidMask.addColorStop(0.98, 'rgba(0,0,0,1)'); solidMask.addColorStop(1.0, 'rgba(0,0,0,0)');
- const dashedMask = ctx.createConicGradient(0, cx, cy); dashedMask.addColorStop(0.0, 'rgba(0,0,0,0)'); dashedMask.addColorStop(0.02, 'rgba(0,0,0,1)'); dashedMask.addColorStop(0.10, 'rgba(0,0,0,1)'); dashedMask.addColorStop(0.18, 'rgba(0,0,0,0)'); dashedMask.addColorStop(0.50, 'rgba(0,0,0,0)'); dashedMask.addColorStop(0.52, 'rgba(0,0,0,1)'); dashedMask.addColorStop(0.60, 'rgba(0,0,0,1)'); dashedMask.addColorStop(0.68, 'rgba(0,0,0,0)'); dashedMask.addColorStop(1.0, 'rgba(0,0,0,0)');
- ctx.drawImage(solidCanvas, 0, 0); ctx.globalCompositeOperation = 'destination-in'; ctx.fillStyle = solidMask; ctx.fillRect(0, 0, size, size);
- const tempCanvas = document.createElement('canvas'); tempCanvas.width = size; tempCanvas.height = size; const tempCtx = tempCanvas.getContext('2d'); tempCtx.drawImage(dashedCanvas, 0, 0); tempCtx.globalCompositeOperation = 'destination-in'; tempCtx.fillStyle = dashedMask; tempCtx.fillRect(0, 0, size, size);
- ctx.globalCompositeOperation = 'lighter'; ctx.drawImage(tempCanvas, 0, 0);
- ctx.globalCompositeOperation = 'destination-over'; ctx.shadowBlur = 40; ctx.shadowColor = color.withAlpha(0.3).toCssColorString(); ctx.strokeStyle = color.withAlpha(0.08).toCssColorString(); ctx.lineWidth = 20; ctx.beginPath(); ctx.arc(cx, cy, radius, 0, Math.PI * 2); ctx.stroke();
- return canvas.toDataURL();
- }
- function createScannerTexture(color) {
- const canvas = document.createElement('canvas'); canvas.width = 512; canvas.height = 512; const ctx = canvas.getContext('2d');
- const sharpColor = color.withAlpha(1.0).toCssColorString(); ctx.lineWidth = 3; ctx.strokeStyle = sharpColor; ctx.shadowBlur = 20; ctx.shadowColor = sharpColor; ctx.beginPath(); ctx.moveTo(256, 256); ctx.lineTo(506, 256); ctx.stroke(); return canvas.toDataURL();
- }
- function createLightBeamTexture(color) {
- const canvas = document.createElement('canvas'); canvas.width = 64; canvas.height = 256; const ctx = canvas.getContext('2d');
- const gradient = ctx.createLinearGradient(0, 256, 0, 0);
- gradient.addColorStop(0, color.withAlpha(0.6).toCssColorString()); gradient.addColorStop(0.4, color.withAlpha(0.1).toCssColorString()); gradient.addColorStop(1, color.withAlpha(0.0).toCssColorString());
- ctx.fillStyle = gradient; ctx.fillRect(0, 0, 64, 256); return canvas.toDataURL();
- }
- const TWO_PI = Math.PI * 2;
- export default {
- name: 'CesiumTransition',
- props: {
- // 要高亮的省份名称
- province: {
- type: String,
- default: '北京市'
- },
- // 微观标记点(null 则不显示POI)
- poi: {
- type: Object,
- default: null
- },
- // 区域中心坐标 [lon, lat](无POI时用于相机定位)
- districtCenter: {
- type: Array,
- default: null
- },
- // 路网数据
- roads: {
- type: Array,
- default: () => [
- { name: "阜石路-阜成路快速路", width: 12, glowPower: 0.3, color: '#00ffff', path: [[116.18, 39.93], [116.22, 39.93], [116.26, 39.928], [116.30, 39.925]] },
- { name: "石景山路-复兴路", width: 12, glowPower: 0.3, color: '#ff3333', path: [[116.18, 39.907], [116.224, 39.907], [116.25, 39.906], [116.30, 39.905]] },
- { name: "莲石东路快速路", width: 12, glowPower: 0.3, color: '#00ff00', path: [[116.18, 39.89], [116.22, 39.888], [116.26, 39.885], [116.30, 39.88]] },
- { name: "西五环路", width: 10, glowPower: 0.25, color: '#ffaa00', path: [[116.205, 39.95], [116.203, 39.92], [116.202, 39.89], [116.20, 39.86]] },
- { name: "玉泉路", width: 10, glowPower: 0.25, color: '#cc00ff', path: [[116.25, 39.94], [116.25, 39.907], [116.248, 39.88], [116.245, 39.86]] },
- { name: "西四环路", width: 10, glowPower: 0.25, color: '#ffff00', path: [[116.285, 39.94], [116.283, 39.91], [116.28, 39.88], [116.278, 39.85]] }
- ]
- },
- // 微观区域卫星底图
- satelliteImage: {
- type: Object,
- default: () => ({
- url: './beijing-satellite.jpg',
- bounds: [116.10, 39.80, 116.38, 39.98] // [west, south, east, north]
- })
- },
- // 中国边界 GeoJSON 路径
- boundaryUrl: {
- type: String,
- default: './china.json'
- },
- // 微观俯冲视角高度(米)
- microViewRange: {
- type: Number,
- default: 10000
- }
- },
- data() {
- return {
- isAnimating: false
- };
- },
- mounted() {
- this._viewer = null;
- this._preRenderListener = null;
- this._chinaDataSource = null;
- this._chinaEffectsSource = null;
- this._microEffectsSource = null;
- this._macroAlpha = 0.0;
- this._destroyed = false;
- this._pendingTimers = [];
- this._coords = { start: [-15.0, 35.86, 45000000], china: [104.19, 35.86, 14000000] };
- this.$nextTick(async () => {
- if (!this.$refs.cesiumContainer) return;
- // 尝试复用预加载的 Viewer
- const preloaded = await CesiumPreloader.acquire(this.$refs.cesiumContainer);
- this.initCesium(preloaded);
- if (!preloaded) {
- await this.waitForGlobeReady();
- }
- if (!this._destroyed) this.startTransition();
- });
- },
- beforeDestroy() {
- this._destroyed = true;
- this._pendingTimers.forEach(id => clearTimeout(id));
- this._pendingTimers = [];
- if (this._viewer) {
- if (this._preRenderListener) {
- this._viewer.scene.preRender.removeEventListener(this._preRenderListener);
- }
- // Cesium destroy() 内部会 removeChild,但 Vue 可能已移除 DOM,需要先确保容器在文档中
- const cesiumWidget = this._viewer.cesiumWidget && this._viewer.cesiumWidget.container;
- if (cesiumWidget && !cesiumWidget.parentNode) {
- document.body.appendChild(cesiumWidget);
- }
- try {
- this._viewer.destroy();
- } catch (e) {
- // 忽略 DOM 已被 Vue 移除导致的 removeChild 错误
- }
- this._viewer = null;
- }
- },
- methods: {
- waitForGlobeReady() {
- return new Promise(resolve => {
- const startTime = Date.now();
- const maxWait = 3000; // 最多等待3秒,避免卡住
- const check = () => {
- if (this._destroyed) { resolve(); return; }
- if ((this._viewer && this._viewer.scene.globe.tilesLoaded) || (Date.now() - startTime > maxWait)) {
- resolve();
- } else {
- requestAnimationFrame(check);
- }
- };
- requestAnimationFrame(check);
- });
- },
- initCesium(preloadedViewer) {
- this._baseGold = Cesium.Color.GOLD;
- this._baseWhite = Cesium.Color.WHITE;
- this._baseBlack = Cesium.Color.BLACK;
- this._dynamicGold = this._baseGold.withAlpha(0);
- this._dynamicWhite = this._baseWhite.withAlpha(0);
- this._dynamicBlack = this._baseBlack.withAlpha(0);
- this._poiThemeColor = Cesium.Color.fromCssColorString(
- (this.poi && this.poi.themeColor) || '#00bfff'
- );
- // 将 props 中的 roads 转为 Cesium 颜色对象
- this._majorRoads = this.roads.map(r => ({
- ...r,
- color: Cesium.Color.fromCssColorString(r.color)
- }));
- if (preloadedViewer) {
- // 复用预加载的 Viewer(瓦片已渲染好)
- this._viewer = preloadedViewer;
- } else {
- // 降级:从头创建
- this._viewer = new Cesium.Viewer(this.$refs.cesiumContainer, {
- animation: false, timeline: false, baseLayerPicker: false, geocoder: false,
- homeButton: false, sceneModePicker: false, navigationHelpButton: false, infoBox: false,
- fullscreenButton: false, selectionIndicator: false, shadows: false, shouldAnimate: false,
- requestRenderMode: false,
- imageryProvider: new Cesium.UrlTemplateImageryProvider({
- url: './tiles/{z}/{y}/{x}.jpg',
- maximumLevel: 12
- })
- });
- this._viewer.cesiumWidget.creditContainer.style.display = "none";
- }
- const scene = this._viewer.scene;
- scene.fog.enabled = false;
- scene.skyAtmosphere.show = false;
- scene.globe.showGroundAtmosphere = false;
- scene.globe.enableLighting = true;
- scene.globe.tileCacheSize = 300;
- scene.globe.maximumScreenSpaceError = 1.5;
- this._viewer.clock.currentTime = Cesium.JulianDate.fromDate(new Date('2026-01-01T01:30:00Z'));
- this._viewer.clock.shouldAnimate = false;
- const baseLayer = this._viewer.imageryLayers.get(0);
- if (baseLayer) {
- baseLayer.brightness = 0.75; // 亮度:1.0 是原图,小于 1.0 变暗,大于 1.0 变亮
- baseLayer.contrast = 1.3; // 对比度
- baseLayer.gamma = 1; // 新增这一行:默认值是 1.0,调高可以显著提亮暗部环境
- }
-
- const cam = this._viewer.scene.screenSpaceCameraController;
- cam.enableRotate = false;
- cam.enableTranslate = false;
- cam.enableZoom = false;
- cam.enableTilt = false;
- cam.enableLook = false;
- // 微观区域高清卫星底图
- if (this.satelliteImage && this.satelliteImage.url) {
- const b = this.satelliteImage.bounds;
- this._viewer.imageryLayers.addImageryProvider(
- new Cesium.SingleTileImageryProvider({
- url: this.satelliteImage.url,
- rectangle: Cesium.Rectangle.fromDegrees(b[0], b[1], b[2], b[3])
- })
- );
- // 针对本地大图的专项优化
- this._viewer.scene.globe.maximumScreenSpaceError = 1.0; // 降低误差,强制渲染高清
- this._viewer.scene.globe.tileCacheSize = 200; // 增加缓存
- }
- this._viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(...this._coords.start) });
- this.buildMacroLayer();
- this.buildMicroLayer();
- this._preRenderListener = this._viewer.scene.preRender.addEventListener(() => {
- if (!this._microEffectsSource || !this._microEffectsSource.show) return;
- // POI 标签跟踪
- if (this.poi && this.$refs.poiLabel && this.$refs.poiLabel.style.opacity !== "0") {
- const pos3D = Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat);
- const screenPos = Cesium.SceneTransforms.wgs84ToWindowCoordinates(this._viewer.scene, pos3D);
- if (screenPos && screenPos.y > 0) {
- this.$refs.poiLabel.style.display = 'flex';
- this.$refs.poiLabel.style.left = screenPos.x + 'px';
- this.$refs.poiLabel.style.top = (screenPos.y - 150) + 'px';
- } else {
- this.$refs.poiLabel.style.display = 'none';
- }
- }
- });
- },
- buildMacroLayer() {
- this._chinaEffectsSource = new Cesium.CustomDataSource('chinaEffects');
- this._viewer.dataSources.add(this._chinaEffectsSource);
- this._chinaEffectsSource.show = false;
- Cesium.GeoJsonDataSource.load(this.boundaryUrl).then(ds => {
- if (this._destroyed) return;
- this._chinaDataSource = ds;
- const entities = ds.entities.values;
- const provinceMainLand = {};
- for (let i = 0; i < entities.length; i++) {
- const entity = entities[i];
- if (entity.polygon) {
- entity.polygon.fill = false;
- entity.polygon.outline = false;
- const positions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions;
- entity.polyline = new Cesium.PolylineGraphics({
- positions, width: 2,
- material: new Cesium.PolylineGlowMaterialProperty({
- glowPower: 0.05,
- color: new Cesium.CallbackProperty(() => this._dynamicGold, false)
- })
- });
- if (entity.name === this.province) {
- const pointCount = positions.length;
- if (!provinceMainLand[entity.name] || pointCount > provinceMainLand[entity.name].pointCount) {
- provinceMainLand[entity.name] = { pointCount, center: Cesium.BoundingSphere.fromPoints(positions).center };
- }
- }
- }
- }
- this._viewer.dataSources.add(ds);
- for (const name in provinceMainLand) {
- const mainCenter = provinceMainLand[name].center;
- this._chinaEffectsSource.entities.add({
- position: mainCenter,
- label: {
- text: name, font: 'bold 28px Microsoft YaHei',
- fillColor: new Cesium.CallbackProperty(() => this._dynamicWhite, false),
- outlineColor: new Cesium.CallbackProperty(() => this._dynamicBlack, false),
- outlineWidth: 3, style: Cesium.LabelStyle.FILL_AND_OUTLINE,
- heightReference: Cesium.HeightReference.RELATIVE_TO_GROUND,
- pixelOffset: new Cesium.Cartesian2(0, -10),
- distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 20000000)
- }
- });
- for (let i = 0; i < 3; i++) {
- const offset = (4000 / 3) * i, startTime = Date.now() + offset;
- this._chinaEffectsSource.entities.add({
- position: mainCenter,
- ellipse: {
- semiMinorAxis: new Cesium.CallbackProperty(() => 350000 * (((Date.now() - startTime) % 4000) / 4000), false),
- semiMajorAxis: new Cesium.CallbackProperty(() => 350000 * (((Date.now() - startTime) % 4000) / 4000), false),
- material: new Cesium.ColorMaterialProperty(new Cesium.CallbackProperty(() => {
- const t = ((Date.now() - startTime) % 4000) / 4000;
- return Cesium.Color.DEEPSKYBLUE.withAlpha((1.0 - t) * 0.8 * this._macroAlpha);
- }, false)), height: 5000 + i * 100
- }
- });
- }
- }
- });
- },
- buildMicroLayer() {
- this._microEffectsSource = new Cesium.CustomDataSource('microEffects');
- this._viewer.dataSources.add(this._microEffectsSource);
- this._microEffectsSource.show = false;
- // POI 标记(可选)
- if (this.poi) {
- const pos3D = Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat);
- const slowRingImg = createOuterRingTexture(this._poiThemeColor);
- const fastScannerImg = createScannerTexture(this._poiThemeColor);
- const beamImg = createLightBeamTexture(this._poiThemeColor);
- this._microEffectsSource.entities.add({ position: pos3D, ellipse: { semiMinorAxis: this.poi.radarRadius, semiMajorAxis: this.poi.radarRadius, material: new Cesium.ImageMaterialProperty({ image: slowRingImg, transparent: true }), stRotation: new Cesium.CallbackProperty(() => (Date.now() / 5000.0) % TWO_PI, false), height: 20 } });
- this._microEffectsSource.entities.add({ position: pos3D, ellipse: { semiMinorAxis: this.poi.radarRadius, semiMajorAxis: this.poi.radarRadius, material: new Cesium.ImageMaterialProperty({ image: fastScannerImg, transparent: true }), stRotation: new Cesium.CallbackProperty(() => (Date.now() / 300.0) % TWO_PI, false), height: 21 } });
- this._microEffectsSource.entities.add({ position: Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat, 2000.0), cylinder: { length: 4000, topRadius: 20, bottomRadius: 200, material: new Cesium.ImageMaterialProperty({ image: beamImg, transparent: true }) } });
- this._microEffectsSource.entities.add({ position: Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat, 50), point: { pixelSize: 15, color: Cesium.Color.WHITE, outlineColor: this._poiThemeColor, outlineWidth: 3 } });
- }
- },
- fadeMacroLayer(startAlpha, endAlpha, durationMs) {
- return new Promise(resolve => {
- if (startAlpha < endAlpha && this._chinaDataSource) {
- this._chinaDataSource.show = true;
- this._chinaEffectsSource.show = true;
- }
- const startTime = Date.now();
- const animateFade = () => {
- if (this._destroyed) { resolve(); return; }
- let p = (Date.now() - startTime) / durationMs; if (p >= 1.0) p = 1.0;
- this._macroAlpha = startAlpha + (endAlpha - startAlpha) * p;
- this._dynamicGold = this._baseGold.withAlpha(this._macroAlpha);
- this._dynamicWhite = this._baseWhite.withAlpha(this._macroAlpha);
- this._dynamicBlack = this._baseBlack.withAlpha(this._macroAlpha);
- if (p < 1.0) {
- requestAnimationFrame(animateFade);
- } else {
- if (endAlpha === 0 && this._chinaDataSource) {
- this._chinaDataSource.show = false;
- this._chinaEffectsSource.show = false;
- }
- resolve();
- }
- };
- requestAnimationFrame(animateFade);
- });
- },
- animatePathGrowing(roadObj, delayTime) {
- return new Promise(resolve => {
- const timerId = setTimeout(() => {
- if (this._destroyed) { resolve(); return; }
- const positions = roadObj.path.map(p => Cesium.Cartesian3.fromDegrees(p[0], p[1]));
- const distances = [0]; let totalLength = 0;
- for (let i = 1; i < positions.length; i++) {
- totalLength += Cesium.Cartesian3.distance(positions[i - 1], positions[i]);
- distances.push(totalLength);
- }
- let progress = 0.0, isFinished = false;
- this._microEffectsSource.entities.add({
- polyline: {
- positions: new Cesium.CallbackProperty(function () {
- if (isFinished) return positions;
- progress += 0.025;
- if (progress >= 1.0) { isFinished = true; resolve(); return positions; }
- const targetDist = progress * totalLength;
- const pts = [];
- for (let i = 1; i < positions.length; i++) {
- pts.push(positions[i - 1]);
- if (targetDist <= distances[i]) {
- const seg = (targetDist - distances[i - 1]) / (distances[i] - distances[i - 1]);
- const p = new Cesium.Cartesian3();
- Cesium.Cartesian3.lerp(positions[i - 1], positions[i], seg, p);
- pts.push(p); break;
- }
- }
- return pts;
- }, false),
- width: roadObj.width,
- material: new Cesium.PolylineGlowMaterialProperty({ glowPower: roadObj.glowPower, color: roadObj.color })
- }
- });
- }, delayTime);
- this._pendingTimers.push(timerId);
- });
- },
- _safeDelay(ms) {
- return new Promise(resolve => {
- const id = setTimeout(resolve, ms);
- this._pendingTimers.push(id);
- });
- },
- async startTransition() {
- if (this.isAnimating) return;
- this.isAnimating = true;
- // 阶段1: 飞向中国 (2s)
- this._viewer.camera.flyTo({
- destination: Cesium.Cartesian3.fromDegrees(...this._coords.china), duration: 2
- });
- const fadeInId = setTimeout(() => {
- if (!this._destroyed) this.fadeMacroLayer(0.0, 1.0, 1000);
- }, 800);
- this._pendingTimers.push(fadeInId);
- await this._safeDelay(3000);
- if (this._destroyed) return;
- // 阶段2: 俯冲到微观
- const targetCenter = this.poi
- ? [this.poi.lon, this.poi.lat]
- : (this.districtCenter || [116.70, 39.80]);
- const targetSphere = Cesium.BoundingSphere.fromPoints([Cesium.Cartesian3.fromDegrees(targetCenter[0], targetCenter[1])]);
- this._viewer.camera.flyToBoundingSphere(targetSphere, {
- offset: new Cesium.HeadingPitchRange(0.0, Cesium.Math.toRadians(-45), this.microViewRange),
- duration: 2, easingFunction: Cesium.EasingFunction.CUBIC_IN_OUT
- });
- this.fadeMacroLayer(1.0, 0.0, 800);
- // 阶段3: 显示微观效果
- await this._safeDelay(1500);
- if (this._destroyed) return;
- this._microEffectsSource.show = true;
- if (this.poi && this.$refs.poiLabel) this.$refs.poiLabel.style.opacity = 1;
- await this._safeDelay(1000);
- if (this._destroyed) return;
- this.$emit('complete');
- }
- }
- };
- </script>
- <style scoped>
- .cesium-transition-wrapper {
- position: fixed;
- top: 0;
- left: 0;
- width: 100vw;
- height: 100vh;
- z-index: 9999;
- background: #020813;
- overflow: hidden;
- font-family: "Microsoft YaHei", sans-serif;
- }
- .cesium-container {
- width: 100%;
- height: 100%;
- margin: 0;
- padding: 0;
- }
- .ui-layer {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- pointer-events: none;
- }
- .html-label {
- position: absolute;
- padding: 4px 10px;
- border-radius: 2px;
- pointer-events: none;
- transition: opacity 0.5s;
- transform: translate(-50%, -100%);
- display: flex;
- flex-direction: column;
- align-items: center;
- white-space: nowrap;
- font-weight: bold;
- z-index: 5;
- border: 1px solid currentColor;
- background: rgba(0, 20, 30, 0.7);
- box-shadow: inset 0 0 10px currentColor;
- text-shadow: 0 0 5px #000;
- }
- .html-label::after {
- content: '';
- width: 2px;
- height: 35px;
- background: currentColor;
- margin-top: 5px;
- box-shadow: 0 0 5px currentColor;
- }
- </style>
|