diff --git a/src/ol/source/VectorTile.js b/src/ol/source/VectorTile.js index a3159f53d7..f8841589e6 100644 --- a/src/ol/source/VectorTile.js +++ b/src/ol/source/VectorTile.js @@ -200,74 +200,78 @@ class VectorTile extends UrlTile { const minZoom = sourceTileGrid.getMinZoom(); const previousSourceTiles = this.sourceTilesByTileKey_[tile.getKey()]; + let sourceTiles, covered, empty, loadedZ; if (previousSourceTiles && previousSourceTiles.length > 0 && previousSourceTiles[0].tileCoord[0] === sourceZ) { - return previousSourceTiles; - } - - const sourceTiles = []; - let loadedZ = sourceZ + 1; - let covered, empty; - do { - --loadedZ; + sourceTiles = previousSourceTiles; covered = true; - empty = true; - sourceTileGrid.forEachTileCoord(extent, loadedZ, function(sourceTileCoord) { - const coordKey = getKey(sourceTileCoord); - let sourceTile; - if (coordKey in this.sourceTileByCoordKey_) { - sourceTile = this.sourceTileByCoordKey_[coordKey]; - const state = sourceTile.getState(); - if (state === TileState.LOADED || state === TileState.ERROR || state === TileState.EMPTY) { - empty = empty && state === TileState.EMPTY; - sourceTiles.push(sourceTile); + empty = false; + loadedZ = sourceZ; + } else { + sourceTiles = []; + loadedZ = sourceZ + 1; + do { + --loadedZ; + covered = true; + empty = true; + sourceTileGrid.forEachTileCoord(extent, loadedZ, function(sourceTileCoord) { + const coordKey = getKey(sourceTileCoord); + let sourceTile; + if (coordKey in this.sourceTileByCoordKey_) { + sourceTile = this.sourceTileByCoordKey_[coordKey]; + const state = sourceTile.getState(); + if (state === TileState.LOADED || state === TileState.ERROR || state === TileState.EMPTY) { + empty = empty && state === TileState.EMPTY; + sourceTiles.push(sourceTile); + return; + } + } else if (loadedZ === sourceZ) { + const tileUrl = this.tileUrlFunction(sourceTileCoord, pixelRatio, projection); + if (tileUrl !== undefined) { + sourceTile = new this.tileClass(sourceTileCoord, TileState.IDLE, tileUrl, + this.format_, this.tileLoadFunction); + sourceTile.extent = sourceTileGrid.getTileCoordExtent(sourceTileCoord); + sourceTile.projection = projection; + sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]); + this.sourceTileByCoordKey_[coordKey] = sourceTile; + empty = false; + listen(sourceTile, EventType.CHANGE, this.handleTileChange, this); + sourceTile.load(); + } + } else { + empty = false; + } + covered = false; + if (!sourceTile) { return; } - } else if (loadedZ === sourceZ) { - const tileUrl = this.tileUrlFunction(sourceTileCoord, pixelRatio, projection); - if (tileUrl !== undefined) { - sourceTile = new this.tileClass(sourceTileCoord, TileState.IDLE, tileUrl, - this.format_, this.tileLoadFunction); - sourceTile.extent = sourceTileGrid.getTileCoordExtent(sourceTileCoord); - sourceTile.projection = projection; - sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]); - this.sourceTileByCoordKey_[coordKey] = sourceTile; - empty = false; - listen(sourceTile, EventType.CHANGE, this.handleTileChange, this); - sourceTile.load(); + if (sourceTile.getState() !== TileState.EMPTY && tile.getState() === TileState.IDLE) { + tile.loadingSourceTiles++; + const key = listen(sourceTile, EventType.CHANGE, function() { + const state = sourceTile.getState(); + const sourceTileKey = sourceTile.getKey(); + if (state === TileState.LOADED || state === TileState.ERROR) { + if (state === TileState.LOADED) { + unlistenByKey(key); + tile.loadingSourceTiles--; + delete tile.errorSourceTileKeys[sourceTileKey]; + } else if (state === TileState.ERROR) { + tile.errorSourceTileKeys[sourceTileKey] = true; + } + if (tile.loadingSourceTiles - Object.keys(tile.errorSourceTileKeys).length === 0) { + tile.hifi = true; + tile.sourceZ = sourceZ; + tile.setState(isEmpty(tile.errorSourceTileKeys) ? TileState.LOADED : TileState.ERROR); + } + } + }); } - } else { - empty = false; + }.bind(this)); + if (!covered) { + sourceTiles.length = 0; } - covered = false; - if (!sourceTile) { - return; - } - if (sourceTile.getState() !== TileState.EMPTY && tile.getState() === TileState.IDLE) { - tile.loadingSourceTiles++; - const key = listen(sourceTile, EventType.CHANGE, function() { - const state = sourceTile.getState(); - const sourceTileKey = sourceTile.getKey(); - if (state === TileState.LOADED || state === TileState.ERROR) { - if (state === TileState.LOADED) { - unlistenByKey(key); - tile.loadingSourceTiles--; - delete tile.errorSourceTileKeys[sourceTileKey]; - } else if (state === TileState.ERROR) { - tile.errorSourceTileKeys[sourceTileKey] = true; - } - if (tile.loadingSourceTiles - Object.keys(tile.errorSourceTileKeys).length === 0) { - tile.hifi = true; - tile.sourceZ = sourceZ; - tile.setState(isEmpty(tile.errorSourceTileKeys) ? TileState.LOADED : TileState.ERROR); - } - } - }); - } - }.bind(this)); - if (!covered) { - sourceTiles.length = 0; - } - } while (!covered && loadedZ > minZoom); + } while (!covered && loadedZ > minZoom); + } + if (!empty && tile.getState() === TileState.IDLE) { tile.setState(TileState.LOADING); } diff --git a/test/spec/ol/source/vectortile.test.js b/test/spec/ol/source/vectortile.test.js index b8499ca834..d1b8acbd7b 100644 --- a/test/spec/ol/source/vectortile.test.js +++ b/test/spec/ol/source/vectortile.test.js @@ -11,16 +11,17 @@ import {createXYZ} from '../../../../src/ol/tilegrid.js'; import TileGrid from '../../../../src/ol/tilegrid/TileGrid.js'; import {listen, unlistenByKey} from '../../../../src/ol/events.js'; import TileState from '../../../../src/ol/TileState.js'; -import {getCenter} from '../../../../src/ol/extent.js'; describe('ol.source.VectorTile', function() { - const format = new MVT(); - const source = new VectorTileSource({ - format: format, - url: 'spec/ol/data/{z}-{x}-{y}.vector.pbf' + let format, source; + beforeEach(function() { + format = new MVT(); + source = new VectorTileSource({ + format: format, + url: 'spec/ol/data/{z}-{x}-{y}.vector.pbf' + }); }); - let tile; describe('constructor', function() { it('sets the format on the instance', function() { @@ -45,15 +46,9 @@ describe('ol.source.VectorTile', function() { describe('#getTile()', function() { it('creates a tile with the correct tile class', function() { - tile = source.getTile(0, 0, 0, 1, getProjection('EPSG:3857')); + const tile = source.getTile(0, 0, 0, 1, getProjection('EPSG:3857')); expect(tile).to.be.a(VectorRenderTile); - }); - - it('sets the correct tileCoord on the created tile', function() { expect(tile.getTileCoord()).to.eql([0, 0, 0]); - }); - - it('fetches tile from cache when requested again', function() { expect(source.getTile(0, 0, 0, 1, getProjection('EPSG:3857'))) .to.equal(tile); }); @@ -122,7 +117,7 @@ describe('ol.source.VectorTile', function() { describe('Tile load events', function() { it('triggers tileloadstart and tileloadend with ol.VectorTile', function(done) { - tile = source.getTile(14, 8938, 5680, 1, getProjection('EPSG:3857')); + const tile = source.getTile(14, 8938, 5680, 1, getProjection('EPSG:3857')); let started = false; source.on('tileloadstart', function() { started = true; @@ -209,45 +204,59 @@ describe('ol.source.VectorTile', function() { target.style.width = '100px'; target.style.height = '100px'; document.body.appendChild(target); - const extent = [1824704.739223726, 6141868.096770482, 1827150.7241288517, 6144314.081675608]; - let url = 'spec/ol/data/14-8938-5680.vector.pbf?'; + + const urls = [ + 'spec/ol/data/14-8938-5680.vector.pbf?num=0&coord={z},{x},{y}', + 'spec/ol/data/14-8938-5680.vector.pbf?num=1&coord={z},{x},{y}', + 'spec/ol/data/14-8938-5680.vector.pbf?num=2&coord={z},{x},{y}', + 'spec/ol/data/14-8938-5680.vector.pbf?num=3&coord={z},{x},{y}' + ]; + const source = new VectorTileSource({ format: new MVT(), - url: url, - minZoom: 14, - maxZoom: 14 + url: urls[0] }); const map = new Map({ target: target, layers: [ new VectorTileLayer({ - extent: extent, source: source }) ], view: new View({ - center: getCenter(extent), - zoom: 14 + center: [0, 0], + zoom: 0 }) }); + map.renderSync(); - const limit = 3; + + const max = urls.length + 3; let count = 0; - source.on('tileloadend', function() { - setTimeout(function() { + let tile = source.getTile(0, 0, 0, 1, map.getView().getProjection()); + tile.addEventListener('change', function onTileChange(e) { + if (e.target.getState() !== TileState.LOADED && !e.target.hifi) { + return; + } + e.target.removeEventListener('change', onTileChange); + + map.once('rendercomplete', function() { + expect(map.tileQueue_.getTilesLoading()).to.be(0); + ++count; - if (count === limit) { + if (count === max) { document.body.removeChild(target); map.dispose(); done(); + return; } - url = url + count; - source.setUrl(url); - const queue = map.tileQueue_; - expect(queue.getTilesLoading()).to.be(0); - }, 100); + source.setUrl(urls[count % urls.length]); + tile = source.getTile(0, 0, 0, 1, map.getView().getProjection()); + tile.addEventListener('change', onTileChange); + }); + }); });