Добавить источник к существующему слою в GL mapbox

Название в значительной степени говорит о том, что я собираюсь делать.

Я использую Firebase как серверную часть для маркеров на карте и использую метод on('child_added') для их отслеживания. Для каждого узла в определенном месте в базе данных on('child_added') сработает один раз.

Это также относится к создаваемым новым узлам, поэтому это идеально подходит для асинхронного добавления новых маркеров на карту по мере их добавления в базу данных.

Чтобы отобразить их на карте, mapbox GL требует, чтобы я преобразовал данные в geojson, создал источник, а затем добавил этот источник в слой. Код ниже показывает это и фактически отображает маркеры на карте.

markersRef.on('child_added', function(childSnapshot) { //fires once for every child node
    var currentKey = childSnapshot.key; //the key of current child
    var entry = childSnapshot.val(); //the value of current child

    //creates a geojson object from child
    var geojson = {
        "type": "FeatureCollection",
        "features": [{
            "type": "Feature",
            "geometry": {
                "type": "Point",
                "coordinates": [entry.position.long, entry.position.lat]
            }
        }],
        "properties": {
            title: entry.title,
            text: entry.text
        }
    };

    //creates a source with the geojson object from above
    map.addSource(currentKey, { //currentKey is the name of this source
        "type": "geojson",
        "data": geojson,
        cluster: true //clusters the points in this source
    });

    //adds the source defined above to a layer that will be displayed on a map
    map.addLayer({
        "id": currentKey, // Sets id as current child's key 
        "source": currentKey, // The source layer defined above
    });
});

Проблема в том, что маркеры будут в отдельных источниках, поэтому они будут отображаться на разных слоях. Поэтому я не могу их объединить или, например, поиск по ним.

Я ищу способ добавить источник к существующему слою. Это позволило бы мне создать слой вне метода on('child_added'), а затем добавить источники к этому слою.

Я просмотрел документы GL mapbox, но не могу найти там ничего, что позволило бы мне это сделать. В этом отношении он кажется очень ограниченным по сравнению с mapbox js.

Я считаю это очень важной особенностью и не понимаю, почему это невозможно. Я надеюсь, что у некоторых из вас есть обходной путь или способ добиться асинхронного добавления маркеров на карту в mapbox GL.


person Mathias Mølgaard    schedule 05.09.2016    source источник


Ответы (2)


Как документация на https://www.mapbox.com/mapbox-gl-js/api/#geojsonsource указывает: объект данных GeoJSON или URL-адрес для него. Последнее предпочтительнее в случае больших файлов GeoJSON.

Здесь происходит то, что источники geojson, загруженные через URL-адрес, загружаются с использованием рабочего потока фонового потока, поэтому они не влияют на основной поток, в основном всегда загружают ваши данные через URL-адрес или стиль mapbox, чтобы выгрузить весь синтаксический анализ JSON и загрузку слоя в другой поток. Таким образом, в любое время, когда у вас есть событие изменения, запущенное из вашего мониторинга firebase, вы можете просто перезагрузить URL-адрес, который вы используете для первоначальной загрузки источника.

Кроме того, основатель Leaflet и замечательный разработчик Mapbox Владимир Агафонкин обсуждает это здесь: https://github.com/mapbox/mapbox-gl-js/issues/2289, и по сути это то, что они делают в своем примере в реальном времени: https://www.mapbox.com/mapbox-gl-js/example/live-geojson/.

Кроме того, вот пример с socket.io, который я использую на стороне клиента:

const url = {server url that retrieves geojson},
      socket = {setup all your socket initiation, etc};

      socket.on('msg', function(data) {

            if (data) {
                //Here is where you can manipulate the JSON object returned from the socket server
                console.log("Message received is: %s", JSON.stringify(data));
                if(data.fetch){
                    map.getSource('stuff').setData(url)
                }

            } else {
                console.log("Message received is empty: so it is %s", JSON.stringify(data));
            }

        });


        map.on('load', function(feature) {

            map.addSource('events', {
                type: 'stuff',
                data: url
            });
            map.addLayer({
                "id": "events",
                "type": "symbol",
                "source": "events",
                "layout": {
                    "icon-image": "{icon}"
                }
            });
        });
person droid-zilla    schedule 28.10.2016

У меня точно такая же проблема. Я немного искал это и нашел атрибут setData для GeoJSONSource: https://www.mapbox.com/mapbox-gl-js/api/#geojsonsource#setdata

map.addSource("points", markers);
map.addLayer({
  "id": "points",
  "type": "symbol",
  "source": "points",
  "layout": {
  "icon-image": "{icon}-15",
  "icon-allow-overlap": true,
  "icon-ignore-placement": true,
  "icon-size": 2,
  "icon-offset": [0, -10],
  }
});

Позже я обновляю исходный код, не создавая новый слой, например:

map.getSource('points').setData(newMarkers)

Таким образом, это обновляет источник без создания нового слоя. Затем вы можете искать по этому слою. Единственная проблема, с которой я столкнулся, заключалась в том, что setData стирает все предыдущие данные (нет функции "addData"), поэтому вам нужно сохранить предыдущие маркеры и добавить их снова. Дайте мне знать, если найдете способ решения этой проблемы.

person justswim    schedule 24.09.2016
comment
Что ж, я считаю, что это лучшее решение на данный момент. В конце концов я связался с Mapbox, и на самом деле это тоже было их предложением. Я думаю, это работает, но я считаю, что это должно быть довольно неэффективно, особенно с большим набором данных. В любом случае, спасибо за ответ! Я буду держать вас в курсе, если найду другое решение - сделайте то же самое :) - person Mathias Mølgaard; 26.09.2016
comment
Кажется, я припоминаю, что где-то читал, что mapboxGL автоматически отличает новые данные от предыдущих и обновляет только то, что необходимо ... - person songololo; 14.12.2017