地图洪水预演

lsf-dev
秦子超 2026-02-24 15:04:58 +08:00
parent 7cfb666f82
commit de8bd19e77
10 changed files with 1018 additions and 3 deletions

362
public/data/json/czml1.json Normal file

File diff suppressed because one or more lines are too long

421
public/data/json/czml2.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,15 @@
const { Cesium } = window;
export async function getCzml(viewer, path) {
viewer.dataSources._dataSources.forEach(dataSource => {
if (dataSource.name === 'CZML1111') { // 确保你知道你想要移除的数据源名称
viewer.dataSources.remove(dataSource);
}
});
const { czml } = await fetch(path)
.then(resp => resp.json())
.then(data => data)
.catch(() => []);
viewer.dataSources.add(Cesium.CzmlDataSource.load(czml));
viewer.clock.shouldAnimate = false; // 暂停动画
}

View File

@ -1,5 +1,6 @@
import React, { useState, useEffect } from 'react';
import { Radio, message } from 'antd';
import { useDispatch, useSelector } from 'react-redux'
import arrowIcon from '@/assets/images/card/arrow.png';
import NormalSelect from '../../../../../../../components/Form/NormalSelect'
import './index.less'
@ -9,11 +10,11 @@ import { httpget, httppost } from '@/utils/request';
const FloodPreview = ({setPlanData}) => {
const dispatch = useDispatch();
const [ options, setOptions ] = useState([])
const [ radio, setRadio ] = useState(1)
const [ planId, setPlanId ] = useState(null)
const [ data, setData ] = useState({})
console.log(data);
useEffect(()=>{
getPlan()
},[])
@ -114,7 +115,10 @@ const FloodPreview = ({setPlanData}) => {
<div className='flood-preview-section-btn'>
<div className="uav-button" onClick={() => {
if(data.id){
data.czmlPath = `${process.env.PUBLIC_URL}/data/json/czml1.json`
setPlanData(data)
dispatch.map.setLayerVisible({ ['SatelliteImage']: false });
dispatch.map.setMode('3d');
}
}}>洪水预演</div>
</div>

View File

@ -3,11 +3,9 @@ import { Table, message } from 'antd';
import MyCharts from './charts'
import Count from './count'
import './index.less'
import { httpget, httppost } from '@/utils/request';
const ForecastSection = () => {
const [data, setData] = useState({})
console.log(data);
useEffect(()=>{
getData()
},[])

View File

@ -0,0 +1,101 @@
import React, { useEffect, useState, useRef } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import moment from 'moment';
import Player from './playerBtn'
import { getCzml } from '../../../../../MapCtrl/M3D/layers/czmlLayer3D'
const { Cesium } = window;
const records = [
{ tm:'2000-01-01 04:00:00', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:01', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:02', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:03', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:04', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:05', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:06', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:07', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:08', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:09', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:10', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:11', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:12', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:13', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:14', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:15', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:16', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:17', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:18', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:19', data:[], text:'测试', tm2:null, },
{ tm:'2000-01-01 04:00:20', data:[], text:'测试', tm2:null, },
]
const Page = ({planData}) => {
const dispatch = useDispatch();
let mapObj = useSelector(s => s.map.map)
const [ clock, setClock ] = useState(null)
const [ playerData, setPlayerData ] = useState([])
//将预报方案的时间,按照records的长度平均分配tm是cesium时间tm2是展示时间
useEffect(()=>{
const startTime = planData?.startTm
const endTime = planData?.endTm
if( startTime && endTime ){
const start = new Date(startTime.replace(' ', 'T'));
const end = new Date(endTime.replace(' ', 'T'));
const interval = (end - start) / (records.length - 1);
const list = records.map((item, index) => ({
...item,
tm2: moment(new Date(start.getTime() + interval * index)).format('YYYY-MM-DD HH:mm:ss')
}));
setPlayerData(list)
}else{
setPlayerData([])
}
},[planData])
useEffect(()=>{
//当前map对象是cesium
if(!mapObj?._cesiumWidget){
return
}
mapObj.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(114.786546000,31.496518000,1500),
orientation: {
heading: Cesium.Math.toRadians(-90),
pitch: Cesium.Math.toRadians(-35.0),
roll: 0.0
}
});
getCzml(mapObj,planData.czmlPath)
return ()=>{
mapObj.dataSources._dataSources.forEach(dataSource => {
if (dataSource.name === 'CZML1111') { // 确保你知道你想要移除的数据源名称
mapObj.dataSources.remove(dataSource);
}
});
}
},[mapObj, planData])
useEffect(()=>{
if(clock!==null && mapObj?._cesiumWidget && playerData?.length>0){
const tm = playerData[clock].tm
if(tm){
const str = `${moment(tm).format('YYYY-MM-DD')}T${moment(tm).format('HH:mm:ss')}Z`
mapObj.clock.currentTime = Cesium.JulianDate.fromIso8601(str);
}
}
if(clock===null){return}
},[clock,mapObj,playerData])
return (
<div className='siyu-view-player'>
{ playerData.length>0 && <Player data={playerData} setClock={setClock}/> }
</div>
)
}
export default Page

View File

@ -0,0 +1,21 @@
.SliderPlayerBox{
padding: 0px 20px;
background: rgba(40, 53, 59, 0.7);
border-radius: 10px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
.SliderPlayerBox_playbtn{
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
margin: -2px 15px 0 20px;
}
.SliderPlayerBox_slider{
padding: 16px 37px 0px 0px;
width: 600px;
}
}

View File

@ -0,0 +1,81 @@
import React, { useEffect, useState, useRef } from 'react'
import { PlayCircleOutlined, PauseCircleOutlined } from '@ant-design/icons';
import {Slider} from 'antd';
import './index.less'
const Page = ({ data, setClock }) => {
const [player,setPlayer] = useState(false)
const [index,setIndex] = useState(0)
const marks = {
[0]: {
style: { color: '#fff' },
label: <span style={{width: "130px", fontSize: "12px", display:'inline-block', marginTop:'3px'}}>{data?.[0]?.tm2||''}</span>,
},
[data.length - 1]: {
style: { color: '#fff' },
label: <div style={{width: "130px", fontSize: "12px", display:'inline-block', marginTop:'3px', marginLeft: "-32px"}}>{data?.[data?.length-1]?.tm2||""}</div>,
}
};
useEffect(()=>{
setIndex(0)
setPlayer(false)
},[data])
useEffect(() => {
if (player) {
let num = index;
const h = setInterval(() => {
num = num + 1;
if (num >= data.length) {
num = 0;
}
setIndex(num);
}, 1100);
return () => {
clearInterval(h);
}
}
}, [player, index]);
useEffect(()=>{
if(index!==null){
setClock(index)
}
},[index])
return (
<>
{
data.length>0?
<div className='SliderPlayerBox'>
<div className='SliderPlayerBox_playbtn' onClick={()=>setPlayer(!player)}>
{ player?<PauseCircleOutlined style={{color: "#007AFF", fontSize: "25px"}}/>:<PlayCircleOutlined style={{color: "#007AFF", fontSize: "25px"}}/> }
</div>
<div className='SliderPlayerBox_slider'>
<Slider
disabled={player}
min={0}
max={data.length-1}
value={index}
marks={marks}
tooltip={{
open:true,
formatter:(value) => data[value].tm2
}}
onChange={(val) => setIndex(val)}
/>
</div>
</div>:null
}
</>
)
}
export default Page

View File

@ -10,6 +10,7 @@ import AllWeatherModal from '../SiQuan/components/ModalComponents/AllWeatherModa
import ForecastSection from './components/ForecastSection';
import FloodPreview from './components/FloodPreview';
import PlanPreview from './components/PlanPreview'
import Player from './components/Player'
import './index.less';
@ -64,6 +65,8 @@ const SiYu = () => {
</CommonCard>
</div>
{ planData!==null?<Player planData={planData}/>:null}
<div className={`side-panel right ${!showPanels ? 'hidden' : ''}`}>
{
planData?

View File

@ -55,4 +55,13 @@
.card-2 { flex: 1; }
.card-3 { flex: 1; }
}
.siyu-view-player{
position: absolute;
bottom: 40px;
left: 50%;
transform: translateX(-50%);
z-index: 20;
pointer-events: auto;
}
}