Как предварительно кэшировать тайлы с помощью OpenLayers для анимации даты

Я работаю над анимацией карты OpenLayers с несколькими слоями в течение определенного периода времени. Я бы хотел предварительно кэшировать плитки ol.layer.tile, чтобы иметь плавные переходы между датами. Любые предложения о том, как предварительно кэшировать / предварительно загружать эти плитки?

2 ответа

Решение

Вы можете положиться на кеш вашего браузера здесь. И это требует, чтобы ваш сервер отправлял правильные заголовки кэша, чтобы браузер не получал изображения повторно при каждом запросе. С учетом этих предварительных условий выполните следующие действия:

  1. Вызов ol.source.TileImage#getTileUrlFunction на вашем источнике, чтобы вы могли вычислить URL тайлов, которые вы хотите кэшировать.

  2. Вызов ol.source.TileImage#getTileGrid на вашем источнике, чтобы вы могли получить координаты плитки для экстента и уровня масштабирования, которые вы хотите кэшировать

  3. Вызов ol.tilegrid.TileGrid#forEachTileCoord с функцией, которая вычисляет URL для каждой плитки и устанавливает его как src для объекта изображения. При этом следите за количеством загружаемых плиток, чтобы знать, когда вы закончите.

  4. Повторите вышеупомянутое для всех измерений, после внесения соответствующих изменений размеров в ваш источник.

В конце ваш код для предварительной загрузки одного измерения может выглядеть примерно так:

var loadingCount = 0;
var myTileUrlFunction = mySource.getTileUrlFunction();
var myTileGrid = mySource.getTileGrid();
myTileGrid.forEachTileCoord(myExtent, myZoom, function(tileCoord) {
  var url = myTileUrlFunction.call(mySource, tileCoord, ol.has.DEVICE_PIXEL_RATIO, myProjection);
  var img = new Image();
  img.onload = function() {
    --loadingCount;
    if (loadingCount == 0) {
      // ready to animate
    }
  }
  ++loadingCount;
  img.src = url;
}

Решение, позволяющее обойти заголовки, предотвращающие кеш.

var i = 0;
var renderer = new ol.renderer.canvas.TileLayer(layer);
var tileSource = layer.getSource();
var datePromise = new Promise(function(resolve, reject) {
    tileGrid.forEachTileCoord(extent, currentZ, function(tileCoord) {
        tile = tileSource.getTile(tileCoord[0], tileCoord[1], tileCoord[2], pixelRatio, projection);
        tile.load();
        var loader = function(e) {
            if(e.type === 'tileloadend') {
                --i;
                if(i === 0) {
                    resolve();
                }
            } else {
                 reject(new Error('No response at this URL'));
            }
            /* remove listeners */
            this.un('tileloadend', loader);
            this.un('tileloaderror', loader);
        };
        tileSource.on('tileloadend', loader);
        tileSource.on('tileloaderror', loader);
        ++i;
    });
});
Другие вопросы по тегам