|
|
@@ -3,6 +3,7 @@
|
|
|
<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' }"
|
|
|
@@ -53,18 +54,15 @@ export default {
|
|
|
type: String,
|
|
|
default: '北京市'
|
|
|
},
|
|
|
- // 微观标记点
|
|
|
+ // 微观标记点(null 则不显示POI)
|
|
|
poi: {
|
|
|
type: Object,
|
|
|
- default: () => ({
|
|
|
- lon: 116.22405,
|
|
|
- lat: 39.90515,
|
|
|
- label: '鲁谷西街与政达路交叉口',
|
|
|
- radarRadius: 200,
|
|
|
- themeColor: '#00bfff', // CSS 颜色字符串
|
|
|
- fontColor: '#00ffff',
|
|
|
- fontSize: 20
|
|
|
- })
|
|
|
+ default: null
|
|
|
+ },
|
|
|
+ // 区域中心坐标 [lon, lat](无POI时用于相机定位)
|
|
|
+ districtCenter: {
|
|
|
+ type: Array,
|
|
|
+ default: null
|
|
|
},
|
|
|
// 路网数据
|
|
|
roads: {
|
|
|
@@ -156,7 +154,9 @@ export default {
|
|
|
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.themeColor || '#00bfff');
|
|
|
+ this._poiThemeColor = Cesium.Color.fromCssColorString(
|
|
|
+ (this.poi && this.poi.themeColor) || '#00bfff'
|
|
|
+ );
|
|
|
|
|
|
// 将 props 中的 roads 转为 Cesium 颜色对象
|
|
|
this._majorRoads = this.roads.map(r => ({
|
|
|
@@ -203,17 +203,21 @@ export default {
|
|
|
this.buildMicroLayer();
|
|
|
|
|
|
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 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';
|
|
|
+ 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';
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
});
|
|
|
},
|
|
|
|
|
|
@@ -290,15 +294,19 @@ export default {
|
|
|
this._viewer.dataSources.add(this._microEffectsSource);
|
|
|
this._microEffectsSource.show = false;
|
|
|
|
|
|
- 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);
|
|
|
+ // 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 } });
|
|
|
+ }
|
|
|
|
|
|
- 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) {
|
|
|
@@ -393,18 +401,21 @@ export default {
|
|
|
if (this._destroyed) return;
|
|
|
|
|
|
// 阶段2: 俯冲到微观
|
|
|
- const targetSphere = Cesium.BoundingSphere.fromPoints([Cesium.Cartesian3.fromDegrees(this.poi.lon, this.poi.lat)]);
|
|
|
+ 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: 显示微观雷达 + POI标签
|
|
|
+ // 阶段3: 显示微观效果
|
|
|
await this._safeDelay(1500);
|
|
|
if (this._destroyed) return;
|
|
|
this._microEffectsSource.show = true;
|
|
|
- if (this.$refs.poiLabel) this.$refs.poiLabel.style.opacity = 1;
|
|
|
+ if (this.poi && this.$refs.poiLabel) this.$refs.poiLabel.style.opacity = 1;
|
|
|
|
|
|
// 阶段4: 路网生长
|
|
|
await this._safeDelay(300);
|