如何获取MapboxGL.GeoJSONSource对象的边界框?

12

我正在设置一个类似于这样的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());

fitBounds文档中指定了Mapbox GL JS希望以[[minLng,minLat],[maxLng,maxLat]]格式提供边界。

有没有一种方法可以确定此GeoJSON图层的最小/最大纬度和经度值?

6个回答

10

根据这篇文章中的“获取边界框”部分,我总结出以下过程...

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]。如果你尝试运行这段代码并且它崩溃了,那可能就是原因。

这个函数应该明确指出它只适用于多边形。就像你所说的,它不适用于其他没有相同结构的几何图形,比如点、多点和线串。 - jabbermonkey
它不适用于多边形,只适用于多点,对于多点它的表现非常好。 - Aleksey Kuznetsov

4

2
我使用的是turf-extent库,这个库由Mapbox团队维护。在你的代码中,你可以使用以下方式导入(ES6)或者require引入: https://www.npmjs.com/package/turf-extent 是这个node模块的链接。
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});

如果您没有使用webpack或浏览器,可以在常规的HTML标签中使用turf.min.js,以下是一个示例: https://bl.ocks.org/danswick/83a8ddff7fb9193176a975a02a896792

祝您编码和制图愉快!


2

根据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;
}

0
首先使用@turf/turf包:
import * as turf from '@turf/turf'

然后通过您的JSON源要素(在本例中为线串)构建一个bbox:

const locationCoords = locations.map(({ latitude, longitude }) => [
    longitude,
    latitude,
])


const line = turf.lineString(locationCoords)
const bbox = turf.bbox(line) as LngLatBoundsLike

newMap.fitBounds(bbox)

0
基于James Chevalier和tobias47n9e的回答。
我采用了递归的方法来扩展答案,以便能够处理所有类型的多边形和多重多边形。根据tobias47n9e的答案,我在某种程度上没有得到结果,因为多边形的不同结构没有被考虑到。
function getPolygonBoundingBox(arr, bounds = [[], []]) {
  for (var i = 0; i < arr.length; i++) {
    if (Array.isArray(arr[i][0][0])){
      bounds = getPolygonBoundingBox(arr[i], bounds);
    } else {
      polygon = arr[i];
      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;
 }
 
 
getPolygonBoundingBox(feature.geometry.coordinates);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接