2026-02-06 11:00:16 +08:00
|
|
|
|
import { config } from "../../../../config";
|
|
|
|
|
|
import LayerMgr3D from './layermgr3d';
|
|
|
|
|
|
import BaseMap from '../basemap';
|
|
|
|
|
|
import { SatelliteImage3D } from "./layers/SatelliteImage3D";
|
|
|
|
|
|
import { Dem3D } from "./layers/Dem3D";
|
|
|
|
|
|
import { Tiles3D } from "./layers/Tiles3D";
|
|
|
|
|
|
import { Water3D } from "./layers/Water3D";
|
|
|
|
|
|
import { BouaLayer3D } from "./layers/BouaLayer3D";
|
|
|
|
|
|
import { BouaMaskLayer3D } from "./layers/BouaMaskLayer3D";
|
|
|
|
|
|
import { VillagesBouaLayer3D } from "./layers/VillagesBouaLayer3D"
|
|
|
|
|
|
|
2026-02-07 15:27:30 +08:00
|
|
|
|
import { getCameraViewPosition, getCameraViewCenter, getNewPosition } from './utils/cesutil'
|
2026-02-06 11:00:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const { Cesium } = window;
|
|
|
|
|
|
|
|
|
|
|
|
function __prepare_ces(dispatch) {
|
2026-02-07 15:27:30 +08:00
|
|
|
|
Cesium.CesiumWidget.prototype.showErrorPanel = function (title, error) {
|
2026-02-06 11:00:16 +08:00
|
|
|
|
dispatch && dispatch.map.setMode('2d');
|
|
|
|
|
|
if (title && title.indexOf('constructing') >= 0) {
|
|
|
|
|
|
alert('无法初始化三维场景,如果一直出现此问题,请尝试下载最新的chrome浏览器');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
alert('三维场景渲染出现问题');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* OL 封装
|
|
|
|
|
|
*/
|
|
|
|
|
|
export default class Map3D extends BaseMap {
|
|
|
|
|
|
constructor({ divid, dispatch, mapCenter }) {
|
|
|
|
|
|
super();
|
|
|
|
|
|
|
|
|
|
|
|
this.mapCenter = mapCenter;
|
|
|
|
|
|
this.dispatch = dispatch;
|
|
|
|
|
|
this.divid = divid; // div element id
|
|
|
|
|
|
this._map = null; // openlayers map obj
|
|
|
|
|
|
this.layerMgr = null;
|
|
|
|
|
|
this.toolMgr = null;
|
|
|
|
|
|
this.demo = null;
|
|
|
|
|
|
this.list = []
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 初始化地图、图层
|
|
|
|
|
|
*/
|
|
|
|
|
|
init() {
|
|
|
|
|
|
__prepare_ces(this.dispatch);
|
|
|
|
|
|
|
|
|
|
|
|
const viewer = new Cesium.Viewer(this.divid, {
|
|
|
|
|
|
shouldAnimate: true, //动画
|
|
|
|
|
|
scene3DOnly: true,//用于强制场景以 3D 模式运行,禁止切换至 2D 或 Columbus 视图
|
|
|
|
|
|
animation: false,//获取动画小部件。
|
|
|
|
|
|
baseLayerPicker: false,//获取BaseLayerPicker。
|
|
|
|
|
|
geocoder: false,//获取地理编码器
|
|
|
|
|
|
sceneModePicker: false,//Gets the SceneModePicker.
|
|
|
|
|
|
fullscreenButton: false,
|
|
|
|
|
|
homeButton: false,
|
|
|
|
|
|
timeline: false,
|
|
|
|
|
|
navigationHelpButton: false,//导航帮助按钮
|
|
|
|
|
|
shadows: false,//确定阴影是否由光源投射。
|
|
|
|
|
|
infoBox: false,
|
|
|
|
|
|
skyAtmosphere: false,//去掉球边缘
|
|
|
|
|
|
selectionIndicator:false,//去掉选择指示器
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
viewer.clock.currentTime = Cesium.JulianDate.fromIso8601('2000-01-01T04:00:07Z');//设置当前时间
|
|
|
|
|
|
|
|
|
|
|
|
//设置地表透明
|
|
|
|
|
|
let globe = viewer.scene.globe;
|
|
|
|
|
|
globe.depthTestAgainstTerrain = false;//关闭深度测试
|
|
|
|
|
|
//viewer.scene.skyAtmosphere.show = false; //关闭大气层阴影
|
|
|
|
|
|
viewer.scene.screenSpaceCameraController.minimumZoomDistance = 100;
|
|
|
|
|
|
// viewer.scene.screenSpaceCameraController.maximumZoomDistance = 200000;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
viewer.scene.globe.enableLighting = false; //关闭光照
|
|
|
|
|
|
viewer.scene.light.intensity = 6 //默认光源强度,太低了模型显示效果差
|
|
|
|
|
|
viewer.shadows = false;//关闭阴影
|
|
|
|
|
|
viewer.scene.globe.depthTestAgainstTerrain = false;//解决地形遮挡entity问题
|
|
|
|
|
|
|
|
|
|
|
|
//优化项--关闭相关特效
|
|
|
|
|
|
viewer.scene.moon.show = false; //月亮
|
|
|
|
|
|
viewer.scene.fog.enabled = false; //雾
|
|
|
|
|
|
viewer.scene.sun.show = false; //太阳
|
|
|
|
|
|
viewer.scene.skyBox.show = false; //天空盒
|
|
|
|
|
|
viewer.resolutionScale = 1.0; //画面细度,默认值为1.0
|
|
|
|
|
|
|
|
|
|
|
|
viewer.scene.fxaa = false;
|
|
|
|
|
|
viewer.scene.postProcessStages.fxaa.enabled = true;
|
|
|
|
|
|
viewer.scene.globe.depthTestAgainstTerrain = true;
|
|
|
|
|
|
viewer.scene.globe.baseColor = Cesium.Color.TRANSPARENT;//设置球的基础色
|
|
|
|
|
|
viewer.scene.globe.undergroundColor= Cesium.Color.BLACK.withAlpha(0.5);//设置球的地下色
|
|
|
|
|
|
viewer.scene.backgroundColor = Cesium.Color.BLACK;
|
|
|
|
|
|
|
|
|
|
|
|
viewer.scene.screenSpaceCameraController.tiltEventTypes = [
|
|
|
|
|
|
Cesium.CameraEventType.RIGHT_DRAG, Cesium.CameraEventType.PINCH,
|
|
|
|
|
|
{ eventType: Cesium.CameraEventType.LEFT_DRAG, modifier: Cesium.KeyboardEventModifier.CTRL },
|
|
|
|
|
|
{ eventType: Cesium.CameraEventType.RIGHT_DRAG, modifier: Cesium.KeyboardEventModifier.CTRL }
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
viewer.scene.screenSpaceCameraController.zoomEventTypes = [
|
|
|
|
|
|
Cesium.CameraEventType.MIDDLE_DRAG, Cesium.CameraEventType.WHEEL, Cesium.CameraEventType.PINCH
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
this.layerMgr = new LayerMgr3D(viewer);
|
|
|
|
|
|
this.getLayer3D(viewer)//加载地图
|
|
|
|
|
|
|
2026-02-07 15:27:30 +08:00
|
|
|
|
let lastPosition = {x:null,y:null,z:null};//记录上次移动坐标
|
|
|
|
|
|
let moveStartTime = Date.now();//记录上次setMapCenter事件, 用于防抖
|
|
|
|
|
|
let flag = false //帧检测移动后改为true
|
|
|
|
|
|
const timeInterval = 500; //防抖时间
|
2026-02-06 11:00:16 +08:00
|
|
|
|
viewer.scene.postRender.addEventListener(() => {
|
|
|
|
|
|
this.dispatch.runtime.tickViewChanged();
|
|
|
|
|
|
// this.layerMgr.frameUpdate();
|
2026-02-07 15:27:30 +08:00
|
|
|
|
|
|
|
|
|
|
const currentPos = viewer.camera.position
|
|
|
|
|
|
const { x, y, z } = lastPosition
|
|
|
|
|
|
if(currentPos.x===x && currentPos.y===y && currentPos.z===z){
|
|
|
|
|
|
if(flag && (Date.now() - moveStartTime >= timeInterval)){
|
|
|
|
|
|
const { lon, lat, height:olZoom } = getCameraViewCenter(viewer)||{};
|
|
|
|
|
|
console.log(lon, lat, olZoom);
|
|
|
|
|
|
if(lon && lat && olZoom){
|
|
|
|
|
|
this.dispatch.runtime.setMapCenter({
|
|
|
|
|
|
center: [lon, lat],
|
|
|
|
|
|
zoom: olZoom,
|
|
|
|
|
|
pitch: config.pitch3d,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
flag = false
|
|
|
|
|
|
moveStartTime = Date.now()
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
//在移动
|
|
|
|
|
|
lastPosition = { x: currentPos.x, y: currentPos.y, z: currentPos.z };
|
|
|
|
|
|
flag = true
|
|
|
|
|
|
}
|
2026-02-06 11:00:16 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
let destination = Cesium.Cartesian3.fromDegrees(115.064,30.989,5000) //默认相机位置
|
|
|
|
|
|
if(this.mapCenter){
|
|
|
|
|
|
destination = getCameraViewPosition(this.mapCenter)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置相机位置
|
|
|
|
|
|
viewer.camera.setView({
|
|
|
|
|
|
destination: destination,
|
|
|
|
|
|
orientation: {
|
|
|
|
|
|
heading: Cesium.Math.toRadians(0),
|
|
|
|
|
|
pitch: Cesium.Math.toRadians(config.pitch3d),
|
|
|
|
|
|
roll: 0.0,
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
this._map = viewer;
|
|
|
|
|
|
const toremove = document.getElementsByClassName('cesium-widget-credits');
|
|
|
|
|
|
if (toremove && toremove[0]) {
|
|
|
|
|
|
toremove[0].style.display = 'none';
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
coordinateToPixel(lgtd, lttd, elev) {
|
|
|
|
|
|
if(!this._map){
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const pt = Cesium.Cartesian3.fromDegrees(lgtd, lttd, elev);
|
|
|
|
|
|
const result = Cesium.SceneTransforms.worldToWindowCoordinates(
|
|
|
|
|
|
this._map.scene, pt);
|
|
|
|
|
|
if (!result) {
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
return [result.x, result.y, pt.x, pt.y, pt.z];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 组件卸载时,需要销毁map对象
|
|
|
|
|
|
*/
|
|
|
|
|
|
destroy() {
|
|
|
|
|
|
console.log('##############destroy##############');
|
|
|
|
|
|
if (!this.layerMgr) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
this.layerMgr.destroy();
|
|
|
|
|
|
if (this._map) {
|
|
|
|
|
|
this._map.destroy();
|
|
|
|
|
|
this._map = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* get layer obj
|
|
|
|
|
|
*/
|
|
|
|
|
|
getLayer(name) {
|
|
|
|
|
|
return this.layerMgr.getLayer(name);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-07 15:27:30 +08:00
|
|
|
|
zoomTo(cameraTarget={}) {
|
2026-02-06 11:00:16 +08:00
|
|
|
|
if (cameraTarget.center) {
|
2026-02-07 15:27:30 +08:00
|
|
|
|
if(cameraTarget.fixed){//固定相机朝向
|
|
|
|
|
|
const camera = this._map.camera;
|
|
|
|
|
|
const destination = getNewPosition(cameraTarget.center, cameraTarget.zoom, camera)
|
|
|
|
|
|
if(!destination){
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
camera.flyTo({
|
|
|
|
|
|
destination: destination,
|
|
|
|
|
|
orientation: {
|
|
|
|
|
|
heading: camera.heading,
|
|
|
|
|
|
pitch: camera.pitch,
|
|
|
|
|
|
roll: 0.0,
|
|
|
|
|
|
},
|
|
|
|
|
|
duration: 1,
|
|
|
|
|
|
});
|
|
|
|
|
|
}else{
|
|
|
|
|
|
this._map.camera.flyTo({
|
|
|
|
|
|
destination: getCameraViewPosition(cameraTarget),
|
|
|
|
|
|
orientation: {
|
|
|
|
|
|
heading: Cesium.Math.toRadians(0),
|
|
|
|
|
|
pitch: Cesium.Math.toRadians(config.pitch3d),
|
|
|
|
|
|
roll: 0.0,
|
|
|
|
|
|
},
|
|
|
|
|
|
duration: 1.5, // 飞行时间,单位秒,可以根据需要调整
|
|
|
|
|
|
// 其他可选参数,例如:
|
|
|
|
|
|
// maximumHeight: 10000, // 最大高度
|
|
|
|
|
|
// pitchAdjustHeight : 1000, // 在飞行过程中调整俯仰角的高度阈值
|
|
|
|
|
|
// flyOverLongitude: 100, // 飞越经度,用于控制飞行路径
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-02-06 11:00:16 +08:00
|
|
|
|
} else if (cameraTarget.bound) {
|
|
|
|
|
|
const b = cameraTarget.bound;
|
|
|
|
|
|
const p1 = Cesium.Cartesian3.fromDegrees(...b[0]);
|
|
|
|
|
|
const p2 = Cesium.Cartesian3.fromDegrees(...b[1]);
|
|
|
|
|
|
this._map.camera.flyToBoundingSphere(Cesium.BoundingSphere.fromPoints([p1, p2]));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async getLayer3D(viewer) {
|
|
|
|
|
|
Dem3D(viewer)//地形
|
|
|
|
|
|
SatelliteImage3D(viewer)//卫星地图
|
|
|
|
|
|
// Tiles3D(viewer)//倾斜摄影
|
|
|
|
|
|
// Water3D(viewer)//水面
|
|
|
|
|
|
VillagesBouaLayer3D(viewer)//乡镇边界
|
|
|
|
|
|
BouaLayer3D(viewer)//县界
|
|
|
|
|
|
BouaMaskLayer3D(viewer)//县界外遮罩层
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-02-07 15:27:30 +08:00
|
|
|
|
|
|
|
|
|
|
// // 这是一个测试性能的工具留着
|
|
|
|
|
|
// let listenerExecutionTimes = []; // 记录每次执行的时间
|
|
|
|
|
|
// const start = performance.now();
|
|
|
|
|
|
// const end = performance.now();
|
|
|
|
|
|
// listenerExecutionTimes.push(end - start);
|
|
|
|
|
|
|
|
|
|
|
|
// setInterval(() => {
|
|
|
|
|
|
// if (listenerExecutionTimes.length > 0) {
|
|
|
|
|
|
// const avg = listenerExecutionTimes.reduce((a, b) => a + b, 0) / listenerExecutionTimes.length;
|
|
|
|
|
|
// console.log(`平均每帧监听函数执行时间: ${avg.toFixed(3)}ms`);
|
|
|
|
|
|
// listenerExecutionTimes = []; // 清空
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }, 1000);
|