【问题标题】:OpenLayers 3 Reload Layer(s)OpenLayers 3 重新加载层
【发布时间】:2016-12-07 02:31:20
【问题描述】:

我正在使用 OL3 开发一个项目,我需要能够手动(通过按钮按下)或自动(基于时间)重新加载矢量图层,如果自上次使用 HTTP 条件 GET(304 标头)加载后它们已更新等等)。

我为 KML 图层找到了这篇非常旧的帖子 (https://gis.stackexchange.com/questions/333/how-to-dynamically-refresh-reload-a-kml-layer-in-openlayers),但它似乎使用了 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

检查 OL3 的 API 参考后,似乎不存在此类函数。最接近的是 setProperties() 或 setAttributions()。两者都不起作用。似乎并非所有层类型都实现 getSource()。

更新 2:

refresh() 重新加载图块,但似乎没有从服务器请求它们。相反,它们似乎是从缓存(而不是 HTTP 缓存)加载的。没有发出任何请求,没有 HTTP 304 或类似的东西。将尝试 KML 方法的变体并很快发布结果。

更新 3:

在尝试了很多不同的解决方案后,我偶然发现了一些适用于矢量图层的东西。通过调用图层 source.clear() 函数,然后调用 Map.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:

使用 Jonatas 的答案,我得到了更好的结果。重新加载时会立即弹出新功能。但是,旧的要素不会从地图中删除,并且许多已移动位置的要素会在地图上显示两次。以下是我的代码:

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:

我注意到,如果我删除除以下代码之外的所有其他代码:

source.clear();

调用 XHR GET 请求并且功能不会消失。为什么清除源不删除所有功能?

更新 6:

在发现 ol.source.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() 是一种可怕的方法,并且仅用于测试目的。成功/失败回调函数将是完美的,当查看 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 源的广泛测试,证明这是一种极其可靠的刷新方法!

【问题讨论】:

  • 它确实存在于 一些 源类型:TileWMS
  • 啊,我明白了!您对适用于所有源类型的解决方案有任何想法吗?看起来这将是一个非常基本的功能,应该内置到图层对象中。
  • 我认为您提到的 KML 解决方案可能仍然有效。您正在查看地图和图层,您应该查看来源。许多(全部?)ol sourcetypes 都提到了refresh() 方法。
  • 毕竟你没有说你的源是什么类型的,你正在检索什么类型的文件。
  • @JonatasWalker 感谢您指出这一点!我一定是在某个时候从我的帖子中编辑了它……我正在寻找一种方法来刷新矢量源,主要是 KML 和 GeoJSON。

标签: javascript openlayers-3


【解决方案1】:

嗯,还有其他选择!拥有自己的装载机。

加载此脚本 - 以防有人仍在使用旧浏览器

<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);
    });
}

【讨论】:

    【解决方案2】:

    尝试对此进行改编:

    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 告诉浏览器这是一个新的加载。

    【讨论】:

    • 迄今为止最好的解决方案!它间歇性地工作。我注意到在更新 KML 文件(添加或删除功能)后,它每次都会加载新功能,但不会删除已从 KML 文件中删除的功能。即使在刷新整个页面之后,这些功能也会保留下来。在页面消失之前,需要在 5-10 分钟内重新加载页面数次。有什么想法吗?
    • 此外,每当我更改功能的名称时,如果我添加了名称,更改就会立即显示出来。如果我将名称设置回其原始状态并尝试重新加载,除非我重新加载整个页面,否则不会获取更改。
    • 您是否知道如何为特征加载器实现可选的成功失败参数?
    • 这对我也有用。我在类似于 ajax 工作方式的“setInterval”(设置间隔)函数中使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-26
    • 2018-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多