Как получить ограничивающую рамку объекта mapboxgl.GeoJSONSource?

Я настраиваю карту 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?


person James Chevalier    schedule 27.02.2016    source источник


Ответы (4)


На основе раздела «Получение ограничивающей рамки» этого сообщения, я придумал этот процесс ...

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(){
    • When the map loads, let's do the stuff in this function.
  • $.getJSON('http://citystrides.dev/city_name.geojson', function(response){
    • Get the city's GeoJSON data. This is an asynchronous call, so we have to put the all the code that uses this data (the response) inside this function.
  • var boundingBox = getBoundingBox(response);
    • Get the bounding box of this GeoJSON data. This is calling the , function(){ that appears after the 'map on style load' block.
  • var cityBoundary = new mapboxgl.GeoJSONSource({ data: response } );
    • Build Mapbox's GeoJSON data.
  • map.addSource('city', cityBoundary);
    • Add the source to Mapbox.
  • map.addLayer({
    • Add the layer to Mapbox.
  • map.fitBounds([[boundingBox.xMin, boundingBox.yMin], [boundingBox.xMax, boundingBox.yMax]]);
    • Adjust the map to fix the GeoJSON data into view.
  • function getBoundingBox(data) {
    • This function iterates over the returned GeoJSON data, finding the minimum and maximum latitude and longitude values.

В функции getBoundingBox следует отметить следующую строку:

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

В исходном посте, ссылка на который приведена выше, эта строка была написана как coords = data.features[i].geometry.coordinates[0];, потому что их данные для списка координат были массивом массивов. Мои данные не отформатированы таким образом, поэтому мне пришлось отказаться от [0]. Если вы попробуете этот код, и он взорвется, это может быть причиной.

person James Chevalier    schedule 28.02.2016
comment
Эта функция, вероятно, должна указывать, что она работает только для многоугольников. Как вы сказали, это не сработает для других геометрий, у которых нет такой же структуры, как Point, MultiPoint и LineStrings. - person jabbermonkey; 25.04.2016
comment
Это не для полигонов. Только для MultiPoints, и для них это работает неплохо. - person Aleksey Kuznetsov; 03.09.2020

Я использую библиотеку turf-extension, которая так или иначе поддерживается группой 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});

Вот пример использования turf.min.js в обычном теге html, если вы не используете веб-пакет или браузер: https://bl.ocks.org/danswick/83a8ddff7fb9193176a975a02a896792

Удачного кодирования и отображения!

person droid-zilla    schedule 25.11.2016

На основе ответа Джеймса Шевалье. Для многоугольных / многополигональных наборов тайлов, которые назначаются карте в 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;
}
person tobias47n9e    schedule 17.03.2017

Вы можете использовать библиотеку turf.js. У него есть bbox функция:

const bbox = turf.bbox(foo);

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

person Stophface    schedule 07.08.2019