使用mapbox 绘制台风风圈、台风路径

目录

1、台风路径信息准备与添加

    1.1 数据准备,这里可以从中央气象台台风网抓取数据http://typhoon.nmc.cn/web.html

    1.2 添加地图信息

 2、添加台风风圈

     1、使用坐标转换计算

  2、使用turf.js计算台风风圈范围

3、台风路径的播放效果


1、台风路径信息准备与添加

    1.1 数据准备,这里可以从中央气象台台风网抓取数据http://typhoon.nmc.cn/web.html

    1.2 添加地图信息

         添加台风预报路径

 function addTyLine(map, typData) {
  // 最后的点位添加编号名称
  typData.points[typData.points.length - 1].forecast.forEach((element, index) => {
    let coordList = [];
    element.forecastpoints.map(item => {
      coordList.push([Number(item.lng), Number(item.lat)]);
    });
    if (!map.getSource(`${typData.tfid}_typhon_route_line_${element.tm}`)) {
      map.addSource(`${typData.tfid}_typhon_route_line_${element.tm}`, {
        type: 'geojson',
        data: {
          type: 'Feature',
          properties: {},
          geometry: {
            type: 'LineString',
            coordinates: coordList,
          },
        },
      });
    }
    if (!map.getLayer(`typhon_route_${typData.tfid}_${index}`)) {
      map.addLayer({
        id: `typhon_route_${typData.tfid}_${index}`,
        type: 'line',
        source: `${typData.tfid}_typhon_route_line_${element.tm}`,
        layout: {
          'line-join': 'round',
          'line-cap': 'round',
        },
        paint: {
          'line-color': '设定颜色',
          'line-width': 2,
          'line-dasharray': [0.005, 3],
        },
      });
    }
  });
}

        根据数据的格式来整理成geojson添加

预报站点信息、已测路径信息、已测站点信息同理添加

 2、添加台风风圈

     关于台风风圈,已知的数据有台风中心点以及台风半径,而台风半径又分为西北、西南、东南、东北四个方位角,这里在网上搜集了两种方法:

     1、使用坐标转换计算

      已知的中心点坐标为wgs84投影类型,也就是经纬度,需将其转换为投影坐标系来计算距离,再根据距离将其转换为经纬度来添加

let coords_7 = getCircleCoords(coordList[time], radiusData);

map.addSource(`currentFill_${typData.tfid}`, {
      type: 'geojson',
      data: {
        type: 'Feature',
        properties: {
          name: typData.name,
          radius: '7',
        },
        geometry: {
          type: 'Polygon',
          coordinates: coords_7,
        },
      },
    });
  map.addLayer({
    id: `currentFill_${typData.tfid}`,
    source: `currentFill_${typData.tfid}`,
    type: 'fill',
    paint: {
      'fill-color': ['match', ['get', 'radius'], '7', '#ffff00', '10', '#ffa911', '#ff5341'],
      'fill-opacity': 0.2,
      'fill-outline-color': ['match', ['get', 'radius'], '7', '#ffff00', '10', '#ffa911', '#ff5341'],
},
  });

getCircleCoords(center, radiusData) {
 //radiusData = {
   // ne: 100,
    //nw: 120,
    //sw: 120,
    //se: 10,
  //};

  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];
}

传入的radiusData  需包含四个半径,格式如上;

proj4.js是坐标系转换通用的库,需单独引入;

以上方法可行,但是算出来的台风风圈经过验证存在一点误差,所以这里介绍另外一种使用turf.js计算的方法,算出来的风圈范围跟官网一致;

  2、使用turf.js计算台风风圈范围

drawTyphoonCircle(p, radiusData) {
  var center = turf.point(p);
  let quadrant = {
    // 逆时针算角度
    0: 'ne',
    1: 'sw',
    2: 'se',
    3: 'nw',
  };
  if (radiusData[quadrant[0]]) {
    var options = { number: 2048 };
    var arc_ne = turf.lineArc(center, radiusData[quadrant[0]], 0, 89.9, options);
    var arc_se = turf.lineArc(center, radiusData[quadrant[3]], 90, 179.9, options);
    var arc_sw = turf.lineArc(center, radiusData[quadrant[2]], 180, 269.9, options);
    var arc_nw = turf.lineArc(center, radiusData[quadrant[1]], 270, 360.1, options);

    var arcs = [];
    arcs.push(arc_ne, arc_se, arc_sw, arc_nw);

    var typhoonCircleCoords = [];
    for (var i = 0; i < arcs.length; i++) {
      var rawCoords1 = arcs[i].geometry.coordinates;

      for (var j = 0; j < rawCoords1.length; j++) {
        typhoonCircleCoords.push(rawCoords1[j]);
      }
    }

    var lineAll = turf.lineString(typhoonCircleCoords);
    var typhoonCirclePolygon = turf.lineToPolygon(lineAll);
    console.log('typhoonCirclePolygon', typhoonCirclePolygon);
    return typhoonCirclePolygon;
  } else {
    return;
  }

}

    这里返回直接是geojson,

3、台风路径的播放效果

设置定时器,对geojson数据源定时修改,用到的核心方法是    map.getSource(`currentPoint`).setData(geojson);记得动画播放结束后要clearInterval()哦

let time = 0
updateSource[typData.tfid] = setInterval(async () => {
    time++;
    if (!typData.points[time]) {
      clearInterval(updateSource[typData.tfid]);
      updateSource[typData.tfid] = null;
      return;
    }
    radiusSeven = typData.points[time]?.radius7.split('|');
    radiusData = {
      ne: radiusSeven[0],
      nw: radiusSeven[1],
      sw: radiusSeven[2],
      se: radiusSeven[3],
    };
    // let coords_7 = getCircleCoords(coordList[time], radiusData);
    let coords_7 = drawTyphoonCircle(coordList[time], radiusData);
    const geojson_7 = await {
      type: 'FeatureCollection',
      features: [
        {
          type: 'Feature',
          geometry: {
            type: 'Polygon',
            coordinates: coords_7?.geometry?.coordinates,
          },
          properties: {
            tfid: typData.tfid,
            radius: '7',
          },
        },
      ],
    };
    radiusTen = typData.points[time].radius10.split('|');
    radiusTenData = {
      ne: radiusTen[0],
      nw: radiusTen[1],
      sw: radiusTen[2],
      se: radiusTen[3],
    };
    let coords_10 = drawTyphoonCircle(coordList[time], radiusTenData);
    const geojson_10 = await {
      type: 'FeatureCollection',
      features: [
        {
          type: 'Feature',
          geometry: {
            type: 'Polygon',
            coordinates: coords_10?.geometry?.coordinates,
          },
          properties: {
            name: typData.name,
            radius: '10',
          },
        },
      ],
    };
    let radiusTwelve = typData.points[time].radius12.split('|');
    let radiusTwelveData = {
      ne: radiusTwelve[0],
      nw: radiusTwelve[1],
      sw: radiusTwelve[2],
      se: radiusTwelve[3],
    };
    let coords_12 = drawTyphoonCircle(coordList[time], radiusTwelveData);
    const geojson_12 = await {
      type: 'FeatureCollection',
      features: [
        {
          type: 'Feature',
          geometry: {
            type: 'Polygon',
            coordinates: coords_12?.geometry?.coordinates,
          },
          properties: {
            name: typData.name,
            radius: '12',
          },
        },
      ],
    };
    const geojson = await {
      type: 'FeatureCollection',
      features: [
        {
          type: 'Feature',
          geometry: {
            type: 'Point',
            coordinates: coordList[time],
          },
        },
      ],
    };
    try {
      if (!coordList[time] || !typData.points[time]) {
        clearInterval(updateSource[typData.tfid]);
        updateSource[typData.tfid] = null;
        return;
      }
      map.getSource(`currentPoint_${typData.tfid}`).setData(geojson);
      map.getSource(`currentFill_${typData.tfid}`).setData(geojson_7);
      map.getSource(`currentFill_10_${typData.tfid}`).setData(geojson_10);
      map.getSource(`currentFill_12_${typData.tfid}`).setData(geojson_12);
    } catch (err) {
      // If the updateSource interval is defined, clear the interval to stop updating the source.
      if (updateSource) {
        clearInterval(updateSource[typData.tfid]);
        updateSource[typData.tfid] = null;
      }
      throw new Error(err);
    }
  }, 100);

类似台风路径的播放效果官网上也有所介绍,https://docs.mapbox.com/mapbox-gl-js/example/animate-point-along-route/其里面的核心内容就是设置定时器更新数据源 ,当然数据源的要求是geojson, map.getSource('pointSourceName').setData(pointGeojson); 

好的,以下是使用Mapbox绘制一个正方形的示例代码: 首先,你需要在Mapbox官网注册并创建一个账户,然后创建一个新的地图项目,并获取你的访问令牌(access token)。 然后,你需要引入MapboxJavaScript库,并在HTML中添加一个`<div>`元素作为地图容器。接着,你可以使用以下代码创建一个地图,并添加一个正方形: ```html <!DOCTYPE html> <html> <head> <title>Mapbox - First Map</title> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src='https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.js'></script> <link href='https://api.mapbox.com/mapbox-gl-js/v2.1.1/mapbox-gl.css' rel='stylesheet' /> <style> #map { height: 400px; } </style> </head> <body> <div id='map'></div> <script> // 初始化地图,设置中心点和缩放级别 mapboxgl.accessToken = 'YOUR_ACCESS_TOKEN'; var map = new mapboxgl.Map({ container: 'map', style: 'mapbox://styles/mapbox/streets-v11', center: [-122.4194, 37.7749], zoom: 12 }); // 添加一个正方形 var square = turf.square([-122.4248, 37.7649], 0.2, {units: 'kilometers'}); map.on('load', function() { map.addLayer({ 'id': 'square', 'type': 'fill', 'source': { 'type': 'geojson', 'data': square }, 'paint': { 'fill-color': '#088', 'fill-opacity': 0.4 } }); }); </script> </body> </html> ``` 在这个示例代码中,我们首先引入了MapboxJavaScript库,并在HTML中添加了一个`<div>`元素作为地图容器。然后,我们使用`mapboxgl.Map`函数创建了一个地图,并设置了中心点和缩放级别。接着,我们使用Turf.js创建了一个正方形,并在地图加载完成后,使用`map.addLayer`函数将其添加到地图上。 你需要将代码中的`YOUR_ACCESS_TOKEN`替换为你自己的访问令牌。运行代码后,你应该能够在地图上看到一个正方形。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值