diff --git a/src/ol/VectorImageTile.js b/src/ol/VectorImageTile.js index 8e0ea79d23..98e34d2c77 100644 --- a/src/ol/VectorImageTile.js +++ b/src/ol/VectorImageTile.js @@ -6,7 +6,6 @@ import Tile from './Tile.js'; import TileState from './TileState.js'; import {createCanvasContext2D} from './dom.js'; import {listen, unlistenByKey} from './events.js'; -import {getHeight, getIntersection, getWidth} from './extent.js'; import EventType from './events/EventType.js'; import {loadFeaturesXhr} from './featureloader.js'; @@ -26,23 +25,11 @@ class VectorImageTile extends Tile { * @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate. * @param {TileState} state State. * @param {number} sourceRevision Source revision. - * @param {import("./format/Feature.js").default} format Feature format. - * @param {import("./Tile.js").LoadFunction} tileLoadFunction Tile load function. * @param {import("./tilecoord.js").TileCoord} urlTileCoord Wrapped tile coordinate for source urls. - * @param {import("./Tile.js").UrlFunction} tileUrlFunction Tile url function. * @param {import("./tilegrid/TileGrid.js").default} sourceTileGrid Tile grid of the source. - * @param {import("./tilegrid/TileGrid.js").default} tileGrid Tile grid of the renderer. * @param {Object} sourceTiles Source tiles. - * @param {number} pixelRatio Pixel ratio. - * @param {import("./proj/Projection.js").default} projection Projection. - * @param {typeof import("./VectorTile.js").default} tileClass Class to - * instantiate for source tiles. - * @param {function(this: import("./source/VectorTile.js").default, import("./events/Event.js").default): void} handleTileChange - * Function to call when a source tile's state changes. */ - constructor(tileCoord, state, sourceRevision, format, tileLoadFunction, - urlTileCoord, tileUrlFunction, sourceTileGrid, tileGrid, sourceTiles, - pixelRatio, projection, tileClass, handleTileChange) { + constructor(tileCoord, state, sourceRevision, urlTileCoord, sourceTileGrid, sourceTiles) { super(tileCoord, state, {transition: 0}); @@ -114,37 +101,6 @@ class VectorImageTile extends Tile { this.sourceTileListenerKeys_ = []; this.key = sourceRevision.toString(); - - if (urlTileCoord && sourceTileGrid) { - const extent = this.extent = tileGrid.getTileCoordExtent(urlTileCoord); - const resolution = this.resolution_ = tileGrid.getResolution(urlTileCoord[0]); - const sourceZ = sourceTileGrid.getZForResolution(resolution); - sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) { - let sharedExtent = getIntersection(extent, - sourceTileGrid.getTileCoordExtent(sourceTileCoord)); - const sourceExtent = sourceTileGrid.getExtent(); - if (sourceExtent) { - sharedExtent = getIntersection(sharedExtent, sourceExtent, sharedExtent); - } - if (getWidth(sharedExtent) / resolution >= 0.5 && - getHeight(sharedExtent) / resolution >= 0.5) { - // only include source tile if overlap is at least 1 pixel - const sourceTileKey = sourceTileCoord.toString(); - let sourceTile = sourceTiles[sourceTileKey]; - if (!sourceTile) { - const tileUrl = tileUrlFunction(sourceTileCoord, pixelRatio, projection); - sourceTile = sourceTiles[sourceTileKey] = new tileClass(sourceTileCoord, - tileUrl == undefined ? TileState.EMPTY : TileState.IDLE, - tileUrl == undefined ? '' : tileUrl, - format, tileLoadFunction); - this.sourceTileListenerKeys_.push( - listen(sourceTile, EventType.CHANGE, handleTileChange)); - } - sourceTile.consumers++; - this.tileKeys.push(sourceTileKey); - } - }.bind(this)); - } } /** @@ -230,9 +186,8 @@ class VectorImageTile extends Tile { for (let i = 0, ii = tileKeys.length; i < ii; ++i) { this.sourceTiles_[tileKeys[i]].consumers++; } - const tile = new VectorImageTile(this.tileCoord, TileState.IDLE, Number(this.key), null, null, - this.wrappedTileCoord, null, null, null, this.sourceTiles_, - undefined, null, null, null); + const tile = new VectorImageTile(this.tileCoord, TileState.IDLE, Number(this.key), + this.wrappedTileCoord, null, this.sourceTiles_); tile.extent = this.extent; tile.tileKeys = tileKeys; tile.context_ = this.context_; diff --git a/src/ol/source/VectorTile.js b/src/ol/source/VectorTile.js index 5be126a92f..33918dd80f 100644 --- a/src/ol/source/VectorTile.js +++ b/src/ol/source/VectorTile.js @@ -9,6 +9,9 @@ import {toSize} from '../size.js'; import UrlTile from './UrlTile.js'; import {getKeyZXY} from '../tilecoord.js'; import {createXYZ, extentFromProjection, createForProjection} from '../tilegrid.js'; +import {getIntersection, getWidth, getHeight} from '../extent.js'; +import {listen} from '../events.js'; +import EventType from '../events/EventType.js'; /** * @typedef {Object} Options @@ -151,6 +154,49 @@ class VectorTile extends UrlTile { this.sourceTiles_ = {}; } + /** + * Finds and assigns source tiles for a vector image tile. + * @param {VectorImageTile} tile Tile. + * @param {number} pixelRatio Pixel ratio. + * @param {import("../proj/Projection").default} projection Projection. + */ + assignTiles(tile, pixelRatio, projection) { + if (!tile.wrappedTileCoord) { + return; + } + const sourceTileGrid = this.tileGrid; + const tileGrid = this.getTileGridForProjection(projection); + const urlTileCoord = tile.wrappedTileCoord; + const extent = tile.extent = tileGrid.getTileCoordExtent(urlTileCoord); + const resolution = this.resolution_ = tileGrid.getResolution(urlTileCoord[0]); + const sourceZ = sourceTileGrid.getZForResolution(resolution); + sourceTileGrid.forEachTileCoord(extent, sourceZ, function(sourceTileCoord) { + let sharedExtent = getIntersection(extent, + sourceTileGrid.getTileCoordExtent(sourceTileCoord)); + const sourceExtent = sourceTileGrid.getExtent(); + if (sourceExtent) { + sharedExtent = getIntersection(sharedExtent, sourceExtent, sharedExtent); + } + if (getWidth(sharedExtent) / resolution >= 0.5 && + getHeight(sharedExtent) / resolution >= 0.5) { + // only include source tile if overlap is at least 1 pixel + const sourceTileKey = sourceTileCoord.toString(); + let sourceTile = this.sourceTiles_[sourceTileKey]; + if (!sourceTile) { + const tileUrl = this.tileUrlFunction(sourceTileCoord, pixelRatio, projection); + sourceTile = this.sourceTiles_[sourceTileKey] = new this.tileClass(sourceTileCoord, + tileUrl == undefined ? TileState.EMPTY : TileState.IDLE, + tileUrl == undefined ? '' : tileUrl, + this.format_, this.tileLoadFunction); + tile.sourceTileListenerKeys_.push( + listen(sourceTile, EventType.CHANGE, this.handleTileChange.bind(this))); + } + sourceTile.consumers++; + tile.tileKeys.push(sourceTileKey); + } + }.bind(this)); + } + /** * @inheritDoc */ @@ -168,11 +214,11 @@ class VectorTile extends UrlTile { tileCoord, urlTileCoord !== null ? TileState.IDLE : TileState.EMPTY, this.getRevision(), - this.format_, this.tileLoadFunction, urlTileCoord, this.tileUrlFunction, - this.tileGrid, this.getTileGridForProjection(projection), - this.sourceTiles_, pixelRatio, projection, this.tileClass, - this.handleTileChange.bind(this)); + urlTileCoord, + this.tileGrid, + this.sourceTiles_); + this.assignTiles(tile, pixelRatio, projection); this.tileCache.set(tileCoordKey, tile); return tile; } diff --git a/test/spec/ol/renderer/canvas/vectortilelayer.test.js b/test/spec/ol/renderer/canvas/vectortilelayer.test.js index 8e44634d7a..22a17d62d2 100644 --- a/test/spec/ol/renderer/canvas/vectortilelayer.test.js +++ b/test/spec/ol/renderer/canvas/vectortilelayer.test.js @@ -244,11 +244,10 @@ describe('ol.renderer.canvas.VectorTileLayer', function() { sourceTile.getImage = function() { return document.createElement('canvas'); }; - const tile = new VectorImageTile([0, 0, 0], undefined, 1, undefined, - undefined, [0, 0, 0], undefined, createXYZ(), createXYZ(), {'0,0,0': sourceTile}, undefined, - undefined, undefined, undefined); + const tile = new VectorImageTile([0, 0, 0], undefined, 1, [0, 0, 0], createXYZ(), {'0,0,0': sourceTile}); tile.transition_ = 0; - tile.wrappedTileCoord = [0, 0, 0]; + tile.tileKeys = ['0,0,0']; + tile.extent = getProjection('EPSG:3857').getExtent(); tile.setState(TileState.LOADED); tile.getSourceTile = function() { return sourceTile; diff --git a/test/spec/ol/vectorimagetile.test.js b/test/spec/ol/vectorimagetile.test.js index b1b093a68b..6431d8fea5 100644 --- a/test/spec/ol/vectorimagetile.test.js +++ b/test/spec/ol/vectorimagetile.test.js @@ -1,9 +1,8 @@ import TileState from '../../../src/ol/TileState.js'; -import VectorImageTile, {defaultLoadFunction} from '../../../src/ol/VectorImageTile.js'; -import VectorTile from '../../../src/ol/VectorTile.js'; +import {defaultLoadFunction} from '../../../src/ol/VectorImageTile.js'; +import VectorTileSource from '../../../src/ol/source/VectorTile.js'; import {listen, listenOnce} from '../../../src/ol/events.js'; import GeoJSON from '../../../src/ol/format/GeoJSON.js'; -import {get as getProjection} from '../../../src/ol/proj.js'; import {createXYZ} from '../../../src/ol/tilegrid.js'; import TileGrid from '../../../src/ol/tilegrid/TileGrid.js'; @@ -11,13 +10,11 @@ import TileGrid from '../../../src/ol/tilegrid/TileGrid.js'; describe('ol.VectorImageTile', function() { it('configures loader that sets features on the source tile', function(done) { - const format = new GeoJSON(); - const url = 'spec/ol/data/point.json'; - const tile = new VectorImageTile([0, 0, 0], 0, url, format, - defaultLoadFunction, [0, 0, 0], function() { - return url; - }, createXYZ(), createXYZ(), {}, - 1, getProjection('EPSG:3857'), VectorTile, function() {}); + const source = new VectorTileSource({ + format: new GeoJSON(), + url: 'spec/ol/data/point.json' + }); + const tile = source.getTile(0, 0, 0, 1, source.getProjection()); tile.load(); const sourceTile = tile.getTile(tile.tileKeys[0]); @@ -31,17 +28,16 @@ describe('ol.VectorImageTile', function() { }); it('sets sourceTilesLoaded when previously failed source tiles are loaded', function(done) { - const format = new GeoJSON(); - const url = 'spec/ol/data/unavailable.json'; let sourceTile; - const tile = new VectorImageTile([0, 0, 0] /* one world away */, 0, url, format, - function(tile, url) { + const source = new VectorTileSource({ + format: new GeoJSON(), + url: 'spec/ol/data/unavailable.json', + tileLoadFunction: function(tile, url) { sourceTile = tile; defaultLoadFunction(tile, url); - }, [0, 0, 0], function() { - return url; - }, createXYZ(), createXYZ(), {}, - 1, getProjection('EPSG:3857'), VectorTile, function() {}); + } + }); + const tile = source.getTile(0, 0, 0, 1, source.getProjection()); tile.load(); let calls = 0; @@ -63,13 +59,11 @@ describe('ol.VectorImageTile', function() { }); it('sets ERROR state when source tiles fail to load', function(done) { - const format = new GeoJSON(); - const url = 'spec/ol/data/unavailable.json'; - const tile = new VectorImageTile([0, 0, 0], 0, url, format, - defaultLoadFunction, [0, 0, 0], function() { - return url; - }, createXYZ(), createXYZ(), {}, - 1, getProjection('EPSG:3857'), VectorTile, function() {}); + const source = new VectorTileSource({ + format: new GeoJSON(), + url: 'spec/ol/data/unavailable.json' + }); + const tile = source.getTile(0, 0, 0, 1, source.getProjection()); tile.load(); @@ -80,12 +74,11 @@ describe('ol.VectorImageTile', function() { }); it('sets EMPTY state when tile has only empty source tiles', function(done) { - const format = new GeoJSON(); - const url = ''; - const tile = new VectorImageTile([0, 0, 0], 0, url, format, - defaultLoadFunction, [0, 0, 0], function() {}, - createXYZ(), createXYZ(), {}, - 1, getProjection('EPSG:3857'), VectorTile, function() {}); + const source = new VectorTileSource({ + format: new GeoJSON(), + url: '' + }); + const tile = source.getTile(0, 0, 0, 1, source.getProjection()); tile.load(); @@ -96,33 +89,37 @@ describe('ol.VectorImageTile', function() { }); it('only loads tiles within the source tileGrid\'s extent', function() { - const format = new GeoJSON(); const url = 'spec/ol/data/point.json'; - const tileGrid = new TileGrid({ - resolutions: [0.02197265625, 0.010986328125, 0.0054931640625], - origin: [-180, 90], - extent: [-88, 35, -87, 36] - }); - const sourceTiles = {}; - const tile = new VectorImageTile([1, 0, 0], 0, url, format, - defaultLoadFunction, [1, 0, 0], function(zxy) { + const source = new VectorTileSource({ + projection: 'EPSG:4326', + format: new GeoJSON(), + tileGrid: new TileGrid({ + resolutions: [0.02197265625, 0.010986328125, 0.0054931640625], + origin: [-180, 90], + extent: [-88, 35, -87, 36] + }), + tileUrlFunction: function(zxy) { return url; - }, tileGrid, - createXYZ({extent: [-180, -90, 180, 90], tileSize: 512}), - sourceTiles, 1, getProjection('EPSG:4326'), VectorTile, function() {}); + }, + url: url + }); + const tile = source.getTile(0, 0, 0, 1, source.getProjection()); + tile.load(); expect(tile.tileKeys.length).to.be(1); expect(tile.getTile(tile.tileKeys[0]).tileCoord).to.eql([0, 16, 9]); }); it('#dispose() while loading', function() { - const format = new GeoJSON(); - const url = 'spec/ol/data/point.json'; - const tile = new VectorImageTile([0, 0, 0] /* one world away */, 0, url, format, - defaultLoadFunction, [0, 0, 0], function() { - return url; - }, createXYZ(), createXYZ({tileSize: 512}), {}, - 1, getProjection('EPSG:3857'), VectorTile, function() {}); + const source = new VectorTileSource({ + format: new GeoJSON(), + url: 'spec/ol/data/point.json', + tileGrid: createXYZ() + }); + source.getTileGridForProjection = function() { + return createXYZ({tileSize: 512}); + }; + const tile = source.getTile(0, 0, 0, 1, source.getProjection()); tile.load(); expect(tile.loadListenerKeys_.length).to.be(4); @@ -136,13 +133,15 @@ describe('ol.VectorImageTile', function() { }); it('#dispose() when source tiles are loaded', function(done) { - const format = new GeoJSON(); - const url = 'spec/ol/data/point.json'; - const tile = new VectorImageTile([0, 0, 0], 0, url, format, - defaultLoadFunction, [0, 0, 0], function() { - return url; - }, createXYZ(), createXYZ({tileSize: 512}), {}, - 1, getProjection('EPSG:3857'), VectorTile, function() {}); + const source = new VectorTileSource({ + format: new GeoJSON(), + url: 'spec/ol/data/point.json', + tileGrid: createXYZ() + }); + source.getTileGridForProjection = function() { + return createXYZ({tileSize: 512}); + }; + const tile = source.getTile(0, 0, 0, 1, source.getProjection()); tile.load(); listenOnce(tile, 'change', function() {