diff --git a/examples/layer-extent.html b/examples/layer-extent.html new file mode 100644 index 0000000000..95bc7d041c --- /dev/null +++ b/examples/layer-extent.html @@ -0,0 +1,68 @@ + + + + + + + + + + + Limited Layer Extent + + + + + +
+ +
+
+
+
+
+ +
+ +
+

Limited layer extent

+

Restricting layer rendering to a limited extent.

+
+

+ This example uses the layer.setExtent() method to + modify the extent of the overlay layer. Use the controls below + to limit rendering based on an extent. +

+

+

+ + + + + +
+

+

+ See the layer-extent.js + source for details on how this is done. +

+
+
extent, tilejson
+
+ +
+ +
+ + + + + + + diff --git a/examples/layer-extent.js b/examples/layer-extent.js new file mode 100644 index 0000000000..fca59929fa --- /dev/null +++ b/examples/layer-extent.js @@ -0,0 +1,50 @@ +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.layer.Tile'); +goog.require('ol.proj'); +goog.require('ol.source.TileJSON'); + +function transform(extent) { + return ol.proj.transformExtent(extent, 'EPSG:4326', 'EPSG:3857'); +} + +var extents = { + northwest: transform([-180, 0, 0, 85]), + northeast: transform([0, 0, 180, 85]), + southeast: transform([0, -85, 180, 0]), + southwest: transform([-180, -85, 0, 0]), + world: transform([-180, -85, 180, 85]) +}; + +var base = new ol.layer.Tile({ + source: new ol.source.TileJSON({ + url: 'http://api.tiles.mapbox.com/v3/' + + 'mapbox.world-black.jsonp', + crossOrigin: 'anonymous' + }) +}); + +var overlay = new ol.layer.Tile({ + extent: extents.northwest, + source: new ol.source.TileJSON({ + url: 'http://api.tiles.mapbox.com/v3/' + + 'mapbox.world-glass.jsonp', + crossOrigin: 'anonymous' + }) +}); + +var map = new ol.Map({ + layers: [base, overlay], + renderer: exampleNS.getRendererFromQueryString(), + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 1 + }) +}); + +for (var key in extents) { + document.getElementById(key).onclick = function(event) { + overlay.setExtent(extents[event.target.id]); + }; +} diff --git a/src/ol/renderer/canvas/canvaslayerrenderer.js b/src/ol/renderer/canvas/canvaslayerrenderer.js index 65fa90866e..25538ddf56 100644 --- a/src/ol/renderer/canvas/canvaslayerrenderer.js +++ b/src/ol/renderer/canvas/canvaslayerrenderer.js @@ -1,8 +1,10 @@ goog.provide('ol.renderer.canvas.Layer'); goog.require('goog.array'); +goog.require('goog.asserts'); goog.require('goog.vec.Mat4'); goog.require('ol.dom'); +goog.require('ol.extent'); goog.require('ol.layer.Layer'); goog.require('ol.render.Event'); goog.require('ol.render.EventType'); @@ -44,6 +46,35 @@ ol.renderer.canvas.Layer.prototype.composeFrame = var image = this.getImage(); if (!goog.isNull(image)) { + + // clipped rendering if layer extent is set + var extent = layerState.extent; + var clipped = goog.isDef(extent); + if (clipped) { + goog.asserts.assert(goog.isDef(extent)); + var topLeft = ol.extent.getTopLeft(extent); + var topRight = ol.extent.getTopRight(extent); + var bottomRight = ol.extent.getBottomRight(extent); + var bottomLeft = ol.extent.getBottomLeft(extent); + + ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, + topLeft, topLeft); + ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, + topRight, topRight); + ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, + bottomRight, bottomRight); + ol.vec.Mat4.multVec2(frameState.coordinateToPixelMatrix, + bottomLeft, bottomLeft); + + context.save(); + context.beginPath(); + context.moveTo(topLeft[0], topLeft[1]); + context.lineTo(topRight[0], topRight[1]); + context.lineTo(bottomRight[0], bottomRight[1]); + context.lineTo(bottomLeft[0], bottomLeft[1]); + context.clip(); + } + var imageTransform = this.getImageTransform(); // for performance reasons, context.save / context.restore is not used // to save and restore the transformation matrix and the opacity. @@ -72,6 +103,10 @@ ol.renderer.canvas.Layer.prototype.composeFrame = context.setTransform(1, 0, 0, 1, 0, 0); } context.globalAlpha = alpha; + + if (clipped) { + context.restore(); + } } this.dispatchPostComposeEvent(context, frameState); diff --git a/src/ol/renderer/canvas/canvastilelayerrenderer.js b/src/ol/renderer/canvas/canvastilelayerrenderer.js index 8ccc72d1ac..978aa41aa4 100644 --- a/src/ol/renderer/canvas/canvastilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvastilelayerrenderer.js @@ -5,16 +5,13 @@ goog.provide('ol.renderer.canvas.TileLayer'); goog.require('goog.array'); goog.require('goog.asserts'); -goog.require('goog.events'); goog.require('goog.object'); goog.require('goog.vec.Mat4'); -goog.require('ol.Object'); goog.require('ol.Size'); goog.require('ol.TileRange'); goog.require('ol.TileState'); goog.require('ol.dom'); goog.require('ol.extent'); -goog.require('ol.layer.LayerProperty'); goog.require('ol.layer.Tile'); goog.require('ol.renderer.Map'); goog.require('ol.renderer.canvas.Layer'); @@ -81,32 +78,10 @@ ol.renderer.canvas.TileLayer = function(mapRenderer, tileLayer) { */ this.renderedTiles_ = null; - /** - * @private - * @type {Array.} - */ - this.eventKeys_ = [ - goog.events.listen( - tileLayer, ol.Object.getChangeEventType(ol.layer.LayerProperty.EXTENT), - this.handleLayerExtentChanged_, false, this) - ]; - }; goog.inherits(ol.renderer.canvas.TileLayer, ol.renderer.canvas.Layer); -/** - * @inheritDoc - */ -ol.renderer.canvas.TileLayer.prototype.disposeInternal = function() { - for (var i = 0, ii = this.eventKeys_.length; i < ii; ++i) { - goog.events.unlistenByKey(this.eventKeys_[i]); - } - this.eventKeys_.length = 0; - goog.base(this, 'disposeInternal'); -}; - - /** * @inheritDoc */ @@ -123,19 +98,6 @@ ol.renderer.canvas.TileLayer.prototype.getImageTransform = function() { }; -/** - * Handle layer extent changes. We clear the canvas any time the layer extent - * changes. - * @private - */ -ol.renderer.canvas.TileLayer.prototype.handleLayerExtentChanged_ = function() { - if (!goog.isNull(this.context_)) { - this.context_.clearRect(0, 0, this.canvasSize_[0], this.canvasSize_[1]); - this.renderedCanvasZ_ = NaN; - } -}; - - /** * @inheritDoc */ @@ -278,11 +240,6 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame = if (z != this.renderedCanvasZ_ || !this.renderedCanvasTileRange_.containsTileRange(tileRange)) { this.renderedCanvasTileRange_ = null; - // Due to limited layer extent, we may be rendering tiles on a small - // portion of the canvas. - if (z < this.renderedCanvasZ_) { - this.context_.clearRect(0, 0, canvasWidth, canvasHeight); - } } } }