leaflet.motion台风路径动画绘制

在气象领域中,对台风的准确可视化呈现对于灾害预警和防范具有重要意义。本文将深入探讨一段使用 JavaScript 实现台风可视化功能的代码。原本只是简单的绘制台风的路径,但是后面的需求要求显示台风各个历史节点的动画绘制,于是难度增加了,最后还是使用leaflet的插件(leaflet.motion)完成了动画需求,以下就来介绍我的动画实现方式,请多指教。

一、代码结构与模块导入

首先,代码通过一系列的 import 语句引入了所需的模块和库,如 typhone_typetyphoon_directiontyphoonCircle_colors 等,为后续的台风绘制和数据处理提供了基础支持。这个是内部的一个字典库,可以自己定义,这里就不放出来了。

二、useTyphoon 函数

这是核心的函数,用于处理台风数据与地图的交互。

数据存储与缓存

函数内部定义了多个变量用于存储台风绘制的要素集合、已绘制的台风 ID 缓存等。避免每次绘制都是全清,然后全部一起绘制的情况。

绘制台风相关要素

通过 drawTyphoonByCodes 方法,根据传入的台风 ID 数组,进行新增和删除台风要素的处理。对于新增的台风,依次绘制实况线、未来线、当前标记、标题等。

线的绘制与动画效果

motionPolyline 函数用于动态绘制线,并可设置线的样式和是否显示气流图标。这里就是使用leaflet的插件(leaflet.motion)实现的,也是实现动画的主要代码块。

清除台风要素

clearFeaturesByIds 函数用于删除指定 ID 的台风相关要素。

三、辅助函数

convertKtsToBeaufort 函数用于将风速单位从节(kts)转换为蒲福风级。

drawTitle 函数用于在台风标记上添加名称。

getTyphoonContent 函数根据台风 ID、节点数据和类型生成不同的弹出内容。

getTyphoonDirection 函数将方向编码转换为中文描述。

四、具体绘制函数

drawLiveLine 绘制台风实况线,并为节点添加标记和弹出内容。

drawCurrentMarker 标记台风当前所在位置,并设置弹出内容。

drawFutureLine 绘制未来线。

drawWindCircle 绘制不同等级的风圈。

这段代码通过精细的设计和功能划分,实现了在地图上对台风相关要素的动态绘制和管理,为气象数据的可视化展示提供了强大的支持。

五、数据

使用的数据比较难懂,竟然不是json而是一个数组,我也只能按这种数据格式组织以下的代码

[
"2927830": {
    "name": "马力斯(MALIKSI)",
    "data": [
      2927830,
      "MALIKSI",
      "马力斯",
      2402,
      2402,
      20240002,
      "菲律宾语,快速的意思",
      "stop",
      [
        [
          2927836,
          "202405300900",
          1717059600000,
          "TD",
          112.2,
          17.4,
          1000,
          15,
          "N",
          26,
          [],
          {
            "BABJ": [
              [
                12,
                "202405300900",
                112.3,
                20.2,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                24,
                "202405300900",
                112.1,
                21.4,
                995,
                20,
                "BABJ",
                "TS"
              ],
              [
                36,
                "202405300900",
                112.8,
                22.7,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                48,
                "202405300900",
                114.1,
                23.7,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405301700",
            "2024年05月30日17时00分",
            null,
            null
          ]
        ],
        [
          2927842,
          "202405301200",
          1717070400000,
          "TD",
          112.1,
          17.8,
          1000,
          15,
          "N",
          24,
          [],
          {
            "BABJ": [
              [
                12,
                "202405301200",
                112.2,
                20.3,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                24,
                "202405301200",
                112.2,
                21.7,
                995,
                20,
                "BABJ",
                "TS"
              ],
              [
                36,
                "202405301200",
                112.8,
                22.9,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                48,
                "202405301200",
                114.7,
                24.1,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405302000",
            "2024年05月30日20时00分",
            null,
            null
          ]
        ],
        [
          2927848,
          "202405301500",
          1717081200000,
          "TD",
          111.9,
          18.5,
          1000,
          15,
          "N",
          17,
          [],
          {
            "BABJ": [
              [
                12,
                "202405301500",
                112,
                20.3,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                24,
                "202405301500",
                112.4,
                21.7,
                995,
                20,
                "BABJ",
                "TS"
              ],
              [
                36,
                "202405301500",
                113,
                23,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                48,
                "202405301500",
                114.9,
                24,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405302300",
            "2024年05月30日23时00分",
            null,
            null
          ]
        ],
        [
          2927854,
          "202405301800",
          1717092000000,
          "TD",
          111.5,
          18.9,
          1000,
          15,
          "NNE",
          15,
          [],
          {
            "BABJ": [
              [
                12,
                "202405301800",
                112.1,
                20.4,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                24,
                "202405301800",
                112.5,
                22,
                995,
                20,
                "BABJ",
                "TS"
              ],
              [
                36,
                "202405301800",
                113.5,
                23.3,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                48,
                "202405301800",
                115.6,
                24.2,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405310200",
            "2024年05月31日02时00分",
            null,
            null
          ]
        ],
        [
          2927859,
          "202405302100",
          1717102800000,
          "TD",
          111.5,
          18.9,
          1000,
          15,
          "NNE",
          17,
          [],
          {
            "BABJ": [
              [
                12,
                "202405302100",
                111.9,
                20.6,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                24,
                "202405302100",
                112.3,
                22.3,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                36,
                "202405302100",
                113.8,
                23.8,
                1000,
                15,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405310500",
            "2024年05月31日05时00分",
            null,
            null
          ]
        ],
        [
          2927864,
          "202405310000",
          1717113600000,
          "TD",
          111.6,
          19.1,
          1000,
          15,
          "NNE",
          19,
          [],
          {
            "BABJ": [
              [
                12,
                "202405310000",
                112.1,
                21,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                24,
                "202405310000",
                112.7,
                22.8,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405310000",
                114,
                23.8,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405310800",
            "2024年05月31日08时00分",
            null,
            null
          ]
        ],
        [
          2927869,
          "202405310300",
          1717124400000,
          "TD",
          111.9,
          20.3,
          1000,
          15,
          "NNE",
          15,
          [],
          {
            "BABJ": [
              [
                12,
                "202405310300",
                112.2,
                21.8,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                24,
                "202405310300",
                112.7,
                23,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405310300",
                114.1,
                24,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405311100",
            "2024年05月31日11时00分",
            null,
            null
          ]
        ],
        [
          2927917,
          "202405310600",
          1717135200000,
          "TS",
          111.9,
          20.3,
          998,
          18,
          "NNE",
          15,
          [
            [
              "30KTS",
              80,
              150,
              120,
              60,
              2927917
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405310600",
                111.9,
                21.1,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                12,
                "202405310600",
                112.2,
                21.8,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                18,
                "202405310600",
                112.6,
                22.7,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405310600",
                113.1,
                23.5,
                1002,
                13,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405310600",
                114.6,
                24.5,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405311400",
            "2024年05月31日14时00分",
            null,
            null
          ]
        ],
        [
          2927928,
          "202405310700",
          1717138800000,
          "TS",
          111.9,
          20.3,
          998,
          18,
          "NNE",
          15,
          [
            [
              "30KTS",
              80,
              150,
              120,
              60,
              2927928
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405310700",
                111.95,
                21.2167,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                12,
                "202405310700",
                112.2667,
                21.95,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                18,
                "202405310700",
                112.6833,
                22.8333,
                1000,
                14,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405310700",
                113.225,
                23.5833,
                1000,
                13,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405310700",
                114.725,
                24.5833,
                1000,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405311500",
            "2024年05月31日15时00分",
            null,
            null
          ]
        ],
        [
          2927942,
          "202405310800",
          1717142400000,
          "TS",
          111.9,
          20.3,
          998,
          18,
          "NNE",
          15,
          [
            [
              "30KTS",
              80,
              150,
              120,
              60,
              2927942
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405310800",
                112,
                21.3333,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                12,
                "202405310800",
                112.3333,
                22.1,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                18,
                "202405310800",
                112.7667,
                22.9667,
                1000,
                14,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405310800",
                113.35,
                23.6667,
                1000,
                13,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405310800",
                114.85,
                24.6667,
                1000,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405311600",
            "2024年05月31日16时00分",
            null,
            null
          ]
        ],
        [
          2927953,
          "202405310900",
          1717146000000,
          "TS",
          111.9,
          20.4,
          998,
          18,
          "N",
          16,
          [
            [
              "30KTS",
              80,
              150,
              120,
              60,
              2927953
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405310900",
                111.8,
                21.2,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                12,
                "202405310900",
                112.2,
                22.1,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405310900",
                112.8,
                23,
                1002,
                13,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405310900",
                113.3,
                23.8,
                1004,
                12,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405310900",
                115.5,
                24.7,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405311700",
            "2024年05月31日17时00分",
            null,
            null
          ]
        ],
        [
          2928006,
          "202405311000",
          1717149600000,
          "TS",
          111.9,
          20.5,
          998,
          18,
          "N",
          16,
          [
            [
              "30KTS",
              80,
              150,
              120,
              60,
              2928006
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405311000",
                111.8667,
                21.35,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                12,
                "202405311000",
                112.3,
                22.25,
                1000,
                14,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405311000",
                112.8833,
                23.1333,
                1000,
                13,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405311000",
                113.4833,
                23.875,
                1000,
                12,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405311000",
                115.6833,
                24.775,
                1000,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405311800",
            "2024年05月31日18时00分",
            null,
            null
          ]
        ],
        [
          2928020,
          "202405311100",
          1717153200000,
          "TS",
          111.9,
          20.5,
          998,
          18,
          "N",
          16,
          [
            [
              "30KTS",
              80,
              150,
              120,
              60,
              2928020
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405311100",
                111.9333,
                21.5,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                12,
                "202405311100",
                112.4,
                22.4,
                1000,
                14,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405311100",
                112.9667,
                23.2667,
                1000,
                12,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405311100",
                113.6667,
                23.95,
                1000,
                12,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405311100",
                115.8667,
                24.85,
                1000,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405311900",
            "2024年05月31日19时00分",
            null,
            null
          ]
        ],
        [
          2928078,
          "202405311200",
          1717156800000,
          "TS",
          111.4,
          20.7,
          998,
          18,
          "NNE",
          22,
          [
            [
              "30KTS",
              80,
              150,
              120,
              60,
              2928078
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405311200",
                111.7,
                21.9,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                12,
                "202405311200",
                112.2,
                22.9,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405311200",
                113,
                23.8,
                1002,
                13,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405311200",
                113.9,
                24.4,
                1004,
                12,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405311200",
                116.3,
                24.9,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405312000",
            "2024年05月31日20时00分",
            null,
            null
          ]
        ],
        [
          2928087,
          "202405311300",
          1717160400000,
          "TS",
          111.4,
          20.9,
          998,
          18,
          "NNE",
          20,
          [
            [
              "30KTS",
              70,
              150,
              100,
              50,
              2928087
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405311300",
                111.7833,
                22.0667,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                12,
                "202405311300",
                112.3333,
                23.05,
                1000,
                14,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405311300",
                113.15,
                23.9,
                1000,
                13,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405311300",
                114.1,
                24.4417,
                1000,
                12,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405311300",
                116.5,
                24.9417,
                1000,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405312100",
            "2024年05月31日21时00分",
            null,
            null
          ]
        ],
        [
          2928101,
          "202405311400",
          1717164000000,
          "TS",
          111.5,
          21.1,
          998,
          18,
          "NNE",
          18,
          [
            [
              "30KTS",
              50,
              150,
              100,
              40,
              2928101
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405311400",
                111.8667,
                22.2333,
                998,
                18,
                "BABJ",
                "TS"
              ],
              [
                12,
                "202405311400",
                112.4667,
                23.2,
                1000,
                14,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405311400",
                113.3,
                24,
                1000,
                12,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405311400",
                114.3,
                24.4833,
                1000,
                12,
                "BABJ",
                "TD"
              ],
              [
                36,
                "202405311400",
                116.7,
                24.9833,
                1000,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405312200",
            "2024年05月31日22时00分",
            null,
            null
          ]
        ],
        [
          2928144,
          "202405311500",
          1717167600000,
          "TS",
          111.5,
          21.2,
          998,
          18,
          "NNE",
          22,
          [
            [
              "30KTS",
              50,
              150,
              100,
              40,
              2928144
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405311500",
                111.9,
                22.3,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                12,
                "202405311500",
                112.6,
                23.3,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405311500",
                113.4,
                24.2,
                1002,
                13,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405311500",
                114.6,
                24.9,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202405312300",
            "2024年05月31日23时00分",
            null,
            null
          ]
        ],
        [
          2928154,
          "202405311600",
          1717171200000,
          "TS",
          111.5,
          21.2,
          998,
          18,
          "NNE",
          22,
          [
            [
              "30KTS",
              30,
              150,
              100,
              30,
              2928154
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405311600",
                112.0167,
                22.4667,
                998,
                15,
                "BABJ",
                "TD"
              ],
              [
                12,
                "202405311600",
                112.7333,
                23.45,
                1000,
                14,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405311600",
                113.6,
                24.3167,
                1000,
                13,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405311600",
                114.8,
                25.0167,
                1000,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202406010000",
            "2024年06月01日00时00分",
            null,
            null
          ]
        ],
        [
          2928165,
          "202405311700",
          1717174800000,
          "TS",
          111.7,
          21.6,
          998,
          18,
          "NNE",
          18,
          [],
          {
            "BABJ": [
              [
                6,
                "202405311700",
                112.1333,
                22.6333,
                998,
                15,
                "BABJ",
                "TD"
              ],
              [
                12,
                "202405311700",
                112.8667,
                23.6,
                1000,
                14,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405311700",
                113.8,
                24.4333,
                1000,
                12,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405311700",
                115,
                25.1333,
                1000,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202406010100",
            "2024年06月01日01时00分",
            null,
            null
          ]
        ],
        [
          2928203,
          "202405311800",
          1717178400000,
          "TD",
          111.7,
          21.6,
          1000,
          15,
          "NNE",
          22,
          [],
          {
            "BABJ": [
              [
                6,
                "202405311800",
                112.1,
                22.7,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                12,
                "202405311800",
                112.9,
                23.7,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405311800",
                113.9,
                24.5,
                1002,
                13,
                "BABJ",
                "TD"
              ],
              [
                24,
                "202405311800",
                115.2,
                25.2,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202406010200",
            "2024年06月01日02时00分",
            null,
            null
          ]
        ],
        [
          2928231,
          "202405312100",
          1717189200000,
          "TD",
          111.8,
          22,
          1000,
          15,
          "NNE",
          21,
          [
            [
              "30KTS",
              30,
              150,
              100,
              30,
              2928231
            ]
          ],
          {
            "BABJ": [
              [
                6,
                "202405312100",
                112.4,
                23,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                12,
                "202405312100",
                113.1,
                23.9,
                1002,
                13,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202405312100",
                114.1,
                24.6,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202406010454",
            "2024年06月01日04时54分",
            null,
            null
          ]
        ],
        [
          2928259,
          "202406010000",
          1717200000000,
          "TD",
          112.2,
          22.6,
          1000,
          15,
          "NNE",
          20,
          [],
          {
            "BABJ": [
              [
                6,
                "202406010000",
                112.6,
                23.5,
                1000,
                15,
                "BABJ",
                "TD"
              ],
              [
                12,
                "202406010000",
                113.2,
                24.4,
                1002,
                13,
                "BABJ",
                "TD"
              ],
              [
                18,
                "202406010000",
                114.6,
                25.1,
                1004,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202406010800",
            "2024年06月01日08时00分",
            null,
            null
          ]
        ],
        [
          2928279,
          "202406010300",
          1717210800000,
          "TD",
          112.4,
          22.8,
          1000,
          15,
          "NE",
          20,
          [],
          {
            "BABJ": [
              [
                6,
                "202406010300",
                112.9,
                23.9,
                1000,
                13,
                "BABJ",
                "TD"
              ],
              [
                12,
                "202406010300",
                113.9,
                24.6,
                1002,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202406011100",
            "2024年06月01日11时00分",
            null,
            null
          ]
        ],
        [
          2928297,
          "202406010600",
          1717221600000,
          "TD",
          112.6,
          23.3,
          1002,
          13,
          "NE",
          24,
          [],
          {
            "BABJ": [
              [
                6,
                "202406010600",
                113.4,
                24.3,
                1002,
                13,
                "BABJ",
                "TD"
              ],
              [
                12,
                "202406010600",
                114.6,
                25,
                1003,
                12,
                "BABJ",
                "TD"
              ]
            ]
          },
          [
            "202406011400",
            "2024年06月01日14时00分",
            null,
            null
          ]
        ]
      ],
      null
    ]
  }
]

六、完整代码

import {typhone_type, typhoon_direction, typhoonCircle_colors} from "@/utils/leaflet/L.typhoon";
import '@/utils/leaflet/L.typhoon.js'
import moment from "moment";
import 'leaflet.animatedmarker/src/AnimatedMarker';
import 'leaflet.motion/dist/leaflmotion';

/**
 * 风相关的hook
 * @param typhoonData 台风数据
 * @param map 地图实例
 * @param duration 绘制间隔时间
 * @returns {{drawTyphoonByCodes: drawTyphoonByCodes, clearFeaturesByIds: clearFeaturesByIds}}
 */
export function useTyphoon(typhoonData, map, duration = 10) {
    //所有台风绘制的要素group的集合
    let allTyphoonList = {};

    //所有台风绘制的要素group的集合
    let allFeatureGroup = {};

    //已经绘制的台风id集合(缓存)
    let typhoonIds_cache = [];

    /**
     * 根据台风数据的code,绘制台风相关的要素
     * @param ids 台风id数组
     */
    function drawTyphoonByCodes(ids = []) {
        //新增的台风id集合
        let addIds = ids.filter(id => !typhoonIds_cache.includes(id));
        //删除的台风id集合
        let deleteIds = typhoonIds_cache.filter(id => !ids.includes(id));
        if (deleteIds.length > 0) {
            clearFeaturesByIds(deleteIds);
        }

        addIds.forEach(id => {
            allTyphoonList = {
                ...allTyphoonList, [id]: {
                    liveLine: null, futureLine: null, currentMarker: null, windCircle: null, title: null
                }
            }
            drawFutureLine(id);
            drawLiveLine(id);
            drawCurrentMarker(id);
            drawTitle(id);
        });

        typhoonIds_cache = [...typhoonIds_cache, ...addIds];
        Object.entries(allTyphoonList).forEach(([id, typhoon]) => {
            let {liveLine, futureLine, title, currentMarker, windCircle} = typhoon || {};
            if (!(liveLine && title && currentMarker) || !addIds.includes(id)) {
                return;
            }

            futureLine = futureLine || [];

            //当前这个台风的featureGroup
            let currentFeatureGroup = allFeatureGroup?.[id];
            if (!currentFeatureGroup) {
                currentFeatureGroup = L.featureGroup().addTo(map);
                allFeatureGroup = {...allFeatureGroup, [id]: currentFeatureGroup};
            }

            //添加线的动画效果(实况)
            let liveSeqGroup = L.motion.seq([...liveLine], {
                auto: false,
            }).addTo(currentFeatureGroup);

            //添加线的动画效果(预报)
            let futureSeqGroup = L.motion.seq([...futureLine], {
                auto: false,
            }).addTo(currentFeatureGroup);

            //动态添加圆形气流图标(实况)
            liveSeqGroup.on(L.Motion.Event.Section, (e) => {
                let {sourceTarget} = e;
                let {_activeLayer: {options: {circleMarker}}} = sourceTarget;
                if (circleMarker) {
                    circleMarker.addTo(currentFeatureGroup);
                }
            });

            //实况绘制完成,开始绘制预报
            liveSeqGroup.on(L.Motion.Event.Ended, (e) => {
                //添加当前台风的实况圆形气流图标
                currentMarker.addTo(currentFeatureGroup);
                futureSeqGroup.motionStart();
            });

            //动态添加圆形气流图标(未来)
            futureSeqGroup.on(L.Motion.Event.Section, (e) => {
                let {sourceTarget} = e;
                let {_activeLayer: {options: {circleMarker}}} = sourceTarget;
                if (circleMarker) {
                    circleMarker.addTo(currentFeatureGroup);
                }

                if (windCircle?.length > 0) {
                    windCircle.forEach((feature) => {
                        currentFeatureGroup.addLayer(feature);
                    });
                }
            });

            title.addTo(currentFeatureGroup);
            map.flyTo(title?.getLatLng());
            setTimeout(() => {
                liveSeqGroup.motionStart();
            }, 500);
        });
    }

    /**
     * 获取风的级别
     * @param kts 风速(kts)
     * @returns {number}
     */
    function convertKtsToBeaufort(kts) {
        if (kts >= 0 && kts <= 1) {
            return 0;
        } else if (kts <= 3) {
            return 1;
        } else if (kts <= 6) {
            return 2;
        } else if (kts <= 10) {
            return 3;
        } else if (kts <= 16) {
            return 4;
        } else if (kts <= 21) {
            return 5;
        } else if (kts <= 27) {
            return 6;
        } else if (kts <= 33) {
            return 7;
        } else if (kts <= 40) {
            return 8;
        } else if (kts <= 47) {
            return 9;
        } else if (kts <= 55) {
            return 10;
        } else if (kts <= 63) {
            return 11;
        } else {
            return 12;
        }
    }

    /**
     * 动态绘制线
     * @param latLngs 线的坐标数组
     * @param options 线的样式
     * @param showMarker 是否显示气流图标
     * @returns {*}
     */
    function motionPolyline(latLngs = [], options = {color: "transparent"}, showMarker = true) {
        return L.motion.polyline(latLngs, options, {
            autoStart: false, duration: duration, easing: L.Motion.Ease.easeInOutQuart
        }, showMarker ? {
            removeOnEnd: true, showMarker: false, icon: L.icon({
                iconUrl: require('@/assets/typhoon/typhoon.gif'), size: [50, 50], iconAnchor: [25, 25]
            }),
        } : null);
    }

    /**
     * 删除指定id的台风相关的要素
     * @param ids 台风id数组
     */
    function clearFeaturesByIds(ids = []) {
        if (ids.length === 0) {
            Object.values(allFeatureGroup).forEach(typhoonGroup => {
                if (typhoonGroup) {
                    typhoonGroup.clearLayers();
                    typhoonGroup.eachLayer((feature) => {
                        typhoonGroup.removeLayer(feature);
                    });
                }
            });
            allTyphoonList = {};
            typhoonIds_cache = [];
            return;
        }

        ids.forEach(id => {
            let typhoonGroup = allFeatureGroup?.[id];
            if (typhoonGroup) {
                typhoonGroup.clearLayers();
                typhoonGroup.eachLayer((feature) => {
                    typhoonGroup.removeLayer(feature);
                });

                delete allTyphoonList[id];
                typhoonIds_cache = typhoonIds_cache.filter(item => item !== id);
            }
        });
    }

    /**
     * 台风名称添加到marker上
     * @param id 台风id
     */
    function drawTitle(id) {
        const data = typhoonData?.[id]?.data;
        if (data) {
            const center = [data?.[8]?.[0]?.[5], data?.[8]?.[0]?.[4]];
            let [, code, name] = data;
            let titleStr = `<div style="font-size: 14px;font-weight: bold;color: #333;text-align: center;white-space: nowrap;text-shadow:  -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;">${name}(${code})</div>`;
            const title = L.divIcon({
                html: titleStr, className: 'title-text', iconSize: [10, 14], iconAnchor: [-10, 7],
            });
            allTyphoonList[id].title = L.marker(center, {icon: title});
        }
    }

    /**
     * 获取台风节点的popup内容
     * @param id 台风id
     * @param pointData 节点数据
     * @param type
     * @returns {string}
     */
    function getTyphoonContent(id, pointData, type) {
        //当前这个台风的信息
        const currentTyphoonData = typhoonData?.[id]?.data;
        if (!currentTyphoonData) {
            return '';
        }
        //这个台风实况节点的时间
        const tbj = pointData?.[2] ? moment(pointData[2]).format('YYYY年MM月DD日HH时') : null;
        let content;

        //台风英文名称
        let typhoonECName = currentTyphoonData[1];
        //台风名称
        let typhoonName = currentTyphoonData[2];
        //台风编号
        let typhoonNum = currentTyphoonData[4];

        //节点中心位置
        let centerPosition = [`${pointData[5]?.toFixed(1)}N/,${pointData[4]?.toFixed(1)}E`];
        //节点最大风速
        let maxWindSpeed = `${pointData[7]}米/秒`;
        //节点中心气压
        let centerPressure = `${pointData[6]}百帕`;
        //节点移动方向
        let moveDirection = `${getTyphoonDirection(pointData[8])}`;
        //节点移动速度
        let moveSpeed = `${pointData[9]}公里/小时`;

        //如果是台风预测节点
        if (type === 'FutureMarker') {
            //台风实况路径节点数据集合
            const points = currentTyphoonData?.[8] || [];
            //最后一个实况节点数据
            let lastPoint = points[points.length - 1];
            //预报机构
            let forecastInstitution = pointData[6] ? (pointData[6] === 'BABJ' ? '中央气象台' : data[6]) : '';
            let _d = moment(lastPoint[2] + pointData[0] * 3600000).format('YYYY年MM月DD日HH时');

            centerPosition = `${pointData[3].toFixed(1)}N/${pointData[2].toFixed(1)}E`;
            maxWindSpeed = `${pointData[5]}米/秒`;
            centerPressure = `${pointData[4]}百帕`;
            content = '<div class=\'customLeafletPopup\'>' + '<div class=\'popupTitle\'>' + typhoonNum + (typhoonName ? typhoonName : typhoonECName) + '</div>' + '<table style = \'font-family: 微软雅黑; font-weight: normal; margin-top:5px;font-size: 12px;\' cellspacing=\'0\' cellpadding=\'0\' width=\'170px\'>' + '<tr><td class="label" width=\'65px\'>预报机构:</td><td>' + forecastInstitution + '</td></tr>' + '<tr><td class="label">到达时间:</td><td>' + _d + '</td></tr>' + '<tr><td class="label">中心位置:</td><td>' + centerPosition + '</td></tr>' + '<tr><td class="label">最大风速:</td><td>' + maxWindSpeed + '</td></tr>' + '<tr><td class="label">中心气压:</td><td>' + centerPressure + '</td></tr>' + '</table></div>';
        } else if (type === 'CurrentMarker') {
            let windCircleInfo = pointData?.[10];

            let windCircleList = windCircleInfo.map((item, index) => {
                let [windLevel, eastNorth, eastSouth, westSouth, westNorth] = item;
                windLevel = windLevel.toUpperCase().replace('KTS', '');
                windLevel = convertKtsToBeaufort(windLevel);
                return `<div class="flex" style="background: rgba(6, 22, 67, 0.12);padding: 4px 0;border-radius: 4px;margin-bottom: 4px;">
                      <div class="circle-level" style="color:${typhoonCircle_colors[{
                    7: 0, 10: 1, 12: 2
                }[windLevel]]?.color};font-family: MiSans,serif;font-size: 16px;font-weight: 500;line-height: normal;letter-spacing: 0;margin-right: 10px;text-align: right;">
                      <div style="width: 40px;font-weight: 500;line-height: 35px;">${windLevel}级</div>
                      </div>
                      <div style="margin-right: 24px;text-align: center;">
                      <div style="font-family: MiSans,serif;font-size: 12px;font-weight: normal;line-height: normal;letter-spacing: 0;color: rgba(255, 255, 255, 0.6);">东北</div>
                      <div style="text-align:center;font-family: MiSans,serif;font-size: 14px;font-weight: 600;line-height: normal;letter-spacing: 0;color: rgba(255, 255, 255, 0.9);width: 30px;">${eastNorth}</div>
                      </div>
                     <div style="margin-right: 24px;text-align: center;;">
                    <div style="font-family: MiSans,serif;font-size: 12px;font-weight: normal;line-height: normal;letter-spacing: 0;color: rgba(255, 255, 255, 0.6);">东南</div>
                    <div style="text-align:center;font-family: MiSans,serif;font-size: 14px;font-weight: 600;line-height: normal;letter-spacing: 0;color: rgba(255, 255, 255, 0.9);width: 30px;">${eastSouth}</div>
                    </div>
                    <div style="margin-right: 24px;text-align: center;;">
                    <div style="font-family: MiSans,serif;font-size: 12px;font-weight: normal;line-height: normal;letter-spacing: 0;color: rgba(255, 255, 255, 0.6);">西南</div>
                    <div style="text-align:center;font-family: MiSans,serif;font-size: 14px;font-weight: 600;line-height: normal;letter-spacing: 0;color: rgba(255, 255, 255, 0.9);width: 30px;">${westSouth}</div>
                    </div>
                    <div style="margin-right: 24px;text-align: center;;">
                    <div style="font-family: MiSans,serif;font-size: 12px;font-weight: normal;line-height: normal;letter-spacing: 0;color: rgba(255, 255, 255, 0.6);">西北</div>
                    <div style="text-align:center;font-family: MiSans,serif;font-size: 14px;font-weight: 600;line-height: normal;letter-spacing: 0;color: rgba(255, 255, 255, 0.9);width: 30px;">${westNorth}</div>
                    </div>
                </div>`;
            }).join('');

            content = '<div class=\'customLeafletPopup\'> ' + '<div class=\'popupTitle\'>' + typhoonNum + (typhoonName ? typhoonName : typhoonECName) + '</div>' + '<div style="height: 267px;overflow-y: auto;" class="customScrollbarSmall"><table style = \'font-family: 微软雅黑; font-weight: normal; margin-top:5px;font-size: 12px;\' cellspacing = \'0\' cellpadding = \'0\' width = \'200px\' >' + '<tr><td class="label" width=\'65px\'>过去时间:</td><td>' + tbj + '</td></tr >' + '<tr><td class="label">中心位置:</td><td > ' + centerPosition + '</td ></tr> ' + '<tr><td class="label">最大风速:</td><td>' + maxWindSpeed + '</td></tr > ' + '<tr><td class="label">中心气压:</td><td>' + centerPressure + '</td></tr > ' + '<tr><td class="label">移动方向:</td><td>' + moveDirection + '</td></tr> ' + '<tr><td class="label">移动速度:</td><td>' + moveSpeed + '</td></tr > ' + '</table>'+'<div style="height: 1px;background: linear-gradient(90deg, rgba(19, 106, 255, 0) 0%, rgba(19, 141, 255, 0.9922) 53%, rgba(19, 232, 255, 0) 99%);margin: 8px 0;"></div>' +'<div style="color: rgba(255, 255, 255, 0.6);">风圈半径</div>'+ windCircleList+'</div>';
        } else {
            content = '<div class=\'customLeafletPopup\'> ' + '<div class=\'popupTitle\'>' + typhoonNum + (typhoonName ? typhoonName : typhoonECName) + '</div>' + '<table style = \'font-family: 微软雅黑; font-weight: normal; margin-top:5px;font-size: 12px;\' cellspacing = \'0\' cellpadding = \'0\' width = \'170px\' >' + '<tr><td class="label" width=\'65px\'>过去时间:</td><td>' + tbj + '</td></tr >' + '<tr><td class="label">中心位置:</td><td > ' + centerPosition + '</td ></tr> ' + '<tr><td class="label">最大风速:</td><td>' + maxWindSpeed + '</td></tr > ' + '<tr><td class="label">中心气压:</td><td>' + centerPressure + '</td></tr > ' + '<tr><td class="label">移动方向:</td><td>' + moveDirection + '</td></tr> ' + '<tr><td class="label">移动速度:</td><td>' + moveSpeed + '</td></tr > ' + '</table></div>';
        }
        return content;
    }

    /**
     * 获取中文的方向描述
     * @param direction
     * @returns {*}
     */
    function getTyphoonDirection(direction) {
        return direction?.split('').map(d => {
            return typhoon_direction[d];
        }).filter(item => !!item).join('');
    }

    /**
     * 绘制台风实况线(实线)
     * @param id 台风id
     */
    function drawLiveLine(id) {
        const data = typhoonData?.[id]?.data;
        if (!data) {
            return;
        }
        //台风实况路径节点数据集合
        const points = data?.[8] || [];
        allTyphoonList[id].liveLine = points.map((pointData, index) => {
            //当前节点坐标
            const point = [pointData[5], pointData[4]];
            //上一个坐标
            const point_pre = index > 0 ? [points[index - 1]?.[5], points[index - 1]?.[4]] : [...point];
            //热带气旋类型
            let type = pointData?.[3];
            type = type?.toUpperCase();

            //节点标记
            const circleMarker = L.circleMarker(point, {
                radius: 6, color: '#ffffff', weight: 2, opacity: 1, fillColor: typhone_type?.[type], fillOpacity: 1,
            });
            let popupContent = getTyphoonContent(id, pointData, 'LiveMarker');
            circleMarker.bindPopup(popupContent).openPopup(map);
            circleMarker.on('mouseover', e => {
                circleMarker.setRadius(8);
            });
            circleMarker.on('mouseout', e => {
                circleMarker.setRadius(6);
            });

            return motionPolyline([point_pre, point], {
                weight: 2,
                color: typhone_type?.[type] || 'white',
                fillColor: typhone_type?.[type],
                opacity: 1,
                circleMarker
            });
        }).filter(line => !!line);
    }

    /**
     * 标记台风当前所在位置(gif图标 )
     * @param id
     */
    function drawCurrentMarker(id) {
        const data = typhoonData?.[id]?.data;
        if (!data) {
            return;
        }
        //台风实况路径节点数据集合
        const points = data?.[8] || [];
        //最后一个节点数据
        let lastPoint = points[points.length - 1];
        //绘制风圈(风圈数据存在最后一个实况节点)
        if (lastPoint?.[10]?.length > 0) {
            drawWindCircle(id, lastPoint, lastPoint?.[10]);
        }
        //当前台风所在位置
        const position = [lastPoint?.[5], lastPoint?.[4]];
        //台风动图(旋转的gif)
        const typhoonGifMarker = L.marker(position, {
            icon: L.icon({
                iconUrl: require('@/assets/typhoon/typhoon.gif'), size: [50, 50], iconAnchor: [25, 25]
            })
        });

        const popupContent = getTyphoonContent(id, lastPoint, 'CurrentMarker');
        typhoonGifMarker.bindPopup(popupContent).openPopup(map);
        allTyphoonList[id].currentMarker = typhoonGifMarker;
    }

    /**
     * 绘制未来线
     * @param id
     */
    function drawFutureLine(id) {
        const data = typhoonData?.[id]?.data;
        if (!data) {
            return;
        }
        //台风实况路径节点数据集合
        const points = data?.[8] || [];
        //最后一个实况节点数据
        let lastPoint = points[points.length - 1];
        //台风未来节点数据
        const futurePointList = lastPoint?.[11] || [];

        //最后一个实况节点的位置就是未来线的起点
        let path = [[lastPoint[5], lastPoint[4]]];
        Object.entries(futurePointList).forEach(([key, positionList = []]) => {
            //未来节点之间的线段集合
            allTyphoonList[id].futureLine = positionList.map((positionData, index) => {
                //当前节点坐标
                const currentPoint = [positionData[3], positionData[2]];
                //热带气旋类型
                let type = positionData?.[7];
                type = type?.toUpperCase();

                //节点标记
                const circleMarker = L.circleMarker(currentPoint, {
                    radius: 6, color: '#ffffff', weight: 2, opacity: 1, fillColor: typhone_type?.[type], fillOpacity: 1
                });
                let popupContent = getTyphoonContent(id, positionData, 'FutureMarker');
                circleMarker.bindPopup(popupContent).openPopup(map);

                circleMarker.on('mouseover', e => {
                    circleMarker.setRadius(8);
                });
                circleMarker.on('mouseout', e => {
                    circleMarker.setRadius(6);
                });

                //轨迹线
                let line = motionPolyline([...path, currentPoint], {
                    weight: 2,
                    color: typhone_type?.[type],
                    fillColor: typhone_type?.[type],
                    opacity: 1,
                    dashArray: ['5', '5'],
                    circleMarker
                }, false);

                path = [[...currentPoint]];
                return line;
            }).filter(line => !!line);
        });
    }

    /**
     * 绘制不同等级的风圈
     * @param id
     * @param cdata
     * @param winC
     */
    function drawWindCircle(id, cdata, winC = []) {
        //风圈的位置坐标
        let position = [cdata?.[5], cdata?.[4]];
        //遍历生成风圈
        allTyphoonList[id].windCircle = winC.map((windData, i) => {
            let [, ne, se, nw, sw] = windData;
            const windCircle = {ne, se, nw, sw};
            const options = {
                ...typhoonCircle_colors[i], clickable: true, radius: 100, className: 'windCircleMarker'
            };
            return L.typhoon(position, windCircle, options, map);
        });
    }

    return {drawTyphoonByCodes, clearFeaturesByIds};
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端程序员_花姐夫Jun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值