diff --git a/public/assets/icons/DiQiu.png b/public/assets/icons/DiQiu.png deleted file mode 100644 index 92f1c9e..0000000 Binary files a/public/assets/icons/DiQiu.png and /dev/null differ diff --git a/public/assets/icons/ZhongXin.png b/public/assets/icons/ZhongXin.png deleted file mode 100644 index d0e2fd8..0000000 Binary files a/public/assets/icons/ZhongXin.png and /dev/null differ diff --git a/public/assets/icons/bg.png b/public/assets/icons/bg.png new file mode 100644 index 0000000..c6778ef Binary files /dev/null and b/public/assets/icons/bg.png differ diff --git a/public/assets/icons/center.png b/public/assets/icons/center.png new file mode 100644 index 0000000..a7087d0 Binary files /dev/null and b/public/assets/icons/center.png differ diff --git a/public/assets/icons/changyong.png b/public/assets/icons/changyong.png deleted file mode 100644 index fc932fa..0000000 Binary files a/public/assets/icons/changyong.png and /dev/null differ diff --git a/public/assets/icons/download.png b/public/assets/icons/download.png new file mode 100644 index 0000000..30ad75d Binary files /dev/null and b/public/assets/icons/download.png differ diff --git a/public/assets/icons/fangda.png b/public/assets/icons/fangda.png new file mode 100644 index 0000000..c1323b4 Binary files /dev/null and b/public/assets/icons/fangda.png differ diff --git a/public/assets/icons/quanping.png b/public/assets/icons/quanping.png new file mode 100644 index 0000000..7473f8e Binary files /dev/null and b/public/assets/icons/quanping.png differ diff --git a/public/assets/icons/quanping2.png b/public/assets/icons/quanping2.png new file mode 100644 index 0000000..2d474d4 Binary files /dev/null and b/public/assets/icons/quanping2.png differ diff --git a/public/assets/icons/search.png b/public/assets/icons/search.png new file mode 100644 index 0000000..88e65a4 Binary files /dev/null and b/public/assets/icons/search.png differ diff --git a/public/assets/icons/shouqi.png b/public/assets/icons/shouqi.png new file mode 100644 index 0000000..2f09736 Binary files /dev/null and b/public/assets/icons/shouqi.png differ diff --git a/public/assets/icons/shouqi2.png b/public/assets/icons/shouqi2.png deleted file mode 100644 index 9c9e7aa..0000000 Binary files a/public/assets/icons/shouqi2.png and /dev/null differ diff --git a/public/assets/icons/suoxiao.png b/public/assets/icons/suoxiao.png new file mode 100644 index 0000000..eb6cd0c Binary files /dev/null and b/public/assets/icons/suoxiao.png differ diff --git a/public/assets/icons/tianqi.png b/public/assets/icons/tianqi.png new file mode 100644 index 0000000..74215e3 Binary files /dev/null and b/public/assets/icons/tianqi.png differ diff --git a/public/assets/icons/tuceng.png b/public/assets/icons/tuceng.png index 61f2654..47dfe4d 100644 Binary files a/public/assets/icons/tuceng.png and b/public/assets/icons/tuceng.png differ diff --git a/public/assets/icons/zhankai.png b/public/assets/icons/zhankai.png new file mode 100644 index 0000000..e25c497 Binary files /dev/null and b/public/assets/icons/zhankai.png differ diff --git a/public/assets/icons/zhankai2.png b/public/assets/icons/zhankai2.png deleted file mode 100644 index 467c527..0000000 Binary files a/public/assets/icons/zhankai2.png and /dev/null differ diff --git a/src/models/runtime/index.ts b/src/models/runtime/index.ts index 50055e3..dbb7647 100644 --- a/src/models/runtime/index.ts +++ b/src/models/runtime/index.ts @@ -17,7 +17,8 @@ export const runtime = createModel()({ markers: {}, viewTick: 1, //用来刷新页面更新Marker位置 showPanels: true, //是否展开面板 - homeCheckedObj: {}, //首页展开面板对象 + isFullScreen: false, //是否全屏 + homeCheckedObj: {}, //首页展开面板对象大屏不用 featurePops: [], // [{ id, type, data, lgtd, lttd, elev }] layerSetting: {}, @@ -81,6 +82,12 @@ export const runtime = createModel()({ showPanels: val, } }, + setIsFullScreen(state, val) { + return { + ...state, + isFullScreen: val, + } + }, setHomeCheckedObj(state, val) { return { ...state, diff --git a/src/utils/tools.js b/src/utils/tools.js index cced45b..66f88bd 100644 --- a/src/utils/tools.js +++ b/src/utils/tools.js @@ -626,4 +626,43 @@ export const download = (url) => { // 模拟点击事件,开始下载 downloadLink.click(); - } \ No newline at end of file + } + +export const showFullScreen = (show=false) => { + //当前是否全屏 + const checkFullScreen = () => { + return !!( + document.fullscreenElement || + document.webkitFullscreenElement || + document.mozFullScreenElement || + document.msFullscreenElement + ); + }; + + if(show && !checkFullScreen()){ + // 进入全屏 + const elem = document?.documentElement; + if (elem?.requestFullscreen) { + elem?.requestFullscreen(); + } else if (elem?.mozRequestFullScreen) { /* Firefox */ + elem?.mozRequestFullScreen(); + } else if (elem?.webkitRequestFullscreen) { /* Chrome, Safari & Opera */ + elem?.webkitRequestFullscreen(); + } else if (elem?.msRequestFullscreen) { /* IE/Edge */ + elem?.msRequestFullscreen(); + } + } + + if(!show && checkFullScreen()){ + // 退出全屏 + if (document?.exitFullscreen) { + document?.exitFullscreen(); + } else if (document?.mozCancelFullScreen) { /* Firefox */ + document?.mozCancelFullScreen(); + } else if (document?.webkitExitFullscreen) { /* Chrome, Safari & Opera */ + document?.webkitExitFullscreen(); + } else if (document?.msExitFullscreen) { /* IE/Edge */ + document?.msExitFullscreen(); + } + } +} \ No newline at end of file diff --git a/src/views/Home/MapCtrl/M2D/Map2D.js b/src/views/Home/MapCtrl/M2D/Map2D.js index 88d0f6f..84f9927 100644 --- a/src/views/Home/MapCtrl/M2D/Map2D.js +++ b/src/views/Home/MapCtrl/M2D/Map2D.js @@ -82,7 +82,7 @@ export default class Map2D extends BaseMap { this.dispatch.runtime.setMapCenter({ center: this.PROJ2GG(center), zoom: zoom, - pitch: config.homePitch, + pitch: config.pitch3d, }) } }); diff --git a/src/views/Home/MapCtrl/M3D/Map3D.js b/src/views/Home/MapCtrl/M3D/Map3D.js index 3ff0f18..d8d0087 100644 --- a/src/views/Home/MapCtrl/M3D/Map3D.js +++ b/src/views/Home/MapCtrl/M3D/Map3D.js @@ -9,13 +9,13 @@ import { BouaLayer3D } from "./layers/BouaLayer3D"; import { BouaMaskLayer3D } from "./layers/BouaMaskLayer3D"; import { VillagesBouaLayer3D } from "./layers/VillagesBouaLayer3D" -import { getCameraViewPosition, getCameraViewCenter } from './utils/cesutil' +import { getCameraViewPosition, getCameraViewCenter, getNewPosition } from './utils/cesutil' const { Cesium } = window; function __prepare_ces(dispatch) { - Cesium.CesiumWidget.prototype.showErrorPanel = function (title) { + Cesium.CesiumWidget.prototype.showErrorPanel = function (title, error) { dispatch && dispatch.map.setMode('2d'); if (title && title.indexOf('constructing') >= 0) { alert('无法初始化三维场景,如果一直出现此问题,请尝试下载最新的chrome浏览器'); @@ -104,31 +104,38 @@ export default class Map3D extends BaseMap { Cesium.CameraEventType.MIDDLE_DRAG, Cesium.CameraEventType.WHEEL, Cesium.CameraEventType.PINCH ]; - let isInitialMove = true; - //监听地图移动完成事件 - viewer.camera.moveEnd.addEventListener(() => { - if (isInitialMove) { - isInitialMove = false; - return; - } - //获取当前相机高度 - 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.homePitch, - }) - } - }); - this.layerMgr = new LayerMgr3D(viewer); this.getLayer3D(viewer)//加载地图 + let lastPosition = {x:null,y:null,z:null};//记录上次移动坐标 + let moveStartTime = Date.now();//记录上次setMapCenter事件, 用于防抖 + let flag = false //帧检测移动后改为true + const timeInterval = 500; //防抖时间 viewer.scene.postRender.addEventListener(() => { this.dispatch.runtime.tickViewChanged(); // this.layerMgr.frameUpdate(); + + 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 + } }); let destination = Cesium.Cartesian3.fromDegrees(115.064,30.989,5000) //默认相机位置 @@ -188,21 +195,38 @@ export default class Map3D extends BaseMap { return this.layerMgr.getLayer(name); } - zoomTo(cameraTarget) { + zoomTo(cameraTarget={}) { if (cameraTarget.center) { - 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, // 飞越经度,用于控制飞行路径 - }); + 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, // 飞越经度,用于控制飞行路径 + }); + } } else if (cameraTarget.bound) { const b = cameraTarget.bound; const p1 = Cesium.Cartesian3.fromDegrees(...b[0]); @@ -221,3 +245,17 @@ export default class Map3D extends BaseMap { BouaMaskLayer3D(viewer)//县界外遮罩层 } } + +// // 这是一个测试性能的工具留着 +// 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); \ No newline at end of file diff --git a/src/views/Home/MapCtrl/M3D/layermgr3d.js b/src/views/Home/MapCtrl/M3D/layermgr3d.js index c246ce0..fc6f4f1 100644 --- a/src/views/Home/MapCtrl/M3D/layermgr3d.js +++ b/src/views/Home/MapCtrl/M3D/layermgr3d.js @@ -48,7 +48,7 @@ export default class LayerMgr3D extends LayerMgr { */ addAppLayers(dispatch, visible, setting, otherParams) { visible = visible || {}; - // dispatch.map.setMap(this.viewer); + dispatch.map.setMap(this.viewer); //河流 this.addLayer(new HLLayer3D({ visible: visible[HLLayer3D.LayerName], setting, dispatch })); //湖泊 diff --git a/src/views/Home/MapCtrl/M3D/layers/FeatureLayer3D.js b/src/views/Home/MapCtrl/M3D/layers/FeatureLayer3D.js index 39f41f3..e4c3f6e 100644 --- a/src/views/Home/MapCtrl/M3D/layers/FeatureLayer3D.js +++ b/src/views/Home/MapCtrl/M3D/layers/FeatureLayer3D.js @@ -75,7 +75,7 @@ export default class FeatureLayer3D extends BaseLayer3D { */ setData(records) { const viewer = this._viewer; - if (!viewer || !viewer.dataSourceDisplay?.defaultDataSource) { + if (!viewer || !viewer?.dataSourceDisplay?.defaultDataSource) { console.log('viewer null'); return; } diff --git a/src/views/Home/MapCtrl/M3D/utils/cesutil.js b/src/views/Home/MapCtrl/M3D/utils/cesutil.js index 59ce822..3c5b804 100644 --- a/src/views/Home/MapCtrl/M3D/utils/cesutil.js +++ b/src/views/Home/MapCtrl/M3D/utils/cesutil.js @@ -97,42 +97,43 @@ export function getCameraViewPosition(mapCenter) { } //获取摄像机焦点经纬度和高度 -export function getCameraViewCenter(viewer) { +export function getCameraViewCenter(viewer={}) { // 1. 获取屏幕中心点的射线(从相机到屏幕中心) - const ray = viewer.camera.getPickRay(new Cesium.Cartesian2( - viewer.canvas.clientWidth / 2, - viewer.canvas.clientHeight / 2 + const ray = viewer?.camera.getPickRay(new Cesium.Cartesian2( + viewer?.canvas.clientWidth / 2, + viewer?.canvas.clientHeight / 2 )); // 2. 计算射线与地球表面的交点 - const intersection = viewer.scene.globe.pick(ray, viewer.scene); + const intersection = viewer?.scene.globe.pick(ray, viewer?.scene); if (intersection) { // 如果有交点(看向地球) const cartographic = Cesium.Cartographic.fromCartesian(intersection); return { lon: Cesium.Math.toDegrees(cartographic.longitude), lat: Cesium.Math.toDegrees(cartographic.latitude), - height: heigjtToZoom(viewer.camera.positionCartographic.height)//cartographic.height + height: heigjtToZoom(viewer?.camera.positionCartographic.height)//cartographic.height }; } else { + console.log('如果看向天空或太空,获取射线与椭球体的交点'); // 如果看向天空或太空,获取射线与椭球体的交点 - const ellipsoid = viewer.scene.globe.ellipsoid; - const intersection2 = viewer.scene.camera.pickEllipsoid( + const ellipsoid = viewer?.scene.globe.ellipsoid; + const intersection2 = viewer?.scene.camera.pickEllipsoid( new Cesium.Cartesian2( - viewer.canvas.clientWidth / 2, - viewer.canvas.clientHeight / 2 + viewer?.canvas.clientWidth / 2, + viewer?.canvas.clientHeight / 2 ), ellipsoid ); - if (intersection2) { - const cartographic = Cesium.Cartographic.fromCartesian(intersection2); - return { - lon: Cesium.Math.toDegrees(cartographic.longitude), - lat: Cesium.Cartographic.toDegrees(cartographic.latitude), - height: 0 - }; - } + // if (intersection2) { + // // const cartographic = Cesium.Cartographic.fromCartesian(intersection2); + // // return { + // // lon: Cesium?.Math?.toDegrees(cartographic.longitude), + // // lat: Cesium?.Cartographic?.toDegrees(cartographic.latitude), + // // height: 0 + // // }; + // } } } @@ -192,5 +193,36 @@ export function zoomToHeight(olZoom) { } //cesium的摄像机height转openlayers的zoom export function heigjtToZoom(height) { - return Math.max(0, Math.min(28, Math.log2(120000000 / (height - 400) ))) -} \ No newline at end of file + return Math.max(0, Math.min(28, Math.log2(120000000 / (height>400?(height - 400):height) ))) +} + +//根据经纬度、当前相机朝向、zoom,返回Cartesian3位置 +export function getNewPosition(center, zoom, camera ) { + //相机坐标的高度 + const height = zoomToHeight(zoom) + //获取摄像机朝向方向的单位向量(长度1) + const direction = Cesium.Cartesian3.normalize( camera.directionWC, new Cesium.Cartesian3()); + const reverseDirection = Cesium.Cartesian3.negate(direction, new Cesium.Cartesian3());//这里要取反用来计算处摄像机所处的位置 + //相机与地表焦点的坐标 + const position = Cesium.Cartesian3.fromDegrees(center[0], center[1], 200); + //相机俯仰角 + const pitch = camera.pitch + if(pitch>=0){ + console.log('请朝向地面'); + return false + } + //直线距离 + const distance = height / Math.sin(-pitch); + // 计算移动后的位置 + const newPosition = new Cesium.Cartesian3(); + Cesium.Cartesian3.add( + position, // 当前位置 + Cesium.Cartesian3.multiplyByScalar( + reverseDirection, // 方向向量 + distance, // 移动距离 + new Cesium.Cartesian3() // 临时向量 + ), + newPosition // 结果位置 + ); + return newPosition +} diff --git a/src/views/Home/components/Business/SiQuan/index.less b/src/views/Home/components/Business/SiQuan/index.less index 7652176..8db0733 100644 --- a/src/views/Home/components/Business/SiQuan/index.less +++ b/src/views/Home/components/Business/SiQuan/index.less @@ -1,6 +1,6 @@ .siquan-view { width: 100%; - height: 100%; + height: 0; position: relative; @import "../common.less"; diff --git a/src/views/Home/index.js b/src/views/Home/index.js index 113672b..6484f6a 100644 --- a/src/views/Home/index.js +++ b/src/views/Home/index.js @@ -1,4 +1,5 @@ import React, { useState, useEffect } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; import Header from './components/Layouts/Header'; import SiQuan from './components/Business/SiQuan'; import SiZhi from './components/Business/SiZhi'; @@ -7,11 +8,19 @@ import SiGuan from './components/Business/SiGuan'; import MapCtrl from './MapCtrl/index' import MapToolBox from './mapToolBox' import './index.less'; +import { showFullScreen } from '@/utils/tools'; const HomePage = () => { const [activeMenu, setActiveMenu] = useState('siquan'); const [userInfo, setUserInfo] = useState({ userName: '系统管理员' }); const [isReady, setIsReady] = useState(false); + const isFullScreen = useSelector(s => s.runtime.isFullScreen); + const dispatch = useDispatch() + + useEffect(()=>{ + //根据isFullScreen判断当前是否进入全屏 + showFullScreen(isFullScreen) + },[isFullScreen]) useEffect(() => { // 兼容 Hash 路由模式:参数可能跟在 # 后面 (例如 /#/home?token=...) @@ -34,6 +43,7 @@ const HomePage = () => { setUserInfo({ userName: finalUserName }); setIsReady(true); + dispatch.runtime.setHome() }, []); const renderContent = () => { diff --git a/src/views/Home/mapToolBox/index.js b/src/views/Home/mapToolBox/index.js index 914eadc..e9d2f40 100644 --- a/src/views/Home/mapToolBox/index.js +++ b/src/views/Home/mapToolBox/index.js @@ -1,18 +1,25 @@ import React, { useEffect, useReducer, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Checkbox, message } from 'antd'; -import {CloseOutlined} from '@ant-design/icons'; +import { CloseOutlined } from '@ant-design/icons'; import { useLocation } from 'react-router' import './index.less' export default function Btn() { - const showPanels = useSelector((s) => s.runtime.showPanels) - const homeCheckedObj = useSelector((s) => s.runtime.homeCheckedObj) - const layerVisible = useSelector(s => s.map.layerVisible); - const mode = useSelector(s=>s.map.mode) const dispatch = useDispatch() const location = useLocation() - const [open, setOpen] = useState(false) + const showPanels = useSelector((s) => s.runtime.showPanels) + const layerVisible = useSelector(s => s.map.layerVisible); + const isFullScreen = useSelector(s => s.runtime.isFullScreen) + const mapCenter = useSelector(s => s.runtime.mapCenter)||{} + const mode = useSelector(s=>s.map.mode) + const [open, setOpen] = useState(false)//是否弹出图层窗口 + const [targetZoom, setTargetZoom] = useState(null)//点击缩放按钮后地图目标的zoom值 + + useEffect(()=>{ + //移动地图后同步targetZoom值 + setTargetZoom(mapCenter?.zoom||null) + },[mapCenter]) const layerVisibleChanged = (event)=>{ const vo = { [event.target.name]: event.target.checked }; @@ -49,22 +56,45 @@ export default function Btn() { } } - return (
-
{setOpen(!open)}}> - +
dispatch.runtime.setShowPanels(!showPanels)}> + +
+
{}}> +
dispatch.runtime.setHome()}> - +
-
dispatch.runtime.setShowPanels(!showPanels)}> - { - showPanels ? - - : +
{}}> + +
+
{ + if(mapCenter?.zoom === targetZoom){ + dispatch.runtime.setCameraTarget({...mapCenter, zoom: mapCenter.zoom + 1, fixed:true}) + setTargetZoom(mapCenter.zoom + 1) } + }}> + +
+
{ + if(mapCenter?.zoom === targetZoom){ + dispatch.runtime.setCameraTarget({...mapCenter, zoom: mapCenter.zoom - 1, fixed:true }) + setTargetZoom(mapCenter.zoom - 1) + } + }}> + +
+
{}}> + +
+
dispatch.runtime.setIsFullScreen(!isFullScreen)}> + +
+
{setOpen(!open)}}> +
diff --git a/src/views/Home/mapToolBox/index.less b/src/views/Home/mapToolBox/index.less index e17445f..5411159 100644 --- a/src/views/Home/mapToolBox/index.less +++ b/src/views/Home/mapToolBox/index.less @@ -12,8 +12,10 @@ align-items: center; .mapToolBtnIcon{ - width: 30px; - height: 30px; + width: 28px; + height: 28px; + padding: 7px; + background: url(../../../../public//assets/icons/bg.png) 50% 50% / 100% 100% no-repeat; margin-top: 5px; cursor: pointer; }