refactor
This commit is contained in:
parent
9edef5775d
commit
477bf6f6bd
1180
package-lock.json
generated
1180
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,13 @@
|
|||||||
import { Routes, Route, Navigate } from "react-router-dom";
|
import { Routes, Route, Navigate } from "react-router-dom";
|
||||||
import HomeLayout from "@/components/HomeLayout";
|
import HomeLayout from "@/components/home/Layout";
|
||||||
import MapLayout from "./components/map/Layout";
|
import DomainOne from "./components/domain/One";
|
||||||
import "./App.less";
|
import "./App.less";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<HomeLayout />} />
|
<Route path="/" element={<HomeLayout />} />
|
||||||
<Route path="map/:type" element={<MapLayout />}></Route>
|
<Route path="map/1" element={<DomainOne />}></Route>
|
||||||
<Route path="*" element={<Navigate to={"/"} replace={true} />} />
|
<Route path="*" element={<Navigate to={"/"} replace={true} />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
|
128
src/components/common/WavePoint/index.jsx
Normal file
128
src/components/common/WavePoint/index.jsx
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import { Fragment } from "react";
|
||||||
|
import { Entity, EllipseGraphics } from "resium";
|
||||||
|
import wave from "@/assets/wave.png";
|
||||||
|
|
||||||
|
function WavePoint({
|
||||||
|
stationLon,
|
||||||
|
stationLat,
|
||||||
|
value = 360,
|
||||||
|
deviationR = 5000,
|
||||||
|
eachInterval = 1500,
|
||||||
|
maxR = 3600 * 100,
|
||||||
|
}) {
|
||||||
|
const data = {
|
||||||
|
stationLon, // 经度
|
||||||
|
stationLat, // 纬度
|
||||||
|
value, // 传感器的大小
|
||||||
|
deviationR, // 差值 差值越大 速度越快
|
||||||
|
eachInterval, // 两个圈的时间间隔
|
||||||
|
imageUrl: wave,
|
||||||
|
maxR,
|
||||||
|
};
|
||||||
|
|
||||||
|
var r1 = 0,
|
||||||
|
r2 = 0;
|
||||||
|
var r3 = 0,
|
||||||
|
r4 = 0;
|
||||||
|
function changeOne() {
|
||||||
|
r1 = r1 + data.deviationR;
|
||||||
|
if (r1 >= data.maxR) {
|
||||||
|
r1 = 0;
|
||||||
|
}
|
||||||
|
return r1;
|
||||||
|
}
|
||||||
|
function changeR2() {
|
||||||
|
r2 = r2 + data.deviationR;
|
||||||
|
if (r2 >= data.maxR) {
|
||||||
|
r2 = 0;
|
||||||
|
}
|
||||||
|
return r2;
|
||||||
|
}
|
||||||
|
|
||||||
|
const point1 = (
|
||||||
|
<Entity
|
||||||
|
id={`wave-point-1-${stationLon}-${stationLat}`}
|
||||||
|
position={Cesium.Cartesian3.fromDegrees(
|
||||||
|
data.stationLon,
|
||||||
|
data.stationLat,
|
||||||
|
0
|
||||||
|
)}
|
||||||
|
show={true}
|
||||||
|
>
|
||||||
|
<EllipseGraphics
|
||||||
|
semiMinorAxis={new Cesium.CallbackProperty(changeOne, false)}
|
||||||
|
semiMajorAxis={new Cesium.CallbackProperty(changeR2, false)}
|
||||||
|
height={10}
|
||||||
|
material={
|
||||||
|
new Cesium.ImageMaterialProperty({
|
||||||
|
image: data.imageUrl,
|
||||||
|
repeat: Cesium.Cartesian2(1.0, 1.0),
|
||||||
|
transparent: true,
|
||||||
|
color: new Cesium.CallbackProperty(function () {
|
||||||
|
var alp = 1 - r1 / data.maxR;
|
||||||
|
return Cesium.Color.WHITE.withAlpha(alp);
|
||||||
|
}, false),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Entity>
|
||||||
|
);
|
||||||
|
|
||||||
|
let point2;
|
||||||
|
|
||||||
|
//第二个圆开始跑
|
||||||
|
setTimeout(function () {
|
||||||
|
function changeTwo() {
|
||||||
|
r3 = r3 + data.deviationR;
|
||||||
|
if (r3 >= data.maxR) {
|
||||||
|
r3 = 0;
|
||||||
|
}
|
||||||
|
return r3;
|
||||||
|
}
|
||||||
|
function changeR12() {
|
||||||
|
r4 = r4 + data.deviationR;
|
||||||
|
if (r4 >= data.maxR) {
|
||||||
|
r4 = 0;
|
||||||
|
}
|
||||||
|
return r4;
|
||||||
|
}
|
||||||
|
point2 = (
|
||||||
|
<Entity
|
||||||
|
position={Cesium.Cartesian3.fromDegrees(
|
||||||
|
data.stationLon,
|
||||||
|
data.stationLat,
|
||||||
|
0
|
||||||
|
)}
|
||||||
|
show={true}
|
||||||
|
id={`wave-point-2-${stationLon}-${stationLat}`}
|
||||||
|
>
|
||||||
|
<EllipseGraphics
|
||||||
|
semiMinorAxis={new Cesium.CallbackProperty(changeTwo, false)}
|
||||||
|
semiMajorAxis={new Cesium.CallbackProperty(changeR12, false)}
|
||||||
|
height={10}
|
||||||
|
material={
|
||||||
|
new Cesium.ImageMaterialProperty({
|
||||||
|
image: data.imageUrl,
|
||||||
|
repeat: Cesium.Cartesian2(1.0, 1.0),
|
||||||
|
transparent: true,
|
||||||
|
color: new Cesium.CallbackProperty(function () {
|
||||||
|
var alp = 1 - r1 / data.maxR;
|
||||||
|
return Cesium.Color.WHITE.withAlpha(alp);
|
||||||
|
//entity的颜色透明 并不影响材质,并且 entity也会透明
|
||||||
|
}, false),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Entity>
|
||||||
|
);
|
||||||
|
}, data.eachInterval);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
{point1}
|
||||||
|
{point2}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default WavePoint;
|
59
src/components/domain/One/Barotorpic.jsx
Normal file
59
src/components/domain/One/Barotorpic.jsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { useCallback, useState } from "react";
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
LabelGraphics,
|
||||||
|
EllipseGraphics,
|
||||||
|
useCesium,
|
||||||
|
CylinderGraphics,
|
||||||
|
} from "resium";
|
||||||
|
import { Color, Cartesian3, LabelStyle } from "cesium";
|
||||||
|
import { useInterval } from "ahooks";
|
||||||
|
|
||||||
|
function Barotropic() {
|
||||||
|
const { viewer } = useCesium();
|
||||||
|
|
||||||
|
const [show, setShow] = useState(false);
|
||||||
|
|
||||||
|
const showAnimate = useCallback(() => {
|
||||||
|
const { currentTime, stopTime } = viewer.clock;
|
||||||
|
const leftTime = Math.floor(
|
||||||
|
stopTime.secondsOfDay - currentTime.secondsOfDay
|
||||||
|
);
|
||||||
|
|
||||||
|
if (leftTime < 10) {
|
||||||
|
setShow(true);
|
||||||
|
} else if (show) setShow(false);
|
||||||
|
}, [show]);
|
||||||
|
|
||||||
|
useInterval(showAnimate, 100);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Entity
|
||||||
|
show={show}
|
||||||
|
name="Barotropic"
|
||||||
|
// description="Barotropic"
|
||||||
|
position={Cartesian3.fromDegrees(88, 60, 0)}
|
||||||
|
>
|
||||||
|
<EllipseGraphics
|
||||||
|
material={new Color(0.73, 0.94, 0.95, 0.4)}
|
||||||
|
semiMinorAxis={150000.0}
|
||||||
|
semiMajorAxis={150000.0}
|
||||||
|
extrudedHeight={1000000.0}
|
||||||
|
rotation={0}
|
||||||
|
// outline
|
||||||
|
/>
|
||||||
|
<LabelGraphics
|
||||||
|
position={Cartesian3.fromDegrees(88, 60, 0)}
|
||||||
|
text={"barotropic"}
|
||||||
|
font="24px Helvetica"
|
||||||
|
fillColor={Color.SKYBLUE}
|
||||||
|
outlineColor={Color.BLACK}
|
||||||
|
outlineWidth={2}
|
||||||
|
style={LabelStyle.FILL_AND_OUTLINE}
|
||||||
|
eyeOffset={new Cesium.Cartesian2(0, 500000)}
|
||||||
|
/>
|
||||||
|
</Entity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Barotropic;
|
131
src/components/domain/One/ChartPanel.jsx
Normal file
131
src/components/domain/One/ChartPanel.jsx
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
import ReactECharts from "echarts-for-react";
|
||||||
|
|
||||||
|
const years = [];
|
||||||
|
|
||||||
|
for (let year = 1980; year <= 2017; year++) {
|
||||||
|
years.push(year);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 高原夏季气温(异常值)
|
||||||
|
const plateauData = [
|
||||||
|
-0.3532047, -0.3800191, -0.4393019, -0.4789361, -0.4674187, -0.4082659,
|
||||||
|
-0.3299886, -0.2692249, -0.2362842, -0.2431858, -0.2888356, -0.3307647,
|
||||||
|
-0.3263536, -0.2682413, -0.1973641, -0.1355748, -0.09169727, -0.05341399,
|
||||||
|
0.00680301, 0.0840551, 0.1391686, 0.1402837, 0.09915907, 0.06798702,
|
||||||
|
0.07436849, 0.1159735, 0.1679915, 0.2133843, 0.2477409, 0.2872947, 0.3583514,
|
||||||
|
0.4338831, 0.4701767, 0.4778886, 0.4858712, 0.5201119, 0.5574191, 0.570379,
|
||||||
|
];
|
||||||
|
|
||||||
|
// 拉布拉多海夏季海温(异常值)
|
||||||
|
const laBrudata = [
|
||||||
|
-0.5808361, -0.6286728, -0.731713, -0.8032401, -0.7824413, -0.687568,
|
||||||
|
-0.5886319, -0.5527237, -0.6027562, -0.7280338, -0.8761956, -0.9766923,
|
||||||
|
-0.9833426, -0.8901258, -0.7279955, -0.5212721, -0.2961609, -0.0860718,
|
||||||
|
0.07991157, 0.166387, 0.1871717, 0.1972264, 0.2479431, 0.3619903, 0.5000346,
|
||||||
|
0.6201853, 0.696692, 0.7417008, 0.7834306, 0.8539514, 0.935372, 0.9951949,
|
||||||
|
0.9844907, 0.9088836, 0.7977505, 0.7049671, 0.644415, 0.6330437,
|
||||||
|
];
|
||||||
|
|
||||||
|
function ChartPanel() {
|
||||||
|
const option = {
|
||||||
|
title: {
|
||||||
|
// text: "Stacked Line",
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: "axis",
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ["ERSST_lancozs", "JRA55_lancozs"],
|
||||||
|
textStyle: { color: "#04fbfd", cursor: "point" },
|
||||||
|
},
|
||||||
|
animationDuration: years.length * 1000,
|
||||||
|
animationEasing: "cubicInOut",
|
||||||
|
grid: {
|
||||||
|
left: "3%",
|
||||||
|
right: "4%",
|
||||||
|
bottom: "3%",
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
// toolbox: {
|
||||||
|
// feature: {
|
||||||
|
// // 下载
|
||||||
|
// saveAsImage: {},
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
xAxis: {
|
||||||
|
type: "category",
|
||||||
|
boundaryGap: false,
|
||||||
|
data: years,
|
||||||
|
axisLine: {
|
||||||
|
onZero: false,
|
||||||
|
symbol: ["none", "arrow"],
|
||||||
|
symbolOffser: [0, 10],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: "value",
|
||||||
|
min: -1.5,
|
||||||
|
max: 2.0,
|
||||||
|
interval: 0.5,
|
||||||
|
splitNumber: 5,
|
||||||
|
splitLine: { show: false },
|
||||||
|
axisLine: {
|
||||||
|
onZero: false,
|
||||||
|
show: true,
|
||||||
|
symbol: ["none", "arrow"],
|
||||||
|
symbolOffset: [0, 10],
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
axisTick: { show: true },
|
||||||
|
scale: true,
|
||||||
|
},
|
||||||
|
dataZoom: { type: "inside", start: 0, end: 100 },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: "ERSST_lancozs",
|
||||||
|
type: "line",
|
||||||
|
stack: "Total",
|
||||||
|
data: laBrudata,
|
||||||
|
smooth: true,
|
||||||
|
color: "red",
|
||||||
|
symbol: "none",
|
||||||
|
itemStyle: {
|
||||||
|
color: "red",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "JRA55_lancozs",
|
||||||
|
type: "line",
|
||||||
|
// stack: "Total",
|
||||||
|
data: plateauData,
|
||||||
|
smooth: false,
|
||||||
|
color: "#00a1ff",
|
||||||
|
symbol: "none",
|
||||||
|
itemStyle: {
|
||||||
|
color: "#00a1ff",
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
type: "dashed",
|
||||||
|
width: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="chart-info-panel">
|
||||||
|
<ReactECharts
|
||||||
|
option={option}
|
||||||
|
lazyUpdate={true}
|
||||||
|
style={{
|
||||||
|
height: "100%",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ChartPanel;
|
28
src/components/domain/One/CustomClock.jsx
Normal file
28
src/components/domain/One/CustomClock.jsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Clock } from "resium";
|
||||||
|
|
||||||
|
// 起始时间
|
||||||
|
const start = Cesium.JulianDate.fromDate(new Date());
|
||||||
|
// 结束时间
|
||||||
|
const stop = Cesium.JulianDate.addSeconds(start, 60, new Cesium.JulianDate());
|
||||||
|
|
||||||
|
function CustomClock() {
|
||||||
|
return (
|
||||||
|
<Clock
|
||||||
|
multiplier={1}
|
||||||
|
shouldAnimate={false}
|
||||||
|
startTime={start.clone()}
|
||||||
|
stopTime={stop.clone()}
|
||||||
|
currentTime={start.clone()}
|
||||||
|
clockRange={Cesium.ClockRange.LOOP_STOP}
|
||||||
|
// onTick={(clock) => {
|
||||||
|
// if (!clock.shouldAnimate) return;
|
||||||
|
// }}
|
||||||
|
// onStop={() => {
|
||||||
|
// if (toolbar.showPanel === undefined)
|
||||||
|
// dispatch.data.updateToolbar({ showPanel: true });
|
||||||
|
// }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomClock;
|
81
src/components/domain/One/CustomFlyTo.jsx
Normal file
81
src/components/domain/One/CustomFlyTo.jsx
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { Camera, useCesium } from "resium";
|
||||||
|
|
||||||
|
function CustomFlyTo() {
|
||||||
|
const { viewer } = useCesium();
|
||||||
|
const { camera } = viewer;
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
function cameraFlyToLine(adjustPitch) {
|
||||||
|
// barotorpic
|
||||||
|
const barotorpic = {
|
||||||
|
destination: Cesium.Cartesian3.fromDegrees(42, 46, 15000000),
|
||||||
|
duration: 30,
|
||||||
|
complete: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 俯视看箭头上升
|
||||||
|
const sideViewOptions = {
|
||||||
|
destination: Cesium.Cartesian3.fromDegrees(-50, 46, 2000000),
|
||||||
|
duration: 5,
|
||||||
|
orientation: {
|
||||||
|
heading: Cesium.Math.toRadians(-15.0),
|
||||||
|
pitch: -Cesium.Math.PI_OVER_FOUR,
|
||||||
|
roll: 0.0,
|
||||||
|
},
|
||||||
|
complete: () => {
|
||||||
|
viewer.clock.shouldAnimate = true;
|
||||||
|
setTimeout(function () {
|
||||||
|
camera.flyTo(barotorpic);
|
||||||
|
}, 1000);
|
||||||
|
dispatch.data.updateImageLayer({
|
||||||
|
labrador: true,
|
||||||
|
});
|
||||||
|
dispatch.data.updateToolbar({ showPanel: true });
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 青藏高原
|
||||||
|
const plateauOptions = {
|
||||||
|
destination: Cesium.Cartesian3.fromDegrees(90, 20, 1600000),
|
||||||
|
duration: 5,
|
||||||
|
orientation: {
|
||||||
|
heading: Cesium.Math.toRadians(-15.0),
|
||||||
|
pitch: -Cesium.Math.PI_OVER_FOUR,
|
||||||
|
roll: 0.0,
|
||||||
|
},
|
||||||
|
complete: function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
camera.flyTo(sideViewOptions);
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 拉布拉多海
|
||||||
|
const labrador = {
|
||||||
|
destination: Cesium.Cartesian3.fromDegrees(-55, 45, 1600000),
|
||||||
|
duration: 10,
|
||||||
|
orientation: {
|
||||||
|
heading: Cesium.Math.toRadians(-15.0),
|
||||||
|
pitch: -Cesium.Math.PI_OVER_FOUR,
|
||||||
|
roll: 0.0,
|
||||||
|
},
|
||||||
|
complete: function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
camera.flyTo(plateauOptions);
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (adjustPitch) {
|
||||||
|
plateauOptions.pitchAdjustHeight = 1000;
|
||||||
|
sideViewOptions.pitchAdjustHeight = 1000;
|
||||||
|
}
|
||||||
|
camera.flyTo(labrador);
|
||||||
|
}
|
||||||
|
cameraFlyToLine();
|
||||||
|
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomFlyTo;
|
119
src/components/domain/One/CustomToolbar.jsx
Normal file
119
src/components/domain/One/CustomToolbar.jsx
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import { useCallback, useState } from "react";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useCesium } from "resium";
|
||||||
|
import { Select } from "antd";
|
||||||
|
|
||||||
|
function CustomToolbar() {
|
||||||
|
const { viewer } = useCesium();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const { toolbar } = useSelector((state) => state.data);
|
||||||
|
const [value, setValue] = useState("sideview");
|
||||||
|
|
||||||
|
const handleChange = (value) => {
|
||||||
|
setValue(value);
|
||||||
|
const pointEntity = viewer.entities.getById("point");
|
||||||
|
if (!viewer) return;
|
||||||
|
if (value === "overhead") {
|
||||||
|
// 俯视
|
||||||
|
viewer.trackedEntity = pointEntity;
|
||||||
|
const destination = pointEntity.position.getValue(
|
||||||
|
viewer.clock.currentTime
|
||||||
|
);
|
||||||
|
if (!destination) return;
|
||||||
|
const newDestination = new Cesium.Cartesian3();
|
||||||
|
newDestination.x = destination.x;
|
||||||
|
newDestination.y = destination.y + 13000000;
|
||||||
|
newDestination.z = destination.z;
|
||||||
|
viewer.camera.flyTo({
|
||||||
|
destination: newDestination,
|
||||||
|
});
|
||||||
|
} else if (value === "sideview") {
|
||||||
|
// 侧视
|
||||||
|
// viewer.trackedEntity = pointEntity;
|
||||||
|
viewer.trackedEntity = undefined;
|
||||||
|
viewer.camera.flyTo({
|
||||||
|
destination: Cesium.Cartesian3.fromDegrees(130, -10.5, 20000000),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 跟随mftata
|
||||||
|
viewer.trackedEntity = pointEntity;
|
||||||
|
const destination = pointEntity.position.getValue(
|
||||||
|
viewer.clock.currentTimes
|
||||||
|
);
|
||||||
|
if (!destination) return;
|
||||||
|
const newDestination = Cesium.Cartesian3.clone(destination);
|
||||||
|
newDestination.y = destination.y + 1000000;
|
||||||
|
viewer.camera.flyTo({
|
||||||
|
destination: newDestination,
|
||||||
|
orientation: {
|
||||||
|
heading: Cesium.Math.toRadians(0.0),
|
||||||
|
pitch: -Cesium.Math.PI_OVER_FOUR,
|
||||||
|
roll: 0.0,
|
||||||
|
},
|
||||||
|
duration: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const navigateHandler = useCallback(() => {
|
||||||
|
navigate("/home", { replace: true });
|
||||||
|
dispatch.data.resetState();
|
||||||
|
}, [navigate, dispatch]);
|
||||||
|
|
||||||
|
const showPanelHandler = useCallback(
|
||||||
|
(value) => {
|
||||||
|
dispatch.data.updateToolbar({
|
||||||
|
showPanel: value,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="toolbar">
|
||||||
|
<div className={"focusBtn"} onClick={navigateHandler}>
|
||||||
|
返回首页
|
||||||
|
</div>
|
||||||
|
{/* <Select
|
||||||
|
// onSelect={handleChange}
|
||||||
|
onChange={handleChange}
|
||||||
|
value={value}
|
||||||
|
getPopupContainer={(node) => node}
|
||||||
|
options={[
|
||||||
|
// {
|
||||||
|
// value: "overhead",
|
||||||
|
// label: "俯视视角",
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
value: "sideview",
|
||||||
|
label: "侧视视角",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "follow",
|
||||||
|
label: "跟随视角",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/> */}
|
||||||
|
<Select
|
||||||
|
onChange={showPanelHandler}
|
||||||
|
value={!!toolbar.showPanel}
|
||||||
|
getPopupContainer={(node) => node}
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
label: "开启展板",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: false,
|
||||||
|
label: "关闭展板",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CustomToolbar;
|
134
src/components/domain/One/Cyclone.jsx
Normal file
134
src/components/domain/One/Cyclone.jsx
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import { Fragment, useCallback } from "react";
|
||||||
|
import { Entity, ModelGraphics, useCesium } from "resium";
|
||||||
|
import arrowRound from "@/assets/arrow_round.glb";
|
||||||
|
|
||||||
|
let totalSeconds = 60;
|
||||||
|
let numberOfSamples = 120;
|
||||||
|
let wheelAngle = 0;
|
||||||
|
|
||||||
|
function Cyclone() {
|
||||||
|
const { viewer } = useCesium();
|
||||||
|
|
||||||
|
// 自转
|
||||||
|
// const position = new Cesium.SampledPositionProperty();
|
||||||
|
|
||||||
|
// const velocityVectorProperty = new Cesium.VelocityVectorProperty(
|
||||||
|
// position,
|
||||||
|
// false
|
||||||
|
// );
|
||||||
|
// const velocityVector = new Cesium.Cartesian3();
|
||||||
|
// const wheelAngleProperty = new Cesium.SampledProperty(Number);
|
||||||
|
|
||||||
|
// for (let index = 0; index < numberOfSamples; index++) {
|
||||||
|
// const factor = index / numberOfSamples;
|
||||||
|
// const time = Cesium.JulianDate.addSeconds(
|
||||||
|
// startTime,
|
||||||
|
// factor * totalSeconds,
|
||||||
|
// new Cesium.JulianDate()
|
||||||
|
// );
|
||||||
|
// velocityVectorProperty.getValue(time, velocityVector);
|
||||||
|
// wheelAngle -= 3;
|
||||||
|
// wheelAngleProperty.addSample(time, wheelAngle);
|
||||||
|
// }
|
||||||
|
// const rotationProperty = new Cesium.CallbackProperty(function (time, result) {
|
||||||
|
// return Cesium.Quaternion.fromAxisAngle(
|
||||||
|
// Cesium.Cartesian3.UNIT_Z,
|
||||||
|
// wheelAngleProperty.getValue(time) || wheelAngleProperty._values[0],
|
||||||
|
// result
|
||||||
|
// );
|
||||||
|
// }, false);
|
||||||
|
|
||||||
|
const getPassTime = useCallback(() => {
|
||||||
|
const { startTime, currentTime } = viewer.clock;
|
||||||
|
const _time = Math.floor(currentTime.secondsOfDay - startTime.secondsOfDay);
|
||||||
|
return _time;
|
||||||
|
}, [viewer]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<Entity
|
||||||
|
id={"Anticyclone-1"}
|
||||||
|
position={
|
||||||
|
new Cesium.CallbackProperty(function (time, result) {
|
||||||
|
const passTime = getPassTime();
|
||||||
|
if (passTime < 10) return;
|
||||||
|
return Cesium.Cartesian3.fromDegrees(-55, 58, 1000000);
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ModelGraphics
|
||||||
|
uri={arrowRound}
|
||||||
|
minimumPixelSize={128}
|
||||||
|
// nodeTransformations={{
|
||||||
|
// 自转
|
||||||
|
// group_0: new Cesium.NodeTransformationProperty({
|
||||||
|
// rotation: rotationProperty,
|
||||||
|
// }),
|
||||||
|
// }}
|
||||||
|
/>
|
||||||
|
</Entity>
|
||||||
|
<Entity
|
||||||
|
id={"Cyclone-1"}
|
||||||
|
position={
|
||||||
|
new Cesium.CallbackProperty(function (time, result) {
|
||||||
|
const passTime = getPassTime();
|
||||||
|
if (passTime < 20) return;
|
||||||
|
return Cesium.Cartesian3.fromDegrees(-32, 72.2, 1000000);
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ModelGraphics uri={arrowRound} minimumPixelSize={128} />
|
||||||
|
</Entity>
|
||||||
|
<Entity
|
||||||
|
id={"Anticyclone-2"}
|
||||||
|
position={
|
||||||
|
new Cesium.CallbackProperty(function (time, result) {
|
||||||
|
const passTime = getPassTime();
|
||||||
|
if (passTime < 30) return;
|
||||||
|
return Cesium.Cartesian3.fromDegrees(20, 77, 1000000);
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ModelGraphics uri={arrowRound} minimumPixelSize={128} />
|
||||||
|
</Entity>
|
||||||
|
<Entity
|
||||||
|
id={"Cyclone-2"}
|
||||||
|
position={
|
||||||
|
new Cesium.CallbackProperty(function (time, result) {
|
||||||
|
const passTime = getPassTime();
|
||||||
|
if (passTime < 40) return;
|
||||||
|
return Cesium.Cartesian3.fromDegrees(63, 69.9, 1000000);
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ModelGraphics uri={arrowRound} minimumPixelSize={128} />
|
||||||
|
</Entity>
|
||||||
|
<Entity
|
||||||
|
id={"Anticyclone-3"}
|
||||||
|
position={
|
||||||
|
new Cesium.CallbackProperty(function (time, result) {
|
||||||
|
const passTime = getPassTime();
|
||||||
|
if (passTime < 50) return;
|
||||||
|
return Cesium.Cartesian3.fromDegrees(88, 60, 1000000);
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ModelGraphics uri={arrowRound} minimumPixelSize={128} />
|
||||||
|
</Entity>
|
||||||
|
<Entity
|
||||||
|
id={"Anticyclone-4"}
|
||||||
|
position={
|
||||||
|
new Cesium.CallbackProperty(function (time, result) {
|
||||||
|
const passTime = getPassTime();
|
||||||
|
if (passTime < 50) return;
|
||||||
|
return Cesium.Cartesian3.fromDegrees(88, 60, 0);
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ModelGraphics uri={arrowRound} minimumPixelSize={128} />
|
||||||
|
</Entity>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Cyclone;
|
71
src/components/domain/One/LabradorImageLayer.jsx
Normal file
71
src/components/domain/One/LabradorImageLayer.jsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
import { ImageryLayer, useCesium } from "resium";
|
||||||
|
import { WebMapServiceImageryProvider } from "cesium";
|
||||||
|
import { useInterval } from "ahooks";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
|
const url = "http://analysis.tpdc.ac.cn/gs/geoserver/phitrellis/wms";
|
||||||
|
const nameList = [
|
||||||
|
1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992,
|
||||||
|
1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
||||||
|
2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
|
||||||
|
].map((item) => "phitrellis:4_1_la_" + item);
|
||||||
|
|
||||||
|
function LabradorImageLayer() {
|
||||||
|
const { viewer } = useCesium();
|
||||||
|
const { imageLayer } = useSelector((state) => state.data);
|
||||||
|
const [delay, setDelay] = useState(undefined);
|
||||||
|
const [index, setIndex] = useState(0);
|
||||||
|
|
||||||
|
//viewer.clock?.shouldAnimate
|
||||||
|
console.log("viewer.clock?.shouldAnimate :>> ", viewer.clock?.shouldAnimate);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { labrador } = imageLayer;
|
||||||
|
if (!!labrador) {
|
||||||
|
setDelay(1000);
|
||||||
|
setIndex(0);
|
||||||
|
}
|
||||||
|
}, [imageLayer]);
|
||||||
|
|
||||||
|
const layers = nameList.map((name, index) => {
|
||||||
|
const tempProvider = useMemo(
|
||||||
|
() =>
|
||||||
|
new WebMapServiceImageryProvider({
|
||||||
|
url: url,
|
||||||
|
layers: name,
|
||||||
|
parameters: {
|
||||||
|
service: "WMS",
|
||||||
|
format: "image/png",
|
||||||
|
transparent: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[name, url]
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<ImageryLayer
|
||||||
|
key={`ImageryLayer-${index}`}
|
||||||
|
imageryProvider={tempProvider}
|
||||||
|
show={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
useInterval(() => {
|
||||||
|
setIndex((index) => index + 1);
|
||||||
|
|
||||||
|
if (index >= nameList.length) {
|
||||||
|
setTimeout(() => {
|
||||||
|
setIndex(0);
|
||||||
|
setDelay(1000);
|
||||||
|
}, (60 - nameList.length) * 1000);
|
||||||
|
setDelay(undefined);
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
if (!viewer.clock?.shouldAnimate) return;
|
||||||
|
|
||||||
|
return layers[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LabradorImageLayer;
|
68
src/components/domain/One/Legend.jsx
Normal file
68
src/components/domain/One/Legend.jsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
const colorBar = [
|
||||||
|
"#4160ac",
|
||||||
|
"#4363ae",
|
||||||
|
"#4867b1",
|
||||||
|
"#4d6bb3",
|
||||||
|
"#5370b6",
|
||||||
|
"#5d79bb",
|
||||||
|
"#6c85c1",
|
||||||
|
"#778dc7",
|
||||||
|
"#8297cd",
|
||||||
|
"#8fa3d3",
|
||||||
|
"#9baed9",
|
||||||
|
"#a6b7de",
|
||||||
|
"#b0c0e3",
|
||||||
|
"#bcc9e6",
|
||||||
|
"#c9d3eb",
|
||||||
|
"#d4ddf1",
|
||||||
|
"#fbd1d2",
|
||||||
|
"#fac4c6",
|
||||||
|
"#f9b8ba",
|
||||||
|
"#f8abae",
|
||||||
|
"#f79fa2",
|
||||||
|
"#f59496",
|
||||||
|
"#f4878a",
|
||||||
|
"#f37a7c",
|
||||||
|
"#f36e70",
|
||||||
|
"#f26264",
|
||||||
|
"#f15759",
|
||||||
|
"#f04c4f",
|
||||||
|
"#f14145",
|
||||||
|
"#ef3637",
|
||||||
|
"#ee2e30",
|
||||||
|
"#ee2529",
|
||||||
|
];
|
||||||
|
|
||||||
|
function Legend() {
|
||||||
|
return (
|
||||||
|
<div className="legend">
|
||||||
|
<div className="legend-title">拉布拉多海海表温度夏季年代际异常值</div>
|
||||||
|
<div className="colorbar">
|
||||||
|
{colorBar.map((color, index) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={`colorbar-item-${index}`}
|
||||||
|
className="colorbar-item"
|
||||||
|
style={{ backgroundColor: color }}
|
||||||
|
title={`${(-3.2 + index * 0.2).toFixed(1)}~${(
|
||||||
|
-3.2 +
|
||||||
|
(index + 1) * 0.2
|
||||||
|
).toFixed(1)}`}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className="legend-text">
|
||||||
|
{[-2.4, -1.6, -0.8, 0, 0.8, 1.6, 2.4, ""].map((item, index) => {
|
||||||
|
return (
|
||||||
|
<div key={`legend-text-item-${index}`} className="legend-text-item">
|
||||||
|
{item}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Legend;
|
35
src/components/domain/One/PlateauPolygon.jsx
Normal file
35
src/components/domain/One/PlateauPolygon.jsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { useCallback, useState } from "react";
|
||||||
|
import { Entity, PolygonGraphics, useCesium } from "resium";
|
||||||
|
import { useInterval } from "ahooks";
|
||||||
|
|
||||||
|
function PlateauPolygon() {
|
||||||
|
const { viewer } = useCesium();
|
||||||
|
const [show, setShow] = useState(false);
|
||||||
|
|
||||||
|
const showAnimate = useCallback(() => {
|
||||||
|
const { currentTime, stopTime } = viewer.clock;
|
||||||
|
const leftTime = Math.floor(
|
||||||
|
stopTime.secondsOfDay - currentTime.secondsOfDay
|
||||||
|
);
|
||||||
|
|
||||||
|
if (leftTime < 10) {
|
||||||
|
setShow(true);
|
||||||
|
} else if (show) setShow(false);
|
||||||
|
}, [show]);
|
||||||
|
|
||||||
|
useInterval(showAnimate, 100);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Entity id="plateau" show={show}>
|
||||||
|
<PolygonGraphics
|
||||||
|
hierarchy={Cesium.Cartesian3.fromDegreesArray([
|
||||||
|
// 85, 30, 91, 30, 91, 35, 85, 35,
|
||||||
|
80, 31, 84, 29.5, 87.4, 28, 91, 28, 98, 29, 94, 35, 79, 34.4, 80, 31,
|
||||||
|
])}
|
||||||
|
material={new Cesium.Color(1, 0, 0, 0.1)}
|
||||||
|
/>
|
||||||
|
</Entity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PlateauPolygon;
|
94
src/components/domain/One/Point.jsx
Normal file
94
src/components/domain/One/Point.jsx
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import { Entity, PointGraphics, useCesium } from "resium";
|
||||||
|
import { useInterval } from "ahooks";
|
||||||
|
|
||||||
|
// 从拉布拉多海到青藏高原
|
||||||
|
const dataLabToQTP = [
|
||||||
|
{ longitude: -55, latitude: 58, height: 1000000, time: 10 },
|
||||||
|
{ longitude: -32, latitude: 72.2, height: 1000000, time: 20 },
|
||||||
|
{ longitude: 20, latitude: 77, height: 1000000, time: 30 },
|
||||||
|
{ longitude: 63, latitude: 69.9, height: 1000000, time: 40 },
|
||||||
|
{ longitude: 88, latitude: 60, height: 1000000, time: 50 },
|
||||||
|
];
|
||||||
|
|
||||||
|
function Point() {
|
||||||
|
const { viewer } = useCesium();
|
||||||
|
const [delay, setDelay] = useState(1000);
|
||||||
|
|
||||||
|
const start = viewer.clock.startTime;
|
||||||
|
const stop = viewer.clock.stopTime;
|
||||||
|
|
||||||
|
const pathMaterial = new Cesium.PolylineDashMaterialProperty({
|
||||||
|
dashLength: 20,
|
||||||
|
color: new Cesium.Color(4 / 255, 251 / 255, 253 / 255),
|
||||||
|
});
|
||||||
|
|
||||||
|
useInterval(() => {
|
||||||
|
if (viewer.clock?.shouldAnimate) setDelay(undefined);
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算飞行路径
|
||||||
|
* 数据坐标
|
||||||
|
* {SampledPositionProperty|*}
|
||||||
|
*/
|
||||||
|
function createProperty(source) {
|
||||||
|
let property = new Cesium.SampledPositionProperty();
|
||||||
|
for (let i = 0; i < source.length; i++) {
|
||||||
|
let time = Cesium.JulianDate.addSeconds(
|
||||||
|
start,
|
||||||
|
source[i].time,
|
||||||
|
new Cesium.JulianDate()
|
||||||
|
);
|
||||||
|
let position = Cesium.Cartesian3.fromDegrees(
|
||||||
|
source[i].longitude,
|
||||||
|
source[i].latitude,
|
||||||
|
source[i].height
|
||||||
|
);
|
||||||
|
// 添加位置,和时间对应
|
||||||
|
property.addSample(time, position);
|
||||||
|
}
|
||||||
|
property.setInterpolationOptions({
|
||||||
|
interpolationDegree: 10,
|
||||||
|
interpolationAlgorithm: Cesium.LagrangePolynomialApproximation,
|
||||||
|
});
|
||||||
|
|
||||||
|
return property;
|
||||||
|
}
|
||||||
|
|
||||||
|
const property = createProperty(dataLabToQTP);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Entity
|
||||||
|
id={"point"}
|
||||||
|
position={property}
|
||||||
|
availability={
|
||||||
|
new Cesium.TimeIntervalCollection([
|
||||||
|
new Cesium.TimeInterval({
|
||||||
|
start: start,
|
||||||
|
stop: stop,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
orientation={new Cesium.VelocityOrientationProperty(property)}
|
||||||
|
path={{
|
||||||
|
resolution: 1,
|
||||||
|
material: pathMaterial,
|
||||||
|
// leadTime、trailTime 不设置 path全显示
|
||||||
|
leadTime: 0, // 设置为0时 模型通过后显示path
|
||||||
|
// trailTime: 0, // 设置为0时 模型通过后隐藏path
|
||||||
|
width: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PointGraphics
|
||||||
|
show={true}
|
||||||
|
color={Cesium.Color.SKYBLUE}
|
||||||
|
pixelSize={10}
|
||||||
|
outlineColor={Cesium.Color.YELLOW}
|
||||||
|
outlineWidth={3}
|
||||||
|
/>
|
||||||
|
</Entity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Point;
|
45
src/components/domain/One/TextInfoPanel.jsx
Normal file
45
src/components/domain/One/TextInfoPanel.jsx
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
import { Scrollbars } from "react-custom-scrollbars-2";
|
||||||
|
import { useInterval } from "ahooks";
|
||||||
|
|
||||||
|
let index = 0;
|
||||||
|
function TextInfoPanel({ title, content }) {
|
||||||
|
const showNumberPerTimes = 1;
|
||||||
|
const { toolbar } = useSelector((state) => state.data);
|
||||||
|
|
||||||
|
const [delay, setDelay] = useState(80);
|
||||||
|
const [contentText, setContentText] = useState("");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
index = 0;
|
||||||
|
}, [toolbar]);
|
||||||
|
|
||||||
|
const showContent = useCallback(() => {
|
||||||
|
const isFinished = contentText.length >= content.length;
|
||||||
|
if (!isFinished) {
|
||||||
|
setContentText((text) => {
|
||||||
|
index += showNumberPerTimes;
|
||||||
|
return text + content[index - 1];
|
||||||
|
});
|
||||||
|
} else setDelay(undefined);
|
||||||
|
}, [contentText]);
|
||||||
|
|
||||||
|
useInterval(showContent, delay);
|
||||||
|
|
||||||
|
const stopHandler = useCallback(() => {
|
||||||
|
setDelay(undefined);
|
||||||
|
index = 0;
|
||||||
|
setContentText(content);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="text-info-panel" onDoubleClick={stopHandler}>
|
||||||
|
<Scrollbars autoHide autoHideTimeout={1000} autoHideDuration={400}>
|
||||||
|
{contentText}
|
||||||
|
</Scrollbars>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TextInfoPanel;
|
71
src/components/domain/One/TibetImageLayer.jsx
Normal file
71
src/components/domain/One/TibetImageLayer.jsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
import { ImageryLayer, useCesium } from "resium";
|
||||||
|
import { WebMapServiceImageryProvider } from "cesium";
|
||||||
|
import { useInterval } from "ahooks";
|
||||||
|
import { useSelector } from "react-redux";
|
||||||
|
|
||||||
|
const url = "http://analysis.tpdc.ac.cn/gs/geoserver/phitrellis/wms";
|
||||||
|
const nameList = [
|
||||||
|
1980, 1981, 1982, 1983, 1984, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992,
|
||||||
|
1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
||||||
|
2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
|
||||||
|
].map((item) => "phitrellis:4_1_tp_" + item);
|
||||||
|
|
||||||
|
function TibetImageLayer() {
|
||||||
|
const { viewer } = useCesium();
|
||||||
|
const { imageLayer } = useSelector((state) => state.data);
|
||||||
|
const [delay, setDelay] = useState(undefined);
|
||||||
|
const [index, setIndex] = useState(0);
|
||||||
|
|
||||||
|
//viewer.clock?.shouldAnimate
|
||||||
|
console.log("viewer.clock?.shouldAnimate :>> ", viewer.clock?.shouldAnimate);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { labrador } = imageLayer;
|
||||||
|
if (!!labrador) {
|
||||||
|
setDelay(1000);
|
||||||
|
setIndex(0);
|
||||||
|
}
|
||||||
|
}, [imageLayer]);
|
||||||
|
|
||||||
|
const layers = nameList.map((name, index) => {
|
||||||
|
const tempProvider = useMemo(
|
||||||
|
() =>
|
||||||
|
new WebMapServiceImageryProvider({
|
||||||
|
url: url,
|
||||||
|
layers: name,
|
||||||
|
parameters: {
|
||||||
|
service: "WMS",
|
||||||
|
format: "image/png",
|
||||||
|
transparent: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
[name, url]
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<ImageryLayer
|
||||||
|
key={`ImageryLayer-${index}`}
|
||||||
|
imageryProvider={tempProvider}
|
||||||
|
show={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
useInterval(() => {
|
||||||
|
setIndex((index) => index + 1);
|
||||||
|
|
||||||
|
if (index >= nameList.length) {
|
||||||
|
setTimeout(() => {
|
||||||
|
setIndex(0);
|
||||||
|
setDelay(1000);
|
||||||
|
}, (60 - nameList.length) * 1000);
|
||||||
|
setDelay(undefined);
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
if (!viewer.clock?.shouldAnimate) return;
|
||||||
|
|
||||||
|
return layers[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TibetImageLayer;
|
33
src/components/domain/One/Updraft.jsx
Normal file
33
src/components/domain/One/Updraft.jsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Entity, PolylineGraphics, useCesium } from "resium";
|
||||||
|
import { Cartesian3 } from "cesium";
|
||||||
|
import { min } from "lodash-es";
|
||||||
|
|
||||||
|
function Updraft() {
|
||||||
|
const { viewer } = useCesium();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Entity
|
||||||
|
id={"Updraft"}
|
||||||
|
position={Cartesian3.fromDegrees(-34.0707383, 60.7117244, 100)}
|
||||||
|
>
|
||||||
|
<PolylineGraphics
|
||||||
|
positions={
|
||||||
|
new Cesium.CallbackProperty(function (time, result) {
|
||||||
|
const { currentTime, startTime } = viewer.clock;
|
||||||
|
const passTime = currentTime.secondsOfDay - startTime.secondsOfDay;
|
||||||
|
const height = 100000 * passTime;
|
||||||
|
return Cesium.Cartesian3.fromDegreesArrayHeights(
|
||||||
|
[-55, 58, 0, -55, 58, min([height, 1000000])],
|
||||||
|
Cesium.Ellipsoid.WGS84,
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}, false)
|
||||||
|
}
|
||||||
|
width={30}
|
||||||
|
material={new Cesium.PolylineArrowMaterialProperty(Cesium.Color.RED)}
|
||||||
|
/>
|
||||||
|
</Entity>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Updraft;
|
11
src/components/domain/One/WavePoints.jsx
Normal file
11
src/components/domain/One/WavePoints.jsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { Fragment } from "react";
|
||||||
|
import WavePoint from "@/components/common/WavePoint";
|
||||||
|
|
||||||
|
export default function WavePoints() {
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<WavePoint stationLon={-55} stationLat={58} />
|
||||||
|
<WavePoint stationLon={88} stationLat={32.5} />
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
49
src/components/domain/One/index.jsx
Normal file
49
src/components/domain/One/index.jsx
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import MapLayout from "@/components/map/Layout";
|
||||||
|
import CustomClock from "./CustomClock";
|
||||||
|
import CustomFlyTo from "./CustomFlyTo";
|
||||||
|
import CustomToolbar from "./CustomToolbar";
|
||||||
|
import Point from "./Point";
|
||||||
|
import PlateauPolygon from "./PlateauPolygon";
|
||||||
|
import TextInfoPanel from "./TextInfoPanel";
|
||||||
|
import Cyclone from "./Cyclone";
|
||||||
|
import Barotropic from "./Barotorpic";
|
||||||
|
import WavePoints from "./WavePoints";
|
||||||
|
import Updraft from "./Updraft";
|
||||||
|
import Legend from "./Legend";
|
||||||
|
import LabradorImageLayer from "./LabradorImageLayer";
|
||||||
|
import TibetImageLayer from "./TibetImageLayer";
|
||||||
|
import ChartPanel from "./ChartPanel";
|
||||||
|
|
||||||
|
export default function DomainOne() {
|
||||||
|
return (
|
||||||
|
<MapLayout>
|
||||||
|
<div className="title">
|
||||||
|
两极协同—拉布拉多海海温偏暖控制夏季高原年代际增温
|
||||||
|
</div>
|
||||||
|
<CustomToolbar />
|
||||||
|
<CustomClock />
|
||||||
|
<CustomFlyTo />
|
||||||
|
<Point />
|
||||||
|
<PlateauPolygon />
|
||||||
|
<div className="left-panel">
|
||||||
|
<div className="top-panel"></div>
|
||||||
|
<div className="bottom-panel">
|
||||||
|
<TextInfoPanel content="基于再分析资料JRA55和线性斜压模式LBM的试验结果,在年代际尺度上,拉布拉多海海温偏暖会引起北大西洋至欧洲地区大气环流异常,导致青藏高原夏季出现年代际增温。" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="right-panel">
|
||||||
|
<div className="top-panel"></div>
|
||||||
|
<div className="bottom-panel">
|
||||||
|
<ChartPanel />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Cyclone />
|
||||||
|
<Barotropic />
|
||||||
|
<WavePoints />
|
||||||
|
<Updraft />
|
||||||
|
<Legend />
|
||||||
|
<LabradorImageLayer />
|
||||||
|
<TibetImageLayer />
|
||||||
|
</MapLayout>
|
||||||
|
);
|
||||||
|
}
|
0
src/components/domain/One/index.module.less
Normal file
0
src/components/domain/One/index.module.less
Normal file
@ -1,55 +1,13 @@
|
|||||||
.mapContainer :global {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
.cesium-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.cesium-widget-credits {
|
|
||||||
display: none !important;
|
|
||||||
visibility: hide !important;
|
|
||||||
}
|
|
||||||
.viewer-toolbar {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
position: absolute;
|
|
||||||
height: 159px;
|
|
||||||
right: 5px;
|
|
||||||
top: 5px;
|
|
||||||
|
|
||||||
.ant-image {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
border: none;
|
|
||||||
img {
|
|
||||||
border-radius: 14%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.viewer-toolbar :hover {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #fff;
|
|
||||||
fill: #fff;
|
|
||||||
background: #48b;
|
|
||||||
border-color: #aef;
|
|
||||||
box-shadow: 0 0 8px #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.homeLayout :global {
|
.homeLayout :global {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: url("../../assets/link.png") 50% no-repeat;
|
background: url("../../../assets/link.png") 50% no-repeat;
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
height: 72px;
|
height: 72px;
|
||||||
background: url("../../assets/title.png") 50% no-repeat;
|
background: url("../../../assets/title.png") 50% no-repeat;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
color: #04fbfd;
|
color: #04fbfd;
|
||||||
display: flex;
|
display: flex;
|
56
src/components/map/Layout/index copy.jsx
Normal file
56
src/components/map/Layout/index copy.jsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { Viewer } from "resium";
|
||||||
|
import CustomClock from "./CustomClock";
|
||||||
|
import CustomFlyTo from "./CustomFlyTo";
|
||||||
|
import CustomToolbar from "./CustomToolbar";
|
||||||
|
import InfoLayout from "./InfoLayout";
|
||||||
|
import Picker from "./Picker";
|
||||||
|
import Legend from "./Legends";
|
||||||
|
import Barotropic from "./Entities/Barotorpic";
|
||||||
|
import Cyclone from "./Entities/Cyclone";
|
||||||
|
import Point from "./Entities/Point";
|
||||||
|
import PlateauPolygon from "./Entities/PlateauPolygon";
|
||||||
|
import Updraft from "./Entities/Udraft";
|
||||||
|
import Watervapor from "./Entities/Watervapor";
|
||||||
|
import WavePoint from "./Entities/WavePoint";
|
||||||
|
import DynamicImageryLayer from "./DynamicImageryLayer";
|
||||||
|
import Circles from "./Entities/Circles";
|
||||||
|
import Site from "./Entities/Site";
|
||||||
|
import styles from "./index.module.less";
|
||||||
|
|
||||||
|
function MapLayout() {
|
||||||
|
return (
|
||||||
|
<Viewer
|
||||||
|
className={styles.cesiumContainer}
|
||||||
|
full
|
||||||
|
homeButton={false}
|
||||||
|
sceneModePicker={false}
|
||||||
|
navigationHelpButton={false}
|
||||||
|
shouldAnimate={false}
|
||||||
|
// infoBox={false}
|
||||||
|
timeline={false}
|
||||||
|
fullscreenButton={false}
|
||||||
|
geocoder={false}
|
||||||
|
baseLayerPicker={false}
|
||||||
|
animation={false}
|
||||||
|
>
|
||||||
|
<CustomClock />
|
||||||
|
<CustomFlyTo />
|
||||||
|
<CustomToolbar />
|
||||||
|
<Point />
|
||||||
|
<PlateauPolygon />
|
||||||
|
<InfoLayout />
|
||||||
|
<Cyclone />
|
||||||
|
<Barotropic />
|
||||||
|
{/* <Watervapor /> */}
|
||||||
|
<WavePoint />
|
||||||
|
<Updraft />
|
||||||
|
<Picker />
|
||||||
|
<Legend />
|
||||||
|
<DynamicImageryLayer />
|
||||||
|
<Circles />
|
||||||
|
<Site />
|
||||||
|
</Viewer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MapLayout;
|
@ -1,26 +1,10 @@
|
|||||||
import { Viewer } from "resium";
|
import { Viewer } from "resium";
|
||||||
import CustomClock from "./CustomClock";
|
|
||||||
import CustomFlyTo from "./CustomFlyTo";
|
|
||||||
import CustomToolbar from "./CustomToolbar";
|
|
||||||
import InfoLayout from "./InfoLayout";
|
|
||||||
import Picker from "./Picker";
|
|
||||||
import Legend from "./Legends";
|
|
||||||
import Barotropic from "./Entities/Barotorpic";
|
|
||||||
import Cyclone from "./Entities/Cyclone";
|
|
||||||
import Point from "./Entities/Point";
|
|
||||||
import PlateauPolygon from "./Entities/PlateauPolygon";
|
|
||||||
import Updraft from "./Entities/Udraft";
|
|
||||||
import Watervapor from "./Entities/Watervapor";
|
|
||||||
import WavePoint from "./Entities/WavePoint";
|
|
||||||
import DynamicImageryLayer from "./DynamicImageryLayer";
|
|
||||||
import Circles from "./Entities/Circles";
|
|
||||||
import Site from "./Entities/Site";
|
|
||||||
import styles from "./index.module.less";
|
import styles from "./index.module.less";
|
||||||
|
|
||||||
function MapLayout() {
|
function MapLayout({ children, className, ...rest }) {
|
||||||
return (
|
return (
|
||||||
<Viewer
|
<Viewer
|
||||||
className={styles.cesiumContainer}
|
className={`${styles.cesiumContainer} ${className}`}
|
||||||
full
|
full
|
||||||
homeButton={false}
|
homeButton={false}
|
||||||
sceneModePicker={false}
|
sceneModePicker={false}
|
||||||
@ -33,22 +17,7 @@ function MapLayout() {
|
|||||||
baseLayerPicker={false}
|
baseLayerPicker={false}
|
||||||
animation={false}
|
animation={false}
|
||||||
>
|
>
|
||||||
<CustomClock />
|
{children}
|
||||||
<CustomFlyTo />
|
|
||||||
<CustomToolbar />
|
|
||||||
<Point />
|
|
||||||
<PlateauPolygon />
|
|
||||||
<InfoLayout />
|
|
||||||
<Cyclone />
|
|
||||||
<Barotropic />
|
|
||||||
{/* <Watervapor /> */}
|
|
||||||
<WavePoint />
|
|
||||||
<Updraft />
|
|
||||||
<Picker />
|
|
||||||
<Legend />
|
|
||||||
<DynamicImageryLayer />
|
|
||||||
<Circles />
|
|
||||||
<Site />
|
|
||||||
</Viewer>
|
</Viewer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar :global {
|
.title {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 72px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: #04fbfd;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 42px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toolbar {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 8px;
|
top: 8px;
|
||||||
left: 12px;
|
left: 12px;
|
||||||
@ -77,4 +91,119 @@
|
|||||||
background-color: #078080;
|
background-color: #078080;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 84px;
|
||||||
|
left: 12px;
|
||||||
|
bottom: 12px;
|
||||||
|
width: 450px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.top-panel {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-panel {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-info-panel {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #04fbfd;
|
||||||
|
color: #02f9ff !important;
|
||||||
|
background-color: #1f485690;
|
||||||
|
pointer-events: auto;
|
||||||
|
font-size: 16px;
|
||||||
|
text-indent: 2em;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 84px;
|
||||||
|
right: 12px;
|
||||||
|
bottom: 12px;
|
||||||
|
width: 450px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.top-panel {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-panel {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-info-panel {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: auto;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #04fbfd;
|
||||||
|
color: #02f9ff !important;
|
||||||
|
background-color: #1f485690;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 40px;
|
||||||
|
width: 50%;
|
||||||
|
left: 25%;
|
||||||
|
// height: 40px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #1f485690;
|
||||||
|
border: 1px solid #04fbfd;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px;
|
||||||
|
|
||||||
|
.legend-title {
|
||||||
|
color: #04fbfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorbar {
|
||||||
|
width: 100%;
|
||||||
|
height: 14px;
|
||||||
|
display: flex;
|
||||||
|
margin: 8px 0;
|
||||||
|
|
||||||
|
.colorbar-item {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
// border-radius: 8px;
|
||||||
|
border: 1px black solid;
|
||||||
|
|
||||||
|
&:not(:nth-child(1)) {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-text {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
width: 100%;
|
||||||
|
height: 20px;
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
.legend-text-item {
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
font-weight: 600;
|
||||||
|
color: white;
|
||||||
|
-webkit-text-stroke: #04fbfd 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user