Bläddra i källkod

修改过渡动画组件,可以动态传递数据

画安 5 dagar sedan
förälder
incheckning
7518b9b56c
2 ändrade filer med 132 tillägg och 60 borttagningar
  1. 81 35
      src/components/CesiumTransition.vue
  2. 51 25
      src/views/TransitionPage.vue

+ 81 - 35
src/components/CesiumTransition.vue

@@ -5,9 +5,9 @@
       <div
         ref="poiLabel"
         class="html-label"
-        style="color: #00ffff; font-size: 20px; opacity: 0; display: none;"
+        :style="{ color: poi.fontColor || '#00ffff', fontSize: (poi.fontSize || 20) + 'px', opacity: 0, display: 'none' }"
       >
-        鲁谷西街与政达路交叉口
+        {{ poi.label }}
       </div>
     </div>
   </div>
@@ -47,6 +47,56 @@ const TWO_PI = Math.PI * 2;
 
 export default {
   name: 'CesiumTransition',
+  props: {
+    // 要高亮的省份名称
+    province: {
+      type: String,
+      default: '北京市'
+    },
+    // 微观标记点
+    poi: {
+      type: Object,
+      default: () => ({
+        lon: 116.22405,
+        lat: 39.90515,
+        label: '鲁谷西街与政达路交叉口',
+        radarRadius: 200,
+        themeColor: '#00bfff',  // CSS 颜色字符串
+        fontColor: '#00ffff',
+        fontSize: 20
+      })
+    },
+    // 路网数据
+    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
@@ -63,7 +113,6 @@ export default {
     this._pendingTimers = [];
 
     this._coords = { start: [-15.0, 35.86, 45000000], china: [104.19, 35.86, 14000000] };
-    this._poi = { lon: 116.22405, lat: 39.90515, radarRadius: 200 };
 
     this.$nextTick(() => {
       if (!this.$refs.cesiumContainer) return;
@@ -107,16 +156,13 @@ export default {
       this._dynamicGold = this._baseGold.withAlpha(0);
       this._dynamicWhite = this._baseWhite.withAlpha(0);
       this._dynamicBlack = this._baseBlack.withAlpha(0);
-      this._poiThemeColor = Cesium.Color.DEEPSKYBLUE;
+      this._poiThemeColor = Cesium.Color.fromCssColorString(this.poi.themeColor || '#00bfff');
 
-      this._majorRoads = [
-        { name: "阜石路-阜成路快速路", width: 12, glowPower: 0.3, color: Cesium.Color.fromCssColorString('#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: Cesium.Color.fromCssColorString('#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: Cesium.Color.fromCssColorString('#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: Cesium.Color.fromCssColorString('#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: Cesium.Color.fromCssColorString('#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: Cesium.Color.fromCssColorString('#ffff00'), path: [[116.285, 39.94], [116.283, 39.91], [116.28, 39.88], [116.278, 39.85]] }
-      ];
+      // 将 props 中的 roads 转为 Cesium 颜色对象
+      this._majorRoads = this.roads.map(r => ({
+        ...r,
+        color: Cesium.Color.fromCssColorString(r.color)
+      }));
 
       this._viewer = new Cesium.Viewer(this.$refs.cesiumContainer, {
         animation: false, timeline: false, baseLayerPicker: false, geocoder: false,
@@ -140,13 +186,16 @@ export default {
       const baseLayer = this._viewer.imageryLayers.get(0);
       if (baseLayer) { baseLayer.brightness = 0.45; baseLayer.contrast = 1.3; }
 
-      // 微观区域高清卫星底图(本地静态图,秒加载,替代远程瓦片)
-      this._viewer.imageryLayers.addImageryProvider(
-        new Cesium.SingleTileImageryProvider({
-          url: './beijing-satellite.jpg',
-          rectangle: Cesium.Rectangle.fromDegrees(116.10, 39.80, 116.38, 39.98)
-        })
-      );
+      // 微观区域高清卫星底图
+      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.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(...this._coords.start) });
 
@@ -156,7 +205,7 @@ export default {
       this._preRenderListener = this._viewer.scene.preRender.addEventListener(() => {
         if (!this._microEffectsSource || !this._microEffectsSource.show || !this.$refs.poiLabel) return;
         if (this.$refs.poiLabel.style.opacity === "0") return;
-        const pos3D = Cesium.Cartesian3.fromDegrees(this._poi.lon, this._poi.lat);
+        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';
@@ -173,11 +222,9 @@ export default {
       this._viewer.dataSources.add(this._chinaEffectsSource);
       this._chinaEffectsSource.show = false;
 
-      Cesium.GeoJsonDataSource.load('./china.json').then(ds => {
+      Cesium.GeoJsonDataSource.load(this.boundaryUrl).then(ds => {
         if (this._destroyed) return;
-        this._viewer.dataSources.add(ds);
         this._chinaDataSource = ds;
-        this._chinaDataSource.show = false;
 
         const entities = ds.entities.values;
         const provinceMainLand = {};
@@ -195,7 +242,7 @@ export default {
                 color: new Cesium.CallbackProperty(() => this._dynamicGold, false)
               })
             });
-            if (entity.name === '北京市') {
+            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 };
@@ -204,7 +251,6 @@ export default {
           }
         }
 
-        // 实体处理完毕后再添加到 viewer
         this._viewer.dataSources.add(ds);
 
         for (const name in provinceMainLand) {
@@ -244,15 +290,15 @@ export default {
       this._viewer.dataSources.add(this._microEffectsSource);
       this._microEffectsSource.show = false;
 
-      const pos3D = Cesium.Cartesian3.fromDegrees(this._poi.lon, this._poi.lat);
+      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 } });
+      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) {
@@ -334,7 +380,7 @@ export default {
       if (this.isAnimating) return;
       this.isAnimating = true;
 
-      // 阶段1: 飞向中国 (2s),飞行0.8s后开始淡入边界
+      // 阶段1: 飞向中国 (2s)
       this._viewer.camera.flyTo({
         destination: Cesium.Cartesian3.fromDegrees(...this._coords.china), duration: 2
       });
@@ -346,10 +392,10 @@ export default {
       await this._safeDelay(3000);
       if (this._destroyed) return;
 
-      // 阶段2: 俯冲到微观 (2s),同时淡出边界
-      const targetSphere = Cesium.BoundingSphere.fromPoints([Cesium.Cartesian3.fromDegrees(this._poi.lon, this._poi.lat)]);
+      // 阶段2: 俯冲到微观
+      const targetSphere = Cesium.BoundingSphere.fromPoints([Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat)]);
       this._viewer.camera.flyToBoundingSphere(targetSphere, {
-        offset: new Cesium.HeadingPitchRange(0.0, Cesium.Math.toRadians(-45), 10000.0),
+        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);
@@ -360,7 +406,7 @@ export default {
       this._microEffectsSource.show = true;
       if (this.$refs.poiLabel) this.$refs.poiLabel.style.opacity = 1;
 
-      // 阶段4: 路网生长 (每条间隔150ms),全部画完立即结束
+      // 阶段4: 路网生长
       await this._safeDelay(300);
       if (this._destroyed) return;
       const roadPromises = this._majorRoads.map((road, i) => this.animatePathGrowing(road, i * 150));

+ 51 - 25
src/views/TransitionPage.vue

@@ -1,10 +1,15 @@
 <template>
   <div class="page">
     <transition name="fade">
-      <CesiumTransition 
-        v-if="isTransitioning" 
-        :autoStart="true" 
-        @complete="onTransitionComplete" 
+      <CesiumTransition
+        v-if="isTransitioning"
+        :province="province"
+        :poi="poi"
+        :roads="roads"
+        :satellite-image="satelliteImage"
+        :boundary-url="boundaryUrl"
+        :micro-view-range="microViewRange"
+        @complete="onTransitionComplete"
       />
     </transition>
   </div>
@@ -15,44 +20,65 @@ import CesiumTransition from '@/components/CesiumTransition.vue';
 
 export default {
   name: "TransitionPage",
-  components: {
-    CesiumTransition
-  },
+  components: { CesiumTransition },
   data() {
     return {
-      isTransitioning: true // 控制过渡动画状态
-    }
-  },
-  mounted() {
-    // 页面加载完成后,自动触发过渡动画(延迟500ms确保渲染就绪)
-    setTimeout(() => {
-      if (this.$refs.transitionComponent) {
-        this.$refs.transitionComponent.startTransition();
-      }
-    }, 500);
+      isTransitioning: true,
+
+      // ====== 以下数据可动态替换 ======
+
+      // 高亮的省份
+      province: '北京市',
+
+      // 微观标记点
+      poi: {
+        lon: 116.22405,
+        lat: 39.90515,
+        label: '鲁谷西街与政达路交叉口',
+        radarRadius: 200,
+        themeColor: '#00bfff',
+        fontColor: '#00ffff',
+        fontSize: 20
+      },
+
+      // 路网数据:color 使用 CSS 颜色字符串
+      roads: [
+        { 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: {
+        url: './beijing-satellite.jpg',
+        bounds: [116.10, 39.80, 116.38, 39.98]  // [west, south, east, north]
+      },
+
+      // 中国边界 GeoJSON
+      boundaryUrl: './china.json',
+
+      // 微观俯冲视角高度(米)
+      microViewRange: 10000
+    };
   },
   methods: {
     onTransitionComplete() {
-      // 动画播放完毕,隐藏组件以释放显存,并显示主界面
       this.isTransitioning = false;
       console.log("进入系统!");
       this.$router.replace("/main");
     }
   }
 }
-
 </script>
 
 <style scoped>
-/* .page{
-  width:100vw; height:100vh;
-  background: radial-gradient(circle at 50% 50%, rgba(25,80,180,0.22), rgba(5,10,28,1) 65%);
-} */
-/* 增加一个淡出过渡让消失时不突兀 */
 .fade-enter-active, .fade-leave-active {
   transition: opacity 1.5s ease;
 }
 .fade-enter, .fade-leave-to {
   opacity: 0;
 }
-</style>
+</style>