Merge pull request #3246 from tschaub/tile-cache

Avoid creating unnecessary images in tile layers.
This commit is contained in:
Tim Schaub
2015-02-19 10:33:31 -07:00
9 changed files with 199 additions and 282 deletions
@@ -287,11 +287,7 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame =
/** @type {Array.<ol.Tile>} */ /** @type {Array.<ol.Tile>} */
var tilesToClear = []; var tilesToClear = [];
var getTileIfLoaded = this.createGetTileIfLoadedFunction(function(tile) { var findLoadedTiles = this.createLoadedTileFinder(tileSource, tilesToDrawByZ);
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED;
}, tileSource, pixelRatio, projection);
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, getTileIfLoaded);
var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
+1 -5
View File
@@ -128,11 +128,7 @@ ol.renderer.dom.TileLayer.prototype.prepareFrame =
var tilesToDrawByZ = {}; var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {}; tilesToDrawByZ[z] = {};
var getTileIfLoaded = this.createGetTileIfLoadedFunction(function(tile) { var findLoadedTiles = this.createLoadedTileFinder(tileSource, tilesToDrawByZ);
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED;
}, tileSource, pixelRatio, projection);
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, getTileIfLoaded);
var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
+27
View File
@@ -85,6 +85,33 @@ ol.renderer.Layer.prototype.forEachLayerAtPixel =
ol.renderer.Layer.prototype.hasFeatureAtCoordinate = goog.functions.FALSE; ol.renderer.Layer.prototype.hasFeatureAtCoordinate = goog.functions.FALSE;
/**
* Create a function that adds loaded tiles to the tile lookup.
* @param {ol.source.Tile} source Tile source.
* @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded
* tiles by zoom level.
* @return {function(number, ol.TileRange):boolean} A function that can be
* called with a zoom level and a tile range to add loaded tiles to the
* lookup.
* @protected
*/
ol.renderer.Layer.prototype.createLoadedTileFinder = function(source, tiles) {
/**
* @param {number} zoom Zoom level.
* @param {ol.TileRange} tileRange Tile range.
* @return {boolean} The tile range is fully loaded.
*/
return function(zoom, tileRange) {
return source.forEachLoadedTile(zoom, tileRange, function(tile) {
if (!tiles[zoom]) {
tiles[zoom] = {};
}
tiles[zoom][tile.tileCoord.toString()] = tile;
});
};
};
/** /**
* @protected * @protected
* @return {ol.layer.Layer} Layer. * @return {ol.layer.Layer} Layer.
@@ -94,6 +94,40 @@ ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() {
}; };
/**
* Create a function that adds loaded tiles to the tile lookup.
* @param {ol.source.Tile} source Tile source.
* @param {Object.<number, Object.<string, ol.Tile>>} tiles Lookup of loaded
* tiles by zoom level.
* @return {function(number, ol.TileRange):boolean} A function that can be
* called with a zoom level and a tile range to add loaded tiles to the
* lookup.
* @protected
*/
ol.renderer.webgl.TileLayer.prototype.createLoadedTileFinder =
function(source, tiles) {
var mapRenderer = this.mapRenderer;
/**
* @param {number} zoom Zoom level.
* @param {ol.TileRange} tileRange Tile range.
* @return {boolean} The tile range is fully loaded.
*/
return function(zoom, tileRange) {
return source.forEachLoadedTile(zoom, tileRange, function(tile) {
var loaded = mapRenderer.isTileTextureLoaded(tile);
if (loaded) {
if (!tiles[zoom]) {
tiles[zoom] = {};
}
tiles[zoom][tile.tileCoord.toString()] = tile;
}
return loaded;
});
};
};
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -190,12 +224,8 @@ ol.renderer.webgl.TileLayer.prototype.prepareFrame =
var tilesToDrawByZ = {}; var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {}; tilesToDrawByZ[z] = {};
var getTileIfLoaded = this.createGetTileIfLoadedFunction(function(tile) { var findLoadedTiles = this.createLoadedTileFinder(
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED && tileSource, tilesToDrawByZ);
mapRenderer.isTileTextureLoaded(tile);
}, tileSource, pixelRatio, projection);
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, getTileIfLoaded);
var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
var allTilesLoaded = true; var allTilesLoaded = true;
+3 -26
View File
@@ -1,7 +1,6 @@
goog.provide('ol.source.TileDebug'); goog.provide('ol.source.TileDebug');
goog.require('ol.Tile'); goog.require('ol.Tile');
goog.require('ol.TileCache');
goog.require('ol.TileCoord'); goog.require('ol.TileCoord');
goog.require('ol.TileState'); goog.require('ol.TileState');
goog.require('ol.dom'); goog.require('ol.dom');
@@ -89,42 +88,20 @@ ol.source.TileDebug = function(options) {
tileGrid: options.tileGrid tileGrid: options.tileGrid
}); });
/**
* @private
* @type {ol.TileCache}
*/
this.tileCache_ = new ol.TileCache();
}; };
goog.inherits(ol.source.TileDebug, ol.source.Tile); goog.inherits(ol.source.TileDebug, ol.source.Tile);
/**
* @inheritDoc
*/
ol.source.TileDebug.prototype.canExpireCache = function() {
return this.tileCache_.canExpireCache();
};
/**
* @inheritDoc
*/
ol.source.TileDebug.prototype.expireCache = function(usedTiles) {
this.tileCache_.expireCache(usedTiles);
};
/** /**
* @inheritDoc * @inheritDoc
*/ */
ol.source.TileDebug.prototype.getTile = function(z, x, y) { ol.source.TileDebug.prototype.getTile = function(z, x, y) {
var tileCoordKey = this.getKeyZXY(z, x, y); var tileCoordKey = this.getKeyZXY(z, x, y);
if (this.tileCache_.containsKey(tileCoordKey)) { if (this.tileCache.containsKey(tileCoordKey)) {
return /** @type {!ol.DebugTile_} */ (this.tileCache_.get(tileCoordKey)); return /** @type {!ol.DebugTile_} */ (this.tileCache.get(tileCoordKey));
} else { } else {
var tile = new ol.DebugTile_([z, x, y], this.tileGrid); var tile = new ol.DebugTile_([z, x, y], this.tileGrid);
this.tileCache_.set(tileCoordKey, tile); this.tileCache.set(tileCoordKey, tile);
return tile; return tile;
} }
}; };
-23
View File
@@ -4,7 +4,6 @@ goog.require('goog.asserts');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.events.EventType'); goog.require('goog.events.EventType');
goog.require('ol.ImageTile'); goog.require('ol.ImageTile');
goog.require('ol.TileCache');
goog.require('ol.TileCoord'); goog.require('ol.TileCoord');
goog.require('ol.TileLoadFunctionType'); goog.require('ol.TileLoadFunctionType');
goog.require('ol.TileState'); goog.require('ol.TileState');
@@ -53,12 +52,6 @@ ol.source.TileImage = function(options) {
this.crossOrigin = this.crossOrigin =
goog.isDef(options.crossOrigin) ? options.crossOrigin : null; goog.isDef(options.crossOrigin) ? options.crossOrigin : null;
/**
* @protected
* @type {ol.TileCache}
*/
this.tileCache = new ol.TileCache();
/** /**
* @protected * @protected
* @type {ol.TileLoadFunctionType} * @type {ol.TileLoadFunctionType}
@@ -87,22 +80,6 @@ ol.source.TileImage.defaultTileLoadFunction = function(imageTile, src) {
}; };
/**
* @inheritDoc
*/
ol.source.TileImage.prototype.canExpireCache = function() {
return this.tileCache.canExpireCache();
};
/**
* @inheritDoc
*/
ol.source.TileImage.prototype.expireCache = function(usedTiles) {
this.tileCache.expireCache(usedTiles);
};
/** /**
* @inheritDoc * @inheritDoc
*/ */
+32 -28
View File
@@ -5,7 +5,9 @@ goog.require('goog.events.Event');
goog.require('goog.functions'); goog.require('goog.functions');
goog.require('ol.Attribution'); goog.require('ol.Attribution');
goog.require('ol.Extent'); goog.require('ol.Extent');
goog.require('ol.TileCache');
goog.require('ol.TileRange'); goog.require('ol.TileRange');
goog.require('ol.TileState');
goog.require('ol.source.Source'); goog.require('ol.source.Source');
goog.require('ol.tilecoord'); goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid'); goog.require('ol.tilegrid.TileGrid');
@@ -65,6 +67,12 @@ ol.source.Tile = function(options) {
*/ */
this.tileGrid = goog.isDef(options.tileGrid) ? options.tileGrid : null; this.tileGrid = goog.isDef(options.tileGrid) ? options.tileGrid : null;
/**
* @protected
* @type {ol.TileCache}
*/
this.tileCache = new ol.TileCache();
}; };
goog.inherits(ol.source.Tile, ol.source.Source); goog.inherits(ol.source.Tile, ol.source.Source);
@@ -72,51 +80,47 @@ goog.inherits(ol.source.Tile, ol.source.Source);
/** /**
* @return {boolean} Can expire cache. * @return {boolean} Can expire cache.
*/ */
ol.source.Tile.prototype.canExpireCache = goog.functions.FALSE; ol.source.Tile.prototype.canExpireCache = function() {
return this.tileCache.canExpireCache();
};
/** /**
* @param {Object.<string, ol.TileRange>} usedTiles Used tiles. * @param {Object.<string, ol.TileRange>} usedTiles Used tiles.
*/ */
ol.source.Tile.prototype.expireCache = goog.abstractMethod; ol.source.Tile.prototype.expireCache = function(usedTiles) {
this.tileCache.expireCache(usedTiles);
};
/** /**
* Look for loaded tiles over a given tile range and zoom level. Adds
* properties to the provided lookup representing key/tile pairs for already
* loaded tiles.
*
* @param {Object.<number, Object.<string, ol.Tile>>} loadedTilesByZ A lookup of
* loaded tiles by zoom level.
* @param {function(number, number, number): ol.Tile} getTileIfLoaded A function
* that returns the tile only if it is fully loaded.
* @param {number} z Zoom level. * @param {number} z Zoom level.
* @param {ol.TileRange} tileRange Tile range. * @param {ol.TileRange} tileRange Tile range.
* @param {function(ol.Tile):(boolean|undefined)} callback Called with each
* loaded tile. If the callback returns `false`, the tile will not be
* considered loaded.
* @return {boolean} The tile range is fully covered with loaded tiles. * @return {boolean} The tile range is fully covered with loaded tiles.
*/ */
ol.source.Tile.prototype.findLoadedTiles = function(loadedTilesByZ, ol.source.Tile.prototype.forEachLoadedTile = function(z, tileRange, callback) {
getTileIfLoaded, z, tileRange) { var covered = true;
// FIXME this could be more efficient about filling partial holes var tile, tileCoordKey, loaded;
var fullyCovered = true; for (var x = tileRange.minX; x <= tileRange.maxX; ++x) {
var tile, tileCoordKey, x, y; for (var y = tileRange.minY; y <= tileRange.maxY; ++y) {
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoordKey = this.getKeyZXY(z, x, y); tileCoordKey = this.getKeyZXY(z, x, y);
if (loadedTilesByZ[z] && loadedTilesByZ[z][tileCoordKey]) { loaded = false;
continue; if (this.tileCache.containsKey(tileCoordKey)) {
} tile = /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
tile = getTileIfLoaded(z, x, y); loaded = tile.getState() === ol.TileState.LOADED;
if (!goog.isNull(tile)) { if (loaded) {
if (!loadedTilesByZ[z]) { loaded = (callback(tile) !== false);
loadedTilesByZ[z] = {};
} }
loadedTilesByZ[z][tileCoordKey] = tile; }
} else { if (!loaded) {
fullyCovered = false; covered = false;
} }
} }
} }
return fullyCovered; return covered;
}; };
+5 -28
View File
@@ -7,7 +7,6 @@ goog.require('goog.events.EventType');
goog.require('goog.net.Jsonp'); goog.require('goog.net.Jsonp');
goog.require('ol.Attribution'); goog.require('ol.Attribution');
goog.require('ol.Tile'); goog.require('ol.Tile');
goog.require('ol.TileCache');
goog.require('ol.TileState'); goog.require('ol.TileState');
goog.require('ol.TileUrlFunction'); goog.require('ol.TileUrlFunction');
goog.require('ol.extent'); goog.require('ol.extent');
@@ -46,12 +45,6 @@ ol.source.TileUTFGrid = function(options) {
*/ */
this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction; this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction;
/**
* @private
* @type {!ol.TileCache}
*/
this.tileCache_ = new ol.TileCache();
/** /**
* @private * @private
* @type {string|undefined} * @type {string|undefined}
@@ -64,22 +57,6 @@ ol.source.TileUTFGrid = function(options) {
goog.inherits(ol.source.TileUTFGrid, ol.source.Tile); goog.inherits(ol.source.TileUTFGrid, ol.source.Tile);
/**
* @inheritDoc
*/
ol.source.TileUTFGrid.prototype.canExpireCache = function() {
return this.tileCache_.canExpireCache();
};
/**
* @inheritDoc
*/
ol.source.TileUTFGrid.prototype.expireCache = function(usedTiles) {
this.tileCache_.expireCache(usedTiles);
};
/** /**
* @return {string|undefined} The template from TileJSON. * @return {string|undefined} The template from TileJSON.
* @api * @api
@@ -195,8 +172,8 @@ ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {
ol.source.TileUTFGrid.prototype.getTile = ol.source.TileUTFGrid.prototype.getTile =
function(z, x, y, pixelRatio, projection) { function(z, x, y, pixelRatio, projection) {
var tileCoordKey = this.getKeyZXY(z, x, y); var tileCoordKey = this.getKeyZXY(z, x, y);
if (this.tileCache_.containsKey(tileCoordKey)) { if (this.tileCache.containsKey(tileCoordKey)) {
return /** @type {!ol.Tile} */ (this.tileCache_.get(tileCoordKey)); return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
} else { } else {
goog.asserts.assert(projection); goog.asserts.assert(projection);
var tileCoord = [z, x, y]; var tileCoord = [z, x, y];
@@ -207,7 +184,7 @@ ol.source.TileUTFGrid.prototype.getTile =
goog.isDef(tileUrl) ? tileUrl : '', goog.isDef(tileUrl) ? tileUrl : '',
this.tileGrid.getTileCoordExtent(tileCoord), this.tileGrid.getTileCoordExtent(tileCoord),
this.preemptive_); this.preemptive_);
this.tileCache_.set(tileCoordKey, tile); this.tileCache.set(tileCoordKey, tile);
return tile; return tile;
} }
}; };
@@ -218,8 +195,8 @@ ol.source.TileUTFGrid.prototype.getTile =
*/ */
ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) { ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) {
var tileCoordKey = this.getKeyZXY(z, x, y); var tileCoordKey = this.getKeyZXY(z, x, y);
if (this.tileCache_.containsKey(tileCoordKey)) { if (this.tileCache.containsKey(tileCoordKey)) {
this.tileCache_.get(tileCoordKey); this.tileCache.get(tileCoordKey);
} }
}; };
+94 -161
View File
@@ -12,176 +12,105 @@ describe('ol.source.Tile', function() {
}); });
}); });
describe('#findLoadedTiles()', function() { describe('#forEachLoadedTile()', function() {
it('adds no tiles if none are already loaded', function() { var callback;
// a source with no loaded tiles beforeEach(function() {
callback = sinon.spy();
});
it('does not call the callback if no tiles are loaded', function() {
var source = new ol.test.source.TileMock({}); var source = new ol.test.source.TileMock({});
var loadedTilesByZ = {};
var grid = source.getTileGrid(); var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180]; var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 3); var zoom = 3;
var range = grid.getTileRangeForExtentAndZ(extent, zoom);
function getTileIfLoaded(z, x, y) { source.forEachLoadedTile(zoom, range, callback);
var tile = source.getTile(z, x, y); expect(callback.callCount).to.be(0);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
source.findLoadedTiles(loadedTilesByZ, getTileIfLoaded, 3, range);
var keys = goog.object.getKeys(loadedTilesByZ);
expect(keys.length).to.be(0);
}); });
it('adds loaded tiles to the lookup (z: 0)', function() { it('does not call getTile() if no tiles are loaded', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({
'0/0/0': true,
'1/0/0': true
});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 0);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
source.findLoadedTiles(loadedTilesByZ, getTileIfLoaded, 0, range);
var keys = goog.object.getKeys(loadedTilesByZ);
expect(keys.length).to.be(1);
var tile = loadedTilesByZ['0']['0/0/0'];
expect(tile).to.be.a(ol.Tile);
expect(tile.state).to.be(ol.TileState.LOADED);
});
it('adds loaded tiles to the lookup (z: 1)', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({
'0/0/0': true,
'1/0/0': true
});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
source.findLoadedTiles(loadedTilesByZ, getTileIfLoaded, 1, range);
var keys = goog.object.getKeys(loadedTilesByZ);
expect(keys.length).to.be(1);
var tile = loadedTilesByZ['1']['1/0/0'];
expect(tile).to.be.a(ol.Tile);
expect(tile.state).to.be(ol.TileState.LOADED);
});
it('returns true when all tiles are already loaded', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({
'1/0/0': true,
'1/0/1': true,
'1/1/0': true,
'1/1/1': true
});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range);
expect(loaded).to.be(true);
});
it('returns true when all tiles are already loaded (part 2)', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({}); var source = new ol.test.source.TileMock({});
sinon.spy(source, 'getTile');
var loadedTilesByZ = {
'1': {
'1/0/0': true,
'1/0/1': true,
'1/1/0': true,
'1/1/1': true,
'1/1/2': true
}
};
var grid = source.getTileGrid(); var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180]; var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1); var zoom = 3;
var range = grid.getTileRangeForExtentAndZ(extent, zoom);
function getTileIfLoaded(z, x, y) { source.forEachLoadedTile(zoom, range, callback);
var tile = source.getTile(z, x, y); expect(source.getTile.callCount).to.be(0);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ? source.getTile.restore();
tile : null;
}
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range);
expect(loaded).to.be(true);
}); });
it('returns false when all tiles are already loaded', function() {
// a source with no loaded tiles it('calls callback for each loaded tile', function() {
var source = new ol.test.source.TileMock({ var source = new ol.test.source.TileMock({
'1/0/0': true, '1/0/0': ol.TileState.LOADED,
'1/0/1': true, '1/0/1': ol.TileState.LOADED,
'1/1/0': true, '1/1/0': ol.TileState.LOADING,
'1/1/1': false '1/1/1': ol.TileState.LOADED
}); });
var loadedTilesByZ = {}; var zoom = 1;
var grid = source.getTileGrid(); var range = new ol.TileRange(0, 1, 0, 1);
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
function getTileIfLoaded(z, x, y) { source.forEachLoadedTile(zoom, range, callback);
var tile = source.getTile(z, x, y); expect(callback.callCount).to.be(3);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range);
expect(loaded).to.be(false);
}); });
it('returns false when all tiles are already loaded (part 2)', function() { it('returns true if range is fully loaded', function() {
// a source with no loaded tiles // a source with no loaded tiles
var source = new ol.test.source.TileMock({}); var source = new ol.test.source.TileMock({
'1/0/0': ol.TileState.LOADED,
'1/0/1': ol.TileState.LOADED,
'1/1/0': ol.TileState.LOADED,
'1/1/1': ol.TileState.LOADED
});
var loadedTilesByZ = { var zoom = 1;
'1': { var range = new ol.TileRange(0, 1, 0, 1);
'1/0/0': true,
'1/0/1': true,
'1/1/0': true,
'1/1/1': false
}
};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
function getTileIfLoaded(z, x, y) { var covered = source.forEachLoadedTile(zoom, range, function() {
var tile = source.getTile(z, x, y); return true;
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ? });
tile : null; expect(covered).to.be(true);
} });
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range); it('returns false if range is not fully loaded', function() {
expect(loaded).to.be(false); // a source with no loaded tiles
var source = new ol.test.source.TileMock({
'1/0/0': ol.TileState.LOADED,
'1/0/1': ol.TileState.LOADED,
'1/1/0': ol.TileState.LOADING,
'1/1/1': ol.TileState.LOADED
});
var zoom = 1;
var range = new ol.TileRange(0, 1, 0, 1);
var covered = source.forEachLoadedTile(zoom, range, function() {
return true;
});
expect(covered).to.be(false);
});
it('allows callback to override loaded check', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({
'1/0/0': ol.TileState.LOADED,
'1/0/1': ol.TileState.LOADED,
'1/1/0': ol.TileState.LOADED,
'1/1/1': ol.TileState.LOADED
});
var zoom = 1;
var range = new ol.TileRange(0, 1, 0, 1);
var covered = source.forEachLoadedTile(zoom, range, function() {
return false;
});
expect(covered).to.be(false);
}); });
}); });
@@ -196,9 +125,10 @@ describe('ol.source.Tile', function() {
* *
* @constructor * @constructor
* @extends {ol.source.Tile} * @extends {ol.source.Tile}
* @param {Object.<string, boolean>} loaded Lookup of already loaded tiles. * @param {Object.<string, ol.TileState>} tileStates Lookup of tile key to
* tile state.
*/ */
ol.test.source.TileMock = function(loaded) { ol.test.source.TileMock = function(tileStates) {
var tileGrid = new ol.tilegrid.TileGrid({ var tileGrid = new ol.tilegrid.TileGrid({
resolutions: [360 / 256, 180 / 256, 90 / 256, 45 / 256], resolutions: [360 / 256, 180 / 256, 90 / 256, 45 / 256],
origin: [-180, -180], origin: [-180, -180],
@@ -210,11 +140,9 @@ ol.test.source.TileMock = function(loaded) {
tileGrid: tileGrid tileGrid: tileGrid
}); });
/** for (var key in tileStates) {
* @type {Object.<string, boolean>} this.tileCache.set(key, new ol.Tile(key.split('/'), tileStates[key]));
* @private }
*/
this.loaded_ = loaded;
}; };
goog.inherits(ol.test.source.TileMock, ol.source.Tile); goog.inherits(ol.test.source.TileMock, ol.source.Tile);
@@ -224,9 +152,14 @@ goog.inherits(ol.test.source.TileMock, ol.source.Tile);
* @inheritDoc * @inheritDoc
*/ */
ol.test.source.TileMock.prototype.getTile = function(z, x, y) { ol.test.source.TileMock.prototype.getTile = function(z, x, y) {
var key = ol.tilecoord.getKeyZXY(z, x, y); var key = this.getKeyZXY(z, x, y);
var tileState = this.loaded_[key] ? ol.TileState.LOADED : ol.TileState.IDLE; if (this.tileCache.containsKey(key)) {
return new ol.Tile([z, x, y], tileState); return /** @type {!ol.Tile} */ (this.tileCache.get(key));
} else {
var tile = new ol.Tile(key, ol.TileState.IDLE);
this.tileCache.set(key, tile);
return tile;
}
}; };
@@ -243,8 +176,8 @@ describe('ol.test.source.TileMock', function() {
describe('#getTile()', function() { describe('#getTile()', function() {
it('returns a tile with state based on constructor arg', function() { it('returns a tile with state based on constructor arg', function() {
var source = new ol.test.source.TileMock({ var source = new ol.test.source.TileMock({
'0/0/0': true, '0/0/0': ol.TileState.LOADED,
'1/0/0': true '1/0/0': ol.TileState.LOADED
}); });
var tile; var tile;
@@ -270,9 +203,9 @@ describe('ol.test.source.TileMock', function() {
goog.require('goog.object'); goog.require('goog.object');
goog.require('ol.Tile'); goog.require('ol.Tile');
goog.require('ol.TileRange');
goog.require('ol.TileState'); goog.require('ol.TileState');
goog.require('ol.proj'); goog.require('ol.proj');
goog.require('ol.source.Source'); goog.require('ol.source.Source');
goog.require('ol.source.Tile'); goog.require('ol.source.Tile');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid'); goog.require('ol.tilegrid.TileGrid');