diff --git a/examples/min-max-resolution.html b/examples/min-max-resolution.html new file mode 100644 index 0000000000..37c8f43314 --- /dev/null +++ b/examples/min-max-resolution.html @@ -0,0 +1,65 @@ + + + + + + + + + + + Min/max resolution example + + + + + +
+ +
+
+
+
+
+ +
+ +
+

Min/max resolution example

+

Show/hide layers depending on current view resolution.

+
+

+ Zoom in twice: the MapBox layer should hide whereas the OSM layer should be shown. +

+

+ If you continue to zoom in, you'll see the OSM layer also disappear. +

+

+ The rendering of the layers are here controlled using minResolution and maxResolution options. +

+

See the min-max-resolution.js source to see how this is done.

+
+
minResolution, maxResolution, resolution
+
+ +
+ +
+ + + + + + diff --git a/examples/min-max-resolution.js b/examples/min-max-resolution.js new file mode 100644 index 0000000000..3a05f8bd8d --- /dev/null +++ b/examples/min-max-resolution.js @@ -0,0 +1,33 @@ +goog.require('ol.Map'); +goog.require('ol.View2D'); +goog.require('ol.layer.Tile'); +goog.require('ol.source.OSM'); +goog.require('ol.source.TileJSON'); + + +/** + * Create the map. + */ +var map = new ol.Map({ + layers: [ + new ol.layer.Tile({ + source: new ol.source.OSM(), + minResolution: 200, + maxResolution: 2000 + }), + new ol.layer.Tile({ + source: new ol.source.TileJSON({ + url: 'http://api.tiles.mapbox.com/v3/' + + 'mapbox.natural-earth-hypso-bathy.jsonp', + crossOrigin: 'anonymous' + }), + minResolution: 2000, + maxResolution: 20000 + }) + ], + target: 'map', + view: new ol.View2D({ + center: [653600, 5723680], + zoom: 5 + }) +}); diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index f40df1dd09..1d9fb7aa7f 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -337,6 +337,10 @@ * @property {number|undefined} opacity Opacity. * @property {number|undefined} saturation Saturation. * @property {boolean|undefined} visible Visibility. + * @property {number|undefined} minResolution The minimum resolution + * (inclusive) at which this layer will be visible. + * @property {number|undefined} maxResolution The maximum resolution + * (exclusive) below which this layer will be visible. */ /** @@ -348,6 +352,10 @@ * @property {number|undefined} saturation Saturation. * @property {ol.source.Source} source Source for this layer. * @property {boolean|undefined} visible Visibility. Default is true (visible). + * @property {number|undefined} minResolution The minimum resolution + * (inclusive) at which this layer will be visible. + * @property {number|undefined} maxResolution The maximum resolution + * (exclusive) below which this layer will be visible. */ /** @@ -358,6 +366,10 @@ * @property {number|undefined} opacity Opacity. * @property {number|undefined} saturation Saturation. * @property {boolean|undefined} visible Visibility. + * @property {number|undefined} minResolution The minimum resolution + * (inclusive) at which this layer will be visible. + * @property {number|undefined} maxResolution The maximum resolution + * (exclusive) below which this layer will be visible. * @property {Array.|ol.Collection|undefined} layers Child layers. */ @@ -371,6 +383,10 @@ * @property {number|undefined} saturation Saturation. * @property {ol.source.Source} source Source for this layer. * @property {boolean|undefined} visible Visibility. Default is true (visible). + * @property {number|undefined} minResolution The minimum resolution + * (inclusive) at which this layer will be visible. + * @property {number|undefined} maxResolution The maximum resolution + * (exclusive) below which this layer will be visible. */ /** @@ -383,6 +399,10 @@ * @property {ol.source.Source} source Source for this layer. * @property {ol.style.Style|undefined} style Style. * @property {boolean|undefined} visible Visibility. Default is true (visible). + * @property {number|undefined} minResolution The minimum resolution + * (inclusive) at which this layer will be visible. + * @property {number|undefined} maxResolution The maximum resolution + * (exclusive) below which this layer will be visible. */ /** diff --git a/src/ol/layer/layerbase.js b/src/ol/layer/layerbase.js index 67ba0decc0..30c8f8f2e5 100644 --- a/src/ol/layer/layerbase.js +++ b/src/ol/layer/layerbase.js @@ -18,7 +18,9 @@ ol.layer.LayerProperty = { HUE: 'hue', OPACITY: 'opacity', SATURATION: 'saturation', - VISIBLE: 'visible' + VISIBLE: 'visible', + MAX_RESOLUTION: 'maxResolution', + MIN_RESOLUTION: 'minResolution' }; @@ -29,7 +31,9 @@ ol.layer.LayerProperty = { * opacity: number, * ready: boolean, * saturation: number, - * visible: boolean}} + * visible: boolean, + * maxResolution: number, + * minResolution: number}} */ ol.layer.LayerState; @@ -58,6 +62,12 @@ ol.layer.Base = function(options) { values.saturation = goog.isDef(values.saturation) ? values.saturation : 1; /** @type {boolean} */ values.visible = goog.isDef(values.visible) ? values.visible : true; + /** @type {number} */ + values.maxResolution = goog.isDef(values.maxResolution) ? + values.maxResolution : Infinity; + /** @type {number} */ + values.minResolution = goog.isDef(values.minResolution) ? + values.minResolution : 0; this.setValues(values); @@ -67,6 +77,8 @@ ol.layer.Base = function(options) { ol.Object.getChangeEventType(ol.layer.LayerProperty.HUE), ol.Object.getChangeEventType(ol.layer.LayerProperty.OPACITY), ol.Object.getChangeEventType(ol.layer.LayerProperty.SATURATION), + ol.Object.getChangeEventType(ol.layer.LayerProperty.MAX_RESOLUTION), + ol.Object.getChangeEventType(ol.layer.LayerProperty.MIN_RESOLUTION), goog.events.EventType.LOAD ], this.handleLayerChange, false, this); @@ -134,6 +146,8 @@ ol.layer.Base.prototype.getLayerState = function() { var ready = this.isReady(); var saturation = this.getSaturation(); var visible = this.getVisible(); + var maxResolution = this.getMaxResolution(); + var minResolution = this.getMinResolution(); return { brightness: goog.isDef(brightness) ? goog.math.clamp(brightness, -1, 1) : 0, contrast: goog.isDef(contrast) ? Math.max(contrast, 0) : 1, @@ -141,7 +155,9 @@ ol.layer.Base.prototype.getLayerState = function() { opacity: goog.isDef(opacity) ? goog.math.clamp(opacity, 0, 1) : 1, ready: ready, saturation: goog.isDef(saturation) ? Math.max(saturation, 0) : 1, - visible: goog.isDef(visible) ? !!visible : true + visible: goog.isDef(visible) ? !!visible : true, + maxResolution: goog.isDef(maxResolution) ? maxResolution : Infinity, + minResolution: goog.isDef(minResolution) ? Math.max(minResolution, 0) : 0 }; }; @@ -167,6 +183,32 @@ ol.layer.Base.prototype.getLayersArray = goog.abstractMethod; ol.layer.Base.prototype.getLayerStatesArray = goog.abstractMethod; +/** + * @return {number} MaxResolution. + */ +ol.layer.Base.prototype.getMaxResolution = function() { + return /** @type {number} */ ( + this.get(ol.layer.LayerProperty.MAX_RESOLUTION)); +}; +goog.exportProperty( + ol.layer.Base.prototype, + 'getMaxResolution', + ol.layer.Base.prototype.getMaxResolution); + + +/** + * @return {number} MinResolution. + */ +ol.layer.Base.prototype.getMinResolution = function() { + return /** @type {number} */ ( + this.get(ol.layer.LayerProperty.MIN_RESOLUTION)); +}; +goog.exportProperty( + ol.layer.Base.prototype, + 'getMinResolution', + ol.layer.Base.prototype.getMinResolution); + + /** * @return {number} Opacity. */ @@ -288,6 +330,30 @@ goog.exportProperty( ol.layer.Base.prototype.setHue); +/** + * @param {number} maxResolution MaxResolution. + */ +ol.layer.Base.prototype.setMaxResolution = function(maxResolution) { + this.set(ol.layer.LayerProperty.MAX_RESOLUTION, maxResolution); +}; +goog.exportProperty( + ol.layer.Base.prototype, + 'setMaxResolution', + ol.layer.Base.prototype.setMaxResolution); + + +/** + * @param {number} minResolution MinResolution. + */ +ol.layer.Base.prototype.setMinResolution = function(minResolution) { + this.set(ol.layer.LayerProperty.MIN_RESOLUTION, minResolution); +}; +goog.exportProperty( + ol.layer.Base.prototype, + 'setMinResolution', + ol.layer.Base.prototype.setMinResolution); + + /** * @param {number} opacity Opacity. */ diff --git a/src/ol/layer/layergroup.js b/src/ol/layer/layergroup.js index 205d5fe3b2..9e37389f54 100644 --- a/src/ol/layer/layergroup.js +++ b/src/ol/layer/layergroup.js @@ -206,6 +206,10 @@ ol.layer.Group.prototype.getLayerStatesArray = function(opt_obj) { layerState.opacity *= ownLayerState.opacity; layerState.saturation *= ownLayerState.saturation; layerState.visible = layerState.visible && ownLayerState.visible; + layerState.maxResolution = Math.min( + layerState.maxResolution, ownLayerState.maxResolution); + layerState.minResolution = Math.max( + layerState.minResolution, ownLayerState.minResolution); } return obj; diff --git a/src/ol/renderer/canvas/canvasmaprenderer.js b/src/ol/renderer/canvas/canvasmaprenderer.js index ace032ae56..f081990b78 100644 --- a/src/ol/renderer/canvas/canvasmaprenderer.js +++ b/src/ol/renderer/canvas/canvasmaprenderer.js @@ -114,13 +114,16 @@ ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) { var layerStates = frameState.layerStates; var layersArray = frameState.layersArray; + var viewResolution = frameState.view2DState.resolution; var i, ii, image, layer, layerRenderer, layerState, transform; for (i = 0, ii = layersArray.length; i < ii; ++i) { layer = layersArray[i]; layerRenderer = this.getLayerRenderer(layer); layerState = layerStates[goog.getUid(layer)]; - if (!layerState.visible || !layerState.ready) { + if (!layerState.visible || !layerState.ready || + viewResolution >= layerState.maxResolution || + viewResolution < layerState.minResolution) { continue; } layerRenderer.renderFrame(frameState, layerState); diff --git a/src/ol/renderer/webgl/webglmaprenderer.js b/src/ol/renderer/webgl/webglmaprenderer.js index 41cfeaf50f..f3b1876393 100644 --- a/src/ol/renderer/webgl/webglmaprenderer.js +++ b/src/ol/renderer/webgl/webglmaprenderer.js @@ -551,12 +551,15 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { ++this.textureCacheFrameMarkerCount_; var layersArray = frameState.layersArray; + var viewResolution = frameState.view2DState.resolution; var i, ii, layer, layerRenderer, layerState; for (i = 0, ii = layersArray.length; i < ii; ++i) { layer = layersArray[i]; layerRenderer = this.getLayerRenderer(layer); layerState = frameState.layerStates[goog.getUid(layer)]; - if (layerState.visible && layerState.ready) { + if (layerState.visible && layerState.ready && + viewResolution < layerState.maxResolution && + viewResolution >= layerState.minResolution) { layerRenderer.renderFrame(frameState, layerState); } } @@ -580,10 +583,11 @@ ol.renderer.webgl.Map.prototype.renderFrame = function(frameState) { var currentProgram = null; var locations; for (i = 0, ii = layersArray.length; i < ii; ++i) { - layer = layersArray[i]; layerState = frameState.layerStates[goog.getUid(layer)]; - if (!layerState.visible || !layerState.ready) { + if (!layerState.visible || !layerState.ready || + viewResolution >= layerState.maxResolution || + viewResolution < layerState.minResolution) { continue; } var useColor = diff --git a/test/spec/ol/layer/layer.test.js b/test/spec/ol/layer/layer.test.js index fa1fdf9f9e..473fa96480 100644 --- a/test/spec/ol/layer/layer.test.js +++ b/test/spec/ol/layer/layer.test.js @@ -54,7 +54,9 @@ describe('ol.layer.Layer', function() { opacity: 1, saturation: 1, visible: true, - ready: true + ready: true, + maxResolution: Infinity, + minResolution: 0 }); }); @@ -73,6 +75,8 @@ describe('ol.layer.Layer', function() { opacity: 0.5, saturation: 5, visible: false, + maxResolution: 500, + minResolution: 0.25, foo: 42 }); @@ -82,6 +86,8 @@ describe('ol.layer.Layer', function() { expect(layer.getOpacity()).to.be(0.5); expect(layer.getSaturation()).to.be(5); expect(layer.getVisible()).to.be(false); + expect(layer.getMaxResolution()).to.be(500); + expect(layer.getMinResolution()).to.be(0.25); expect(layer.get('foo')).to.be(42); expect(layer.getLayerState()).to.eql({ brightness: 0.5, @@ -90,7 +96,9 @@ describe('ol.layer.Layer', function() { opacity: 0.5, saturation: 5, visible: false, - ready: true + ready: true, + maxResolution: 500, + minResolution: 0.25 }); goog.dispose(layer); @@ -121,6 +129,8 @@ describe('ol.layer.Layer', function() { layer.setOpacity(0.3); layer.setSaturation(0.3); layer.setVisible(false); + layer.setMaxResolution(500); + layer.setMinResolution(0.25); expect(layer.getLayerState()).to.eql({ brightness: -0.7, contrast: 0.3, @@ -128,7 +138,9 @@ describe('ol.layer.Layer', function() { opacity: 0.3, saturation: 0.3, visible: false, - ready: true + ready: true, + maxResolution: 500, + minResolution: 0.25 }); }); @@ -146,7 +158,9 @@ describe('ol.layer.Layer', function() { opacity: 0, saturation: 0, visible: false, - ready: true + ready: true, + maxResolution: Infinity, + minResolution: 0 }); layer.setBrightness(-3); @@ -162,7 +176,9 @@ describe('ol.layer.Layer', function() { opacity: 1, saturation: 42, visible: true, - ready: true + ready: true, + maxResolution: Infinity, + minResolution: 0 }); }); diff --git a/test/spec/ol/layer/layergroup.test.js b/test/spec/ol/layer/layergroup.test.js index d29acb5378..74f9755e46 100644 --- a/test/spec/ol/layer/layergroup.test.js +++ b/test/spec/ol/layer/layergroup.test.js @@ -50,7 +50,9 @@ describe('ol.layer.Group', function() { opacity: 1, saturation: 1, visible: true, - ready: true + ready: true, + maxResolution: Infinity, + minResolution: 0 }); }); @@ -76,7 +78,9 @@ describe('ol.layer.Group', function() { hue: 180, opacity: 0.5, saturation: 5, - visible: false + visible: false, + maxResolution: 500, + minResolution: 0.25 }); expect(layerGroup.getBrightness()).to.be(0.5); @@ -85,6 +89,8 @@ describe('ol.layer.Group', function() { expect(layerGroup.getOpacity()).to.be(0.5); expect(layerGroup.getSaturation()).to.be(5); expect(layerGroup.getVisible()).to.be(false); + expect(layerGroup.getMaxResolution()).to.be(500); + expect(layerGroup.getMinResolution()).to.be(0.25); expect(layerGroup.getLayerState()).to.eql({ brightness: 0.5, contrast: 10, @@ -92,7 +98,9 @@ describe('ol.layer.Group', function() { opacity: 0.5, saturation: 5, visible: false, - ready: true + ready: true, + maxResolution: 500, + minResolution: 0.25 }); expect(layerGroup.getLayers()).to.be.a(ol.Collection); expect(layerGroup.getLayers().getLength()).to.be(1); @@ -123,6 +131,8 @@ describe('ol.layer.Group', function() { layerGroup.setOpacity(0.3); layerGroup.setSaturation(0.3); layerGroup.setVisible(false); + layerGroup.setMaxResolution(500); + layerGroup.setMinResolution(0.25); expect(layerGroup.getLayerState()).to.eql({ brightness: -0.7, contrast: 0.3, @@ -130,7 +140,9 @@ describe('ol.layer.Group', function() { opacity: 0.3, saturation: 0.3, visible: false, - ready: true + ready: true, + maxResolution: 500, + minResolution: 0.25 }); }); @@ -148,7 +160,9 @@ describe('ol.layer.Group', function() { opacity: 0, saturation: 0, visible: false, - ready: true + ready: true, + maxResolution: Infinity, + minResolution: 0 }); layerGroup.setBrightness(-3); @@ -164,7 +178,9 @@ describe('ol.layer.Group', function() { opacity: 1, saturation: 42, visible: true, - ready: true + ready: true, + maxResolution: Infinity, + minResolution: 0 }); }); @@ -231,7 +247,9 @@ describe('ol.layer.Group', function() { hue: 180, opacity: 0.5, saturation: 5, - visible: false + visible: false, + maxResolution: 500, + minResolution: 0.25 }); it('does not transform layerStates by default', function() { @@ -263,7 +281,9 @@ describe('ol.layer.Group', function() { hue: 180, opacity: 0.5, saturation: 5, - visible: false + visible: false, + maxResolution: 150, + minResolution: 0.2 }); obj = layerGroup.getLayerStatesArray(); @@ -277,7 +297,9 @@ describe('ol.layer.Group', function() { opacity: 0.25, saturation: 25, visible: false, - ready: true + ready: true, + maxResolution: 150, + minResolution: 0.25 }); goog.dispose(layerGroup);