diff --git a/examples/canvas-tiles.html b/examples/canvas-tiles.html index 7340cdc3fc..5dbdde1af5 100644 --- a/examples/canvas-tiles.html +++ b/examples/canvas-tiles.html @@ -21,10 +21,12 @@ DOM WebGL + Canvas
+
diff --git a/examples/canvas-tiles.js b/examples/canvas-tiles.js index 31cd1515d9..ecec31b88b 100644 --- a/examples/canvas-tiles.js +++ b/examples/canvas-tiles.js @@ -41,3 +41,10 @@ var domMap = new ol.Map({ }); domMap.bindTo('layers', webglMap); domMap.bindTo('view', webglMap); + +var canvasMap = new ol.Map({ + renderer: ol.RendererHint.DOM, + target: 'canvasMap' +}); +canvasMap.bindTo('layers', webglMap); +canvasMap.bindTo('view', webglMap); diff --git a/src/objectliterals.exports b/src/objectliterals.exports index dd819ccd2d..3f0a1e984d 100644 --- a/src/objectliterals.exports +++ b/src/objectliterals.exports @@ -133,6 +133,7 @@ @exportObjectLiteralProperty ol.source.TiledWMSOptions.crossOrigin null|string|undefined @exportObjectLiteralProperty ol.source.TiledWMSOptions.extent ol.Extent|undefined @exportObjectLiteralProperty ol.source.TiledWMSOptions.tileGrid ol.tilegrid.TileGrid|undefined +@exportObjectLiteralProperty ol.source.TiledWMSOptions.transparent boolean|undefined @exportObjectLiteralProperty ol.source.TiledWMSOptions.maxZoom number|undefined @exportObjectLiteralProperty ol.source.TiledWMSOptions.projection ol.Projection|undefined @exportObjectLiteralProperty ol.source.TiledWMSOptions.url string|undefined diff --git a/src/ol/renderer/canvas/canvastilelayerrenderer.js b/src/ol/renderer/canvas/canvastilelayerrenderer.js index 9c338b7818..717e23d879 100644 --- a/src/ol/renderer/canvas/canvastilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvastilelayerrenderer.js @@ -1,4 +1,3 @@ -// FIXME don't redraw tiles if not needed // FIXME find correct globalCompositeOperation // FIXME optimize :-) @@ -51,6 +50,12 @@ ol.renderer.canvas.TileLayer = function(mapRenderer, tileLayer) { */ this.transform_ = goog.vec.Mat4.createNumber(); + /** + * @private + * @type {Array.} + */ + this.renderedTiles_ = null; + }; goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer); @@ -96,10 +101,11 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame = var tileResolution = tileGrid.getResolution(z); var tileRange = tileGrid.getTileRangeForExtentAndResolution( frameState.extent, tileResolution); + var tileRangeWidth = tileRange.getWidth(); + var tileRangeHeight = tileRange.getHeight(); var canvasSize = new ol.Size( - tileSize.width * tileRange.getWidth(), - tileSize.height * tileRange.getHeight()); + tileSize.width * tileRangeWidth, tileSize.height * tileRangeHeight); var canvas, context; if (goog.isNull(this.canvas_)) { @@ -111,6 +117,7 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame = this.canvas_ = canvas; this.canvasSize_ = canvasSize; this.context_ = context; + this.renderedTiles_ = new Array(tileRangeWidth * tileRangeHeight); } else { canvas = this.canvas_; context = this.context_; @@ -118,11 +125,10 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame = canvas.width = canvasSize.width; canvas.height = canvasSize.height; this.canvasSize_ = canvasSize; + this.renderedTiles_ = new Array(tileRangeWidth * tileRangeHeight); } } - context.clearRect(0, 0, canvasSize.width, canvasSize.height); - /** * @type {Object.>} */ @@ -169,9 +175,12 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame = /** @type {Array.} */ var zs = goog.array.map(goog.object.getKeys(tilesToDrawByZ), Number); goog.array.sort(zs); + var opaque = tileSource.getOpaque(); var origin = tileGrid.getTileCoordExtent( new ol.TileCoord(z, tileRange.minX, tileRange.maxY)).getTopLeft(); - var currentZ, i, scale, tileCoordKey, tileExtent, tilesToDraw; + var currentZ, i, index, scale, tileCoordKey, tileExtent, tilesToDraw; + var ix, iy, interimTileExtent, interimTileRange, maxX, maxY, minX, minY; + var height, width; for (i = 0; i < zs.length; ++i) { currentZ = zs[i]; tileSize = tileGrid.getTileSize(currentZ); @@ -179,22 +188,44 @@ ol.renderer.canvas.TileLayer.prototype.renderFrame = if (currentZ == z) { for (tileCoordKey in tilesToDraw) { tile = tilesToDraw[tileCoordKey]; - context.drawImage( - tile.getImage(), - tileSize.width * (tile.tileCoord.x - tileRange.minX), - tileSize.height * (tileRange.maxY - tile.tileCoord.y)); + tileCoord = tile.tileCoord; + index = (tileCoord.y - tileRange.minY) * tileRangeWidth + + (tileCoord.x - tileRange.minX); + if (this.renderedTiles_[index] != tile) { + x = tileSize.width * (tile.tileCoord.x - tileRange.minX); + y = tileSize.height * (tileRange.maxY - tile.tileCoord.y); + if (!opaque) { + context.clearRect(x, y, tileSize.width, tileSize.height); + } + context.drawImage(tile.getImage(), x, y); + this.renderedTiles_[index] = tile; + } } } else { scale = tileGrid.getResolution(currentZ) / tileResolution; for (tileCoordKey in tilesToDraw) { tile = tilesToDraw[tileCoordKey]; tileExtent = tileGrid.getTileCoordExtent(tile.tileCoord); - context.drawImage( - tile.getImage(), - (tileExtent.minX - origin.x) / tileResolution, - (origin.y - tileExtent.maxY) / tileResolution, - scale * tileSize.width, - scale * tileSize.height); + x = (tileExtent.minX - origin.x) / tileResolution; + y = (origin.y - tileExtent.maxY) / tileResolution; + width = scale * tileSize.width; + height = scale * tileSize.height; + if (!opaque) { + context.clearRect(x, y, width, height); + } + context.drawImage(tile.getImage(), x, y, width, height); + interimTileRange = + tileGrid.getTileRangeForExtentAndZ(tileExtent, z); + minX = Math.max(interimTileRange.minX, tileRange.minX); + maxX = Math.min(interimTileRange.maxX, tileRange.maxX); + minY = Math.max(interimTileRange.minY, tileRange.minY); + maxY = Math.min(interimTileRange.maxY, tileRange.maxY); + for (ix = minX; ix <= maxX; ++ix) { + for (iy = minY; iy <= maxY; ++iy) { + this.renderedTiles_[(iy - tileRange.minY) * tileRangeWidth + + (ix - tileRange.minX)] = undefined; + } + } } } } diff --git a/src/ol/source/bingmapssource.js b/src/ol/source/bingmapssource.js index 7cd7a27155..430e548a1b 100644 --- a/src/ol/source/bingmapssource.js +++ b/src/ol/source/bingmapssource.js @@ -23,6 +23,7 @@ goog.require('ol.tilegrid.XYZ'); ol.source.BingMaps = function(bingMapsOptions) { goog.base(this, { + opaque: true, projection: ol.projection.getFromCode('EPSG:3857') }); diff --git a/src/ol/source/debugtilesource.js b/src/ol/source/debugtilesource.js index e553081ae3..d9ab21ad80 100644 --- a/src/ol/source/debugtilesource.js +++ b/src/ol/source/debugtilesource.js @@ -90,6 +90,7 @@ ol.source.DebugTileSource = function(options) { goog.base(this, { extent: options.extent, + opaque: false, projection: options.projection, tileGrid: options.tileGrid }); diff --git a/src/ol/source/imagetilesource.js b/src/ol/source/imagetilesource.js index d47b9215e5..b29849a4a6 100644 --- a/src/ol/source/imagetilesource.js +++ b/src/ol/source/imagetilesource.js @@ -18,6 +18,7 @@ goog.require('ol.tilegrid.TileGrid'); * @typedef {{attributions: (Array.|undefined), * crossOrigin: (null|string|undefined), * extent: (ol.Extent|undefined), + * opaque: (boolean|undefined), * projection: (ol.Projection|undefined), * tileGrid: (ol.tilegrid.TileGrid|undefined), * tileUrlFunction: (ol.TileUrlFunctionType|undefined)}} @@ -36,6 +37,7 @@ ol.source.ImageTileSource = function(options) { goog.base(this, { attributions: options.attributions, extent: options.extent, + opaque: options.opaque, projection: options.projection, tileGrid: options.tileGrid }); diff --git a/src/ol/source/mapquestsource.js b/src/ol/source/mapquestsource.js index 08fb316632..ae12b33a25 100644 --- a/src/ol/source/mapquestsource.js +++ b/src/ol/source/mapquestsource.js @@ -26,6 +26,7 @@ ol.source.MapQuestOSM = function() { goog.base(this, { attributions: attributions, + opaque: true, maxZoom: 28, url: 'http://otile{1-4}.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg' }); @@ -54,6 +55,7 @@ ol.source.MapQuestOpenAerial = function() { goog.base(this, { attributions: attributions, maxZoom: 18, + opaque: true, url: 'http://oatile{1-4}.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.jpg' }); diff --git a/src/ol/source/openstreetmapsource.js b/src/ol/source/openstreetmapsource.js index 8bbfaf5742..258fe22637 100644 --- a/src/ol/source/openstreetmapsource.js +++ b/src/ol/source/openstreetmapsource.js @@ -18,6 +18,7 @@ ol.source.OpenStreetMap = function() { goog.base(this, { attributions: [attribution], + opaque: true, maxZoom: 18, url: 'http://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png' }); diff --git a/src/ol/source/stamensource.js b/src/ol/source/stamensource.js index 46f87d83df..90355bf1e5 100644 --- a/src/ol/source/stamensource.js +++ b/src/ol/source/stamensource.js @@ -85,6 +85,7 @@ ol.source.Stamen = function(stamenOptions) { goog.base(this, { attributions: [attribution], maxZoom: config.maxZoom, + opaque: false, url: 'http://{a-d}.tile.stamen.com/' + layer + '/{z}/{x}/{y}.' + config.type }); diff --git a/src/ol/source/tiledwmssource.js b/src/ol/source/tiledwmssource.js index 9c7eb5ec8c..998cff4b43 100644 --- a/src/ol/source/tiledwmssource.js +++ b/src/ol/source/tiledwmssource.js @@ -27,6 +27,9 @@ ol.source.TiledWMS = function(tiledWMSOptions) { var extent = goog.isDef(tiledWMSOptions.extent) ? tiledWMSOptions.extent : projectionExtent; + var transparent = goog.isDef(tiledWMSOptions.transparent) ? + tiledWMSOptions.transparent : true; + var version = goog.isDef(tiledWMSOptions.version) ? tiledWMSOptions.version : '1.3'; @@ -44,7 +47,7 @@ ol.source.TiledWMS = function(tiledWMSOptions) { 'REQUEST': 'GetMap', 'STYLES': '', 'FORMAT': 'image/png', - 'TRANSPARENT': true + 'TRANSPARENT': transparent }; baseParams[version >= '1.3' ? 'CRS' : 'SRS'] = projection.getCode(); goog.object.extend(baseParams, tiledWMSOptions.params); @@ -97,6 +100,7 @@ ol.source.TiledWMS = function(tiledWMSOptions) { crossOrigin: tiledWMSOptions.crossOrigin, extent: extent, tileGrid: tileGrid, + opaque: !transparent, projection: projection, tileUrlFunction: ol.TileUrlFunction.withTileCoordTransform( tileCoordTransform, tileUrlFunction) diff --git a/src/ol/source/tilesource.js b/src/ol/source/tilesource.js index c250951e7e..cb3a5a5133 100644 --- a/src/ol/source/tilesource.js +++ b/src/ol/source/tilesource.js @@ -15,6 +15,7 @@ goog.require('ol.tilegrid.TileGrid'); /** * @typedef {{attributions: (Array.|undefined), * extent: (ol.Extent|undefined), + * opaque: (boolean|undefined), * projection: (ol.Projection|undefined), * tileGrid: (ol.tilegrid.TileGrid|undefined)}} */ @@ -35,6 +36,13 @@ ol.source.TileSource = function(tileSourceOptions) { projection: tileSourceOptions.projection }); + /** + * @private + * @type {boolean} + */ + this.opaque_ = goog.isDef(tileSourceOptions.opaque) ? + tileSourceOptions.opaque : false; + /** * @protected * @type {ol.tilegrid.TileGrid} @@ -98,6 +106,14 @@ ol.source.TileSource.prototype.findLoadedTiles = function(loadedTilesByZ, }; +/** + * @return {boolean} Opaque. + */ +ol.source.TileSource.prototype.getOpaque = function() { + return this.opaque_; +}; + + /** * @inheritDoc */