123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>2025竹节草</title>
- <!-- 使用CDN引入Cesium资源 -->
- <link rel="stylesheet" href="https://cesium.com/downloads/cesiumjs/releases/1.98/Build/Cesium/Widgets/widgets.css">
- <script src="https://cesium.com/downloads/cesiumjs/releases/1.98/Build/Cesium/Cesium.js"></script>
- <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
- <!-- 使用CDN引入libgif.js -->
- <script src="https://cdn.jsdelivr.net/npm/libgif-js@0.1.2/libgif.min.js"></script>
- </head>
- <body style="margin: 0; overflow: hidden; background: #fff; width: 100%; height: 100%; position: absolute; top: 0">
- <div id="map" style="margin: 0 auto; width: 100%; height: 100%"></div>
- <ul
- style="position: absolute;z-index: 100;bottom: 30px;right: 10px; color: #fff;background: #000000cc; list-style: none;;">
- <li>
- <span style=" border-radius: 10px; width: 10px;height: 10px; display: inline-block; background: GREEN;"></span>
- <span>热带低压</span>
- </li>
- <li>
- <span style=" border-radius: 10px; width: 10px;height: 10px; display: inline-block; background: BLUE;"></span>
- <span>热带风暴</span>
- </li>
- <li>
- <span
- style=" border-radius: 10px; width: 10px;height: 10px; display: inline-block; background: YELLOW;"></span>
- <span>强热带风暴</span>
- </li>
- <li>
- <span
- style=" border-radius: 10px; width: 10px;height: 10px; display: inline-block; background: #FBC712;"></span>
- <span>台风</span>
- </li>
- <li>
- <span style=" border-radius: 10px; width: 10px;height: 10px; display: inline-block; background: RED;"></span>
- <span>超强台风</span>
- </li>
- </ul>
- <script type="text/javascript">
- // 请替换为你自己的Cesium令牌
- Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI1ODIwOGQ2Ny1hMTFhLTQ4OGQtODJhZi0wNmMzZGNhNjU5OWMiLCJpZCI6NTkzMTMsImlhdCI6MTYyMzk4ODQ4NX0.40CU0i0LswshdxVXAXEJgfEDJN3EK_jPbo_S8lece9E';
- const viewer = new Cesium.Viewer('map', {});
- viewer.camera.setView({
- destination: Cesium.Cartesian3.fromDegrees(120, 20, 4025692.0)
- });
- let fengquanLayers = [];
- initJJ();
- initPoints();
- let myEntityCollection = new Cesium.CustomDataSource("initPointsCollection");
- viewer.dataSources.add(myEntityCollection);
- // 历史点和线
- function initPoints() {
- // 尝试加载数据,如果失败使用备用数据
- axios.get('./src/assets/Data/202508.json')
- .then((response) => {
- let points = response.data.points;
- processPoints(points);
- })
- .catch(error => {
- console.error('加载JSON数据失败,使用测试数据', error);
- // 使用测试数据
- let testPoints = [
- {
- "lng": 120,
- "lat": 20,
- "strong": "台风",
- "forecast": [
- {
- "forecastpoints": [
- {"lng": 121, "lat": 19},
- {"lng": 122, "lat": 18}
- ]
- }
- ]
- },
- {
- "lng": 121,
- "lat": 19.5,
- "strong": "强台风",
- "forecast": []
- }
- ];
- processPoints(testPoints);
- });
- }
- function processPoints(points) {
- let lineArr = [];
- points.forEach(element => {
- let color = Cesium.Color.RED
- lineArr.push(element.lng)
- lineArr.push(element.lat)
- if (element.strong == "热带低压") {
- color = Cesium.Color.GREEN
- } else if (element.strong == "热带风暴") {
- color = Cesium.Color.BLUE
- } else if (element.strong == "强热带风暴") {
- color = Cesium.Color.YELLOW
- } else if (element.strong == "台风") {
- color = Cesium.Color.fromCssColorString("#FBC712")
- } else if (element.strong == "强台风") {
- color = Cesium.Color.PLUM
- } else if (element.strong == "超强台风") {
- color = Cesium.Color.RED
- }
- var entity1 = new Cesium.Entity({
- position: Cesium.Cartesian3.fromDegrees(element.lng, element.lat),
- point: {
- pixelSize: 5,
- color: color
- },
- });
- myEntityCollection.entities.add(entity1);
- });
- viewer.entities.add({
- polyline: {
- positions: Cesium.Cartesian3.fromDegreesArray(lineArr),
- width: 3,
- clampToGround: true,
- material: Cesium.Color.RED,
- }
- });
-
- if (points.length > 0) {
- initForeast(points[points.length - 1])
- adds(points)
- }
- }
- // 预测
- function initForeast(data) {
- let forecast = data.forecast || [];
- let colorArr = [
- Cesium.Color.fromCssColorString("#2D12FB"),
- Cesium.Color.fromCssColorString("#15E5E7"),
- Cesium.Color.fromCssColorString("#15E74A"),
- Cesium.Color.fromCssColorString("#E76F15"),
- Cesium.Color.fromCssColorString("#15D9E7"),
- ];
- forecast.forEach((ele, ii) => {
- let lineArr = [];
- ele.forecastpoints.forEach((e) => {
- lineArr.push(e.lng)
- lineArr.push(e.lat)
- var entity1 = new Cesium.Entity({
- position: Cesium.Cartesian3.fromDegrees(e.lng, e.lat),
- point: {
- pixelSize: 7,
- color: colorArr[ii]
- },
- });
- myEntityCollection.entities.add(entity1);
- })
- viewer.entities.add({
- polyline: {
- positions: Cesium.Cartesian3.fromDegreesArray(lineArr),
- width: 2,
- clampToGround: true,
- material: new Cesium.PolylineDashMaterialProperty({
- color: colorArr[ii]
- }),
- }
- });
- })
- }
- // 警戒线
- function initJJ() {
- // 24 线
- viewer.entities.add({
- name: '24',
- polyline: {
- positions: Cesium.Cartesian3.fromDegreesArray([
- [127, 34],
- [127, 22],
- [119, 18],
- [119, 11],
- [113, 4.5],
- [105, 0]
- ].flat()),
- width: 2,
- material: Cesium.Color.RED,
- clampToGround: true,
- }
- });
- // 48 线
- viewer.entities.add({
- name: '48',
- polyline: {
- positions: Cesium.Cartesian3.fromDegreesArray([
- [132, 34],
- [132, 22],
- [119, 0],
- [105, 0]
- ].flat()),
- width: 2,
- material: Cesium.Color.YELLOW,
- clampToGround: true,
- }
- });
- viewer.entities.add({
- position: Cesium.Cartesian3.fromDegrees(126.129019, 29.104287),
- label: {
- fillColor: Cesium.Color.RED,
- text: '24小时警戒线',
- font: '14pt monospace',
- }
- });
- viewer.entities.add({
- position: Cesium.Cartesian3.fromDegrees(132, 20),
- label: {
- fillColor: Cesium.Color.YELLOW,
- text: '48小时警戒线',
- font: '14pt monospace',
- }
- });
- }
- let iii = 0;
- let currentPointObj;
- let tbentity;
- function adds(data) {
- addTB()
- setInterval(function () {
- // 防止数组越界
- if (iii >= data.length) {
- iii = 0;
- }
-
- let kkk = iii * 2
- currentPointObj = {
- lon: data[iii].lng,
- lat: data[iii].lat,
- circle7: {
- radius1: 350 - kkk,
- radius2: 450 - kkk,
- radius3: 400 - kkk,
- radius4: 350 - kkk,
- },
- circle10: {
- radius1: 250 - kkk,
- radius2: 270 - kkk,
- radius3: 250 - kkk,
- radius4: 220 - kkk,
- },
- circle12: {
- radius1: 170 - kkk,
- radius2: 150 - kkk,
- radius3: 150 - kkk,
- radius4: 170 - kkk,
- }
- };
- tbentity.position = Cesium.Cartesian3.fromDegrees(data[iii].lng, data[iii].lat)
- iii = (iii + 1) % data.length;
- removeTFLayer();
- addTyphoonCircle();
- }, 200);
- }
- function addTB() {
- let div = document.createElement("div");
- let img = document.createElement("img");
- div.appendChild(img);
- img.src = './tf.gif'; // 确保该GIF文件存在或替换为有效路径
- img.onload = () => {
- let rub = new SuperGif({
- gif: img
- })
- rub.load(() => {
- tbentity = viewer.entities.add({
- position: Cesium.Cartesian3.fromDegrees(75.166493, 39.9060534),
- billboard: {
- image: new Cesium.CallbackProperty(() => {
- return rub.get_canvas().toDataURL("image/png");
- }, false),
- scale: 0.1,
- },
- });
- });
- };
-
- // 处理GIF加载失败的情况
- img.onerror = () => {
- console.error('GIF文件加载失败,使用默认标记');
- // 创建一个简单的替代标记
- tbentity = viewer.entities.add({
- position: Cesium.Cartesian3.fromDegrees(75.166493, 39.9060534),
- point: {
- pixelSize: 15,
- color: Cesium.Color.RED,
- outlineColor: Cesium.Color.WHITE,
- outlineWidth: 2
- }
- });
- };
- }
- function removeTFLayer() {
- let arr = fengquanLayers;
- for (let i = 0; i < arr.length; i++) {
- viewer.entities.remove(arr[i])
- }
- fengquanLayers = [];
- }
-
- function addTyphoonCircle() {
- if (!currentPointObj) return;
-
- const circles = ["circle7", "circle10", "circle12"];
- circles.forEach(item => {
- let en = viewer.entities.add({
- id: `tf_polygon_${item}`,
- name: `tf_polygon_${item}`,
- polygon: {
- hierarchy:
- new Cesium.CallbackProperty(() => {
- let points = [];
- if (currentPointObj[item]) {
- points = getTyphoonPolygonPoints(currentPointObj, item)
- } else {
- points = []
- }
- return new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(points));
- }, false),
- material: Cesium.Color.ORANGE.withAlpha(0.05),
- extrudedHeight: 1000,
- outline: true,
- outlineColor: Cesium.Color.ORANGE,
- outlineWidth: 2,
- },
- polyline: {
- positions:
- new Cesium.CallbackProperty(() => {
- let points = [];
- if (currentPointObj[item]) {
- points = getTyphoonPolygonPoints(currentPointObj, item)
- } else {
- points = []
- }
- return new Cesium.Cartesian3.fromDegreesArray(points);
- }, false),
- material: Cesium.Color.ORANGE,
- width: 2,
- height: 1000,
- }
- })
- fengquanLayers.push(en)
- })
- }
-
- // 获取台风圈面的坐标
- function getTyphoonPolygonPoints(pointObj, cNum) {
- let points = []
- let center = [pointObj.lon * 1, pointObj.lat * 1]
- let radiusList = [
- pointObj[cNum]['radius1'],
- pointObj[cNum]['radius2'],
- pointObj[cNum]['radius3'],
- pointObj[cNum]['radius4'],
- ]
- let startAngleList = [0, 90, 180, 270]
- let fx, fy
- startAngleList.forEach((startAngle, index) => {
- let radius = radiusList[index] / 100
- let pointNum = 90
- let endAngle = startAngle + 90
- let sin, cos, x, y, angle
- for (let i = 0; i <= pointNum; i++) {
- angle = startAngle + ((endAngle - startAngle) * i) / pointNum
- sin = Math.sin((angle * Math.PI) / 180)
- cos = Math.cos((angle * Math.PI) / 180)
- x = center[0] + radius * sin
- y = center[1] + radius * cos
- points.push(x, y);
- if (startAngle == 0 && i == 0) {
- fx = x;
- fy = y;
- }
- }
- })
- points.push(fx, fy);
- return points
- }
- </script>
- </body>
- </html>
|