【问题标题】:How do I get the bounding box of a mapboxgl.GeoJSONSource object?如何获取 mapboxgl.GeoJSONSource 对象的边界框?
【发布时间】:2016-06-10 23:11:38
【问题描述】:

我正在像这样设置 Mapbox GL JS 地图:

mapboxgl.accessToken = 'pk.my_token';
var cityBoundaries   = new mapboxgl.GeoJSONSource({ data: 'http://domain.com/city_name.geojson' } );
var map              = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v8',
  center: [cityLongitude,cityLatitude],
  zoom: 13
});

然后我将 GeoJSON 数据加载到地图上,如下所示:

map.on('style.load', function(){
  map.addSource('city', cityBoundaries);
  map.addLayer({
    'id': 'city',
    'type': 'line',
    'source': 'city',
    'paint': {
      'line-color': 'blue',
      'line-width': 3
    }
  });
});

此时,我有一张以我在new mapboxgl.Map 中指定的位置为中心的地图,它的缩放级别为 13。因此,地图上只有一部分 GeoJSON 数据可见。我想重新居中并重新缩放地图,以便整个 GeoJSON 数据可见。

在 Mapbox JS 中,我会通过将 GeoJSON 数据加载到 featureLayer 中然后将地图拟合到其边界来做到这一点:

map.fitBounds(featureLayer.getBounds());

Mapbox GL JS 的fitBounds documentation 表示它想要[[minLng, minLat], [maxLng, maxLat]] 格式的边界。

有没有办法确定这个 GeoJSON 层的混合/最大纬度和经度值?

【问题讨论】:

    标签: mapbox mapbox-gl-js


    【解决方案1】:

    基于this post 的“获取边界框”部分,我想出了这个过程...

    map.on('style.load', function(){
      $.getJSON('http://citystrides.dev/city_name.geojson', function(response){
        var boundingBox = getBoundingBox(response);
        var cityBoundary = new mapboxgl.GeoJSONSource({ data: response } );
    
        map.addSource('city', cityBoundary);
        map.addLayer({
          'id': 'city',
          'type': 'line',
          'source': 'city',
          'paint': {
            'line-color': 'blue',
            'line-width': 3
          }
        });
        map.fitBounds([[boundingBox.xMin, boundingBox.yMin], [boundingBox.xMax, boundingBox.yMax]]);
      })
    });
    
    function getBoundingBox(data) {
      var bounds = {}, coords, point, latitude, longitude;
    
      for (var i = 0; i < data.features.length; i++) {
        coords = data.features[i].geometry.coordinates;
    
        for (var j = 0; j < coords.length; j++) {
          longitude = coords[j][0];
          latitude = coords[j][1];
          bounds.xMin = bounds.xMin < longitude ? bounds.xMin : longitude;
          bounds.xMax = bounds.xMax > longitude ? bounds.xMax : longitude;
          bounds.yMin = bounds.yMin < latitude ? bounds.yMin : latitude;
          bounds.yMax = bounds.yMax > latitude ? bounds.yMax : latitude;
        }
      }
    
      return bounds;
    }
    

    以下是代码正在做什么的演练,供任何需要详细解释的人使用:

    • map.on('style.load', function(){
      • 地图加载后,让我们在这个函数中做一些事情。
    • $.getJSON('http://citystrides.dev/city_name.geojson', function(response){
      • 获取城市的 GeoJSON 数据。这是一个异步调用,因此我们必须将使用此数据的所有代码(response)放入此函数中。
    • var boundingBox = getBoundingBox(response);
      • 获取此 GeoJSON 数据的边界框。这是调用出现在“样式加载地图”块之后的, function(){
    • var cityBoundary = new mapboxgl.GeoJSONSource({ data: response } );
      • 构建 Mapbox 的 GeoJSON 数据。
    • map.addSource('city', cityBoundary);
      • 将源添加到 Mapbox。
    • map.addLayer({
      • 将图层添加到 Mapbox。
    • map.fitBounds([[boundingBox.xMin, boundingBox.yMin], [boundingBox.xMax, boundingBox.yMax]]);
      • 调整地图以将 GeoJSON 数据固定到视图中。
    • function getBoundingBox(data) {
      • 此函数迭代返回的 GeoJSON 数据,查找最小和最大纬度和经度值。

    getBoundingBox 函数中需要注意的是这一行:

    coords = data.features[i].geometry.coordinates;
    

    在上面链接的原始帖子中,这一行写为coords = data.features[i].geometry.coordinates[0];,因为它们的坐标列表数据是一个数组数组。我的数据不是这样格式化的,所以我不得不删除[0]。如果您尝试使用此代码并崩溃,这可能就是原因。

    【讨论】:

    • 这个函数可能应该指定它只适用于多边形。正如您所说,它不适用于其他结构不同的几何图形,例如 Point、MultiPoint 和 LineStrings。
    • 它不适用于多边形。仅适用于多点,它对它们非常有效。
    【解决方案2】:

    我使用的是 turf-extent 库,它由 Mapbox 团队维护。 https://www.npmjs.com/package/turf-extent 是节点模块链接。 在您的代码中,您只需导入(ES6)或要求这样:

    ES6/Webpack: import extent from 'turf-extent';
    Via script tag: `<script src='https://api.mapbox.com/mapbox.js/plugins/turf/v2.0.2/turf.min.js'></script>`
    

    然后将您的响应反馈给函数,例如:

    ES6/Webpack: let orgBbox = extent(response);
    Normal: var orgBbox = turf.extent(geojson);
    

    然后你可以使用数组值来设置你的地图中心:

    center: [orgBbox[0], orgBbox[1]]
    

    或者你想要的,以适应边界:

    map.fitBounds(orgBbox, {padding: 20});
    

    这是一个在常规 html 标记中使用 turf.min.js 的示例,以防您不使用 webpack 或浏览器: https://bl.ocks.org/danswick/83a8ddff7fb9193176a975a02a896792

    快乐的编码和映射!

    【讨论】:

      【解决方案3】:

      基于 James Chevalier 的回答。对于在 Mapbox Studio 中分配给地图的多边形/多多边形图块集,我使用它来获取边界框:

      getPolygonBoundingBox: function(feature) {
          // bounds [xMin, yMin][xMax, yMax]
          var bounds = [[], []];
          var polygon;
          var latitude;
          var longitude;
      
          for (var i = 0; i < feature.geometry.coordinates.length; i++) {
              if (feature.geometry.coordinates.length === 1) {
                  // Polygon coordinates[0][nodes]
                  polygon = feature.geometry.coordinates[0];
              } else {
                  // Polygon coordinates[poly][0][nodes]
                  polygon = feature.geometry.coordinates[i][0];
              }
      
              for (var j = 0; j < polygon.length; j++) {
                  longitude = polygon[j][0];
                  latitude = polygon[j][1];
      
                  bounds[0][0] = bounds[0][0] < longitude ? bounds[0][0] : longitude;
                  bounds[1][0] = bounds[1][0] > longitude ? bounds[1][0] : longitude;
                  bounds[0][1] = bounds[0][1] < latitude ? bounds[0][1] : latitude;
                  bounds[1][1] = bounds[1][1] > latitude ? bounds[1][1] : latitude;
              }
          }
      
          return bounds;
      }
      

      【讨论】:

        【解决方案4】:

        您可以使用turf.js 库。它有一个bbox 函数:

        const bbox = turf.bbox(foo);
        

        https://turfjs.org/docs/#bbox

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-04-03
          • 2015-03-14
          • 2020-12-08
          • 1970-01-01
          • 2018-08-23
          • 2019-09-18
          相关资源
          最近更新 更多