diff --git a/src/ol/source/VectorTile.js b/src/ol/source/VectorTile.js index 3c0c126a4c..89871d3ff2 100644 --- a/src/ol/source/VectorTile.js +++ b/src/ol/source/VectorTile.js @@ -200,11 +200,10 @@ class VectorTile extends UrlTile { const minZoom = sourceTileGrid.getMinZoom(); const previousSourceTiles = this.sourceTilesByTileKey_[tile.getKey()]; - let sourceTiles, covered, empty, loadedZ; + let sourceTiles, covered, loadedZ; if (previousSourceTiles && previousSourceTiles.length > 0 && previousSourceTiles[0].tileCoord[0] === sourceZ) { sourceTiles = previousSourceTiles; covered = true; - empty = false; loadedZ = sourceZ; } else { sourceTiles = []; @@ -212,7 +211,6 @@ class VectorTile extends UrlTile { do { --loadedZ; covered = true; - empty = true; sourceTileGrid.forEachTileCoord(extent, loadedZ, function(sourceTileCoord) { const coordKey = getKey(sourceTileCoord); let sourceTile; @@ -220,7 +218,6 @@ class VectorTile extends UrlTile { 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; } @@ -233,12 +230,9 @@ class VectorTile extends UrlTile { sourceTile.projection = projection; sourceTile.resolution = sourceTileGrid.getResolution(sourceTileCoord[0]); this.sourceTileByCoordKey_[coordKey] = sourceTile; - empty = false; sourceTile.addEventListener(EventType.CHANGE, this.handleTileChange.bind(this)); sourceTile.load(); } - } else { - empty = false; } covered = false; if (!sourceTile) { @@ -272,14 +266,14 @@ class VectorTile extends UrlTile { } while (!covered && loadedZ > minZoom); } - if (!empty && tile.getState() === TileState.IDLE) { + if (tile.getState() === TileState.IDLE) { tile.setState(TileState.LOADING); } - if (covered || empty) { + if (covered) { tile.hifi = sourceZ === loadedZ; tile.sourceZ = loadedZ; if (tile.getState() < TileState.LOADED) { - tile.setState(empty ? TileState.EMPTY : TileState.LOADED); + tile.setState(TileState.LOADED); } else if (!previousSourceTiles || !equals(sourceTiles, previousSourceTiles)) { this.removeSourceTiles(tile); this.addSourceTiles(tile, sourceTiles); @@ -334,8 +328,8 @@ class VectorTile extends UrlTile { const tileCoord = [z, x, y]; let urlTileCoord = this.getTileCoordForTileUrlFunction(tileCoord, projection); const sourceExtent = this.getTileGrid().getExtent(); + const tileGrid = this.getTileGridForProjection(projection); if (urlTileCoord && sourceExtent) { - const tileGrid = this.getTileGridForProjection(projection); const tileExtent = tileGrid.getTileCoordExtent(urlTileCoord); // make extent 1 pixel smaller so we don't load tiles for < 0.5 pixel render space bufferExtent(tileExtent, -tileGrid.getResolution(z), tileExtent); @@ -343,9 +337,21 @@ class VectorTile extends UrlTile { urlTileCoord = null; } } + let empty = true; + if (urlTileCoord !== null) { + const sourceTileGrid = this.tileGrid; + const resolution = tileGrid.getResolution(z); + const sourceZ = sourceTileGrid.getZForResolution(resolution, 1); + // make extent 1 pixel smaller so we don't load tiles for < 0.5 pixel render space + const extent = tileGrid.getTileCoordExtent(urlTileCoord); + bufferExtent(extent, -resolution, extent); + sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) { + empty = empty && !this.tileUrlFunction(sourceTileCoord, pixelRatio, projection); + }.bind(this)); + } const newTile = new VectorRenderTile( tileCoord, - urlTileCoord !== null ? TileState.IDLE : TileState.EMPTY, + empty ? TileState.EMPTY : TileState.IDLE, urlTileCoord, this.tileGrid, this.getSourceTiles.bind(this, pixelRatio, projection), diff --git a/test/spec/ol/source/vectortile.test.js b/test/spec/ol/source/vectortile.test.js index 6dfb743500..93e7c1e1ab 100644 --- a/test/spec/ol/source/vectortile.test.js +++ b/test/spec/ol/source/vectortile.test.js @@ -71,19 +71,13 @@ describe('ol.source.VectorTile', function() { }); }); - it('handles empty tiles', function(done) { + it('handles empty tiles', function() { const source = new VectorTileSource({ format: new GeoJSON(), url: '' }); const tile = source.getTile(0, 0, 0, 1, source.getProjection()); - - const key = listen(tile, 'change', function(e) { - unlistenByKey(key); - expect(tile.getState()).to.be(TileState.EMPTY); - done(); - }); - tile.load(); + expect(tile.getState()).to.be(TileState.EMPTY); }); it('creates empty tiles outside the source extent', function() { @@ -103,14 +97,30 @@ describe('ol.source.VectorTile', function() { expect(tile.getState()).to.be(TileState.EMPTY); }); + it('creates empty tiles when the tileUrlFunction returns undefined', function() { + const source = new VectorTileSource({ + tileUrlFunction: function(tileCoord) { + return; + } + }); + const tile = source.getTile(1, 1, 1, 1, source.getProjection()); + expect(tile.getState()).to.be(TileState.EMPTY); + }); + it('creates non-empty tiles outside the world extent when wrapX === true', function() { - const source = new VectorTileSource({}); + const source = new VectorTileSource({ + url: '{z}/{x}/{y}.pbf' + }); const tile = source.getTile(0, -1, 0, 1, source.getProjection()); expect(tile.getState()).to.be(TileState.IDLE); }); it('creates non-empty tiles for overzoomed resolutions', function() { const source = new VectorTileSource({ + url: '{z}/{x}/{y}.pbf', + tileLoadFunction: function(tile) { + tile.setLoader(function() {}); + }, maxZoom: 16 }); const tile = source.getTile(24, 9119385, 5820434, 1, source.getProjection());