让 openlayers 从 visible = false 的层加载数据

Having openlayers load data from layer with visible = false

我有一个带有矢量源的矢量层,加载起来非常昂贵,但渲染起来却不那么昂贵。我的 GUI 中有一个按钮来切换图层的可见性。 问题是,第一次将 visibility 设置为 true 时,加载需要很长时间。 我想在加载其余数据(从所有可见层)时提前加载该层的数据,这样当可见性设置为 true 时,它​​只需要渲染它。 这在 Openlayers 中可能吗?

我尝试了各种方法,比如在 'precompose' 上将可见性设置为 true,然后在发送 HTTP 请求后将其设置为 false(使用自定义 'loadend' 事件),但我做不到不能让它正常工作;我无法再关闭图层。我猜这是因为在第一次加载后,它缓存了数据,所以我的自定义 'loadend' 事件不再触发。 无论如何,我更喜欢更优雅的解决方案。

编辑: 我不能像 Mike 的回答那样预先发送请求,因为没有 请求。该请求取决于范围和投影,因此在矢量源的 loader 函数中进行。

如果数据不会改变,可以在创建图层时预加载。

这是一个没有预加载的例子。打开地图 5 秒后,三个数据层可见。只有这样才能从矢量源中指定的 url 请求数据,然后可以看到它以不同的速度加载,因为其中一层必须下载 40mb KML 文件。

var raster_OSM = new ol.layer.Tile({
    source:  new ol.source.OSM() 
});

var resolutions = ol.tilegrid.createXYZ().getResolutions();

var style_Cnty = new ol.style.Style({
    stroke: new ol.style.Stroke({
        color: '#3399CC',
        width: 1.25
    })
});

var vector_Cnty = new ol.layer.Vector({
    source: new ol.source.Vector({
        url: 'https://raw.githubusercontent.com/tanhe03/kml/master/gz_2010_us_050_00_500k.kml',
        format: new ol.format.KML({extractStyles: false})
    }),
    maxResolution: resolutions[3],
    style: function(feature, resolution) {
        var styles = [ style_Cnty ];
        if (resolution < resolutions[8]) {
            var geom = feature.getGeometry();
            styles.push(
                new ol.style.Style({
                    geometry: geom.getInteriorPoints ? geom.getInteriorPoints() : geom.getInteriorPoint(),
                    text: new ol.style.Text({
                        font: 'bold 16px sans-serif',
                        fill: new ol.style.Fill({
                            color: '#3399CC'
                        }),
                        backgroundFill: new ol.style.Fill({
                            color: 'rgba(255,255,255,0.5)'
                        }),                            
                        text: feature.get('Name')
                    })
                })
            )
        }
        return styles;
    },
    visible: false
});

var vector_State = new ol.layer.Vector({
    source: new ol.source.Vector({
        url: 'https://raw.githubusercontent.com/tanhe03/kml/master/gz_2010_us_040_00_500k.kml',
        format: new ol.format.KML({extractStyles: false})
    }),
    maxResolution: resolutions[1],
    style: new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: 'purple',
            width: 1.25
        }) 
    }),
    visible: false
});

var vector_US = new ol.layer.Vector({
    source: new ol.source.Vector({
        url: 'https://raw.githubusercontent.com/tanhe03/kml/master/gz_2010_us_outline_500k.kml',
        format: new ol.format.KML({extractStyles: false})
    }),
    style: new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: '#3399CC',
            width: 1.25
        }) 
    }),
    visible: false
});

var map = new ol.Map({
  layers: [raster_OSM, vector_Cnty, vector_State, vector_US],
  target: 'map',
  view: new ol.View({
    center: ol.proj.transform([-96, 38], 'EPSG:4326', 'EPSG:3857'),
    zoom: 4
  })
});

setTimeout(function(){
  vector_Cnty.setVisible(true);
  vector_State.setVisible(true);
  vector_US.setVisible(true);
}, 5000);
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>

但在此示例中,数据的预加载在创建图层时开始。 XHR 立即请求 url,解析响应并将功能添加到源。当图层在 5 秒后可见时,应该已经加载了所有三个图层。

var raster_OSM = new ol.layer.Tile({
    source:  new ol.source.OSM() 
});

var resolutions = ol.tilegrid.createXYZ().getResolutions();

var style_Cnty = new ol.style.Style({
    stroke: new ol.style.Stroke({
        color: '#3399CC',
        width: 1.25
    })
});

var vector_Cnty = new ol.layer.Vector({
    source: new ol.source.Vector({
        format: new ol.format.KML({extractStyles: false})
    }),
    maxResolution: resolutions[3],
    style: function(feature, resolution) {
        var styles = [ style_Cnty ];
        if (resolution < resolutions[8]) {
            var geom = feature.getGeometry();
            styles.push(
                new ol.style.Style({
                    geometry: geom.getInteriorPoints ? geom.getInteriorPoints() : geom.getInteriorPoint(),
                    text: new ol.style.Text({
                        font: 'bold 16px sans-serif',
                        fill: new ol.style.Fill({
                            color: '#3399CC'
                        }),
                        backgroundFill: new ol.style.Fill({
                            color: 'rgba(255,255,255,0.5)'
                        }),                            
                        text: feature.get('Name')
                    })
                })
            )
        }
        return styles;
    },
    visible: false
});

var vector_State = new ol.layer.Vector({
    source: new ol.source.Vector({
        format: new ol.format.KML({extractStyles: false})
    }),
    maxResolution: resolutions[1],
    style: new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: 'purple',
            width: 1.25
        }) 
    }),
    visible: false
});

var vector_US = new ol.layer.Vector({
    source: new ol.source.Vector({
        format: new ol.format.KML({extractStyles: false})
    }),
    style: new ol.style.Style({
        stroke: new ol.style.Stroke({
            color: '#3399CC',
            width: 1.25
        }) 
    }),
    visible: false
});

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://raw.githubusercontent.com/tanhe03/kml/master/gz_2010_us_050_00_500k.kml');
xhr.onload = function() {
  var source = vector_Cnty.getSource();
  source.addFeatures(source.getFormat().readFeatures(this.responseText, {featureProjection: 'EPSG:3857'})); 
}
xhr.send();

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://raw.githubusercontent.com/tanhe03/kml/master/gz_2010_us_040_00_500k.kml');
xhr.onload = function() {
  var source = vector_State.getSource();
  source.addFeatures(source.getFormat().readFeatures(this.responseText, {featureProjection: 'EPSG:3857'})); 
}
xhr.send();

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://raw.githubusercontent.com/tanhe03/kml/master/gz_2010_us_outline_500k.kml');
xhr.onload = function() {
  var source = vector_US.getSource();
  source.addFeatures(source.getFormat().readFeatures(this.responseText, {featureProjection: 'EPSG:3857'})); 
}
xhr.send();

var map = new ol.Map({
  layers: [raster_OSM, vector_Cnty, vector_State, vector_US],
  target: 'map',
  view: new ol.View({
    center: ol.proj.transform([-96, 38], 'EPSG:4326', 'EPSG:3857'),
    zoom: 4
  })
});

setTimeout(function(){
  vector_Cnty.setVisible(true);
  vector_State.setVisible(true);
  vector_US.setVisible(true);
}, 5000);
html, body, .map {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
<link href="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css" rel="stylesheet" />
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<div id="map" class="map"></div>

如果您希望动态加载图层,则必须使其可见,否则不会发送请求。 让它工作的一种方法是使图层可见但阻止绘制要素(return 样式函数中的空样式)

var visible = false; // turn it to true to have the features drawn
var vector = new ol.layer.Vector({
  source: new ol.source.Vector({
    // your source definition
  }),
  visible: true,
  style: function(feature, resolution) {
    if (!visible) {
      return [];
    } else {
      return your_style_for_the_feature;
    }
  }
});

图层将被加载和绘制,但由于未绘制要素,因此不会显示任何内容。只需在样式函数中将 return 您的样式设置为 visible 为 true 并绘制它们。 您还必须告诉来源它必须使用 changed 函数重绘:

// Draw the layer
visible = true;
vector.getSource().changed();