OpenLayers 3 перезагрузить слой(Ы)

Я работаю над проектом, использующим OL3, в котором мне нужно иметь возможность вручную (нажатием кнопки) или автоматически (на основе времени) перезагружать векторные слои, если они были обновлены с момента последней загрузки с использованием условного http GETs (304 заголовков и т. д.).

Я нашел этот очень старый пост (https://gis.stackexchange.com/questions/333/how-to-dynamically-refresh-reload-a-kml-layer-in-openlayers) для слоев KML, но он, похоже, использует переменные, больше не найденные в OL3 и я не уверен, что это позволит загружать только файлы, которые были изменены с момента последней загрузки. На первый взгляд кажется, что полная перезагрузка принудительно, даже если файл не был изменен.

в API нет ничего, что напоминало бы функцию перезагрузки для объектов карты или слоя в OL3. Есть ли способ сделать это?

обновление 1:

Я нашел возможный способ сделать это в качестве ответа на этот вопрос: https://gis.stackexchange.com/questions/125074/openlayers3-how-to-reload-a-layer-from-geoserver-when-underlying-data-change используя код:

layer.getSource().updateParams({"time": Date.now()});

однако, когда я запускаю этот код я получаю ошибку:

TypeError: selectedLayer.getSource(...).updateParams is not a function

при проверке ссылки API для OL3 кажется, что таких функций не существует. Ближайший-setProperties () или setAttributions (). Ни о какой работе. Также кажется, что не все типы слоев реализуют getSource().

обновление 2:

refresh () перезагружает плитки, но, похоже, не запрашивает их с сервера. Скорее всего, они загружаются из кэша (но не из кэша HTTP). Никаких запросов не делается, нет HTTP 304s или что-то в этом роде. Будет пробовать вариант подхода KML и публиковать результаты в ближайшее время.

обновление 3:

после попытки множества различных решений I случайно наткнулся на что-то, что работало для векторных слоев. Вызывая источник слоя.функция clear (), а затем вызов карты.updateSize (), слой автоматически перезагружается из исходного URL-адреса. Выдается запрос XHR GET, и если исходный файл изменился, он будет перезагружен из файла. Если исходный файл не изменился, будет выдан 304 и источник будет перезагружен из кэша.

Ниже приведена функция, которая должна использовать этот метод для перезагрузки данного слой:

function refreshLayer(selectedLayer)
{
    var selectedLayerSource = selectedLayer.getSource();

    if(selectedLayerSource instanceof ol.source.Vector)
    {
        //do vector reload
        selectedLayerSource.clear();
        map.updateSize();
    }
    else
    {
        //reload the entire page
        window.location.reload();
    }
}

однако, похоже, что при первых нескольких попытках (в зависимости от браузера) запрос отправляется, код 200 отправляется обратно, но слой не отражает никаких изменений. После нескольких попыток (и перезагрузки страницы несколько раз) он работает. Как только он начинает работать для слоя, он продолжает работать так часто, как исходный файл изменяется. Кто-нибудь знает, что происходит?

обновление 4:

использование адаптации Ответ йонатаса я получаю лучшие результаты. Новые функции появляются мгновенно при перезагрузке. Однако старые объекты не удаляются с карты, и многие объекты, которые переместили местоположения, отображаются на карте дважды. Ниже приведен мой код:

function refreshSelectedLayer()
{
    console.log("This feature is still in the process of being implemented. Refresh may not actually occur.");

    var selectedLayerSource = selectedLayer.getSource();

    if(selectedLayerSource instanceof ol.source.Vector)
    {
        var now = Date.now();
        var format = selectedLayerSource.getFormat();
        var url = selectedLayerSource.getUrl();
        url = url + '?t=' + now;

        loader = ol.featureloader.xhr(url, format);

        selectedLayerSource.clear();
        loader.call(selectedLayerSource, [], 1, 'EPSG:3857');

        map.updateSize();
    }
    else if(selectedLayerSource instanceof ol.source.Tile)
    {
        selectedLayerSource.changed();
        selectedLayerSource.refresh();
    }
}

обратите внимание, что VAR selectedLayer установлен в другом месте кода. Есть идеи, почему происходят эти очень странные результаты?

обновление 5:

Я заметил, что если я удалю весь другой код, кроме the:

source.clear();

вызов запроса XHR GET сделан, и функции не исчезают. Почему очистка источника не удаляет все функции?

обновление 6:

после обнаружения этого ol.источник.clear () фактически не удалял объекты из данного источника данных/слоя, Я заменил его, используя следующий код:

selectedLayerSource.forEachFeature(function(feature){
        selectedLayerSource.removeFeature(feature);
    });

выводя объекты в слое до и после каждого шага, я получил это:

var now = Date.now();
    var format = selectedLayerSource.getFormat();
    var url = selectedLayerSource.getUrl();
    url = url + '?t=' + now;

    console.log("time: "+now+"  format: "+format+"  url: "+url);

    loader = ol.featureloader.xhr(url, format);

    console.log(selectedLayerSource.getFeatures());
    console.log("Deleting features...");

    /*
        Try adding code here to manually remove all features from source
    */
    selectedLayerSource.forEachFeature(function(feature){
        selectedLayerSource.removeFeature(feature);
    });

    console.log(selectedLayerSource.getFeatures());

    console.log("Loading features from file...");

    loader.call(selectedLayerSource, [], 1, 'EPSG:3857');

    window.setTimeout(function(){
        console.log(selectedLayerSource.getFeatures());
        map.updateSize();
    }, 500);

, который выводит в консоль:

"time: 1471462410554  format: [object Object]  url: http://server/file.ext?t=1471462410554" file.php:484:3
Array [ Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, 1 more… ] file.php:491:3
Deleting features... file.php:492:3
Array [  ] file.php:501:3
Loading features from file... file.php:503:3
GET XHR http://server/file.ext [HTTP/1.1 200 OK 34ms]
Array [ Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, 1 more… ]

после нескольких тестов со слоями GeoJSON и KML я подтвердил, что этот метод работает!!!

однако, поскольку загрузчик делает свой запрос асинхронно, я остаюсь с проблемой того, как выполнить код после вызова функции загрузчика. Очевидно, что использование setTimeout () - ужасный способ сделать это и был реализован только для целей тестирования. Функция обратного вызова success/failure было бы идеально и при взгляде на источник featureloader.js похоже, что они предлагаются в качестве параметров в ol.featureloader.loadFeaturesXhr. См. ниже блок кода от featureloader.js:

/**
 * @param {string|ol.FeatureUrlFunction} url Feature URL service.
 * @param {ol.format.Feature} format Feature format.
 * @param {function(this:ol.VectorTile, Array.<ol.Feature>, ol.proj.Projection)|function(this:ol.source.Vector, Array.<ol.Feature>)} success
 *     Function called with the loaded features and optionally with the data
 *     projection. Called with the vector tile or source as `this`.
 * @param {function(this:ol.VectorTile)|function(this:ol.source.Vector)} failure
 *     Function called when loading failed. Called with the vector tile or
 *     source as `this`.
 * @return {ol.FeatureLoader} The feature loader.
 */
ol.featureloader.loadFeaturesXhr = function(url, format, success, failure)

Я попытался реализовать эти функции, так как при создании загрузчика:

loader = ol.featureloader.xhr(url, format, 
        function(){
            console.log(selectedLayerSource.getFeatures());
            map.updateSize();
            console.log("Successful load!");
        },
        function(){
            console.log("Could not load "+selectedLayerName+" layer data from "+url);
        }
    );

но ни одна функция вызывается. Есть предложения? Я чувствую, что упускаю что-то очень простое...

обновление 7:

используя решение, предоставленное @Jonatas Walker, я адаптировал его для использования jQuery:

        var now = Date.now();
        var format = selectedLayerSource.getFormat();
        var url = selectedLayerSource.getUrl();
        url = url + '?t=' + now;

        //make AJAX request to source url
        $.ajax({url: url, success: function(result){

            //manually remove features from the source
            selectedLayerSource.forEachFeature(function(feature){
                selectedLayerSource.removeFeature(feature);
            });

            //create features from AJAX results
            var features = format.readFeatures(result, {
                featureProjection: 'EPSG:3857'
            });

            //add features to the source
            selectedLayerSource.addFeatures(features);

        },
        error: function(err){
            alert("Could not load features from "+selectedLayerName+" at "+url+" error code: "+err.status);
        }
        });

после обширного тестирования с источниками GeoJSON и KML это оказалось чрезвычайно надежным методом обновления!

2 ответов


Ну, есть и другие варианты! Имейте свой собственный загрузчик.

загрузите этот скрипт-на случай, если кто-то все еще использует старые браузеры

<script src="//cdn.polyfill.io/v2/polyfill.min.js?features=fetch"></script>

затем загрузите файл JSON и знаю когда он будет готов/загружено:

function refreshSelectedLayer(layer) {

  var now = Date.now();
  var source = layer.getSource();
  var format = new ol.format.GeoJSON();
  var url = '//your_server.net/tmp/points.json?t=' + now;


  fetch(url)
    .then(function(response) {
      return response.json();
    }).then(function(json) {
      console.log('parsed json', json);

      source.clear(); // if this is not enough try yours

      var features = format.readFeatures(json, {
        featureProjection: 'EPSG:3857'
      });
      source.addFeatures(features);

    }).catch(function(ex) {
      console.log('parsing failed', ex);
    });
}

попробуйте адаптацию этого:

function refreshSource() {
  var now = Date.now();
  var source = vectorLayer.getSource();
  var format = new ol.format.GeoJSON();
  var url = '//your_server.net/tmp/points.json?t=' + now;
  var loader = ol.featureloader.xhr(url, format);

  source.clear();
  loader.call(source, [], 1, 'EPSG:3857');
}

трюк заключается в том, чтобы сообщить браузеру, что это новая загрузка, изменив url-адрес.