diff --git a/package.json b/package.json index 9fcbe6d..d4b2bee 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "dependencies": { "@ant-design/aliyun-theme": "^0.0.5", "@ant-design/colors": "^7.0.0", + "@ant-design/icons": "^4.7.0", "@craco/craco": "^7.1.0", "@rematch/core": "^2.2.0", "@rematch/loading": "^2.1.2", diff --git a/src/App.js b/src/App.js index 59a2029..5b02128 100644 --- a/src/App.js +++ b/src/App.js @@ -4,6 +4,7 @@ import DomainOne from "@/components/domain/One"; import DomainTwo from "@/components/domain/Two"; import DomainThree from "@/components/domain/Three"; import DomainFour from "@/components/domain/Four"; +import DomainFive from "./components/domain/Five"; import "./App.less"; function App() { @@ -14,6 +15,7 @@ function App() { }> }> }> + }> } /> ); diff --git a/src/App.less b/src/App.less index 5cd42f5..0222a74 100644 --- a/src/App.less +++ b/src/App.less @@ -5,4 +5,5 @@ body, #root { height: 100%; width: 100%; + font-family: sans-serif !important; } diff --git a/src/assets/High.png b/src/assets/High.png new file mode 100644 index 0000000..43bd71a Binary files /dev/null and b/src/assets/High.png differ diff --git a/src/assets/Low.png b/src/assets/Low.png new file mode 100644 index 0000000..8900b63 Binary files /dev/null and b/src/assets/Low.png differ diff --git a/src/assets/anti-Hadleycell.png b/src/assets/anti-Hadleycell.png new file mode 100644 index 0000000..ec3e9e3 Binary files /dev/null and b/src/assets/anti-Hadleycell.png differ diff --git a/src/assets/anticyclone.png b/src/assets/anticyclone.png new file mode 100644 index 0000000..2599680 Binary files /dev/null and b/src/assets/anticyclone.png differ diff --git a/src/assets/cyclone.png b/src/assets/cyclone.png new file mode 100644 index 0000000..3bf61e0 Binary files /dev/null and b/src/assets/cyclone.png differ diff --git a/src/assets/updraft.png b/src/assets/updraft.png new file mode 100644 index 0000000..2c10cb0 Binary files /dev/null and b/src/assets/updraft.png differ diff --git a/src/assets/waterwapor.png b/src/assets/waterwapor.png new file mode 100644 index 0000000..ff67d9d Binary files /dev/null and b/src/assets/waterwapor.png differ diff --git a/src/components/common/CustomToolbar/index.jsx b/src/components/common/CustomToolbar/index.jsx index 3d4598c..c384d11 100644 --- a/src/components/common/CustomToolbar/index.jsx +++ b/src/components/common/CustomToolbar/index.jsx @@ -1,117 +1,130 @@ -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { useNavigate } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router-dom"; import { useCesium } from "resium"; -import { Select } from "antd"; +import { Button, Drawer, List, Select } from "antd"; +import { HomeOutlined, MenuUnfoldOutlined } from "@ant-design/icons"; +import { useMouse } from "ahooks"; +import styles from "./index.module.less"; function CustomToolbar() { const { viewer } = useCesium(); const navigate = useNavigate(); const dispatch = useDispatch(); + const location = useLocation(); 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 [mouseX, setMouseX] = useState(0); + const [drawerOpen, setDrawerOpen] = useState(false); - const navigateHandler = useCallback(() => { - navigate("/home", { replace: true }); - dispatch.data.resetState(); - }, [navigate, dispatch]); - - const showPanelHandler = useCallback( - (value) => { - dispatch.data.updateToolbar({ - showPanel: value, - }); + const mapList = [ + { + label: "首页", + value: "/", + icon: , + onClick: () => { + navigate("/home", { replace: true }); + }, }, - [dispatch] - ); + { + label: "两极协同—拉布拉多海海温偏暖控制夏季高原年代际增温", + value: "/map/1", + icon: , + onClick: () => { + navigate("/map/1", { replace: true }); + }, + }, + { + label: "两极协同—南极涛动有效调节青藏高原降水和加热", + value: "/map/2", + icon: , + onClick: () => { + navigate("/map/2", { replace: true }); + }, + }, + { + label: "两极协同—连接南极和北极的热带大西洋经向模的媒介作用", + value: "/map/3", + icon: , + onClick: () => { + navigate("/map/3", { replace: true }); + }, + }, + { + label: "三极联动影响青藏高原上层温度", + value: "/map/4", + icon: , + onClick: () => { + navigate("/map/4", { replace: true }); + }, + }, + { + label: "三级联动影响东亚夏季风", + value: "/map/5", + icon: , + onClick: () => { + navigate("/map/5", { replace: true }); + }, + }, + ]; + + useEffect(() => { + const handleMouseMove = (event) => { + setMouseX(event.clientX); + }; + + document.addEventListener("mousemove", handleMouseMove); + + return () => { + document.removeEventListener("mousemove", handleMouseMove); + }; + }, []); + + const isAtRightEdge = mouseX >= window.innerWidth - 10; + const iaClose = mouseX + 320 <= window.innerWidth; + + useEffect(() => { + if (isAtRightEdge && !drawerOpen) { + setDrawerOpen(true); + } else if (iaClose && drawerOpen) { + setDrawerOpen(false); + } + }, [isAtRightEdge, iaClose]); + + const onDrawerClose = useCallback(() => { + setDrawerOpen(false); + }, []); return ( -
-
- 返回首页 -
- {/* node} - options={[ - { - value: true, - label: "开启展板", - }, - { - value: false, - label: "关闭展板", - }, - ]} - /> +
+ + { + return ( + + + + ); + }} + > +
); } diff --git a/src/components/common/CustomToolbar/index.module.less b/src/components/common/CustomToolbar/index.module.less new file mode 100644 index 0000000..fa8a2d4 --- /dev/null +++ b/src/components/common/CustomToolbar/index.module.less @@ -0,0 +1,54 @@ +.drawerToolbar :global { + transition: all 0.3s ease; + + .ant-drawer-content-wrapper { + .ant-drawer-content { + background-color: #1f4856; + + .ant-drawer-body { + padding: 0; + + .ant-list { + .ant-list-item { + .ant-list-item-meta { + // justify-content: center; + align-items: center; + + .ant-list-item-meta-avatar { + font-size: 24px; + color: aliceblue; + margin-left: 16px; + } + + .ant-list-item-meta-content { + .ant-list-item-meta-title { + font-size: 1.2rem; + color: aliceblue; + } + } + } + + &:hover { + cursor: pointer; + background-color: #94bebf; + + .ant-list-item-meta-avatar { + color: #1f4856; + } + + .ant-list-item-meta-content { + .ant-list-item-meta-title { + color: #1f4856; + } + } + } + } + + .active-item { + background-color: cadetblue !important; + } + } + } + } + } +} diff --git a/src/components/common/TextInfoPanel/index.jsx b/src/components/common/TextInfoPanel/index.jsx index 42754b5..a9f31e5 100644 --- a/src/components/common/TextInfoPanel/index.jsx +++ b/src/components/common/TextInfoPanel/index.jsx @@ -4,7 +4,8 @@ import { Scrollbars } from "react-custom-scrollbars-2"; import { useInterval } from "ahooks"; let index = 0; -function TextInfoPanel({ title, content }) { + +function TextInfoPanel({ content }) { const showNumberPerTimes = 1; const { toolbar } = useSelector((state) => state.data); diff --git a/src/components/domain/Five/ChartPanel.jsx b/src/components/domain/Five/ChartPanel.jsx new file mode 100644 index 0000000..4197b77 --- /dev/null +++ b/src/components/domain/Five/ChartPanel.jsx @@ -0,0 +1,115 @@ +import ReactECharts from "echarts-for-react"; + +const years = []; + +for (let year = 2011; year <= 2020; year++) { + years.push(year); +} + +const observedData = [ + -0.90765893, 0.14846958, 1.6577014, -0.32029018, -1.2422978, 0.44113398, + -0.45218363, 1.897564, -0.6926195, -0.529819, +]; + +const predictedData = [ + -0.20760797, 0.206235, 0.85673275, 0.13969683, -0.39370838, 0.23775028, + -0.34866039, 0.93110625, 0.19143088, 0.5760311, +]; + +function ChartPanel() { + const option = { + title: { + // text: "Stacked Line", + }, + tooltip: { + trigger: "axis", + }, + legend: { + data: ["观测结果", "预测结果"], + 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: -2.0, + 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: "观测结果", + type: "line", + stack: "Total", + data: observedData, + color: "black", + symbol: "none", + itemStyle: { + color: "black", + }, + }, + { + name: "预测结果", + type: "line", + // stack: "Total", + data: predictedData, + color: "red", + symbol: "none", + itemStyle: { + color: "red", + }, + }, + ], + }; + + return ( +
+ +
+ ); +} + +export default ChartPanel; diff --git a/src/components/domain/Five/CustomFlyTo.jsx b/src/components/domain/Five/CustomFlyTo.jsx new file mode 100644 index 0000000..9b37ed6 --- /dev/null +++ b/src/components/domain/Five/CustomFlyTo.jsx @@ -0,0 +1,11 @@ +import { Cartesian3 } from "cesium"; +import { CameraFlyTo } from "resium"; + +export default function CustomFlyTo() { + return ( + + ); +} diff --git a/src/components/domain/Five/FormPanel.jsx b/src/components/domain/Five/FormPanel.jsx new file mode 100644 index 0000000..4e30750 --- /dev/null +++ b/src/components/domain/Five/FormPanel.jsx @@ -0,0 +1,133 @@ +import { Button, Form, Input, Select } from "antd"; + +const layout = { + labelCol: { span: 6 }, + wrapperCol: { span: 16 }, +}; +const tailLayout = { + wrapperCol: { offset: 6, span: 16 }, +}; + +const { Option } = Select; + +export default function FormPanel({ setShow }) { + const [form] = Form.useForm(); + + return ( +
+
{ + console.log("Success:", values); + setShow(true); + }} + > + + + + + + + +
+
+ ); +} diff --git a/src/components/domain/Five/index.jsx b/src/components/domain/Five/index.jsx new file mode 100644 index 0000000..16ddca8 --- /dev/null +++ b/src/components/domain/Five/index.jsx @@ -0,0 +1,35 @@ +import MapLayout from "@/components/map/Layout"; +import CustomToolbar from "@/components/common/CustomToolbar"; +import CustomClock from "@/components/common/CustomClock"; +import TextInfoPanel from "@/components/common/TextInfoPanel"; +import CustomFlyTo from "./CustomFlyTo"; +import FormPanel from "./FormPanel"; +import ChartPanel from "./ChartPanel"; +// import RectangleLayer from "./RectangleLayer"; +import { useState } from "react"; + +export default function DomainFive() { + const [show, setShow] = useState(false); + + return ( + +
三极联动影响东亚夏季风
+ + + +
+ +
+
+
+ +
+
{show && }
+
+ {/* */} +
+ ); +} diff --git a/src/components/domain/Four/FormPanel.jsx b/src/components/domain/Four/FormPanel.jsx index cf066d2..b1aec62 100644 --- a/src/components/domain/Four/FormPanel.jsx +++ b/src/components/domain/Four/FormPanel.jsx @@ -1,14 +1,16 @@ import { Button, Form, Input, Select } from "antd"; const layout = { - labelCol: { span: 8 }, + labelCol: { span: 6 }, wrapperCol: { span: 16 }, }; const tailLayout = { - wrapperCol: { offset: 8, span: 16 }, + wrapperCol: { offset: 6, span: 16 }, }; -export default function FormPanel() { +const { Option } = Select; + +export default function FormPanel({ setShow }) { const [form] = Form.useForm(); return ( @@ -18,21 +20,52 @@ export default function FormPanel() { form={form} name="control-hooks" initialValues={{ - sic: "sic_s", + sic: ["sic_s"], + sce: ["sc_ea", "sc_tp"], + st: [ + "ts_1", + "ts_2", + "ts_3", + "ts_4", + "ts_5", + "ts_6", + "ts_7", + "ts_8", + "ts_9", + "ts_10", + "ts_11", + "ts_12", + ], + }} + onFinish={(values) => { + console.log("Success:", values); + setShow(true); }} > - + - + - +