前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mapbox GL台风路径的播放实现

mapbox GL台风路径的播放实现

作者头像
lzugis
发布2020-03-23 17:34:19
1.5K0
发布2020-03-23 17:34:19
举报

概述

前面的文章中写了基于openlayers4的台风路径播放,最近用到mapbox GL,也要实现相似的功能,网上找了好久都没有找到,于是就放弃了“拿来主义”的想法,只能自己动手了。经过一下午的努力,终于有了一个雏形,在此分享出来,希望对你有用!

效果

实现后效果
实现后效果

实现

1、数据获取

测试数据是从温州台风网,抓取了201929号台风数据作为测试数据。

2、添加台风编号和名称到地图

代码语言:javascript
复制
addTyphoonLabel(data) {
  const ele = document.createElement('div');
  ele.setAttribute('class', 'typhoon-label');
  ele.innerHTML = data.tfbh + data.name;
  var r = data.points[0];
  const option = {
    element: ele,
    anchor: 'left',
    offset: [10, 0]
  }
  var marker = new mapboxgl.Marker(option).setLngLat([r.longitude, r.latitude]).addTo(map);
  that.typhoonData[data.tfbh]['label'] = marker;
}

对应的样式为:

代码语言:javascript
复制
$white65: rgba(255, 255, 255, 0.65);
.typhoon-label {
  background-color: $white65;
  border-radius: 5px;
  padding: 2px 5px;
  font-size: 12px;
  color: black;
  &:after {
    top: 6px;
		border: solid transparent;
		content: " ";
		height: 0;
		width: 0;
		position: absolute;
		pointer-events: none;
  }
  &:after {
    border-right-color: $white65;
    border-width: 5px;
    left: -10px;
  }
}

3、添加风圈

说明:添加的顺序分别为风圈、路径和实况点,目的是为了让三者按照顺序叠加展示。

代码语言:javascript
复制
addTyphoonCircle(data) {
  var points = data.points;
  var geojson = {
    'type': 'FeatureCollection',
    'features': []
  };
  for (var i = 0; i < points.length; i++) {
    var p = points[i];
    var center = [p.longitude, p.latitude];
    // 7级风圈
    if(p.radius7 > 0) {
      var coords = that.getCircleCoords(center, p.radius7_quad);
      geojson.features.push({
        type: 'Feature',
        geometry: {
          type: 'Polygon',
          coordinates: coords
        },
        properties: {
          index: i,
          radius: '7'
        }
      });
    }
    // 10级风圈
    if(p.radius10 > 0) {
      var coords = that.getCircleCoords(center, p.radius10_quad);
      geojson.features.push({
        type: 'Feature',
        geometry: {
          type: 'Polygon',
          coordinates: coords
        },
        properties: {
          index: i,
          radius: '10'
        }
      });
    }
    // 12级风圈
    if(p.radius12 > 0) {
      var coords = that.getCircleCoords(center, p.radius12_quad);
      geojson.features.push({
        type: 'Feature',
        geometry: {
          type: 'Polygon',
          coordinates: coords
        },
        properties: {
          index: i,
          radius: '12'
        }
      });
    }
  }
  map.addSource('circle-source-' + data.tfbh , {
    type: 'geojson',
    data: geojson
  });
  map.addLayer({
    id: 'circle-layer-' + data.tfbh,
    type: 'fill',
    source: 'circle-source-' + data.tfbh,
    paint: {
      'fill-color': [
        'match',
        ['get', 'radius'],
        '7',
        '#00bab2',
        '10',
        '#ffff00',
        '#da7341'
      ],
      'fill-opacity': 0.2,
      'fill-outline-color': [
        'match',
        ['get', 'radius'],
        '7',
        '#00bab2',
        '10',
        '#ffff00',
        '#da7341'
      ]
    }
  });
}

里面用到了一个生成风圈的方法,方法如下:

代码语言:javascript
复制
getCircleCoords(center, radiusData) {
  center = proj4(proj4('EPSG:4326'), proj4('EPSG:3857'), center);
  let _coords = [];
  let _angInterval = 6;
  let _pointNums = 360 / (_angInterval * 4);
  let quadrant = {
    // 逆时针算角度
    '0': 'ne',
    '1': 'nw',
    '2': 'sw',
    '3': 'se'
  };
  for (let i = 0; i < 4; i++) {
    let _r = parseFloat(radiusData[quadrant[i]]) * 1000; // 单位是km
    if (!_r) _r = 0;
    for (let j = i * _pointNums; j <= (i + 1) * _pointNums; j++) {
      let _ang = _angInterval * j;
      let x = center[0] + _r * Math.cos((_ang * Math.PI) / 180);
      let y = center[1] + _r * Math.sin((_ang * Math.PI) / 180);
      var coord = proj4(proj4('EPSG:3857'), proj4('EPSG:4326'), [x, y]);
      _coords.push(coord);
    }
  }

  return [_coords];
}

说明:由于没有找到坐标转换的方法,所以就引用的proj4js做了投影的转换。

4、添加路径

路径的添加包括实况和预报路径的添加,由于line-dasharray自身的BUG,在实现的时候就添加了两层,实现代码如下:

代码语言:javascript
复制
addTyphoonPath(data) {
  var points = data.points;
  var geojsonLive = {
    'type': 'FeatureCollection',
    'features': []
  };
  var geojsonForc = {
    'type': 'FeatureCollection',
    'features': []
  };
  var pts =[[points[0].longitude, points[0].latitude]];
  for (var i = 1; i < points.length; i++) {
    var p = points[i];
    pts.push([p.longitude, p.latitude]);
    geojsonLive.features.push({
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: pts.concat([])
      },
      properties: {
        index: i,
        type: 'live'
      }
    });
    // 预报路径
    var _p = points[i - 1];
    var _pts = [[_p.longitude, _p.latitude]];
    var _points = _p.forecast[0]['points'];
    for(var j = 0;j < _points.length; j++) {
      var _fp = _points[j];
      _pts.push([_fp.longitude, _fp.latitude]);
    }
    geojsonForc.features.push({
      type: 'Feature',
      geometry: {
        type: 'LineString',
        coordinates: _pts
      },
      properties: {
        index: i - 1,
        type: 'forc'
      }
    });
  }
  // 实况线
  map.addSource('path-source-live-' + data.tfbh , {
    type: 'geojson',
    data: geojsonLive
  });
  map.addLayer({
    id: 'path-layer-live-' + data.tfbh,
    type: 'line',
    source: 'path-source-live-' + data.tfbh,
    paint: {
      'line-color': '#ffffff',
      'line-width': 3
    }
  });

  // 预报线
  map.addSource('path-source-forc-' + data.tfbh , {
    type: 'geojson',
    data: geojsonForc
  });
  map.addLayer({
    id: 'path-layer-forc-' + data.tfbh,
    type: 'line',
    source: 'path-source-forc-' + data.tfbh,
    paint: {
      'line-color': '#ec5d72',
      'line-width': 1,
      'line-dasharray': [5, 3]
    }
  });
}

5、添加点

点包括:实况点和预报点。由于涉及到后面播放的控制,此处将两者分别添加了。

代码语言:javascript
复制
addTyphoonPoints(data) {
  var points = data.points;
  var geojsonLive = {
    'type': 'FeatureCollection',
    'features': []
  };
  var geojsonForc = {
    'type': 'FeatureCollection',
    'features': []
  };
  for (var i = 0; i < points.length; i++) {
    var p = points[i];
    p.index = i;
    geojsonLive.features.push({
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [p.longitude, p.latitude]
      },
      properties: p
    });
    // 预报点
    var forcPoints = p.forecast[0]['points'];
    for(var j = 0; j < forcPoints.length; j++) {
      var _p = forcPoints[j];
      _p.index = i;
      geojsonForc.features.push({
        type: 'Feature',
        geometry: {
          type: 'Point',
          coordinates: [_p.longitude, _p.latitude]
        },
        properties: _p
      });
    }
  }

  var paint = {
    'circle-color': [
      'step',
      ['get', 'speed'],
      'rgba(153, 255, 153, .9)',
      17.2,
      'rgba(102, 204, 255, .9)',
      24.5,
      'rgba(255, 255, 102, .9)',
      32.7,
      'rgba(253, 139, 0, .9)',
      41.5,
      'rgba(255, 51, 0, .9)',
      50.1,
      'rgba(255, 0, 255, .9)'
    ],
    'circle-radius': 6,
    'circle-stroke-width': 0
  }
  // 实况点
  map.addSource('points-source-live-' + data.tfbh , {
    type: 'geojson',
    data: geojsonLive
  });
  map.addLayer({
    id: 'points-layer-live-' + data.tfbh,
    type: 'circle',
    source: 'points-source-live-' + data.tfbh,
    paint: paint
  });

  // 预报点
  map.addSource('points-source-forc-' + data.tfbh , {
    type: 'geojson',
    data: geojsonForc
  });
  map.addLayer({
    id: 'points-layer-forc-' + data.tfbh,
    type: 'circle',
    source: 'points-source-forc-' + data.tfbh,
    paint: paint
  });
}

6、播放与播放控制

代码语言:javascript
复制
playTyphoon() {
  var tfbh = that.typhoonPlay;
  var index = that.typhoonData[tfbh]['playIndex'];
  // 台风风圈
  map.setPaintProperty(
    'circle-layer-' + tfbh,
    'fill-opacity',
    [
      'match',
      ['get', 'index'],
      index,
      0.2,
      0
    ]
  );
  // 实况线
  map.setPaintProperty(
    'path-layer-live-' + tfbh,
    'line-opacity',
    [
      'match',
      ['get', 'index'],
      index,
      0.65,
      0
    ]
  );
  // 预报线
  map.setPaintProperty(
    'path-layer-forc-' + tfbh,
    'line-opacity',
    [
      'match',
      ['get', 'index'],
      index,
      1,
      0
    ]
  );
  // 实况点
  map.setPaintProperty(
    'points-layer-live-' + tfbh,
    'circle-opacity',
    [
      'step',
      ['get', 'index'],
      1,
      index + 0.1,
      0
    ]
  );
  // 预报点
  map.setPaintProperty(
    'points-layer-forc-' + tfbh,
    'circle-opacity',
    [
      'match',
      ['get', 'index'],
      index,
      1,
      0
    ]
  );
},
play() {
  var tfbh = that.typhoonPlay;
  that.typhoonData[tfbh]['playFlag'] = setInterval(function() {
    that.typhoonData[tfbh]['playIndex']++;
    var len = that.typhoonData[tfbh]['data']['points'].length;
    if(that.typhoonData[tfbh]['playIndex'] === len) {
      that.stop();
    } else {
      that.playTyphoon();
    }
  }, 1000)
},
stop() {
  var tfbh = that.typhoonPlay;
  window.clearInterval(that.typhoonData[tfbh]['playFlag']);
}

技术博客 CSDN:http://blog.csdn.NET/gisshixisheng

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-03-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 效果
  • 实现
    • 1、数据获取
      • 2、添加台风编号和名称到地图
        • 3、添加风圈
          • 4、添加路径
            • 5、添加点
              • 6、播放与播放控制
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档