添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Repository files navigation

wind-layer

a maptalks | mapbox-gl | openlayers | leaflet | bmap | amap extension to show wind field。

wind-layer 是一个专注于气象格点数据可视的插件,设计之处是参考了 earth cambecc 的一个气象数据的展示,他使用了流体场的方式去展示了全球的风速和风向,富有很强的 表现力, 这个插件的早期的很多核心代码也是来源于此。当然现在它不仅仅是做风场的展示,常规的气象数据都可以依赖此插件进行可视化。

特性 (1.x 通用版本相对于原始 windy.js )

  • 易于配置粒子数量,原始 windy.js 只能给定一个系数,会根据地图元素的大小进行计算粒子数量;现在可以支持系数方式和固定粒子数量以及回调函数的的三种方式。
  • 颜色配置支持三种方式: String:固定颜色值 Function: 通过回调函数的风速值设定颜色(但是会有一定的性能损失) String[]: 按照风速值范围等间隔渲染,无法做到精确匹配对应值的颜色。
  • 线条宽度支持动态设置。
  • 抽离了核心渲染库,便于扩展到其他地图渲染库。
  • 2.x webgl 版本

    gl-core 扩展目前只针对 mapbox maplibre maptalks 做了相关适配,其他引擎适配欢迎 PR。

    目前计划支持的图层如下:

  • 常规 raster 图层,为了解决多时次瓦片序列播放问题。
  • 常规 Image 图层,单张 raster 图层。
  • 色斑图渲染,支持瓦片和单张。
  • 多数据源支持(geotiff、灰度图-可解析带 exif 信息、png-多通道浮点数压缩)。
  • geotiff 的支持需要配置 configDeps , exif 默认支持,因为在 safari 浏览器下 configDeps 有兼容性问题,所以默认打包了 exif 的解析库。
  • mapboxWind.configDeps(['https://unpkg.com/geotiff/dist-browser/geotiff.js']);
  • TimelineSource(时序数据源)支持。
  • 粒子渲染,支持瓦片和单张。
  • 箭头图层,支持瓦片和单张(矢量数据:风或洋流)。
  • 图层拾取。
  • 图层掩膜。
  • TIP: 注意 2.0 之后不再支持 jsonArray 数据和 EPSG:4326 的图片数据,如果有需求请使用 1.x 版本

    pnpm install openlayers-wind pnpm install @sakitam-gis/maptalks-wind pnpm install amap-wind pnpm install bmap-wind pnpm install leaflet-wind pnpm install @sakitam-gis/mapbox-wind pnpm install @sakitam-gis/maplibre-wind # yarn yarn add wind-core yarn add wind-gl-core yarn add src-wind yarn add ol5-wind yarn add openlayers-wind yarn add @sakitam-gis/maptalks-wind yarn add amap-wind yarn add bmap-wind yarn add leaflet-wind yarn add @sakitam-gis/mapbox-wind yarn add @sakitam-gis/maplibre-wind

    部分插件亦可以通过浏览器引入

    在浏览器中使用 script 标签直接引入文件,并使用全局变量。

    我们在仓库发布包内的 dist 目录下提供了 xxx.js 以及 xxx.min.js

    Project unpkg jsdelivr wind-core https://unpkg.com/wind-core/dist/wind-core.js https://cdn.jsdelivr.net/npm/wind-core/dist/wind-core.js wind-gl-core https://unpkg.com/wind-gl-core/dist/wind-gl-core.js https://cdn.jsdelivr.net/npm/wind-gl-core/dist/wind-gl-core.js ol-wind ol6 重构原因,无法直接使用,你可以自行构建 https://cdn.jsdelivr.net/npm/@sakitam-gis/[email protected]/dist/ https://unpkg.com/ol-wind/dist/ol-wind.js https://cdn.jsdelivr.net/npm/ol-wind/dist/ol-wind.js ol5-wind https://unpkg.com/ol5-wind/dist/ol-wind.js https://cdn.jsdelivr.net/npm/ol5-wind/dist/ol-wind.js openlayers-wind https://unpkg.com/openlayers-wind/dist/ol-wind.js https://cdn.jsdelivr.net/npm/openlayers-wind/dist/ol-wind.js @sakitam-gis/maptalks-wind https://unpkg.com/@sakitam-gis/maptalks-wind/dist/maptalks-wind.js https://cdn.jsdelivr.net/npm/@sakitam-gis/maptalks-wind/dist/maptalks-wind.js amap-wind https://unpkg.com/amap-wind/dist/amap-wind.js https://cdn.jsdelivr.net/npm/amap-wind/dist/amap-wind.js bmap-wind https://unpkg.com/bmap-wind/dist/bmap-wind.js https://cdn.jsdelivr.net/npm/bmap-wind/dist/bmap-wind.js leaflet-wind https://unpkg.com/leaflet-wind/dist/leaflet-wind.js https://cdn.jsdelivr.net/npm/leaflet-wind/dist/leaflet-wind.js @sakitam-gis/mapbox-wind https://unpkg.com/@sakitam-gis/mapbox-wind/dist/mapbox-wind.js https://cdn.jsdelivr.net/npm/@sakitam-gis/mapbox-wind/dist/mapbox-wind.js @sakitam-gis/maplibre-wind https://unpkg.com/@sakitam-gis/maplibre-wind/dist/maplibre-wind.js https://cdn.jsdelivr.net/npm/@sakitam-gis/maplibre-wind/dist/maplibre-wind.js

    基础使用可以分为三步:

  • 引入相应的 WebGIS 地图类库,引入对应的可视化图层扩展插件。
  • 正常初始化一个地图。
  • 创建一个 WindLayer ,设置风场格点的 U V 数据和图层参数 并添加到地图上。
  • 以下以 maptalks 为例:

    npm + es6

    <template>
      <div class="demo-content">
        <div class="demo-content-datgui"></div>
        <div class="map-warp" ref="map"></div>
      </div>
    </template>
    <script>
      import 'maptalks/dist/maptalks.css';
      import {
        Map,
        TileLayer,
      } from 'maptalks';
      import { WindLayer } from 'maptalks-wind';
      export default {
        name: 'maptalks-wind-base',
        data() {
          return {};
        watch: {},
        methods: {
          initMap() {
            const map = new Map(this.$refs.map, {
              center: [113.53450137499999, 34.44104525],
              zoom: 3,
              baseLayer: new TileLayer('base', {
                urlTemplate: '//{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
                // urlTemplate: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
                subdomains: ['a', 'b', 'c', 'd'],
            });
            fetch('/data/wind.json')
              .then(res => res.json())
              .then(res => {
                const windLayer = new WindLayer('wind', res, {
                  windOptions: {
                    // colorScale: scale,
                    velocityScale: 1 / 20,
                    paths: 5000,
                    // eslint-disable-next-line no-unused-vars
                    colorScale: [
                      "rgb(36,104, 180)",
                      "rgb(60,157, 194)",
                      "rgb(128,205,193 )",
                      "rgb(151,218,168 )",
                      "rgb(198,231,181)",
                      "rgb(238,247,217)",
                      "rgb(255,238,159)",
                      "rgb(252,217,125)",
                      "rgb(255,182,100)",
                      "rgb(252,150,75)",
                      "rgb(250,112,52)",
                      "rgb(245,64,32)",
                      "rgb(237,45,28)",
                      "rgb(220,24,32)",
                      "rgb(180,0,35)"
                    // colorScale: scale,
                  // map: map,
                  // projection: 'EPSG:4326'
                });
                console.log(map, windLayer);
                map.addLayer(windLayer);
              });
        mounted() {
          this.initMap();
    </script>
    <style lang="less">
      .demo-content {
        width: 100%;
        height: 100%;
        position: relative;
        background-color: #cbe0ff;
        &-datgui {
          position: absolute;
          top: 10px;
          left: 10px;
          z-index: 1;
          pointer-events: auto;
        .map-warp {
          width: 100%;
          height: 100%;
    </style>
    <!DOCTYPE html>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Map - Display a map</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/maptalks/dist/maptalks.css">
    <style type="text/css">
      html, body {
        margin: 0;
        height: 100%;
        width: 100%
      .container {
        width: 100%;
        height: 100%
    </style>
    <div id="map" class="container"></div>
    <script src="https://cdn.jsdelivr.net/npm/maptalks/dist/maptalks.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@sakitam-gis/maptalks-wind/dist/maptalks-wind.js"></script>
    <script>
      const map = new maptalks.Map('map', {
        center: [113.53450137499999, 34.44104525],
        zoom: 5,
        baseLayer: new maptalks.TileLayer('base', {
          // urlTemplate: 'https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',
          urlTemplate: 'https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
          subdomains: ['a', 'b', 'c', 'd'],
      });
      fetch('data.json')
        .then(res => res.json())
        .then(res => {
          const windLayer = new MaptalksWind.WindLayer('wind', res, {
            windOptions: {
              // colorScale: (m) => {
              //   // console.log(m);
              //   return '#fff';
              // },
              colorScale: [
                "rgb(36,104, 180)",
                "rgb(60,157, 194)",
                "rgb(128,205,193 )",
                "rgb(151,218,168 )",
                "rgb(198,231,181)",
                "rgb(238,247,217)",
                "rgb(255,238,159)",
                "rgb(252,217,125)",
                "rgb(255,182,100)",
                "rgb(252,150,75)",
                "rgb(250,112,52)",
                "rgb(245,64,32)",
                "rgb(237,45,28)",
                "rgb(220,24,32)",
                "rgb(180,0,35)"
              // velocityScale: 1 / 20,
              // paths: 5000,
              frameRate: 16,
              maxAge: 60,
              globalAlpha: 0.9,
              velocityScale: 1 / 30,
              // paths: 10000,
              paths: () => { // can be number or function
                const zoom = map.getZoom();
                return zoom * 1000;
          });
          console.log(map, windLayer);
          map.addLayer(windLayer);
        });
    </script>
    </body>
    </html>

    文档请移步 正在完善中......

    如何获取数据

    天气数据由 全球预报系统 (GFS)生成, 由美国国家气象局管理。 预测每天产生四次,并可用于 从 NOMADS 下载。 这些文件位于 GRIB2 格式并包含超过 300条记录 。 我们只需要这些记录中的一小部分就可以在特定的等压线上可视化风资料。 下面的命令下载 1000 hPa风向量,并使用 grib2json 将它们转换为JSON格式。

    YYYYMMDD=<a date, for example: 20140101>
    curl "http://nomads.ncep.noaa.gov/cgi-bin/filter_gfs.pl?file=gfs.t00z.pgrb2.1p00.f000&lev_10_m_above_ground=on&var_UGRD=on&var_VGRD=on&dir=%2Fgfs.${YYYYMMDD}00" -o gfs.t00z.pgrb2.1p00.f000
    grib2json -d -n -o current-wind-surface-level-gfs-1.0.json gfs.t00z.pgrb2.1p00.f000
    cp current-wind-surface-level-gfs-1.0.json <earth-git-repository>/public/data/weather/current

    对于 2.x 版本的数据格式我们可以使用 https://github.com/sakitam-gis/raster-process 来生成所需要的瓦片和单张图片。

    Acknowledgments

  • https://github.com/cambecc/earth
  • http://earth.nullschool.net
  • https://github.com/Esri/wind-js
  • https://github.com/danwild/wind-js-leaflet
  • https://github.com/IHCantabria/Leaflet.CanvasLayer.Field
  • https://github.com/mapbox/webgl-wind
  • https://github.com/astrosat/windgl
  • License