This commit is contained in:
baol 2023-10-13 13:06:19 +08:00
commit 74454c3a33
46 changed files with 1121 additions and 552 deletions

View File

@ -1,9 +1,10 @@
import { ClockRange, JulianDate } from "cesium";
import { Clock } from "resium"; import { Clock } from "resium";
// //
const start = Cesium.JulianDate.fromDate(new Date()); const start = JulianDate.fromDate(new Date());
// //
const stop = Cesium.JulianDate.addSeconds(start, 60, new Cesium.JulianDate()); const stop = JulianDate.addSeconds(start, 30, new JulianDate());
function CustomClock() { function CustomClock() {
return ( return (
@ -13,7 +14,7 @@ function CustomClock() {
startTime={start.clone()} startTime={start.clone()}
stopTime={stop.clone()} stopTime={stop.clone()}
currentTime={start.clone()} currentTime={start.clone()}
clockRange={Cesium.ClockRange.LOOP_STOP} clockRange={ClockRange.LOOP_STOP}
// onTick={(clock) => { // onTick={(clock) => {
// if (!clock.shouldAnimate) return; // if (!clock.shouldAnimate) return;
// }} // }}

View File

@ -1,6 +1,14 @@
import { Fragment } from "react"; import { Fragment } from "react";
import { Entity, EllipseGraphics } from "resium"; import { Entity, EllipseGraphics, LabelGraphics } from "resium";
import wave from "@/assets/wave.png"; import wave from "@/assets/wave.png";
import {
CallbackProperty,
Cartesian2,
Cartesian3,
Color,
ImageMaterialProperty,
LabelStyle,
} from "cesium";
function WavePoint({ function WavePoint({
stationLon, stationLon,
@ -10,6 +18,7 @@ function WavePoint({
eachInterval = 1500, eachInterval = 1500,
maxR = 3600 * 100, maxR = 3600 * 100,
color = "WHITE", color = "WHITE",
labelText,
}) { }) {
const data = { const data = {
stationLon, // stationLon, //
@ -43,25 +52,21 @@ function WavePoint({
const point1 = ( const point1 = (
<Entity <Entity
id={`wave-point-1-${stationLon}-${stationLat}`} id={`wave-point-1-${stationLon}-${stationLat}`}
position={Cesium.Cartesian3.fromDegrees( position={Cartesian3.fromDegrees(data.stationLon, data.stationLat, 0)}
data.stationLon,
data.stationLat,
0
)}
show={true} show={true}
> >
<EllipseGraphics <EllipseGraphics
semiMinorAxis={new Cesium.CallbackProperty(changeOne, false)} semiMinorAxis={new CallbackProperty(changeOne, false)}
semiMajorAxis={new Cesium.CallbackProperty(changeR2, false)} semiMajorAxis={new CallbackProperty(changeR2, false)}
height={10} height={10}
material={ material={
new Cesium.ImageMaterialProperty({ new ImageMaterialProperty({
image: data.imageUrl, image: data.imageUrl,
repeat: Cesium.Cartesian2(1.0, 1.0), repeat: Cartesian2(1.0, 1.0),
transparent: true, transparent: true,
color: new Cesium.CallbackProperty(function () { color: new CallbackProperty(function () {
var alp = 1 - r1 / data.maxR; var alp = 1 - r1 / data.maxR;
return Cesium.Color[color].withAlpha(alp); return Color[color].withAlpha(alp);
}, false), }, false),
}) })
} }
@ -89,26 +94,22 @@ function WavePoint({
} }
point2 = ( point2 = (
<Entity <Entity
position={Cesium.Cartesian3.fromDegrees( position={Cartesian3.fromDegrees(stationLon, stationLat, 0)}
data.stationLon,
data.stationLat,
0
)}
show={true} show={true}
id={`wave-point-2-${stationLon}-${stationLat}`} id={`wave-point-2-${stationLon}-${stationLat}`}
> >
<EllipseGraphics <EllipseGraphics
semiMinorAxis={new Cesium.CallbackProperty(changeTwo, false)} semiMinorAxis={new CallbackProperty(changeTwo, false)}
semiMajorAxis={new Cesium.CallbackProperty(changeR12, false)} semiMajorAxis={new CallbackProperty(changeR12, false)}
height={10} height={10}
material={ material={
new Cesium.ImageMaterialProperty({ new ImageMaterialProperty({
image: data.imageUrl, image: data.imageUrl,
repeat: Cesium.Cartesian2(1.0, 1.0), repeat: Cartesian2(1.0, 1.0),
transparent: true, transparent: true,
color: new Cesium.CallbackProperty(function () { color: new CallbackProperty(function () {
var alp = 1 - r1 / data.maxR; var alp = 1 - r1 / data.maxR;
return Cesium.Color.WHITE.withAlpha(alp); return Color.WHITE.withAlpha(alp);
//entity entity //entity entity
}, false), }, false),
}) })
@ -122,6 +123,20 @@ function WavePoint({
<Fragment> <Fragment>
{point1} {point1}
{point2} {point2}
{labelText && (
<Entity position={Cartesian3.fromDegrees(stationLon, stationLat, 0)}>
<LabelGraphics
text={labelText}
font="24px Helvetica"
fillColor={Color.SKYBLUE}
outlineColor={Color.BLACK}
outlineWidth={2}
style={LabelStyle.FILL_AND_OUTLINE}
eyeOffset={new Cartesian2(0, 200000)}
/>{" "}
</Entity>
)}
</Fragment> </Fragment>
); );
} }

View File

@ -0,0 +1,80 @@
import { Cartesian2, Cartesian3, Color, LabelStyle } from "cesium";
import { Fragment } from "react";
import { Entity, LabelGraphics } from "resium";
const points = [
{
position: [13, -70, 30, -67],
name: "sic_s",
},
{
position: [93, 29, 99, 35],
name: "sc_tp",
},
{
position: [68, 48, 76, 52],
name: "sc_ea",
},
{
position: [150, 60, 160, 70],
name: "ts_ac",
},
{
position: [130, 20, 140, 28],
name: "ts_wp",
},
{
position: [150, 12, 175, 22],
name: "ts_np",
},
{
position: [-110, 20, -95, 35],
name: "ts_arn",
},
{
position: [10, -12, 45, -2],
name: "ts_af",
},
{ position: [80, 10, 110, 20], name: "ts_io" },
{ position: [-150, -10, -40, 5], name: "ts_ep" },
{ position: [65, -62, 90, -57], name: "ts_aa" },
{
position: [145, -30, 155, -20],
name: "ts_ea",
},
{ position: [165, -45, 180, -30], name: "ts_nz" },
{ position: [-140, -60, -110, -45], name: "ts_sp" },
{ position: [-70, -78, -50, -70], name: "ts_wd" },
];
function Labels() {
return (
<Fragment>
{points.map((point, index) => {
const { position, name } = point;
const [x, y, z, m] = position;
const lon = (x + z) / 2;
const lat = (y + m) / 2;
return (
<Entity
key={`rectangle-label-${index}`}
position={Cartesian3.fromDegrees(lon, lat, 0)}
>
<LabelGraphics
text={name}
font="24px Helvetica"
fillColor={Color.SKYBLUE}
outlineColor={Color.BLACK}
outlineWidth={2}
style={LabelStyle.FILL_AND_OUTLINE}
eyeOffset={new Cartesian2(0, 0)}
/>
</Entity>
);
})}
</Fragment>
);
}
export default Labels;

View File

@ -1,21 +1,21 @@
import { Rectangle, Color, Math as CesiumMath } from "cesium"; import { Rectangle, Color, Math as CesiumMath } from "cesium";
import { Entity, RectangleGraphics } from "resium"; import { Entity, RectangleGraphics } from "resium";
const points = [ const points = [
[13, -70, 30, -67], [13, -70, 30, -67], //sic_s
[93, 29, 99, 35], [93, 29, 99, 35], //sc_tp
[68, 48, 76, 52], [68, 48, 76, 52], //sc_ea
[150, 60, 160, 70], [150, 60, 160, 70], //ts_ac
[130, 20, 140, 28], [130, 20, 140, 28], //wp
[150, 12, 175, 22], [150, 12, 175, 22], //np
[-110, 20, -95, 35], [-110, 20, -95, 35], //arn
[10, -12, 45, -2], [10, -12, 45, -2], // af
[80, 10, 110, 20], [80, 10, 110, 20], // io
[-150, -10, -40, 5], [-150, -10, -40, 5], //ep
[65, -62, 90, -57], [65, -62, 90, -57], // aa
[145, -30, 155, -20], [145, -30, 155, -20], // ea
[165, -45, 180, -30], [165, -45, 180, -30], // nz
[-140, -60, -110, -45], [-140, -60, -110, -45], // sp
[-70, -78, -50, -70], [-70, -78, -50, -70], // wd
]; ];
export default function RectangleLayer() { export default function RectangleLayer() {
return points.map((p, i) => ( return points.map((p, i) => (

View File

@ -8,6 +8,7 @@ import ChartPanel from "./ChartPanel";
import RectangleLayer from "./RectangleLayer"; import RectangleLayer from "./RectangleLayer";
import { useState } from "react"; import { useState } from "react";
import Legend from "./Legend"; import Legend from "./Legend";
import Labels from "./Labels";
export default function DomainFour() { export default function DomainFour() {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
@ -31,6 +32,7 @@ XGBoos是基于梯度提升决策树方法的分类和回归模型。 LightGBM
<div className="bottom-panel">{show && <ChartPanel />}</div> <div className="bottom-panel">{show && <ChartPanel />}</div>
</div> </div>
{/* <Legend /> */} {/* <Legend /> */}
<Labels />
<RectangleLayer /> <RectangleLayer />
</MapLayout> </MapLayout>
); );

View File

@ -1,6 +1,6 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { Entity, LabelGraphics, EllipseGraphics, useCesium } from "resium"; import { Entity, EllipseGraphics, useCesium } from "resium";
import { Color, Cartesian3, LabelStyle } from "cesium"; import { Color, Cartesian3 } from "cesium";
import { useInterval } from "ahooks"; import { useInterval } from "ahooks";
function Barotropic() { function Barotropic() {
@ -14,7 +14,7 @@ function Barotropic() {
stopTime.secondsOfDay - currentTime.secondsOfDay stopTime.secondsOfDay - currentTime.secondsOfDay
); );
if (leftTime < 10) { if (leftTime < 5) {
setShow(true); setShow(true);
} else if (show) setShow(false); } else if (show) setShow(false);
}, [show]); }, [show]);
@ -34,16 +34,6 @@ function Barotropic() {
extrudedHeight={1000000.0} extrudedHeight={1000000.0}
rotation={0} rotation={0}
/> />
<LabelGraphics
position={Cartesian3.fromDegrees(98, 48, 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> </Entity>
); );
} }

View File

@ -1,75 +1,64 @@
import { Cartesian3, EasingFunction, Math } from "cesium";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { Camera, useCesium } from "resium"; import { useCesium } from "resium";
function CustomFlyTo() { function CustomFlyTo() {
const { viewer } = useCesium(); const { viewer } = useCesium();
const { camera } = viewer; const { camera } = viewer;
const dispatch = useDispatch(); const dispatch = useDispatch();
function cameraFlyToLine(adjustPitch) { function cameraFlyToLine() {
const step1 = {
destination: Cartesian3.fromDegrees(-10, 50, 6000000),
duration: 5,
complete: () => {
camera.flyTo(step2);
},
easingFunction: EasingFunction.LINEAR_NONE,
};
const step2 = {
destination: Cartesian3.fromDegrees(35, 49, 10000000),
duration: 8,
complete: () => {
camera.flyTo(barotorpic);
},
easingFunction: EasingFunction.LINEAR_NONE,
};
// barotorpic // barotorpic
const barotorpic = { const barotorpic = {
destination: Cesium.Cartesian3.fromDegrees(80, 46, 15000000), destination: Cartesian3.fromDegrees(75, 48, 15000000),
duration: 30, duration: 7,
complete: () => {}, complete: () => {},
easingFunction: EasingFunction.LINEAR_NONE,
orientation: {
heading: 6.283,
pitch: -1.569,
roll: 0.45,
},
}; };
// //
const sideViewOptions = { const sideViewOptions = {
destination: Cesium.Cartesian3.fromDegrees(-50, 46, 2000000), destination: Cartesian3.fromDegrees(-50, 46, 2000000),
duration: 5, duration: 5,
orientation: { orientation: {
heading: Cesium.Math.toRadians(-15.0), heading: Math.toRadians(-15.0),
pitch: -Cesium.Math.PI_OVER_FOUR, pitch: -Math.PI_OVER_FOUR,
roll: 0.0, roll: 0.0,
}, },
complete: () => { complete: () => {
viewer.clock.shouldAnimate = true; viewer.clock.shouldAnimate = true;
setTimeout(function () { setTimeout(function () {
camera.flyTo(barotorpic); camera.flyTo(step1);
}, 1000); }, 5000);
dispatch.data.updateImageLayer({ dispatch.data.updateImageLayer({
labrador: true, labrador: 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(sideViewOptions); camera.flyTo(sideViewOptions);
} }
cameraFlyToLine(); cameraFlyToLine();

View File

@ -1,6 +1,14 @@
import { Fragment, useCallback } from "react"; import { Fragment, useCallback } from "react";
import { Entity, ModelGraphics, useCesium } from "resium"; import { Entity, LabelGraphics, ModelGraphics, useCesium } from "resium";
import arrowRound from "@/assets/arrow_round.glb"; import arrowRound from "@/assets/arrow_round.glb";
import {
CallbackProperty,
Cartesian2,
Cartesian3,
Color,
ColorBlendMode,
LabelStyle,
} from "cesium";
let totalSeconds = 60; let totalSeconds = 60;
let numberOfSamples = 120; let numberOfSamples = 120;
@ -44,18 +52,18 @@ function Cyclone() {
return _time; return _time;
}, [viewer]); }, [viewer]);
const anticycloneColor = Cesium.Color.fromCssColorString("#f70000"); const anticycloneColor = Color.fromCssColorString("#f70000");
const cycloneColor = Cesium.Color.fromCssColorString("#00AC4D"); const cycloneColor = Color.fromCssColorString("#00AC4D");
return ( return (
<Fragment> <Fragment>
<Entity <Entity
id={"Anticyclone-1"} id={"Anticyclone-1"}
position={ position={
new Cesium.CallbackProperty(function (time, result) { new CallbackProperty(function (time, result) {
const passTime = getPassTime(); const passTime = getPassTime();
if (passTime < 10) return; if (passTime < 5) return;
return Cesium.Cartesian3.fromDegrees(-62, 69, 1000000); return Cartesian3.fromDegrees(-62, 69, 1000000);
}, true) }, true)
} }
> >
@ -69,16 +77,26 @@ function Cyclone() {
// }), // }),
// }} // }}
color={anticycloneColor} color={anticycloneColor}
colorBlendMode={Cesium.ColorBlendMode.REPLACE} colorBlendMode={ColorBlendMode.REPLACE}
/>
<LabelGraphics
position={Cartesian3.fromDegrees(98, 48, 0)}
text={"Anticyclone"}
font="24px Helvetica"
fillColor={Color.SKYBLUE}
outlineColor={Color.BLACK}
outlineWidth={2}
style={LabelStyle.FILL_AND_OUTLINE}
eyeOffset={new Cartesian2(0, 200000)}
/> />
</Entity> </Entity>
<Entity <Entity
id={"Cyclone-1"} id={"Cyclone-1"}
position={ position={
new Cesium.CallbackProperty(function (time, result) { new CallbackProperty(function (time, result) {
const passTime = getPassTime(); const passTime = getPassTime();
if (passTime < 20) return; if (passTime < 10) return;
return Cesium.Cartesian3.fromDegrees(-20, 55, 1000000); return Cartesian3.fromDegrees(-20, 55, 1000000);
}, true) }, true)
} }
> >
@ -86,16 +104,16 @@ function Cyclone() {
uri={arrowRound} uri={arrowRound}
minimumPixelSize={128} minimumPixelSize={128}
color={cycloneColor} color={cycloneColor}
colorBlendMode={Cesium.ColorBlendMode.REPLACE} colorBlendMode={ColorBlendMode.REPLACE}
/> />
</Entity> </Entity>
<Entity <Entity
id={"Anticyclone-2"} id={"Anticyclone-2"}
position={ position={
new Cesium.CallbackProperty(function (time, result) { new CallbackProperty(function (time, result) {
const passTime = getPassTime(); const passTime = getPassTime();
if (passTime < 30) return; if (passTime < 15) return;
return Cesium.Cartesian3.fromDegrees(29, 49, 1000000); return Cartesian3.fromDegrees(29, 49, 1000000);
}, true) }, true)
} }
> >
@ -103,16 +121,16 @@ function Cyclone() {
uri={arrowRound} uri={arrowRound}
minimumPixelSize={128} minimumPixelSize={128}
color={anticycloneColor} color={anticycloneColor}
colorBlendMode={Cesium.ColorBlendMode.REPLACE} colorBlendMode={ColorBlendMode.REPLACE}
/> />
</Entity> </Entity>
<Entity <Entity
id={"Cyclone-2"} id={"Cyclone-2"}
position={ position={
new Cesium.CallbackProperty(function (time, result) { new CallbackProperty(function (time, result) {
const passTime = getPassTime(); const passTime = getPassTime();
if (passTime < 40) return; if (passTime < 20) return;
return Cesium.Cartesian3.fromDegrees(62, 45, 1000000); return Cartesian3.fromDegrees(62, 45, 1000000);
}, true) }, true)
} }
> >
@ -120,16 +138,16 @@ function Cyclone() {
uri={arrowRound} uri={arrowRound}
minimumPixelSize={128} minimumPixelSize={128}
color={cycloneColor} color={cycloneColor}
colorBlendMode={Cesium.ColorBlendMode.REPLACE} colorBlendMode={ColorBlendMode.REPLACE}
/> />
</Entity> </Entity>
<Entity <Entity
id={"Anticyclone-3"} id={"Anticyclone-3"}
position={ position={
new Cesium.CallbackProperty(function (time, result) { new CallbackProperty(function (time, result) {
const passTime = getPassTime(); const passTime = getPassTime();
if (passTime < 50) return; if (passTime < 25) return;
return Cesium.Cartesian3.fromDegrees(98, 48, 1000000); return Cartesian3.fromDegrees(98, 48, 1000000);
}, true) }, true)
} }
> >
@ -137,16 +155,16 @@ function Cyclone() {
uri={arrowRound} uri={arrowRound}
minimumPixelSize={128} minimumPixelSize={128}
color={anticycloneColor} color={anticycloneColor}
colorBlendMode={Cesium.ColorBlendMode.REPLACE} colorBlendMode={ColorBlendMode.REPLACE}
/> />
</Entity> </Entity>
<Entity <Entity
id={"Anticyclone-4"} id={"Anticyclone-4"}
position={ position={
new Cesium.CallbackProperty(function (time, result) { new CallbackProperty(function (time, result) {
const passTime = getPassTime(); const passTime = getPassTime();
if (passTime < 50) return; if (passTime < 25) return;
return Cesium.Cartesian3.fromDegrees(98, 48, 0); return Cartesian3.fromDegrees(98, 48, 0);
}, true) }, true)
} }
> >
@ -154,7 +172,7 @@ function Cyclone() {
uri={arrowRound} uri={arrowRound}
minimumPixelSize={128} minimumPixelSize={128}
color={anticycloneColor} color={anticycloneColor}
colorBlendMode={Cesium.ColorBlendMode.REPLACE} colorBlendMode={ColorBlendMode.REPLACE}
/> />
</Entity> </Entity>
</Fragment> </Fragment>

View File

@ -0,0 +1,55 @@
import { Fragment, useMemo } from "react";
import { ImageryLayer } from "resium";
import { WebMapServiceImageryProvider } from "cesium";
const url = "http://analysis.tpdc.ac.cn/gs/geoserver/phitrellis/wms";
const name1 = "phitrellis:4_1_sst_JJA_G_dif";
const name2 = "phitrellis:4_1_t2m_JJA_TP_dif ";
function JJAImageLayer() {
const tempProvider1 = useMemo(
() =>
new WebMapServiceImageryProvider({
url: url,
layers: name1,
parameters: {
service: "WMS",
format: "image/png",
transparent: true,
},
}),
[name1, url]
);
const tempProvider2 = useMemo(
() =>
new WebMapServiceImageryProvider({
url: url,
layers: name2,
parameters: {
service: "WMS",
format: "image/png",
transparent: true,
},
}),
[name2, url]
);
return (
<Fragment>
<ImageryLayer
key={`ImageryLayer-sst`}
imageryProvider={tempProvider1}
show={true}
/>
<ImageryLayer
key={`ImageryLayer-t2m`}
imageryProvider={tempProvider2}
show={true}
/>
</Fragment>
);
}
export default JJAImageLayer;

View File

@ -0,0 +1,63 @@
import { Entity, LabelGraphics, useCesium } from "resium";
import { Cartesian2, Cartesian3, Color, LabelStyle } from "cesium";
import { Fragment, useCallback, useState } from "react";
import { useInterval } from "ahooks";
function Labels() {
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 < 5) {
setShow(true);
} else if (show) setShow(false);
}, [show]);
useInterval(showAnimate, 100);
return (
<Fragment>
<Entity position={Cartesian3.fromDegrees(90, 27, 0)}>
<LabelGraphics
text={"青藏高原温度异常"}
font="24px Helvetica"
fillColor={Color.SKYBLUE}
outlineColor={Color.BLACK}
outlineWidth={2}
style={LabelStyle.FILL_AND_OUTLINE}
eyeOffset={new Cartesian2(0, 200000)}
/>
</Entity>
<Entity position={Cartesian3.fromDegrees(-55, 45, 0)}>
<LabelGraphics
text={"拉布拉多海温度异常"}
font="24px Helvetica"
fillColor={Color.SKYBLUE}
outlineColor={Color.BLACK}
outlineWidth={2}
style={LabelStyle.FILL_AND_OUTLINE}
eyeOffset={new Cartesian2(0, 200000)}
/>
</Entity>
<Entity show={show} position={Cartesian3.fromDegrees(98, 48, 0)}>
<LabelGraphics
text={"barotropic"}
font="24px Helvetica"
fillColor={Color.SKYBLUE}
outlineColor={Color.BLACK}
outlineWidth={2}
style={LabelStyle.FILL_AND_OUTLINE}
eyeOffset={new Cartesian2(0, 1200000)}
/>
</Entity>
</Fragment>
);
}
export default Labels;

View File

@ -1,67 +0,0 @@
import { useEffect, useMemo, useState } from "react";
import { ImageryLayer, useCesium } from "resium";
import { WebMapServiceImageryProvider } from "cesium";
import { useInterval } from "ahooks";
import { useDispatch, 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 dispatch = useDispatch();
const { viewer } = useCesium();
const { imageLayer } = useSelector((state) => state.data);
const [delay, setDelay] = useState(undefined);
const [index, setIndex] = useState(0);
useEffect(() => {
const { labrador } = imageLayer;
if (!!labrador) {
setDelay((60 / nameList.length) * 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) {
setIndex(0);
setDelay((60 / nameList.length) * 1000);
}
}, delay);
if (!viewer.clock?.shouldAnimate) return;
return layers[index];
}
export default LabradorImageLayer;

View File

@ -36,7 +36,7 @@ const colorBar = [
function Legend() { function Legend() {
return ( return (
<div className="legend"> <div className="legend">
<div className="legend-title">拉布拉多海海表温度夏季年代际异常值</div> <div className="legend-title">夏季温度年代际异常值</div>
<div className="colorbar"> <div className="colorbar">
{colorBar.map((color, index) => { {colorBar.map((color, index) => {
return ( return (

View File

@ -1,6 +1,7 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { Entity, PolygonGraphics, useCesium } from "resium"; import { Entity, PolygonGraphics, useCesium } from "resium";
import { useInterval } from "ahooks"; import { useInterval } from "ahooks";
import { Cartesian3, Color } from "cesium";
function PlateauPolygon() { function PlateauPolygon() {
const { viewer } = useCesium(); const { viewer } = useCesium();
@ -22,11 +23,11 @@ function PlateauPolygon() {
return ( return (
<Entity id="plateau" show={show}> <Entity id="plateau" show={show}>
<PolygonGraphics <PolygonGraphics
hierarchy={Cesium.Cartesian3.fromDegreesArray([ hierarchy={Cartesian3.fromDegreesArray([
// 85, 30, 91, 30, 91, 35, 85, 35, // 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, 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)} material={new Color(1, 0, 0, 0.1)}
/> />
</Entity> </Entity>
); );

View File

@ -1,14 +1,25 @@
import { useState } from "react"; import { useState } from "react";
import { Entity, PointGraphics, useCesium } from "resium"; import { Entity, PointGraphics, useCesium } from "resium";
import { useInterval } from "ahooks"; import { useInterval } from "ahooks";
import {
Cartesian3,
Color,
JulianDate,
LagrangePolynomialApproximation,
PolylineDashMaterialProperty,
SampledPositionProperty,
TimeInterval,
TimeIntervalCollection,
VelocityOrientationProperty,
} from "cesium";
// //
const dataLabToQTP = [ const dataLabToQTP = [
{ longitude: -62, latitude: 69, height: 1000000, time: 10 }, { longitude: -62, latitude: 69, height: 1000000, time: 5 },
{ longitude: -20, latitude: 55, height: 1000000, time: 20 }, { longitude: -20, latitude: 55, height: 1000000, time: 10 },
{ longitude: 29, latitude: 49, height: 1000000, time: 30 }, { longitude: 29, latitude: 49, height: 1000000, time: 15 },
{ longitude: 62, latitude: 45, height: 1000000, time: 40 }, { longitude: 62, latitude: 45, height: 1000000, time: 20 },
{ longitude: 98, latitude: 48, height: 1000000, time: 50 }, { longitude: 98, latitude: 48, height: 1000000, time: 25 },
]; ];
function Point() { function Point() {
@ -18,9 +29,9 @@ function Point() {
const start = viewer.clock.startTime; const start = viewer.clock.startTime;
const stop = viewer.clock.stopTime; const stop = viewer.clock.stopTime;
const pathMaterial = new Cesium.PolylineDashMaterialProperty({ const pathMaterial = new PolylineDashMaterialProperty({
dashLength: 20, dashLength: 20,
color: new Cesium.Color(4 / 255, 251 / 255, 253 / 255), color: new Color(4 / 255, 251 / 255, 253 / 255),
}); });
useInterval(() => { useInterval(() => {
@ -33,14 +44,10 @@ function Point() {
* {SampledPositionProperty|*} * {SampledPositionProperty|*}
*/ */
function createProperty(source) { function createProperty(source) {
let property = new Cesium.SampledPositionProperty(); let property = new SampledPositionProperty();
for (let i = 0; i < source.length; i++) { for (let i = 0; i < source.length; i++) {
let time = Cesium.JulianDate.addSeconds( let time = JulianDate.addSeconds(start, source[i].time, new JulianDate());
start, let position = Cartesian3.fromDegrees(
source[i].time,
new Cesium.JulianDate()
);
let position = Cesium.Cartesian3.fromDegrees(
source[i].longitude, source[i].longitude,
source[i].latitude, source[i].latitude,
source[i].height source[i].height
@ -50,7 +57,7 @@ function Point() {
} }
property.setInterpolationOptions({ property.setInterpolationOptions({
interpolationDegree: 10, interpolationDegree: 10,
interpolationAlgorithm: Cesium.LagrangePolynomialApproximation, interpolationAlgorithm: LagrangePolynomialApproximation,
}); });
return property; return property;
@ -63,14 +70,14 @@ function Point() {
id={"point"} id={"point"}
position={property} position={property}
availability={ availability={
new Cesium.TimeIntervalCollection([ new TimeIntervalCollection([
new Cesium.TimeInterval({ new TimeInterval({
start: start, start: start,
stop: stop, stop: stop,
}), }),
]) ])
} }
orientation={new Cesium.VelocityOrientationProperty(property)} orientation={new VelocityOrientationProperty(property)}
path={{ path={{
resolution: 1, resolution: 1,
material: pathMaterial, material: pathMaterial,
@ -82,9 +89,9 @@ function Point() {
> >
<PointGraphics <PointGraphics
show={true} show={true}
color={Cesium.Color.SKYBLUE} color={Color.SKYBLUE}
pixelSize={10} pixelSize={10}
outlineColor={Cesium.Color.YELLOW} outlineColor={Color.YELLOW}
outlineWidth={3} outlineWidth={3}
/> />
</Entity> </Entity>

View File

@ -1,65 +0,0 @@
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);
useEffect(() => {
const { labrador } = imageLayer;
if (!!labrador) {
setDelay((60 / nameList.length) * 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) {
setIndex(0);
setDelay((60 / nameList.length) * 1000);
}
}, delay);
if (!viewer.clock?.shouldAnimate) return;
return layers[index];
}
export default TibetImageLayer;

View File

@ -1,5 +1,11 @@
import { Entity, PolylineGraphics, useCesium } from "resium"; import { Entity, PolylineGraphics, useCesium } from "resium";
import { Cartesian3 } from "cesium"; import {
CallbackProperty,
Cartesian3,
Color,
Ellipsoid,
PolylineArrowMaterialProperty,
} from "cesium";
import { min } from "lodash-es"; import { min } from "lodash-es";
function Updraft() { function Updraft() {
@ -12,19 +18,19 @@ function Updraft() {
> >
<PolylineGraphics <PolylineGraphics
positions={ positions={
new Cesium.CallbackProperty(function (time, result) { new CallbackProperty(function (time, result) {
const { currentTime, startTime } = viewer.clock; const { currentTime, startTime } = viewer.clock;
const passTime = currentTime.secondsOfDay - startTime.secondsOfDay; const passTime = currentTime.secondsOfDay - startTime.secondsOfDay;
const height = 100000 * passTime; const height = 200000 * passTime;
return Cesium.Cartesian3.fromDegreesArrayHeights( return Cartesian3.fromDegreesArrayHeights(
[-62, 69, 0, -62, 69, min([height, 1000000])], [-62, 69, 0, -62, 69, min([height, 1000000])],
Cesium.Ellipsoid.WGS84, Ellipsoid.WGS84,
result result
); );
}, false) }, false)
} }
width={30} width={30}
material={new Cesium.PolylineArrowMaterialProperty(Cesium.Color.RED)} material={new PolylineArrowMaterialProperty(Color.RED)}
/> />
</Entity> </Entity>
); );

View File

@ -1,3 +1,9 @@
import {
Cartesian3,
Color,
PolylineArrowMaterialProperty,
PolylineDashMaterialProperty,
} from "cesium";
import { Fragment } from "react"; import { Fragment } from "react";
import { Entity, PolylineGraphics } from "resium"; import { Entity, PolylineGraphics } from "resium";
@ -6,13 +12,13 @@ function WaterVaporPath() {
<Fragment> <Fragment>
<Entity> <Entity>
<PolylineGraphics <PolylineGraphics
positions={Cesium.Cartesian3.fromDegreesArrayHeights([ positions={Cartesian3.fromDegreesArrayHeights([
103, 46, 0, 93, 38, 0, 103, 46, 0, 93, 38, 0,
])} ])}
width={10} width={10}
material={ material={
new Cesium.PolylineDashMaterialProperty({ new PolylineDashMaterialProperty({
color: Cesium.Color.fromCssColorString("#406ec5"), color: Color.fromCssColorString("#406ec5"),
dashLength: 20, dashLength: 20,
}) })
} }
@ -20,13 +26,13 @@ function WaterVaporPath() {
</Entity> </Entity>
<Entity> <Entity>
<PolylineGraphics <PolylineGraphics
positions={Cesium.Cartesian3.fromDegreesArrayHeights([ positions={Cartesian3.fromDegreesArrayHeights([
93, 38, 0, 93, 37.9, 0, 93, 38, 0, 93, 37.9, 0,
])} ])}
width={30} width={30}
material={ material={
new Cesium.PolylineArrowMaterialProperty( new PolylineArrowMaterialProperty(
Cesium.Color.fromCssColorString("#406ec5") Color.fromCssColorString("#406ec5")
) )
} }
/> />

View File

@ -10,10 +10,10 @@ import Barotropic from "./Barotorpic";
import WavePoints from "./WavePoints"; import WavePoints from "./WavePoints";
import Updraft from "./Updraft"; import Updraft from "./Updraft";
import Legend from "./Legend"; import Legend from "./Legend";
import LabradorImageLayer from "./LabradorImageLayer"; import JJAImageLayer from "./JJAImageLayer";
import TibetImageLayer from "./TibetImageLayer";
import ChartPanel from "./ChartPanel"; import ChartPanel from "./ChartPanel";
import EntityLegend from "./EntityLegend"; import EntityLegend from "./EntityLegend";
import Labels from "./Labels";
// import WaterVaporPath from "./WaterVaporPath"; // import WaterVaporPath from "./WaterVaporPath";
export default function DomainOne() { export default function DomainOne() {
@ -39,9 +39,9 @@ export default function DomainOne() {
{/* <WaterVaporPath /> */} {/* <WaterVaporPath /> */}
<Updraft /> <Updraft />
<EntityLegend /> <EntityLegend />
<Labels />
<Legend /> <Legend />
<LabradorImageLayer /> <JJAImageLayer />
<TibetImageLayer />
</MapLayout> </MapLayout>
); );
} }

View File

@ -83,7 +83,7 @@ function ChartPanel() {
data: ["南极", "北极", "青藏高原"], data: ["南极", "北极", "青藏高原"],
textStyle: { color: "#04fbfd", cursor: "point" }, textStyle: { color: "#04fbfd", cursor: "point" },
}, },
animationDuration: years.length * 500, animationDuration: 10 * 1000,
animationEasing: "cubicInOut", animationEasing: "cubicInOut",
grid: { grid: {
left: "3%", left: "3%",

View File

@ -21,9 +21,9 @@ const colorBar = [
"#FFB1B1", "#FFB1B1",
]; ];
function Legend() { function Legend({ style }) {
return ( return (
<div className={styles.legend}> <div className={styles.legend} style={{ ...style }}>
<div className="legend-title"></div> <div className="legend-title"></div>
<div className="colorbar"> <div className="colorbar">
{colorBar.map((color, index) => { {colorBar.map((color, index) => {

View File

@ -0,0 +1,31 @@
import { CameraFlyTo } from "resium";
import { Cartesian3 } from "cesium";
import MapLayout from "@/components/map/Layout";
import CustomToolbar from "@/components/common/CustomToolbar";
import CustomClock from "@/components/common/CustomClock";
import LandImageLayer from "../LandImageLayer";
import WavePoint from "@/components/common/WavePoint";
function ViewerOne({ children }) {
return (
<div className="domain-viewer">
<MapLayout>
<div className="title" style={{ zIndex: 999 }}>
两极协同连接南极和北极的热带大西洋经向模的媒介作用
</div>
<CustomToolbar />
<CustomClock />
<CameraFlyTo
duration={5}
destination={Cartesian3.fromDegrees(80, -85, 10000000)}
/>
<WavePoint stationLon={88} stationLat={-85} labelText={"南极"} />
<LandImageLayer />
{children}
</MapLayout>
</div>
);
}
export default ViewerOne;

View File

@ -0,0 +1,21 @@
import { CameraFlyTo } from "resium";
import { Cartesian3 } from "cesium";
import MapLayout from "@/components/map/Layout";
import WavePoint from "@/components/common/WavePoint";
function ViewerThree({ children }) {
return (
<div className="domain-viewer">
<MapLayout>
<CameraFlyTo
duration={5}
destination={Cartesian3.fromDegrees(100, 33, 10000000)}
/>
<WavePoint stationLon={88} stationLat={33} labelText={"青藏高原"} />
{children}
</MapLayout>
</div>
);
}
export default ViewerThree;

View File

@ -0,0 +1,28 @@
import { CameraFlyTo } from "resium";
import { Cartesian3 } from "cesium";
import MapLayout from "@/components/map/Layout";
import OceanImageLayer from "../OceanImageLayer";
import WavePoint from "@/components/common/WavePoint";
function ViewerTwo({ children }) {
return (
<div className="domain-viewer">
<MapLayout>
<OceanImageLayer />
<CameraFlyTo
duration={5}
destination={Cartesian3.fromDegrees(0, 88, 10000000)}
/>
<WavePoint
color={"WHITE"}
stationLon={0}
stationLat={87}
labelText={"北极"}
/>
{children}
</MapLayout>
</div>
);
}
export default ViewerTwo;

View File

@ -0,0 +1,28 @@
import TextInfoPanel from "@/components/common/TextInfoPanel";
import ChartPanel from "../ChartPanel";
import Legend from "../Legend";
import ViewerOne from "./ViewerOne";
import ViewerTwo from "./ViewerTwo";
import ViewerThree from "./ViewerThree";
import styles from "./index.module.less";
function SceneOne() {
return (
<div className={styles.sceneOne}>
<div className="domain-viewers">
<ViewerOne />
<ViewerTwo />
<ViewerThree />
</div>
<div className="left-panel">
<TextInfoPanel content="利用GISTEMP资料通过EEMD分解方法提取两极温度多年代际变化序列发现南北极温度变化的跷跷板现象与大西洋多年代际振荡AMO紧密相关。而AMO与热带大西洋经向模AMM在年代际尺度上显著相关。ERA5再分析资料显示AMM可以通过Rossby波影响西南极的气温与海冰偶极子。因此AMM可能在联系南北极气候变化的中起到了重要的媒介作用。" />
</div>
<div className="right-panel">
<ChartPanel />
</div>
<Legend />
</div>
);
}
export default SceneOne;

View File

@ -0,0 +1,21 @@
.sceneOne :global {
display: flex;
width: 100%;
height: 100%;
background-color: gray;
.domain-viewers {
width: 100%;
height: calc(100% - 250px);
display: flex;
.domain-viewer {
flex: 1;
position: relative;
.title {
pointer-events: none;
}
}
}
}

View File

@ -0,0 +1,15 @@
import { Button } from "antd";
function SceneSwitch({ scene, setScene }) {
const switchHandler = () => {
setScene(scene === 1 ? 2 : 1);
};
return (
<Button className="scene-switch" type="primary" onClick={switchHandler}>
切换到场景{scene === 1 ? "二" : "一"}
</Button>
);
}
export default SceneSwitch;

View File

@ -0,0 +1,110 @@
import ReactECharts from "echarts-for-react";
const years = [];
for (let year = 1950; year <= 2020; year++) {
years.push(year);
}
const SATData = [];
const SSTData = [];
function SceneChartPanel() {
const option = {
title: {
// text: "Stacked Line",
},
tooltip: {
trigger: "axis",
},
legend: {
data: ["SAT_SVD1", "SST_SVD1"],
textStyle: { color: "#04fbfd", cursor: "point" },
},
animationDuration: 10 * 1000,
animationEasing: "cubicInOut",
grid: {
left: "3%",
right: "4%",
bottom: "3%",
containLabel: true,
},
xAxis: {
type: "category",
boundaryGap: false,
data: years,
axisLine: {
onZero: false,
symbol: ["none", "arrow"],
symbolOffser: [0, 10],
lineStyle: {
color: "#04fbfd",
},
},
},
yAxis: {
type: "value",
min: -3.0,
max: 2.0,
interval: 1.0,
splitNumber: 5,
splitLine: { show: false },
axisLine: {
onZero: false,
show: true,
symbol: ["none", "arrow"],
symbolOffset: [0, 10],
lineStyle: {
color: "#04fbfd",
},
},
axisLabel: {
show: true,
},
axisTick: { show: true },
scale: true,
},
dataZoom: { type: "inside", start: 0, end: 100 },
series: [
{
name: "SAT_SVD1",
type: "line",
stack: "Total",
data: SATData,
smooth: true,
color: "red",
symbol: "none",
itemStyle: {
color: "red",
},
},
{
name: "SST_SVD1",
type: "line",
// stack: "Total",
data: SSTData,
smooth: true,
color: "blue",
symbol: "none",
itemStyle: {
color: "blue",
},
},
],
};
return (
<div className="scene-chart-panel chart-info-panel">
<ReactECharts
option={option}
lazyUpdate={true}
style={{
height: "100%",
width: "100%",
}}
/>
</div>
);
}
export default SceneChartPanel;

View File

@ -0,0 +1,20 @@
import Legend from "../Legend";
import ViewerOne from "../SceneOne/ViewerOne";
import SceneChartPanel from "./SceneChartPanel";
function SceneTwo() {
return (
<div className="scene_two">
<ViewerOne>
<div className="right-panel one" style={{ height: "unset" }}>
<div className="bottom-panel">
<SceneChartPanel />
</div>
</div>
<Legend style={{ bottom: "40px" }} />
</ViewerOne>
</div>
);
}
export default SceneTwo;

View File

@ -1,64 +1,16 @@
import MapLayout from "@/components/map/Layout"; import { useState } from "react";
import CustomToolbar from "@/components/common/CustomToolbar"; import styles from "./index.module.less";
import CustomClock from "@/components/common/CustomClock"; import SceneOne from "./SceneOne";
import TextInfoPanel from "@/components/common/TextInfoPanel"; import SceneTwo from "./SceneTwo";
import ChartPanel from "./ChartPanel"; import SceneSwitch from "./SceneSwitch";
import LandImageLayer from "./LandImageLayer";
import OceanImageLayer from "./OceanImageLayer"; export default function DomainThree() {
import WavePoint from "@/components/common/WavePoint"; const [scene, setScene] = useState(1);
import { CameraFlyTo } from "resium";
import { Cartesian3 } from "cesium";
import Legend from "./Legend";
export default function DomainOne() {
return ( return (
<div <div className={styles.domainThree}>
style={{ {scene === 1 ? <SceneOne /> : <SceneTwo />}
display: "flex", <SceneSwitch scene={scene} setScene={setScene} />
height: "100%",
}}
>
<div style={{ flex: 1, position: "relative" }}>
<MapLayout>
<div className="title" style={{ zIndex: 999 }}>
两极协同连接南极和北极的热带大西洋经向模的媒介作用
</div>
<CustomToolbar />
<CustomClock />
<CameraFlyTo
duration={5}
destination={Cartesian3.fromDegrees(80, -85, 10000000)}
/>
<div className="left-panel one">
<TextInfoPanel content="利用GISTEMP资料通过EEMD分解方法提取两极温度多年代际变化序列发现南北极温度变化的跷跷板现象与大西洋多年代际振荡AMO紧密相关。而AMO与热带大西洋经向模AMM在年代际尺度上显著相关。ERA5再分析资料显示AMM可以通过Rossby波影响西南极的气温与海冰偶极子。因此AMM可能在联系南北极气候变化的中起到了重要的媒介作用。" />
</div>
<WavePoint stationLon={88} stationLat={-85} />
{/* <LandImageLayer /> */}
</MapLayout>
</div>
<div style={{ flex: 1, position: "relative" }}>
<MapLayout>
<OceanImageLayer />
<CameraFlyTo
duration={5}
destination={Cartesian3.fromDegrees(0, 88, 10000000)}
/>
<WavePoint color={"WHITE"} stationLon={0} stationLat={87} />
</MapLayout>
</div>
<div style={{ flex: 1, position: "relative" }}>
<MapLayout>
<CameraFlyTo
duration={5}
destination={Cartesian3.fromDegrees(100, 33, 10000000)}
/>
<div className="right-panel one">
<ChartPanel />
</div>
<WavePoint maxR={3600 * 200} stationLon={88} stationLat={33} />
</MapLayout>
</div>
{/* <Legend /> */}
</div> </div>
); );
} }

View File

@ -1,6 +1,148 @@
.domainThree :global {
height: 100%;
.scene_two {
display: flex;
height: 100%;
.domain-viewer {
flex: 1;
position: relative;
.title {
pointer-events: none;
}
.chart-info-panel {
width: 100%;
height: 100%;
pointer-events: auto;
padding: 12px;
border: 1px solid #04fbfd;
color: #02f9ff !important;
background-color: #1f485690;
transition: all 0.3s ease-in-out;
}
}
}
.scene-switch {
position: absolute;
left: 8px;
top: 8px;
}
.left-panel {
position: absolute;
left: 12px;
bottom: 12px;
width: 450px;
display: flex;
flex-direction: column;
height: 230px;
.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: 18px;
text-indent: 2em;
line-height: 1.5;
z-index: 999;
}
}
.right-panel {
position: absolute;
right: 12px;
bottom: 12px;
width: 450px;
height: 230px;
display: flex;
flex-direction: column;
gap: 12px;
.top-panel {
flex: 1;
}
.bottom-panel {
flex: 1;
}
.form-panel {
width: 100%;
height: 100%;
pointer-events: auto;
padding: 12px;
border: 1px solid #04fbfd;
color: #02f9ff !important;
background-color: #1f485690;
.ant-form-item-label {
label {
color: white;
}
}
.ant-form-item-control {
.ant-select-multiple {
max-height: 300px;
overflow-y: scroll;
&::-webkit-scrollbar {
width: 6px;
height: 1px;
}
&::-webkit-scrollbar-thumb {
border-radius: 6px;
background: #00a2a2;
}
&::-webkit-scrollbar-track {
border-radius: 6px;
background: none;
}
}
}
}
.chart-info-panel {
width: 100%;
height: 100%;
pointer-events: auto;
padding: 12px;
border: 1px solid #04fbfd;
color: #02f9ff !important;
background-color: #1f485690;
transition: all 0.3s ease-in-out;
}
.highlight {
outline: 4px solid #04fbfd;
box-shadow: 0 0 30px #04e0fd;
}
}
.one {
top: 50%;
}
}
.legend :global { .legend :global {
position: absolute; position: absolute;
bottom: 40px; bottom: 270px;
width: 50%; width: 50%;
left: 25%; left: 25%;
z-index: 1000; z-index: 1000;
@ -26,7 +168,6 @@
.colorbar-item { .colorbar-item {
flex: 1; flex: 1;
height: 100%; height: 100%;
// border-radius: 8px;
border: 1px black solid; border: 1px black solid;
&:not(:nth-child(1)) { &:not(:nth-child(1)) {

View File

@ -1,27 +1,46 @@
import { Fragment, useState } from "react"; import { Fragment, useState } from "react";
import { Entity, EllipsoidGraphics, useCesium, PolylineGraphics } from "resium"; import {
Entity,
EllipsoidGraphics,
useCesium,
PolylineGraphics,
LabelGraphics,
} from "resium";
import { useInterval, useThrottleFn } from "ahooks"; import { useInterval, useThrottleFn } from "ahooks";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import {
Cartesian3,
Color,
Math as CesiumMath,
LabelStyle,
PolylineDashMaterialProperty,
Cartesian2,
} from "cesium";
const lowCircle = ( const lowCircle = (
<EllipsoidGraphics <EllipsoidGraphics
radii={new Cesium.Cartesian3(460000.0, 460000.0, 460000.0)} radii={new Cartesian3(460000.0, 460000.0, 460000.0)}
innerRadii={new Cesium.Cartesian3(415000.0, 415000.0, 415000.0)} innerRadii={new Cartesian3(415000.0, 415000.0, 415000.0)}
minimumCone={Cesium.Math.toRadians(89.8)} minimumCone={CesiumMath.toRadians(89.8)}
maximumCone={Cesium.Math.toRadians(90.2)} maximumCone={CesiumMath.toRadians(90.2)}
material={new Cesium.Color(0.29, 0.46, 0.77, 1)} material={new Color(0.29, 0.46, 0.77, 1)}
/> />
); );
const highCircle = ( const highCircle = (
<EllipsoidGraphics <EllipsoidGraphics
radii={new Cesium.Cartesian3(460000.0, 460000.0, 460000.0)} radii={new Cartesian3(460000.0, 460000.0, 460000.0)}
innerRadii={new Cesium.Cartesian3(415000.0, 415000.0, 415000.0)} innerRadii={new Cartesian3(415000.0, 415000.0, 415000.0)}
minimumCone={Cesium.Math.toRadians(89.8)} minimumCone={CesiumMath.toRadians(89.8)}
maximumCone={Cesium.Math.toRadians(90.2)} maximumCone={CesiumMath.toRadians(90.2)}
material={new Cesium.Color(0.99, 0.23, 0.23, 1)} material={new Color(0.99, 0.23, 0.23, 1)}
/> />
); );
// const labelText={
// '5','Rossby' , '', '680'
// }
function Circles() { function Circles() {
const { viewer } = useCesium(); const { viewer } = useCesium();
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -56,7 +75,7 @@ function Circles() {
currentTime.secondsOfDay - startTime.secondsOfDay currentTime.secondsOfDay - startTime.secondsOfDay
); );
if (!shouldAnimate) return; if (!shouldAnimate) return;
if (_time === 40) { if (_time === 20) {
showInfo(); showInfo();
} else if (_time === 0) { } else if (_time === 0) {
closeInfo(); closeInfo();
@ -75,14 +94,12 @@ function Circles() {
<Fragment> <Fragment>
<Entity <Entity
id={`${id}-up`} id={`${id}-up`}
position={Cesium.Cartesian3.fromDegrees(lon, lat, 1000000)} position={Cartesian3.fromDegrees(lon, lat, 1000000)}
> >
{circle} {circle}
</Entity>
{show && (
<Entity id={`${id}-connection-line`}> <Entity id={`${id}-connection-line`}>
<PolylineGraphics <PolylineGraphics
positions={Cesium.Cartesian3.fromDegreesArrayHeights([ positions={Cartesian3.fromDegreesArrayHeights([
lon, lon,
lat, lat,
1000000, 1000000,
@ -92,20 +109,31 @@ function Circles() {
])} ])}
width={2} width={2}
material={ material={
new Cesium.PolylineDashMaterialProperty({ new PolylineDashMaterialProperty({
color: Cesium.Color.WHITE, color: Color.WHITE,
dashLength: 4, dashLength: 4,
}) })
} }
/> />
</Entity> </Entity>
)} </Entity>
<Entity <Entity
id={`${id}-down`} id={`${id}-down`}
position={Cesium.Cartesian3.fromDegrees(lon, lat, 0)} position={Cartesian3.fromDegrees(lon, lat, 0)}
> >
{circle} {circle}
</Entity> </Entity>
<Entity position={Cartesian3.fromDegrees(lon, lat, 0)}>
<LabelGraphics
text={"Rossby波列"}
font="24px Helvetica"
fillColor={Color.SKYBLUE}
outlineColor={Color.BLACK}
outlineWidth={2}
style={LabelStyle.FILL_AND_OUTLINE}
eyeOffset={new Cartesian2(0, 1000000)}
/>
</Entity>
</Fragment> </Fragment>
); );
}; };
@ -115,35 +143,35 @@ function Circles() {
<Circle <Circle
isLow={true} isLow={true}
id={`low-circle-1`} id={`low-circle-1`}
showTime={10} showTime={5}
lon={-110} lon={-110}
lat={-60} lat={-60}
/> />
<Circle <Circle
isLow={false} isLow={false}
id={`height-circle-1`} id={`height-circle-1`}
showTime={20} showTime={10}
lon={-30} lon={-30}
lat={-55} lat={-55}
/> />
<Circle <Circle
isLow={true} isLow={true}
id={`low-circle-2`} id={`low-circle-2`}
showTime={30} showTime={15}
lon={30} lon={30}
lat={-40} lat={-40}
/> />
<Circle <Circle
isLow={false} isLow={false}
id={`height-circle-2`} id={`height-circle-2`}
showTime={40} showTime={20}
lon={65} lon={65}
lat={-35} lat={-35}
/> />
<Circle <Circle
isLow={true} isLow={true}
id={`low-circle-3`} id={`low-circle-3`}
showTime={50} showTime={27}
lon={95} lon={95}
lat={-30} lat={-30}
/> />

View File

@ -1,30 +1,31 @@
import { useCesium } from "resium"; import { Cartesian2, Cartesian3, Math } from "cesium";
import { CloudCollection, useCesium } from "resium";
function Cloud() { function Cloud() {
const { viewer } = useCesium(); const { viewer } = useCesium();
const scene = viewer.scene; const scene = viewer.scene;
const position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, 50); const position = Cartesian3.fromDegrees(-123.0744619, 44.0503706, 50);
Cesium.Math.setRandomNumberSeed(2.5); Math.setRandomNumberSeed(2.5);
function getRandomNumberInRange(minValue, maxValue) { function getRandomNumberInRange(minValue, maxValue) {
return minValue + Cesium.Math.nextRandomNumber() * (maxValue - minValue); return minValue + Math.nextRandomNumber() * (maxValue - minValue);
} }
const clouds = new Cesium.CloudCollection(); const clouds = new CloudCollection();
// manually position clouds in the mountains // manually position clouds in the mountains
function createBackLayerClouds() { function createBackLayerClouds() {
clouds.add({ clouds.add({
position: Cesium.Cartesian3.fromDegrees(-122.6908, 45.496, 300), position: new Cartesian3.fromDegrees(-122.6908, 45.496, 300),
scale: new Cesium.Cartesian2(1500, 250), scale: new Cartesian2(1500, 250),
maximumSize: new Cesium.Cartesian3(50, 15, 13), maximumSize: new Cartesian3(50, 15, 13),
slice: 0.3, slice: 0.3,
}); });
clouds.add({ clouds.add({
position: Cesium.Cartesian3.fromDegrees(-122.72, 45.5, 335), position: new Cartesian3.fromDegrees(-122.72, 45.5, 335),
scale: new Cesium.Cartesian2(1500, 300), scale: new Cartesian2(1500, 300),
maximumSize: new Cesium.Cartesian3(50, 12, 15), maximumSize: new Cartesian3(50, 12, 15),
slice: 0.36, slice: 0.36,
}); });
} }
@ -53,9 +54,9 @@ function Cloud() {
aspectRatio = getRandomNumberInRange(1.5, 2.1); aspectRatio = getRandomNumberInRange(1.5, 2.1);
cloudHeight = getRandomNumberInRange(5, 20); cloudHeight = getRandomNumberInRange(5, 20);
clouds.add({ clouds.add({
position: Cesium.Cartesian3.fromDegrees(long, lat, height), position: Cartesian3.fromDegrees(long, lat, height),
scale: new Cesium.Cartesian2(scaleX, scaleY), scale: new Cartesian2(scaleX, scaleY),
maximumSize: new Cesium.Cartesian3( maximumSize: new Cartesian3(
aspectRatio * cloudHeight, aspectRatio * cloudHeight,
cloudHeight, cloudHeight,
depth depth
@ -65,19 +66,19 @@ function Cloud() {
} }
} }
// manually position clouds in front // manually position clouds in front
const scratch = new Cesium.Cartesian3(); const scratch = new Cartesian3();
function createFrontLayerClouds() { function createFrontLayerClouds() {
clouds.add({ clouds.add({
position: Cesium.Cartesian3.fromDegrees(-122.666, 45.5126, 97), position: Cartesian3.fromDegrees(-122.666, 45.5126, 97),
scale: new Cesium.Cartesian2(400, 150), scale: new Cartesian2(400, 150),
maximumSize: new Cesium.Cartesian3(25, 12, 15), maximumSize: new Cartesian3(25, 12, 15),
slice: 0.36, slice: 0.36,
}); });
clouds.add({ clouds.add({
position: Cesium.Cartesian3.fromDegrees(-122.6665, 45.5262, 76), position: Cartesian3.fromDegrees(-122.6665, 45.5262, 76),
scale: new Cesium.Cartesian2(450, 200), scale: new Cartesian2(450, 200),
maximumSize: new Cesium.Cartesian3(25, 14, 12), maximumSize: new Cartesian3(25, 14, 12),
slice: 0.3, slice: 0.3,
}); });
} }

View File

@ -1,112 +1,137 @@
import { Cartesian3, EasingFunction, Math } from "cesium";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { useCesium } from "resium"; import { useCesium } from "resium";
function CustomFlyTo() { function CustomFlyTo() {
const dispatch = useDispatch(); const dispatch = useDispatch();
const { viewer } = useCesium(); const { viewer, camera } = useCesium();
const { camera } = viewer;
function cameraFlyToLine(adjustPitch) { function cameraFlyToLine() {
// // //
const antarcticalOptions = { // const antarcticalOptions = {
destination: Cesium.Cartesian3.fromDegrees(88, -89, 1600000), // destination: Cartesian3.fromDegrees(88, -89, 1600000),
orientation: { // orientation: {
heading: Cesium.Math.toRadians(15.0), // heading: Math.toRadians(15.0),
pitch: Cesium.Math.toRadians(-60), // pitch: Math.toRadians(-60),
roll: 0.0, // roll: 0.0,
}, // },
duration: 10, // duration: 5,
complete: function () { // complete: function () {
setTimeout(() => { // camera.flyTo(area1Options);
camera.flyTo(plateauOptions); // },
}, 1000); // easingFunction: EasingFunction.LINEAR_NONE,
}, // };
};
const area1Options = { const area1Options = {
destination: Cesium.Cartesian3.fromDegrees(-110, -60, 6000000), destination: Cartesian3.fromDegrees(-110, -86, 10000000),
duration: 5, duration: 5,
complete: function () { orientation: {
setTimeout(function () { heading: 6,
camera.flyTo(area2Options); pitch: -1.3,
}, 1000); roll: -6,
}, },
complete: function () {
viewer.clock.shouldAnimate = true;
dispatch.data.updateToolbar({ showPanel: true });
setTimeout(() => {
camera.flyTo(area2Options);
}, 5000);
},
easingFunction: EasingFunction.LINEAR_NONE,
}; };
const area2Options = { const area2Options = {
destination: Cesium.Cartesian3.fromDegrees(-30, -55, 6000000), destination: Cartesian3.fromDegrees(-30, -65, 10000000),
duration: 5, duration: 5,
complete: function () { complete: function () {
setTimeout(function () { camera.flyTo(area3Options);
camera.flyTo(area3Options); },
}, 1000); easingFunction: EasingFunction.LINEAR_NONE,
orientation: {
heading: 6,
pitch: -1.3,
roll: -6,
}, },
}; };
const area3Options = { const area3Options = {
destination: Cesium.Cartesian3.fromDegrees(30, -40, 6000000), destination: Cartesian3.fromDegrees(30, -40, 10000000),
duration: 5, duration: 5,
complete: function () { complete: function () {
setTimeout(function () { camera.flyTo(area4Options);
camera.flyTo(area4Options);
}, 1000);
}, },
easingFunction: EasingFunction.LINEAR_NONE,
}; };
const area4Options = { const area4Options = {
destination: Cesium.Cartesian3.fromDegrees(65, -35, 6000000), destination: Cartesian3.fromDegrees(65, -55, 10000000),
duration: 5,
complete: function () {
setTimeout(function () {
camera.flyTo(sideViewOptions);
}, 1000);
},
};
//
const plateauOptions = {
destination: Cesium.Cartesian3.fromDegrees(90, 20, 1600000),
duration: 5, duration: 5,
orientation: { orientation: {
heading: Cesium.Math.toRadians(-15.0), heading: 6,
pitch: -Cesium.Math.PI_OVER_FOUR, pitch: -1.3,
roll: 0.0, roll: -6,
}, },
complete: function () { complete: function () {
setTimeout(function () {
camera.flyTo(sideViewOptions);
}, 1000);
},
};
//
const sideViewOptions = {
destination: Cesium.Cartesian3.fromDegrees(80, -60, 16000000),
// destination: Cesium.Cartesian3.fromDegrees(130, -10.5, 20000000),
duration: 5,
orientation: {
heading: Cesium.Math.toRadians(-10.0),
pitch: Cesium.Math.toRadians(-92),
roll: 6.0,
},
complete: () => {
viewer.clock.shouldAnimate = true;
dispatch.data.updateToolbar({ showPanel: true });
setTimeout(() => { setTimeout(() => {
camera.flyTo({ camera.flyTo({
duration: 5, duration: 5,
destination: Cesium.Cartesian3.fromDegrees(90, -12, 14000000), destination: Cartesian3.fromDegrees(90, -12, 14000000),
}); });
}, 40 * 1000); }, 5 * 1000);
}, },
easingFunction: EasingFunction.LINEAR_NONE,
}; };
if (adjustPitch) { const area5Options = {
antarcticalOptions.pitchAdjustHeight = 1000; destination: Cartesian3.fromDegrees(95, -30, 10000000),
plateauOptions.pitchAdjustHeight = 1000; duration: 5,
sideViewOptions.pitchAdjustHeight = 1000; complete: function () {
} // camera.flyTo(sideViewOptions);
camera.flyTo(sideViewOptions); setTimeout(() => {
camera.flyTo({
duration: 5,
destination: Cartesian3.fromDegrees(90, -12, 14000000),
});
}, 5 * 1000);
},
easingFunction: EasingFunction.LINEAR_NONE,
};
//
// const sideViewOptions = {
// destination: Cartesian3.fromDegrees(80, -60, 16000000),
// // destination: Cesium.Cartesian3.fromDegrees(130, -10.5, 20000000),
// duration: 5,
// orientation: {
// heading: Math.toRadians(-10.0),
// pitch: Math.toRadians(-92),
// roll: 6.0,
// },
// complete: () => {
// viewer.clock.shouldAnimate = true;
// dispatch.data.updateToolbar({ showPanel: true });
// setTimeout(() => {
// camera.flyTo({
// duration: 5,
// destination: Cartesian3.fromDegrees(90, -12, 14000000),
// });
// }, 40 * 1000);
// },
// };
const xx = {
destination: Cartesian3.fromDegrees(65, -55, 10000000),
duration: 5,
orientation: {
heading: 6,
pitch: -1.3,
roll: -6,
},
easingFunction: EasingFunction.LINEAR_NONE,
};
camera.flyTo(area1Options);
} }
cameraFlyToLine(); cameraFlyToLine();
return <></>; return <></>;

View File

@ -12,7 +12,7 @@ function IndianOceanSST() {
() => () =>
new WebMapServiceImageryProvider({ new WebMapServiceImageryProvider({
url: url, url: url,
layers: "phitrellis:india_ocean_sst", layers: "phitrellis:4_2_Indian_Ocean_sst",
parameters: { parameters: {
service: "WMS", service: "WMS",
format: "image/png", format: "image/png",

View File

@ -0,0 +1,34 @@
import { Cartesian2, Cartesian3, Color, LabelStyle } from "cesium";
import { Fragment } from "react";
import { Entity, LabelGraphics } from "resium";
function Labels() {
return (
<Fragment>
<Entity position={Cartesian3.fromDegrees(73, -7, 0)}>
<LabelGraphics
text={"印度洋海温异常"}
font="24px Helvetica"
fillColor={Color.SKYBLUE}
outlineColor={Color.BLACK}
outlineWidth={2}
style={LabelStyle.FILL_AND_OUTLINE}
eyeOffset={new Cartesian2(0, 200000)}
/>
</Entity>
<Entity position={Cartesian3.fromDegrees(94, 24, 0)}>
<LabelGraphics
text={"6月青藏高原降水和加热"}
font="24px Helvetica"
fillColor={Color.SKYBLUE}
outlineColor={Color.BLACK}
outlineWidth={2}
style={LabelStyle.FILL_AND_OUTLINE}
eyeOffset={new Cartesian2(0, 0)}
/>
</Entity>
</Fragment>
);
}
export default Labels;

View File

@ -1,4 +1,5 @@
import { useInterval } from "ahooks"; import { useInterval } from "ahooks";
import { Cartesian3, Color, PolylineArrowMaterialProperty } from "cesium";
import { Fragment, useCallback, useState } from "react"; import { Fragment, useCallback, useState } from "react";
import { Entity, PolylineGraphics, useCesium } from "resium"; import { Entity, PolylineGraphics, useCesium } from "resium";
@ -23,26 +24,24 @@ function MoistureTransport() {
<Fragment> <Fragment>
<Entity show={show}> <Entity show={show}>
<PolylineGraphics <PolylineGraphics
positions={Cesium.Cartesian3.fromDegreesArrayHeights([ positions={Cartesian3.fromDegreesArrayHeights([
85, 33, 200000, 87, 32, 0, 85, 33, 200000, 87, 32, 0,
])} ])}
width={15} width={15}
material={ material={
new Cesium.PolylineArrowMaterialProperty( new PolylineArrowMaterialProperty(
Cesium.Color.fromCssColorString("#70ad47") Color.fromCssColorString("#70ad47")
) )
} }
/> />
</Entity> </Entity>
<Entity show={show}> <Entity show={show}>
<PolylineGraphics <PolylineGraphics
positions={Cesium.Cartesian3.fromDegreesArrayHeights([ positions={Cartesian3.fromDegreesArrayHeights([83, 27, 0, 87, 31, 0])}
83, 27, 0, 87, 31, 0,
])}
width={15} width={15}
material={ material={
new Cesium.PolylineArrowMaterialProperty( new PolylineArrowMaterialProperty(
Cesium.Color.fromCssColorString("#70ad47") Color.fromCssColorString("#70ad47")
) )
} }
/> />

View File

@ -1,6 +1,7 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { Entity, PolygonGraphics, useCesium } from "resium"; import { Entity, PolygonGraphics, useCesium } from "resium";
import { useInterval } from "ahooks"; import { useInterval } from "ahooks";
import { Cartesian3, Color } from "cesium";
function PlateauPolygon() { function PlateauPolygon() {
const { viewer } = useCesium(); const { viewer } = useCesium();
@ -12,7 +13,7 @@ function PlateauPolygon() {
stopTime.secondsOfDay - currentTime.secondsOfDay stopTime.secondsOfDay - currentTime.secondsOfDay
); );
if (leftTime < 20) { if (leftTime < 5) {
setShow(true); setShow(true);
} else if (show) setShow(false); } else if (show) setShow(false);
}, [show]); }, [show]);
@ -22,11 +23,11 @@ function PlateauPolygon() {
return ( return (
<Entity id="plateau" show={show}> <Entity id="plateau" show={show}>
<PolygonGraphics <PolygonGraphics
hierarchy={Cesium.Cartesian3.fromDegreesArray([ hierarchy={Cartesian3.fromDegreesArray([
// 85, 30, 91, 30, 91, 35, 85, 35, // 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, 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)} material={new Color(1, 0, 0, 0.1)}
/> />
</Entity> </Entity>
); );

View File

@ -1,16 +1,26 @@
import { useState } from "react"; import { useState } from "react";
import { Entity, PointGraphics, useCesium } from "resium"; import { Entity, PointGraphics, useCesium } from "resium";
import { useInterval } from "ahooks"; import { useInterval } from "ahooks";
import {
Cartesian3,
Color,
JulianDate,
LinearApproximation,
SampledPositionProperty,
TimeInterval,
TimeIntervalCollection,
VelocityOrientationProperty,
} from "cesium";
// //
const dataAntarcticaToQTP = [ const dataAntarcticaToQTP = [
{ longitude: -110, latitude: -60, height: 0, time: 0 }, { longitude: -110, latitude: -60, height: 0, time: 0 },
{ longitude: -110, latitude: -60, height: 1000000, time: 10 }, { longitude: -110, latitude: -60, height: 1000000, time: 5 },
{ longitude: -30, latitude: -55, height: 1000000, time: 20 }, { longitude: -30, latitude: -55, height: 1000000, time: 10 },
{ longitude: 30, latitude: -40, height: 1000000, time: 30 }, { longitude: 30, latitude: -40, height: 1000000, time: 15 },
{ longitude: 65, latitude: -35, height: 1000000, time: 40 }, { longitude: 65, latitude: -35, height: 1000000, time: 20 },
{ longitude: 95, latitude: -30, height: 1000000, time: 50 }, { longitude: 95, latitude: -30, height: 1000000, time: 27 },
{ longitude: 95, latitude: -30, height: 0, time: 60 }, { longitude: 95, latitude: -30, height: 0, time: 30 },
]; ];
function Point() { function Point() {
@ -21,7 +31,7 @@ function Point() {
const start = viewer.clock.startTime; const start = viewer.clock.startTime;
const stop = viewer.clock.stopTime; const stop = viewer.clock.stopTime;
const pathMaterial = new Cesium.Color(4 / 255, 251 / 255, 253 / 255); const pathMaterial = new Color(4 / 255, 251 / 255, 253 / 255);
useInterval(() => { useInterval(() => {
if (viewer.clock?.shouldAnimate) setDelay(undefined); if (viewer.clock?.shouldAnimate) setDelay(undefined);
@ -33,14 +43,10 @@ function Point() {
* {SampledPositionProperty|*} * {SampledPositionProperty|*}
*/ */
function createProperty(source) { function createProperty(source) {
let property = new Cesium.SampledPositionProperty(); let property = new SampledPositionProperty();
for (let i = 0; i < source.length; i++) { for (let i = 0; i < source.length; i++) {
let time = Cesium.JulianDate.addSeconds( let time = JulianDate.addSeconds(start, source[i].time, new JulianDate());
start, let position = Cartesian3.fromDegrees(
source[i].time,
new Cesium.JulianDate()
);
let position = Cesium.Cartesian3.fromDegrees(
source[i].longitude, source[i].longitude,
source[i].latitude, source[i].latitude,
source[i].height source[i].height
@ -50,7 +56,7 @@ function Point() {
} }
property.setInterpolationOptions({ property.setInterpolationOptions({
interpolationDegree: 1, interpolationDegree: 1,
interpolationAlgorithm: Cesium.LinearApproximation, interpolationAlgorithm: LinearApproximation,
}); });
return property; return property;
} }
@ -62,14 +68,14 @@ function Point() {
id={"point"} id={"point"}
position={property} position={property}
availability={ availability={
new Cesium.TimeIntervalCollection([ new TimeIntervalCollection([
new Cesium.TimeInterval({ new TimeInterval({
start, start,
stop, stop,
}), }),
]) ])
} }
orientation={new Cesium.VelocityOrientationProperty(property)} orientation={new VelocityOrientationProperty(property)}
path={{ path={{
resolution: 1, resolution: 1,
material: pathMaterial, material: pathMaterial,
@ -81,8 +87,8 @@ function Point() {
> >
<PointGraphics <PointGraphics
show={true} show={true}
color={Cesium.Color.SKYBLUE} color={Color.SKYBLUE}
outlineColor={Cesium.Color.YELLOW} outlineColor={Color.YELLOW}
outlineWidth={3} outlineWidth={3}
/> />
</Entity> </Entity>

View File

@ -1,5 +1,5 @@
import { Entity, EllipseGraphics } from "resium"; import { Entity, EllipseGraphics } from "resium";
import { Cartesian3 } from "cesium"; import { Cartesian3, Color } from "cesium";
const fluxData = [ const fluxData = [
0.03256254, -0.23182425, -0.040055223, -0.03476936, -0.40450656, -0.18742515, 0.03256254, -0.23182425, -0.040055223, -0.03476936, -0.40450656, -0.18742515,
@ -86,7 +86,7 @@ function HeatFlux({ position, index }) {
`} `}
> >
<EllipseGraphics <EllipseGraphics
material={new Cesium.Color.fromCssColorString(colorBar[dataIndex])} material={new Color.fromCssColorString(colorBar[dataIndex])}
semiMinorAxis={30000.0} semiMinorAxis={30000.0}
semiMajorAxis={30000.0} semiMajorAxis={30000.0}
extrudedHeight={400000} extrudedHeight={400000}

View File

@ -1,5 +1,5 @@
import { Entity, EllipseGraphics } from "resium"; import { Entity, EllipseGraphics } from "resium";
import { Cartesian3 } from "cesium"; import { Cartesian3, Color } from "cesium";
const rainData = [ const rainData = [
0.25309432, 0.296679, 0.39937696, -0.15093477, 0.17799897, 0.1186297, 0.25309432, 0.296679, 0.39937696, -0.15093477, 0.17799897, 0.1186297,
@ -85,7 +85,7 @@ function Rain({ position, index }) {
`} `}
> >
<EllipseGraphics <EllipseGraphics
material={new Cesium.Color.fromCssColorString(colorBar[dataIndex])} material={new Color.fromCssColorString(colorBar[dataIndex])}
semiMinorAxis={30000.0} semiMinorAxis={30000.0}
semiMajorAxis={30000.0} semiMajorAxis={30000.0}
extrudedHeight={200000} extrudedHeight={200000}

View File

@ -1,6 +1,7 @@
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { useInterval } from "ahooks"; import { useInterval } from "ahooks";
import { Entity, PolylineGraphics, useCesium } from "resium"; import { Entity, PolylineGraphics, useCesium } from "resium";
import { Cartesian3, Color, PolylineArrowMaterialProperty } from "cesium";
function SurfaceAnomaly() { function SurfaceAnomaly() {
const { viewer } = useCesium(); const { viewer } = useCesium();
@ -22,14 +23,10 @@ function SurfaceAnomaly() {
return ( return (
<Entity show={show}> <Entity show={show}>
<PolylineGraphics <PolylineGraphics
positions={Cesium.Cartesian3.fromDegreesArrayHeights([ positions={Cartesian3.fromDegreesArrayHeights([90, -30, 0, 90, -21, 0])}
90, -30, 0, 90, -21, 0,
])}
width={10} width={10}
material={ material={
new Cesium.PolylineArrowMaterialProperty( new PolylineArrowMaterialProperty(Color.fromCssColorString("#000"))
Cesium.Color.fromCssColorString("#000")
)
} }
/> />
</Entity> </Entity>

View File

@ -13,6 +13,7 @@ import Circles from "./Circles";
import SurfaceAnomaly from "./SurfaceAnomaly"; import SurfaceAnomaly from "./SurfaceAnomaly";
import MoistureTransport from "./MoistureTransport"; import MoistureTransport from "./MoistureTransport";
import Sites from "./Site"; import Sites from "./Site";
import Labels from "./Labels";
export default function DomainTwo() { export default function DomainTwo() {
return ( return (
@ -22,18 +23,19 @@ export default function DomainTwo() {
<CustomClock /> <CustomClock />
<CustomFlyTo /> <CustomFlyTo />
<Circles /> <Circles />
<EntityLegend />
<IndianOceanSST />
<Labels />
<Legend />
<MoistureTransport />
<Point /> <Point />
<PlateauPolygon /> <PlateauPolygon />
<Sites />
<div className="left-panel one"> <div className="left-panel one">
<TextInfoPanel content="利用ERA5再分析数据诊断和CESM印度洋海温强迫数值实验发现5月的南极涛动正位相AAO激发原子阿蒙森海的纬向波列异常。该异常造成印度洋海温降低进而激发环流异常造成高原上空降水增加、感热通量降低。这一结果有助于提高青藏高原热源的预测技巧改进亚洲夏季风的预测。" /> <TextInfoPanel content="利用ERA5再分析数据诊断和CESM印度洋海温强迫数值实验发现5月的南极涛动正位相AAO激发原子阿蒙森海的纬向波列异常。该异常造成印度洋海温降低进而激发环流异常造成高原上空降水增加、感热通量降低。这一结果有助于提高青藏高原热源的预测技巧改进亚洲夏季风的预测。" />
</div> </div>
<WavePoints /> <WavePoints />
<EntityLegend />
<Legend />
<IndianOceanSST />
{/* <SurfaceAnomaly /> */} {/* <SurfaceAnomaly /> */}
<MoistureTransport />
<Sites />
</MapLayout> </MapLayout>
); );
} }

View File

@ -0,0 +1,16 @@
import { useCesium } from "resium";
function HeadingPitchRoll() {
const { camera } = useCesium();
camera.moveEnd?.addEventListener(function (event) {
const heading = camera.heading;
const pitch = camera.pitch;
const roll = camera.roll;
console.log("heading,pitch,roll :>> ", heading, pitch, roll);
});
return <></>;
}
export default HeadingPitchRoll;

View File

@ -1,3 +1,9 @@
import {
Cartographic,
Math,
ScreenSpaceEventHandler,
ScreenSpaceEventType,
} from "cesium";
import { useState } from "react"; import { useState } from "react";
import { useCesium } from "resium"; import { useCesium } from "resium";
@ -7,26 +13,22 @@ function Picker() {
const [lon, setLon] = useState(); const [lon, setLon] = useState();
const [lat, setLat] = useState(); const [lat, setLat] = useState();
const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas); const handler = new ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (movement) { handler.setInputAction(function (movement) {
const cartesian = viewer.camera.pickEllipsoid( const cartesian = viewer.camera.pickEllipsoid(
movement.endPosition, movement.endPosition,
scene.globe.ellipsoid scene.globe.ellipsoid
); );
if (cartesian) { if (cartesian) {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian); const cartographic = Cartographic.fromCartesian(cartesian);
const longitudeString = Cesium.Math.toDegrees( const longitudeString = Math.toDegrees(cartographic.longitude).toFixed(4);
cartographic.longitude const latitudeString = Math.toDegrees(cartographic.latitude).toFixed(4);
).toFixed(4);
const latitudeString = Cesium.Math.toDegrees(
cartographic.latitude
).toFixed(4);
setLon(longitudeString); setLon(longitudeString);
setLat(latitudeString); setLat(latitudeString);
} else { } else {
// entity.label.show = false; // entity.label.show = false;
} }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE); }, ScreenSpaceEventType.MOUSE_MOVE);
if (!lon && !lat) return <></>; if (!lon && !lat) return <></>;

View File

@ -1,20 +1,10 @@
import { Entity, PointGraphics, Viewer } from "resium"; import { Entity, PointGraphics, Viewer } from "resium";
import styles from "./index.module.less"; import styles from "./index.module.less";
import { useMemo } from "react"; import { Cartesian3, Color } from "cesium";
import { BingMapsImageryProvider, BingMapsStyle } from "cesium";
import Picker from "./Picker"; import Picker from "./Picker";
import HeadingPitchRoll from "./HeadingPitchRoll";
function MapLayout({ children, className, ...rest }) { function MapLayout({ children, className, ...rest }) {
const imageryProvider = useMemo(
() =>
new BingMapsImageryProvider({
url: "https://dev.virtualearth.net",
key: "Ahv1KDJwbpJl4V8zklaRXcoueWXoNLo16osJiU4Zk07vc-VNNzJ0gB81TZyPqNFz",
mapStyle: BingMapsStyle.AERIAL,
}),
[]
);
return ( return (
<Viewer <Viewer
className={`${styles.cesiumContainer} ${className}`} className={`${styles.cesiumContainer} ${className}`}
@ -30,12 +20,12 @@ function MapLayout({ children, className, ...rest }) {
baseLayerPicker={false} baseLayerPicker={false}
animation={false} animation={false}
selectionIndicator={false} selectionIndicator={false}
// imageryProvider={imageryProvider}
> >
<Entity position={Cesium.Cartesian3.fromDegreesArray([0, 90])}> <Entity position={Cartesian3.fromDegreesArray([0, 90])}>
<PointGraphics color={Cesium.Color.SKYBLUE} pixelSize={10} /> <PointGraphics color={Color.SKYBLUE} pixelSize={10} />
</Entity> </Entity>
<Picker /> <Picker />
{/* <HeadingPitchRoll /> */}
{children} {children}
</Viewer> </Viewer>
); );

View File

@ -63,7 +63,7 @@
color: #02f9ff !important; color: #02f9ff !important;
background-color: #1f485690; background-color: #1f485690;
pointer-events: auto; pointer-events: auto;
font-size: 16px; font-size: 18px;
text-indent: 2em; text-indent: 2em;
line-height: 1.5; line-height: 1.5;
z-index: 999; z-index: 999;