From 69d3c76254eb123966d2a9a654b806cc6e270587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Sat, 15 Oct 2011 23:48:13 +0200 Subject: [PATCH 01/44] a "big back buffer" attempt --- lib/OpenLayers/Layer/Grid.js | 63 +++++++++++++++++++++++++++++++++++- lib/OpenLayers/Tile/Image.js | 18 ++++++++--- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 6cbac3b2e9..0282feaba9 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -111,6 +111,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { */ timerId: null, + backBufferData: null, + /** * Constructor: OpenLayers.Layer.Grid * Create a new grid layer @@ -133,6 +135,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.events.addEventType("tileloaded"); this.grid = []; + this.backBufferData = {}; this._moveGriddedTiles = OpenLayers.Function.bind( this.moveGriddedTiles, this @@ -216,6 +219,10 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { return obj; }, + setBackBufferData: function() { + this.backBufferData.resolution = this.getServerResolution(); + }, + /** * Method: moveTo * This function is called whenever the map is moved. All the moving @@ -281,6 +288,30 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } if(forceReTile) { + + if(OpenLayers.Util.indexOf( + this.SUPPORTED_TRANSITIONS, + this.transitionEffect) != -1) { + if(!this.backBufferData.backBuffer) { + this.backBufferData.backBuffer = this.createBackBuffer(); + if(this.backBufferData.backBuffer) { + this.div.insertBefore(this.backBufferData.backBuffer, + this.div.firstChild); + } + } + if(this.backBufferData.backBuffer && this.backBufferData.resolution) { + var resolution = this.getServerResolution(); + var scale = this.backBufferData.resolution / resolution; + this.backBufferData.backBuffer.style.width = 100 * scale + '%'; + this.backBufferData.backBuffer.style.height = 100 * scale + '%'; + var lonLat = {lon: tilesBounds.left, lat: tilesBounds.top}, + position = this.getViewPortPxFromLonLat(lonLat, resolution); + this.backBufferData.backBuffer.style.left = position.x + '%'; + this.backBufferData.backBuffer.style.top = position.y + '%'; + } + + } + this.initGriddedTiles(bounds); } else { this.scheduleMoveGriddedTiles(); @@ -289,6 +320,31 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } }, + createBackBuffer: function() { + var backBuffer; + if(this.grid.length > 0) { + var backBuffer = document.createElement('div'); + backBuffer.id = this.div.id + '_bb'; + backBuffer.style.position = 'absolute'; + backBuffer.style.left = '0%'; + backBuffer.style.top = '0%'; + backBuffer.style.width = '100%'; + backBuffer.style.height = '100%'; + for(var i=0, lenI=this.grid.length; i */ -OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile.BackBufferable, { +OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { /** * Property: url @@ -96,7 +96,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile.BackBufferable, { * options - {Object} */ initialize: function(layer, position, bounds, url, size, options) { - OpenLayers.Tile.BackBufferable.prototype.initialize.apply(this, arguments); + OpenLayers.Tile.prototype.initialize.apply(this, arguments); this.url = url; //deprecated remove me @@ -123,7 +123,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile.BackBufferable, { } // don't handle async requests any more this.asyncRequestId = null; - OpenLayers.Tile.BackBufferable.prototype.destroy.apply(this, arguments); + OpenLayers.Tile.prototype.destroy.apply(this, arguments); }, /** @@ -134,7 +134,7 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile.BackBufferable, { * {Boolean} Was a tile drawn? */ draw: function() { - var drawn = OpenLayers.Tile.BackBufferable.prototype.draw.apply(this, arguments); + var drawn = OpenLayers.Tile.prototype.draw.apply(this, arguments); if (drawn) { if (this.layer != this.layer.map.baseLayer && this.layer.reproject) { this.bounds = this.getBoundsFromBaseLayer(this.position); @@ -335,6 +335,16 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile.BackBufferable, { return frame; }, + cloneMarkup: function() { + if(!this.imgDiv || this.isLoading) { + return; + } + var clone = this.frame.cloneNode(false); + clone.appendChild(this.imgDiv); + this.imgDiv = null; + return clone; + }, + /** * Method: onImageLoad * Handler for the image onload event From bea037679f6c85fcd9fe6c1c678d6f0bcb2d06e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Sun, 16 Oct 2011 22:31:37 +0200 Subject: [PATCH 02/44] better back buffer code, and support for singleTile --- lib/OpenLayers/Layer/Grid.js | 166 +++++++++++++++++++++-------------- 1 file changed, 101 insertions(+), 65 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 0282feaba9..3852c30a2b 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -111,7 +111,17 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { */ timerId: null, - backBufferData: null, + /** + * Property: backBuffer + * {DOMElement} The back buffer. + */ + backBuffer: null, + + /** + * Property: lastResolution + * {Object} The last resolution of the grid. + */ + lastResolution: null, /** * Constructor: OpenLayers.Layer.Grid @@ -135,8 +145,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.events.addEventType("tileloaded"); this.grid = []; - this.backBufferData = {}; - + this._moveGriddedTiles = OpenLayers.Function.bind( this.moveGriddedTiles, this ); @@ -219,10 +228,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { return obj; }, - setBackBufferData: function() { - this.backBufferData.resolution = this.getServerResolution(); - }, - /** * Method: moveTo * This function is called whenever the map is moved. All the moving @@ -247,7 +252,13 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { // total bounds of the tiles var tilesBounds = this.getTilesBounds(); - + + // the new map resolution + var resolution = this.map.getResolution(); + + // the server-supported resolution for the new map resolution + var serverResolution = this.getServerResolution(resolution); + if (this.singleTile) { // We want to redraw whenever even the slightest part of the @@ -255,6 +266,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { // (thus, we do not specify partial -- its default is false) if ( forceReTile || (!dragging && !tilesBounds.containsBounds(bounds))) { + if(this.lastResolution === serverResolution || + (this.lastResolution && + this.transitionEffect === 'resize')) { + this.insertBackBuffer(serverResolution, tilesBounds); + } this.initSingleTile(bounds); } } else { @@ -267,10 +283,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { forceReTile = forceReTile || !tilesBounds.containsBounds(bounds, true); - var resolution = this.map.getResolution(); - var serverResolution = - this.getServerResolution(resolution); - if(resolution !== serverResolution) { bounds = this.map.calculateBounds(null, serverResolution); if(forceReTile) { @@ -288,30 +300,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } if(forceReTile) { - - if(OpenLayers.Util.indexOf( - this.SUPPORTED_TRANSITIONS, - this.transitionEffect) != -1) { - if(!this.backBufferData.backBuffer) { - this.backBufferData.backBuffer = this.createBackBuffer(); - if(this.backBufferData.backBuffer) { - this.div.insertBefore(this.backBufferData.backBuffer, - this.div.firstChild); - } - } - if(this.backBufferData.backBuffer && this.backBufferData.resolution) { - var resolution = this.getServerResolution(); - var scale = this.backBufferData.resolution / resolution; - this.backBufferData.backBuffer.style.width = 100 * scale + '%'; - this.backBufferData.backBuffer.style.height = 100 * scale + '%'; - var lonLat = {lon: tilesBounds.left, lat: tilesBounds.top}, - position = this.getViewPortPxFromLonLat(lonLat, resolution); - this.backBufferData.backBuffer.style.left = position.x + '%'; - this.backBufferData.backBuffer.style.top = position.y + '%'; - } - + if(this.transitionEffect === 'resize' && + (this.lastResolution && + (this.lastResolution !== serverResolution))) { + this.insertBackBuffer(serverResolution, tilesBounds); } - this.initGriddedTiles(bounds); } else { this.scheduleMoveGriddedTiles(); @@ -320,31 +313,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } }, - createBackBuffer: function() { - var backBuffer; - if(this.grid.length > 0) { - var backBuffer = document.createElement('div'); - backBuffer.id = this.div.id + '_bb'; - backBuffer.style.position = 'absolute'; - backBuffer.style.left = '0%'; - backBuffer.style.top = '0%'; - backBuffer.style.width = '100%'; - backBuffer.style.height = '100%'; - for(var i=0, lenI=this.grid.length; i} The current bounds of the tiles. + */ + insertBackBuffer: function(resolution, tilesBounds) { + var backBuffer = this.backBuffer; + if(!backBuffer) { + backBuffer = this.createBackBuffer(); + if(!backBuffer) { + return; + } + this.div.insertBefore(backBuffer, this.div.firstChild); + this.backBuffer = backBuffer; + } + + var style = backBuffer.style; + + // scale + var ratio = this.lastResolution / resolution; + style.width = 100 * ratio + '%'; + style.height = 100 * ratio + '%'; + + // and position + var position = this.getViewPortPxFromLonLat( + {lon: tilesBounds.left, lat: tilesBounds.top}, resolution); + var leftOffset = parseInt(this.map.layerContainerDiv.style.left, 10); + var topOffset = parseInt(this.map.layerContainerDiv.style.top, 10); + backBuffer.style.left = (position.x - leftOffset) + '%'; + backBuffer.style.top = (position.y - topOffset) + '%'; + }, + + /** + * Method: createBackBuffer + * Create a back buffer. We apply a best effort strategy here - if for any + * reason we cannot clone a tile's markup we give up right away. + * + * Returns: + * {DOMElement} The DOM element for the back buffer, undefined if the + * back buffer couldn't have been created. + */ + createBackBuffer: function() { + var backBuffer; + if(this.grid.length > 0) { + var backBuffer = document.createElement('div'); + backBuffer.id = this.div.id + '_bb'; + backBuffer.style.position = 'absolute'; + backBuffer.style.width = '100%'; + backBuffer.style.height = '100%'; + for(var i=0, lenI=this.grid.length; i Date: Sun, 16 Oct 2011 22:32:57 +0200 Subject: [PATCH 03/44] ok, remove Tile.BackBufferable --- lib/OpenLayers/Tile/BackBufferable.js | 218 -------------------------- 1 file changed, 218 deletions(-) delete mode 100644 lib/OpenLayers/Tile/BackBufferable.js diff --git a/lib/OpenLayers/Tile/BackBufferable.js b/lib/OpenLayers/Tile/BackBufferable.js deleted file mode 100644 index 47c3e3198c..0000000000 --- a/lib/OpenLayers/Tile/BackBufferable.js +++ /dev/null @@ -1,218 +0,0 @@ -/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for - * full list of contributors). Published under the Clear BSD license. - * See http://svn.openlayers.org/trunk/openlayers/license.txt for the - * full text of the license. */ - - -/** - * @requires OpenLayers/Tile.js - * @requires OpenLayers/Util.js - */ - -/** - * Class: OpenLayers.Tile.BackBufferable - * Base class for tiles that can have backbuffers during transitions. Do not - * create instances of this class. - */ -OpenLayers.Tile.BackBufferable = OpenLayers.Class(OpenLayers.Tile, { - - /** - * Property: backBufferMode - * {Integer} Bitmap: 0 for no backbuffering at all, 1 for singleTile - * layers, 2 for transition effect set, 3 for both. - */ - backBufferMode: null, - - /** - * Property: backBufferData - * {Object} Object including the necessary data for the back - * buffer. - * - * The object includes three properties: - * tile - {DOMElement} The DOM element for the back buffer. - * bounds - {} The bounds of the tile to back. - * resolution - {Number} The resolution of the tile to back. - */ - backBufferData: null, - - /** - * Method: initialize - * Determines the backBuffer mode and registers events - */ - initialize: function() { - OpenLayers.Tile.prototype.initialize.apply(this, arguments); - - var transitionSupported = OpenLayers.Util.indexOf( - this.layer.SUPPORTED_TRANSITIONS, - this.layer.transitionEffect) != -1; - this.backBufferMode = (this.layer.singleTile && 1) | - (transitionSupported && 2); - - this.backBufferData = {}; - if (!this.size) { - this.size = new OpenLayers.Size(256, 256); - } - }, - - /** - * Method: draw - * Check that a tile should be drawn, and draw it. - * - * Returns: - * {Boolean} Was a tile drawn? - */ - draw: function() { - var draw = OpenLayers.Tile.prototype.shouldDraw.apply(this, arguments); - if (draw) { - this.updateBackBuffer(); - } - this.clear(); - if (!draw) { - this.resetBackBuffer(); - }; - return draw; - }, - - /** - * Method: getTile - * Get the tile's markup. To be implemented by subclasses. - * - * Returns: - * {DOMElement} The tile's markup - */ - - /** - * Method: createBackBuffer - * Create a copy of this tile's markup for the back buffer. To be - * implemented by subclasses. - * - * Returns: - * {DOMElement} A copy of the tile's markup. - */ - - /** - * Method: getTileResolution - * Get the tile's actual resolution. - * - * Returns: - * {Number} - */ - getTileResolution: function() { - var layer = this.layer, - map = layer.map, - mapResolution = map.getResolution(); - return layer.getServerResolution ? - layer.getServerResolution(mapResolution) : - mapResolution; - }, - - /** - * Method: setBackBufferData - * Stores the current bounds and resolution, for offset and ratio - * calculations - */ - setBackBufferData: function() { - this.backBufferData = OpenLayers.Util.extend(this.backBufferData, { - bounds: this.bounds, - resolution: this.getTileResolution() - }); - }, - - /** - * Method: updateBackBuffer - * Update the , and return a new or reposition the - * backBuffer. When a backbuffer is returned, the tile's markup is not - * available any more. - * - * Returns: - * {HTMLDivElement} the tile's markup in a cloned element, or undefined if - * no backbuffer is currently available or needed - */ - updateBackBuffer: function() { - var layer = this.layer, map = layer.map, - backBufferMode = this.backBufferMode, - data = this.backBufferData, - tile = this.getTile(), - backBuffer = data.tile, - prevResolution = data.resolution, - nextResolution = this.getTileResolution(), - ratio = prevResolution ? prevResolution / nextResolution : 1, - - // Cases where we don't position and return a back buffer, but only - // update backBufferData and return undefined: - // (1) current ratio and backBufferMode dont't require a backbuffer - notNeeded = !(ratio == 1 ? backBufferMode & 1 : backBufferMode & 2), - // (2) the tile is not appended to the layer's div - noParent = tile && tile.parentNode !== layer.div, - // (3) we don't have a tile available that we could use as buffer - noTile = !(tile && tile.childNodes.length > 0), - // (4) no backbuffer is displayed for a tile that's still loading - noBackBuffer = !backBuffer && this.isLoading; - - if (notNeeded || noParent || noTile || noBackBuffer) { - this.setBackBufferData(); - return; - } - - // Create a back buffer tile and add it to the DOM - if (!backBuffer) { - backBuffer = this.insertBackBuffer(); - // some browsers fire the onload event before the image is - // displayed, so we keep the buffer until the whole layer finished - // loading to avoid visual glitches - layer.events.register("loadend", this, this.resetBackBuffer); - data.tile = backBuffer; - } - - // Position the back buffer now that we have one - var lonLat = {lon: data.bounds.left, lat: data.bounds.top}, - position = layer.getViewPortPxFromLonLat(lonLat, nextResolution), - containerStyle = map.layerContainerDiv.style, - leftOffset = parseInt(containerStyle.left, 10), - topOffset = parseInt(containerStyle.top, 10), - style = backBuffer.style; - - style.left = (position.x - leftOffset) + "%"; - style.top = (position.y - topOffset) + "%"; - style.width = (this.size.w * ratio) + "%"; - style.height = (this.size.h * ratio) + "%"; - - return backBuffer; - }, - - /** - * Method: resetBackBuffer - * Handler for the layer's loadend event. - */ - resetBackBuffer: function() { - this.layer.events.unregister("loadend", this, this.resetBackBuffer); - this.removeBackBuffer(); - this.setBackBufferData(); - }, - - /** - * Method: removeBackBuffer - * Removes the backBuffer for this tile. - */ - removeBackBuffer: function() { - var backBufferData = this.backBufferData; - var backBuffer = backBufferData.tile; - delete backBufferData.tile; - var parent = backBuffer && backBuffer.parentNode; - if (backBuffer) { - parent.removeChild(backBuffer); - } - }, - - /** - * APIMethod: destroy - * nullify references to prevent circular references and memory leaks - */ - destroy: function() { - this.removeBackBuffer(); - this.layer.events.unregister("loadend", this, this.resetBackBuffer); - this.backBufferData = null; - OpenLayers.Tile.prototype.destroy.apply(this, arguments); - } - -}); From 5ae65d413a75e7846b9220c77f02fe63435d17d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Sun, 16 Oct 2011 22:40:11 +0200 Subject: [PATCH 04/44] the layer may not be in the map anymore when a tile is received --- lib/OpenLayers/Layer/Grid.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 3852c30a2b..dc0a0f8320 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -886,7 +886,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.div.removeChild(this.backBuffer); this.backBuffer = null; } - this.lastResolution = this.getServerResolution(); + if(this.map) { + this.lastResolution = this.getServerResolution(); + } } }; tile.events.register("loadend", this, tile.onLoadEnd); From 475f96db963dbe7828ae00a367c49a77c99d9e29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Tue, 18 Oct 2011 08:11:43 +0200 Subject: [PATCH 05/44] back buffer is not correctly repositioned --- lib/OpenLayers/Layer/Grid.js | 56 ++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index dc0a0f8320..fd13b1aabb 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -118,10 +118,15 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { backBuffer: null, /** - * Property: lastResolution - * {Object} The last resolution of the grid. + * Property: backBufferData + * {Object} An object containing states necessary for the back buffer. It + * includes two state properties: + * - *resolution* the last resolution of the tiles. Used as the "from + * resolution" when transitioning. + * - *lonlat* the geographic coordinates of the tiles grid's top-left + * corner. */ - lastResolution: null, + backBufferData: null, /** * Constructor: OpenLayers.Layer.Grid @@ -145,6 +150,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.events.addEventType("tileloaded"); this.grid = []; + this.backBufferData = {}; this._moveGriddedTiles = OpenLayers.Function.bind( this.moveGriddedTiles, this @@ -173,6 +179,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.clearGrid(); this.grid = null; this.tileSize = null; + this.backBufferData = null; OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); }, @@ -259,6 +266,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { // the server-supported resolution for the new map resolution var serverResolution = this.getServerResolution(resolution); + // the last resolution of the tiles + var lastResolution = this.backBufferData.resolution; + if (this.singleTile) { // We want to redraw whenever even the slightest part of the @@ -266,10 +276,10 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { // (thus, we do not specify partial -- its default is false) if ( forceReTile || (!dragging && !tilesBounds.containsBounds(bounds))) { - if(this.lastResolution === serverResolution || - (this.lastResolution && + if(lastResolution === serverResolution || + (lastResolution && this.transitionEffect === 'resize')) { - this.insertBackBuffer(serverResolution, tilesBounds); + this.applyBackBuffer(serverResolution); } this.initSingleTile(bounds); } @@ -301,9 +311,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { if(forceReTile) { if(this.transitionEffect === 'resize' && - (this.lastResolution && - (this.lastResolution !== serverResolution))) { - this.insertBackBuffer(serverResolution, tilesBounds); + (lastResolution && + (lastResolution !== serverResolution))) { + this.applyBackBuffer(serverResolution); } this.initGriddedTiles(bounds); } else { @@ -395,14 +405,13 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { }, /** - * Method: insertBackBuffer - * Insert a back buffer for a better transition. + * Method: applyBackBuffer + * Create, insert, scale and position a back buffer for the layer. * * Parameters: * resolution - {Number} The resolution to transition to. - * tilesBounds - {} The current bounds of the tiles. */ - insertBackBuffer: function(resolution, tilesBounds) { + applyBackBuffer: function(resolution) { var backBuffer = this.backBuffer; if(!backBuffer) { backBuffer = this.createBackBuffer(); @@ -415,14 +424,14 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { var style = backBuffer.style; - // scale - var ratio = this.lastResolution / resolution; + // scale the back buffer + var ratio = this.backBufferData.resolution / resolution; style.width = 100 * ratio + '%'; style.height = 100 * ratio + '%'; - // and position + // and position it (based on the grid's top-left corner) var position = this.getViewPortPxFromLonLat( - {lon: tilesBounds.left, lat: tilesBounds.top}, resolution); + this.backBufferData.lonlat, resolution); var leftOffset = parseInt(this.map.layerContainerDiv.style.left, 10); var topOffset = parseInt(this.map.layerContainerDiv.style.top, 10); backBuffer.style.left = (position.x - leftOffset) + '%'; @@ -463,6 +472,17 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { return backBuffer; }, + /** + * Method: updateBackBufferData + * Upstate states in the backBufferData property + */ + updateBackBufferData: function() { + this.backBufferData.resolution = this.getServerResolution(); + var topLeftTile = this.grid[0][0]; + this.backBufferData.lonlat = {lon: topLeftTile.bounds.left, + lat: topLeftTile.bounds.top}; + }, + /** * Method: moveByPx * Move the layer based on pixel vector. @@ -887,7 +907,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.backBuffer = null; } if(this.map) { - this.lastResolution = this.getServerResolution(); + this.updateBackBufferData(); } } }; From 1bffc4fe2800761c222a5da59d6e0fce175e8437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Tue, 18 Oct 2011 08:24:32 +0200 Subject: [PATCH 06/44] Tile/Image.js does not require Tile/BackBufferable.js --- lib/OpenLayers/Tile/Image.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index 2eba90b590..6d6f13394e 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -5,7 +5,7 @@ /** - * @requires OpenLayers/Tile/BackBufferable.js + * @requires OpenLayers/Tile.js */ /** From 097112466912b5e5f01f799bc0385b77d120b0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Tue, 18 Oct 2011 08:25:02 +0200 Subject: [PATCH 07/44] Tile.Image inherits from Tile --- lib/OpenLayers/Tile/Image.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index 6d6f13394e..b4dc680aa9 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -15,7 +15,7 @@ * constructor. * * Inherits from: - * - + * - */ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { From b39f4fde1cadd5bad0c831e475e0ad5be99b2b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Tue, 18 Oct 2011 08:25:46 +0200 Subject: [PATCH 08/44] remove Tile.Image:insertBackBuffer and add API docs for Tile.Image:cloneMarkup --- lib/OpenLayers/Tile/Image.js | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/OpenLayers/Tile/Image.js b/lib/OpenLayers/Tile/Image.js index b4dc680aa9..235bad8532 100644 --- a/lib/OpenLayers/Tile/Image.js +++ b/lib/OpenLayers/Tile/Image.js @@ -320,21 +320,13 @@ OpenLayers.Tile.Image = OpenLayers.Class(OpenLayers.Tile, { }, /** - * Method: insertBackBuffer - * Create a copy of this tile's markup and insert it to the layer - * div. + * Method: cloneMarkup + * Clone this tile's markup. * * Returns: - * {DOMElement} The back buffer. + * {DOMElement} The markup, or undefined if the tile has no image + * or if it's currently loading. */ - insertBackBuffer: function() { - var frame = this.frame.cloneNode(false); - this.layer.div.insertBefore(frame, this.frame); - frame.appendChild(this.imgDiv); - this.imgDiv = null; - return frame; - }, - cloneMarkup: function() { if(!this.imgDiv || this.isLoading) { return; From f9ae12f2271adf4422da33f4dc9797d61d24e89f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Wed, 19 Oct 2011 20:42:34 +0200 Subject: [PATCH 09/44] minor refactoring in Layer.Grid - add a removeBackBuffer function --- lib/OpenLayers/Layer/Grid.js | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index fd13b1aabb..fc2232a6a8 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -462,7 +462,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { return; } // to be able to correctly position the back buffer we - // place the first tile at (0, 0) in the back buffer + // place the tiles grid at (0, 0) in the back buffer tile.style.left = (j * this.tileSize.w) + '%'; tile.style.top = (i * this.tileSize.h) + '%'; backBuffer.appendChild(tile); @@ -472,15 +472,31 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { return backBuffer; }, + /** + * Method: removeBackBuffer + * Remove back buffer from DOM. + */ + removeBackBuffer: function() { + if(this.backBuffer && this.backBuffer.parentNode) { + this.div.removeChild(this.backBuffer); + this.backBuffer = null; + } + }, + /** * Method: updateBackBufferData * Upstate states in the backBufferData property */ updateBackBufferData: function() { - this.backBufferData.resolution = this.getServerResolution(); - var topLeftTile = this.grid[0][0]; - this.backBufferData.lonlat = {lon: topLeftTile.bounds.left, - lat: topLeftTile.bounds.top}; + // updateBackBufferData is called asynchronously when tiles are + // received, so we need to check that the map is still there + if (this.map) { + var resolution = this.map.getResolution(); + this.backBufferData.resolution = this.getServerResolution(resolution); + var topLeftTile = this.grid[0][0]; + this.backBufferData.lonlat = {lon: topLeftTile.bounds.left, + lat: topLeftTile.bounds.top}; + } }, /** @@ -902,13 +918,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { //if that was the last tile, then trigger a 'loadend' on the layer if (this.numLoadingTiles == 0) { this.events.triggerEvent("loadend"); - if(this.backBuffer && this.backBuffer.parentNode) { - this.div.removeChild(this.backBuffer); - this.backBuffer = null; - } - if(this.map) { - this.updateBackBufferData(); - } + this.removeBackBuffer(); + this.updateBackBufferData(); } }; tile.events.register("loadend", this, tile.onLoadEnd); From a37202ac09fa4e1c4ef3388307e5120abe2321d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Wed, 19 Oct 2011 23:15:17 +0200 Subject: [PATCH 10/44] remove BackBufferable.js from the js files list in OpenLayers.js --- lib/OpenLayers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/OpenLayers.js b/lib/OpenLayers.js index b378b7d24b..22fb1b8500 100644 --- a/lib/OpenLayers.js +++ b/lib/OpenLayers.js @@ -121,7 +121,6 @@ "OpenLayers/Marker/Box.js", "OpenLayers/Popup.js", "OpenLayers/Tile.js", - "OpenLayers/Tile/BackBufferable.js", "OpenLayers/Tile/Image.js", "OpenLayers/Tile/Image/IFrame.js", "OpenLayers/Tile/WFS.js", From 853bfeaee113cd12289169f18a7504d16a534490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Wed, 19 Oct 2011 23:19:29 +0200 Subject: [PATCH 11/44] necessary adaptations to the Tile.IFrame mixin - back buffering is disabled when using POST and iframe tiles --- lib/OpenLayers/Tile/Image/IFrame.js | 90 +++++++++++++++++++---------- 1 file changed, 59 insertions(+), 31 deletions(-) diff --git a/lib/OpenLayers/Tile/Image/IFrame.js b/lib/OpenLayers/Tile/Image/IFrame.js index 9616036815..15b9d7e505 100644 --- a/lib/OpenLayers/Tile/Image/IFrame.js +++ b/lib/OpenLayers/Tile/Image/IFrame.js @@ -29,40 +29,52 @@ OpenLayers.Tile.Image.IFrame = { useIFrame: null, /** - * Method: updateBackBuffer - * Update the , and return a new or reposition the - * backBuffer. When a backbuffer is returned, the tile's markup is not - * available any more. - * - * Returns: - * {HTMLDivElement} the tile's markup in a cloned element, or undefined if - * no backbuffer is currently available or needed + * Method: draw + * Set useIFrame in the instance, and operate the to/from image from/to + * iframe switch, if necessary. Then call the parent function. + * + * Returns: + * {Boolean} */ - updateBackBuffer: function() { - this.url = this.layer.getURL(this.bounds); - var usedIFrame = this.useIFrame; - this.useIFrame = this.maxGetUrlLength !== null && !this.layer.async && - this.url.length > this.maxGetUrlLength; - var fromIFrame = usedIFrame && !this.useIFrame; - var toIFrame = !usedIFrame && this.useIFrame; - if (fromIFrame || toIFrame) { - // switch between get (image) and post (iframe) - this.clear(); - if (this.imgDiv && this.imgDiv.parentNode === this.frame) { - this.frame.removeChild(this.imgDiv); - } - this.imgDiv = null; - if (fromIFrame) { - // remove eventPane - this.frame.removeChild(this.frame.firstChild); - this.resetBackBuffer(); + draw: function() { + var draw = OpenLayers.Tile.Image.prototype.shouldDraw.call(this); + if(draw) { + + // this.url isn't set to the currect value yet, so we call getURL + // on the layer and store the result in a local variable + var url = this.layer.getURL(this.bounds); + + var usedIFrame = this.useIFrame; + this.useIFrame = this.maxGetUrlLength !== null && + !this.layer.async && + url.length > this.maxGetUrlLength; + + var fromIFrame = usedIFrame && !this.useIFrame; + var toIFrame = !usedIFrame && this.useIFrame; + + if(fromIFrame || toIFrame) { + + // Switching between GET (image) and POST (iframe). + + // We remove the imgDiv (really either an image or an iframe) + // from the frame and set it to null to make sure initImage + // will call createImage. + + if(this.imgDiv && this.imgDiv.parentNode === this.frame) { + this.frame.removeChild(this.imgDiv); + } + this.imgDiv = null; + + // And if we had an iframe we also remove the event pane. + + if(fromIFrame) { + this.frame.removeChild(this.frame.firstChild); + } } } - if (!this.useIFrame) { - OpenLayers.Tile.Image.prototype.updateBackBuffer.apply(this, arguments); - } + return OpenLayers.Tile.Image.prototype.draw.apply(this, arguments); }, - + /** * Method: createImage * Creates the content for the frame on the tile. @@ -183,6 +195,22 @@ OpenLayers.Tile.Image.IFrame = { } else { OpenLayers.Tile.Image.prototype.setImgSrc.apply(this, arguments); } - } + }, + /** + * Method: cloneMarkup + * Override cloneMarkup to not attempt cloning when we use an iframe. + * Moving an iframe from one element to another makes it necessary to + * reload the iframe because its content is lost. So we just give up. + * + * Returns: + * {DOMElement} + */ + cloneMarkup: function() { + var clone; + if(!this.useIFrame) { + clone = OpenLayers.Tile.Image.prototype.cloneMarkup.call(this); + } + return clone; + } }; From 7ffec2e88b30f8319a875144a93aa9a15d5cf682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Wed, 19 Oct 2011 23:19:52 +0200 Subject: [PATCH 12/44] Make the IFrame.html tests pass --- tests/Tile/Image/IFrame.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/Tile/Image/IFrame.html b/tests/Tile/Image/IFrame.html index ce57a31c6a..ab119ade38 100644 --- a/tests/Tile/Image/IFrame.html +++ b/tests/Tile/Image/IFrame.html @@ -15,7 +15,7 @@ var wmsUrl = "http://labs.metacarta.com/wms/vmap0?"; function test_Tile_Image_IFrame_create (t) { - t.plan( 5 ); + t.plan( 3 ); map = new OpenLayers.Map('map'); var bar = new Array(205).join("1234567890"); layer = new OpenLayers.Layer.WMS(name, wmsUrl, @@ -25,7 +25,6 @@ map.addLayer(layer); var tile = layer.addTile(bounds, position); - t.eq(tile.backBufferMode, 2, "backBufferMode is 2 after tile creation"); tile.draw(); t.eq(tile.imgDiv.nodeName.toLowerCase(), "iframe", "IFrame used for long URL"); @@ -33,7 +32,6 @@ layer.mergeNewParams({foo: null}); tile.draw(); t.eq(tile.imgDiv.nodeName.toLowerCase(), "img", "IMG used for short URL"); - t.eq(tile.backBufferMode, 2, "backBufferMode reset to 2"); tile.maxGetUrlLength = 0; tile.draw(); From 76e8a800dacf59c9c7342cfaadca036083bc6fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Wed, 19 Oct 2011 23:47:25 +0200 Subject: [PATCH 13/44] special precautions must be taken in updateBackBufferData --- lib/OpenLayers/Layer/Grid.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index fc2232a6a8..69584c2e97 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -490,10 +490,14 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { updateBackBufferData: function() { // updateBackBufferData is called asynchronously when tiles are // received, so we need to check that the map is still there - if (this.map) { + if(this.map) { var resolution = this.map.getResolution(); this.backBufferData.resolution = this.getServerResolution(resolution); - var topLeftTile = this.grid[0][0]; + } + // the top left tile might have been destroyed, so its bounds + // property may be null + var topLeftTile = this.grid[0][0]; + if(topLeftTile.bounds) { this.backBufferData.lonlat = {lon: topLeftTile.bounds.left, lat: topLeftTile.bounds.top}; } From 39eca86083f0ea9e034d739e2f9538cd6307e6e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Wed, 19 Oct 2011 23:50:43 +0200 Subject: [PATCH 14/44] replace test_insertBackBuffer by test_cloneMarkup in the Tile/Image.html tests --- tests/Tile/Image.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Tile/Image.html b/tests/Tile/Image.html index 0bfa4ae2ec..11d05a1050 100644 --- a/tests/Tile/Image.html +++ b/tests/Tile/Image.html @@ -317,8 +317,8 @@ map.destroy(); } - function test_insertBackBuffer(t) { - t.plan(4); + function test_cloneMarkup(t) { + t.plan(3); var map = new OpenLayers.Map('map'); var layer = new OpenLayers.Layer.WMS( "OpenLayers WMS", @@ -326,11 +326,11 @@ map.addLayer(layer); map.setCenter(new OpenLayers.LonLat(0,0), 5); var tile = layer.grid[0][0]; + tile.isLoading = false; var img = tile.imgDiv; - var backBuffer = tile.insertBackBuffer(); - t.eq(backBuffer.style.left, tile.frame.style.left, "backBuffer tile has same left style as frame"); - t.ok(backBuffer.parentNode === layer.div, "backBuffer inserted into layer div"); - t.ok(backBuffer.firstChild === img, "image appended to backBuffer"); + var clone = tile.cloneMarkup(); + t.eq(clone.style.left, tile.frame.style.left, "clone has same left style as frame"); + t.ok(clone.firstChild === img, "image appended to clone"); t.ok(tile.imgDiv == null, "image reference removed from tile"); map.destroy(); } From bed285593f9acde9d93dab726eb754d56ca86753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Thu, 20 Oct 2011 21:55:30 +0200 Subject: [PATCH 15/44] add tests for Layer.Grid --- tests/Layer/Grid.html | 131 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 2 deletions(-) diff --git a/tests/Layer/Grid.html b/tests/Layer/Grid.html index fd8afb6e9d..4a9b96b44e 100644 --- a/tests/Layer/Grid.html +++ b/tests/Layer/Grid.html @@ -21,13 +21,14 @@ function test_Layer_Grid_constructor (t) { - t.plan( 5 ); + t.plan( 6 ); layer = new OpenLayers.Layer.Grid(name, url, params, null); t.ok( layer instanceof OpenLayers.Layer.Grid, "returns OpenLayers.Layer.Grid object" ); t.eq( layer.buffer, 0, "buffer default is 0"); t.eq( layer.ratio, 1.5, "ratio default is 1.5"); t.eq( layer.numLoadingTiles, 0, "numLoadingTiles starts at 0"); + t.eq( layer.backBufferData, {}, "backBufferData set to empty object"); var obj = {}; var func = function() {}; @@ -586,7 +587,7 @@ function test_Layer_Grid_destroy (t) { - t.plan( 8 ); + t.plan( 9 ); var map = new OpenLayers.Map('map'); layer = new OpenLayers.Layer.Grid(name, url, params); @@ -613,6 +614,7 @@ t.eq( layer.timerId, null, "Tile loading timeout cleared"); t.ok( layer.grid == null, "tiles appropriately destroyed") + t.eq( layer.backBufferData, null, "backBufferData set to null"); // destroy after remove from map layer = new OpenLayers.Layer.WMS(name, url, params); @@ -814,6 +816,131 @@ map.destroy(); } + function test_applyBackBuffer(t) { + t.plan(13); + + var map = new OpenLayers.Map('map2'); + var layer = new OpenLayers.Layer.WMS('', '', {}, { + isBaseLayer: true + }); + map.addLayer(layer); + map.zoomToMaxExtent(); + + var backBuffer; + + // test #1 + layer.createBackBuffer = function() { + return; + }; + layer.applyBackBuffer(2); + t.eq(layer.backBuffer, undefined, + 'back buffer not created if createBackBuffer returns undefined'); + + // test #2 + layer.createBackBuffer = function() { + backBuffer = document.createElement('div'); + return backBuffer; + }; + layer.backBufferData = {resolution: 32, lonlat: map.getCenter()}; + layer.applyBackBuffer(2); + t.ok(layer.backBuffer === backBuffer, + 'back buffer set in layer'); + t.ok(layer.div.firstChild === backBuffer, + 'back buffer inserted as first child'); + t.eq(layer.backBuffer.style.width, '1600%', + 'back buffer has correct width'); + t.eq(layer.backBuffer.style.height, '1600%', + 'back buffer has correct height'); + t.eq(layer.backBuffer.style.left, '250%', + 'back buffer has correct left'); + t.eq(layer.backBuffer.style.top, '275%', + 'back buffer has correct top'); + + // test #3 + layer.createBackBuffer = function() { + backBuffer = document.createElement('div'); + return backBuffer; + }; + layer.backBufferData = {resolution: 32, lonlat: map.getCenter()}; + map.layerContainerDiv.style.left = '20px'; + map.layerContainerDiv.style.top = '-20px'; + layer.applyBackBuffer(2); + t.ok(layer.backBuffer === backBuffer, + 'back buffer set in layer'); + t.ok(layer.div.firstChild === backBuffer, + 'back buffer inserted as first child'); + t.eq(layer.backBuffer.style.width, '1600%', + 'back buffer has correct width'); + t.eq(layer.backBuffer.style.height, '1600%', + 'back buffer has correct height'); + t.eq(layer.backBuffer.style.left, '230%', + 'back buffer has correct left'); + t.eq(layer.backBuffer.style.top, '295%', + 'back buffer has correct top'); + + map.destroy(); + } + + function test_createBackBuffer(t) { + t.plan(6); + + var map = new OpenLayers.Map('map'); + var layer = new OpenLayers.Layer.WMS('', '', {}, { + isBaseLayer: true + }); + map.addLayer(layer); + map.zoomToMaxExtent(); + + var cloneMarkup = OpenLayers.Tile.Image.prototype.cloneMarkup; + + var backBuffer; + + OpenLayers.Tile.Image.prototype.cloneMarkup = function() { + return; + }; + backBuffer = layer.createBackBuffer(); + t.eq(backBuffer, undefined, + 'createBackBuffer returns undefined if cloneMarkup returns undefined'); + + OpenLayers.Tile.Image.prototype.cloneMarkup = function() { + return document.createElement('div'); + }; + backBuffer = layer.createBackBuffer(); + t.ok(backBuffer != undefined, + 'createBackBuffer returns a back buffer'); + t.eq(backBuffer.childNodes[0].style.left, '0%', + 'first tile has correct left'); + t.eq(backBuffer.childNodes[0].style.top, '0%', + 'first tile has correct top'); + t.eq(backBuffer.childNodes[1].style.left, '256%', + 'second tile has correct left'); + t.eq(backBuffer.childNodes[1].style.top, '0%', + 'second tile has correct top'); + + map.destroy(); + OpenLayers.Tile.Image.prototype.cloneMarkup = cloneMarkup; + } + + function test_updateBackBufferData(t) { + t.plan(1); + + var map = new OpenLayers.Map('map', { + resolutions: [32, 16] + }); + var layer = new OpenLayers.Layer.WMS('', '', {}, { + isBaseLayer: true + }); + map.addLayer(layer); + map.setCenter(new OpenLayers.LonLat(0, 0), 0); + + layer.backBufferData = {}; + layer.updateBackBufferData(); + t.eq(layer.backBufferData.resolution, 32, + 'backBufferData has correct resolution'); + + map.destroy(); + } + From 17dc9c2b58929746f6ce0b6e6ee24beefec27c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Thu, 20 Oct 2011 22:02:39 +0200 Subject: [PATCH 16/44] fix test_Layer_Grid_addTileMonitoringHooks --- tests/Layer/Grid.html | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Layer/Grid.html b/tests/Layer/Grid.html index 4a9b96b44e..ca13298278 100644 --- a/tests/Layer/Grid.html +++ b/tests/Layer/Grid.html @@ -483,6 +483,7 @@ g_events = []; + layer.grid = [[{}]]; // to prevent error in updateBackBuffer tile.onLoadEnd.apply(layer); t.eq(g_events[0], "tileloaded", "tileloaded triggered when numLoadingTiles is 0"); t.eq(g_events[1], "loadend", "loadend event triggered when numLoadingTiles is 0"); From 9bab78cde88908c7d5495515d73936f3661cc48b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Thu, 20 Oct 2011 23:03:28 +0200 Subject: [PATCH 17/44] more Layer.Grid tests --- tests/Layer/Grid.html | 190 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) diff --git a/tests/Layer/Grid.html b/tests/Layer/Grid.html index ca13298278..0e9852d9a7 100644 --- a/tests/Layer/Grid.html +++ b/tests/Layer/Grid.html @@ -762,6 +762,97 @@ map.destroy(); } + function test_moveTo_backbuffer_singletile(t) { + t.plan(4); + + var map = new OpenLayers.Map('map', { + resolutions: [1, 0.5, 0.025] + }); + var resolution; + var layer = new OpenLayers.Layer.WMS('', '', {}, { + singleTile: true, + isBaseLayer: true, + transitionEffect: 'resize', + applyBackBuffer: function(res) { + resolution = res; + } + }); + map.addLayer(layer); + + // initial resolution is 0.025 + resolution = undefined; + map.setCenter(new OpenLayers.LonLat(0, 0), 2); + t.eq(resolution, undefined, + 'applyBackBuffer not called on first moveTo'); + layer.backBufferData.resolution = 0.025; + + // move to (-90, 45) + resolution = undefined; + map.setCenter(new OpenLayers.LonLat(-90, 45)); + t.eq(resolution, 0.025, + 'applyBackBuffer called when map is moved'); + layer.backBufferData.resolution = 0.025; + + // change to resolution 1 + resolution = undefined; + map.zoomTo(0); + t.eq(resolution, 1, + 'applyBackBuffer called when map is zoomed out'); + layer.backBufferData.resolution = 1; + + // change to resolution 0.5 + resolution = undefined; + map.zoomTo(1); + t.eq(resolution, 0.5, + 'applyBackBuffer called when map is zoomed out'); + + map.destroy(); + } + + function test_moveTo_backbuffer(t) { + t.plan(4); + + var map = new OpenLayers.Map('map', { + resolutions: [1, 0.5, 0.025] + }); + var resolution; + var layer = new OpenLayers.Layer.WMS('', '', {}, { + isBaseLayer: true, + transitionEffect: 'resize', + applyBackBuffer: function(res) { + resolution = res; + } + }); + map.addLayer(layer); + + // initial resolution is 0.025 + resolution = undefined; + map.setCenter(new OpenLayers.LonLat(0, 0), 2); + t.eq(resolution, undefined, + 'applyBackBuffer not called on first moveTo'); + layer.backBufferData.resolution = 0.025; + + // move to (-90, 45) + resolution = undefined; + map.setCenter(new OpenLayers.LonLat(-90, 45)); + t.eq(resolution, undefined, + 'applyBackBuffer not called when map is moved'); + layer.backBufferData.resolution = 0.025; + + // change to resolution 1 + resolution = undefined; + map.zoomTo(0); + t.eq(resolution, 1, + 'applyBackBuffer called when map is zoomed out'); + layer.backBufferData.resolution = 1; + + // change to resolution 0.5 + map.zoomTo(1); + t.eq(resolution, 0.5, + 'applyBackBuffer called when map is zoomed out'); + + map.destroy(); + } function test_transformDiv(t) { t.plan(8); @@ -942,6 +1033,105 @@ map.destroy(); } + function test_backbuffer_scaled_layer(t) { + t.plan(15); + + // + // set up + // + + var map = new OpenLayers.Map('map', { + resolutions: [32, 16, 8, 4, 2, 1] + }); + var layer = new OpenLayers.Layer.WMS( + "WMS", + window.location.href + "#", + null, + {transitionEffect: "resize"} + ); + + layer.serverResolutions = [32, 16, 8]; + layer.createBackBuffer = function() { + return document.createElement('div'); + }; + + map.addLayer(layer); + map.setCenter(new OpenLayers.LonLat(0, 0), 2); + + layer.updateBackBufferData(); + + // + // test + // + + // change resolution from 8 to 4 + map.zoomTo(3); + t.ok(layer.backBuffer == undefined, + '[8->4] back buffer not applied'); + layer.updateBackBufferData(); + + // change resolution from 8 to 2 + map.zoomTo(2); layer.updateBackBufferData(); map.zoomTo(4); + t.ok(layer.backBuffer == undefined, + '[8->2] back buffer not applies'); + layer.updateBackBufferData(); + + // change resolution from 16 to 4 + map.zoomTo(1); layer.updateBackBufferData(); map.zoomTo(3); + t.ok(layer.backBuffer != undefined, + '[16->4] back buffer applied'); + t.eq(layer.backBuffer.style.width, '200%', + '[16->4] back buffer width is as expected'); + t.eq(layer.backBuffer.style.width, '200%', + '[16->4] back buffer height is as expected'); + layer.updateBackBufferData(); + + // change resolution from 32 to 1 + map.zoomTo(0); layer.updateBackBufferData(); map.zoomTo(5); + t.ok(layer.backBuffer != undefined, + '[32->1] back buffer applied'); + t.eq(layer.backBuffer.style.width, '400%', + '[32->1] back buffer width is as expected'); + t.eq(layer.backBuffer.style.width, '400%', + '[32->1] back buffer height is as expected'); + layer.updateBackBufferData(); + + // change resolution from 4 to 2 + map.zoomTo(3); layer.updateBackBufferData(); map.zoomTo(4); + t.ok(layer.backBuffer == undefined, + '[4->2] back buffer not applied'); + layer.updateBackBufferData(); + + // change resolution from 4 to 1 + map.zoomTo(3); layer.updateBackBufferData(); map.zoomTo(5); + t.ok(layer.backBuffer == undefined, + '[4->1] back buffer not applied'); + + // change resolution from 1 to 4 + map.zoomTo(5); layer.updateBackBufferData(); map.zoomTo(3); + t.ok(layer.backBuffer == undefined, + '[1->4] back buffer not applied'); + + // change resolution from 4 to 8 + map.zoomTo(3); layer.updateBackBufferData(); map.zoomTo(2); + t.ok(layer.backBuffer == undefined, + '[4->8] back buffer not applied'); + + // change resolution from 4 to 16 + map.zoomTo(3); layer.updateBackBufferData(); map.zoomTo(1); + t.ok(layer.backBuffer != undefined, + '[4->16] back buffer applied'); + t.eq(layer.backBuffer.style.width, '50%', + '[4->16] back buffer width is as expected'); + t.eq(layer.backBuffer.style.width, '50%', + '[4->16] back buffer height is as expected'); + + // + // tear down + // + + map.destroy(); + } From dc0867e6550b50f25018b3142eb9afbab53ed88e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Thu, 20 Oct 2011 23:04:17 +0200 Subject: [PATCH 18/44] remove the Tile.BackBufferable tests --- tests/Tile/BackBufferable.html | 260 --------------------------------- tests/list-tests.html | 1 - 2 files changed, 261 deletions(-) delete mode 100644 tests/Tile/BackBufferable.html diff --git a/tests/Tile/BackBufferable.html b/tests/Tile/BackBufferable.html deleted file mode 100644 index 97275891e7..0000000000 --- a/tests/Tile/BackBufferable.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - -
- - diff --git a/tests/list-tests.html b/tests/list-tests.html index b5d052093f..4983e0b4f8 100644 --- a/tests/list-tests.html +++ b/tests/list-tests.html @@ -224,7 +224,6 @@
  • Symbolizer/Text.html
  • Tile.html
  • Tile/Image.html
  • -
  • Tile/BackBufferable.html
  • Tile/Image/IFrame.html
  • Tile/WFS.html
  • Tween.html
  • From 8aaf9ee775f7fe96b4c88a76e0ec20e5bc1db4ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Thu, 20 Oct 2011 23:05:08 +0200 Subject: [PATCH 19/44] remove the unnecessary SUPPORTED_TRANSITIONS array --- lib/OpenLayers/Layer.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/OpenLayers/Layer.js b/lib/OpenLayers/Layer.js index 46ec873be7..ab115223ca 100644 --- a/lib/OpenLayers/Layer.js +++ b/lib/OpenLayers/Layer.js @@ -314,13 +314,6 @@ OpenLayers.Layer = OpenLayers.Class({ */ transitionEffect: null, - /** - * Property: SUPPORTED_TRANSITIONS - * {Array} An immutable (that means don't change it!) list of supported - * transitionEffect values. - */ - SUPPORTED_TRANSITIONS: ['resize'], - /** * Property: metadata * {Object} This object can be used to store additional information on a From 667d21137fa975d71415e731ef98a5a03243259e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Thu, 20 Oct 2011 23:05:34 +0200 Subject: [PATCH 20/44] purely cosmetic change --- lib/OpenLayers/Layer/Grid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 69584c2e97..17401946fe 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -463,8 +463,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } // to be able to correctly position the back buffer we // place the tiles grid at (0, 0) in the back buffer - tile.style.left = (j * this.tileSize.w) + '%'; tile.style.top = (i * this.tileSize.h) + '%'; + tile.style.left = (j * this.tileSize.w) + '%'; backBuffer.appendChild(tile); } } From 55c2f0e0470eb1f27af0f9121454e787cf5fdf14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Thu, 20 Oct 2011 23:08:16 +0200 Subject: [PATCH 21/44] better comments in Image/IFrame.js --- lib/OpenLayers/Tile/Image/IFrame.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/OpenLayers/Tile/Image/IFrame.js b/lib/OpenLayers/Tile/Image/IFrame.js index 15b9d7e505..d1c7dca65d 100644 --- a/lib/OpenLayers/Tile/Image/IFrame.js +++ b/lib/OpenLayers/Tile/Image/IFrame.js @@ -15,9 +15,6 @@ * * This mixin will be applied to instances * configured with set. - * - * Inherits from: - * - */ OpenLayers.Tile.Image.IFrame = { @@ -30,8 +27,8 @@ OpenLayers.Tile.Image.IFrame = { /** * Method: draw - * Set useIFrame in the instance, and operate the to/from image from/to - * iframe switch, if necessary. Then call the parent function. + * Set useIFrame in the instance, and operate the image/iframe switch. + * Then call Tile.Image.draw. * * Returns: * {Boolean} From abcc74cbc77d59b1e1875df2ea853e75d710d2a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Fri, 21 Oct 2011 00:13:16 +0200 Subject: [PATCH 22/44] give a class to the back buffer --- lib/OpenLayers/Layer/Grid.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 17401946fe..4256bda5cb 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -452,6 +452,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { if(this.grid.length > 0) { var backBuffer = document.createElement('div'); backBuffer.id = this.div.id + '_bb'; + backBuffer.className = 'olBackBuffer'; backBuffer.style.position = 'absolute'; backBuffer.style.width = '100%'; backBuffer.style.height = '100%'; From 2f80d52bfd879368ef0576ece9ca7be06c5c6cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Fri, 28 Oct 2011 22:57:10 +0200 Subject: [PATCH 23/44] in single tile mode with no transition effect remove the back buffer when zooming --- lib/OpenLayers/Layer/Grid.js | 15 ++++++++++++++ tests/Layer/Grid.html | 39 ++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 407ad14fc4..646f6b4232 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -274,13 +274,28 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { // We want to redraw whenever even the slightest part of the // current bounds is not contained by our tile. // (thus, we do not specify partial -- its default is false) + if ( forceReTile || (!dragging && !tilesBounds.containsBounds(bounds))) { + + // In single tile mode with no transition effect, we insert + // a non-scaled backbuffer when the layer is moved. But if + // a zoom occurs right after a move, i.e. before the new + // image is received, we need to remove the backbuffer, or + // an ill-positioned image will be visible during the zoom + // transition. + + if(lastResolution !== serverResolution && + this.transitionEffect !== 'resize') { + this.removeBackBuffer(); + } + if(lastResolution === serverResolution || (lastResolution && this.transitionEffect === 'resize')) { this.applyBackBuffer(serverResolution); } + this.initSingleTile(bounds); } } else { diff --git a/tests/Layer/Grid.html b/tests/Layer/Grid.html index 0e9852d9a7..84680826a1 100644 --- a/tests/Layer/Grid.html +++ b/tests/Layer/Grid.html @@ -1033,6 +1033,45 @@ map.destroy(); } + function test_singleTile_move_and_zoom(t) { + + // + // In single tile mode with no transition effect, we insert a non-scaled + // backbuffer when the layer is moved. But if a zoom occurs right after + // a move, i.e. before the new image is received, we need to remove the + // backbuffer, or an ill-positioned image will be visible during the + // zoom transition. + // + + t.plan(2); + + var map = new OpenLayers.Map('map'); + var layer = new OpenLayers.Layer.WMS('', '', {}, { + isBaseLayer: true, + singleTile: true, + ratio: 1 + }); + map.addLayer(layer); + map.setCenter(new OpenLayers.LonLat(0, 0), 0); + + // pretend the image has been loaded + layer.updateBackBufferData(); + layer.grid[0][0].isLoading = false; // this is to be able to create + // a back buffer + + // move + map.setCenter(new OpenLayers.LonLat(10, 10)); + t.ok(layer.backBuffer && layer.backBuffer.parentNode === layer.div, + 'backbuffer inserted after map move'); + + // zoom + map.zoomTo(1); + t.eq(layer.backBuffer, null, + 'back buffer removed when zooming'); + + map.destroy(); + } + function test_backbuffer_scaled_layer(t) { t.plan(15); From f3e0ac9425d167d8c85e405175cfb3df308e4773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Fri, 28 Oct 2011 23:00:13 +0200 Subject: [PATCH 24/44] remove double variable declarations, and make jslint happier --- lib/OpenLayers/Layer/Grid.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 646f6b4232..a243a6b876 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -355,7 +355,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { if(this.serverResolutions && OpenLayers.Util.indexOf(this.serverResolutions, resolution) === -1) { var i, serverResolution; - for(var i=this.serverResolutions.length-1; i>= 0; i--) { + for(i=this.serverResolutions.length-1; i>= 0; i--) { serverResolution = this.serverResolutions[i]; if(serverResolution > resolution) { resolution = serverResolution; @@ -401,8 +401,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { var size = this.map.getSize(); var lcX = parseInt(this.map.layerContainerDiv.style.left, 10); var lcY = parseInt(this.map.layerContainerDiv.style.top, 10); - var x = (lcX - (size.w / 2.)) * (scale - 1); - var y = (lcY - (size.h / 2.)) * (scale - 1); + var x = (lcX - (size.w / 2.0)) * (scale - 1); + var y = (lcY - (size.h / 2.0)) * (scale - 1); this.div.style.left = x + '%'; this.div.style.top = y + '%'; @@ -465,7 +465,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { createBackBuffer: function() { var backBuffer; if(this.grid.length > 0) { - var backBuffer = document.createElement('div'); + backBuffer = document.createElement('div'); backBuffer.id = this.div.id + '_bb'; backBuffer.className = 'olBackBuffer'; backBuffer.style.position = 'absolute'; From c80746b890f461b4e3b77850ac39b8d24cc8b13c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Sat, 29 Oct 2011 12:22:08 +0200 Subject: [PATCH 25/44] Tile.Image.cloneMarkup renamed Tile.Image.createBackBuffer --- lib/OpenLayers/Layer/Grid.js | 2 +- lib/OpenLayers/Tile/Image.js | 14 ++++++++------ lib/OpenLayers/Tile/Image/IFrame.js | 16 ++++++++-------- tests/Layer/Grid.html | 10 +++++----- tests/Tile/Image.html | 9 +++++---- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index a243a6b876..eba00f5e4d 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -473,7 +473,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { backBuffer.style.height = '100%'; for(var i=0, lenI=this.grid.length; i Date: Sat, 29 Oct 2011 21:10:23 +0200 Subject: [PATCH 26/44] comparing backBufferData.resolution and serverResolution to know if backbuffering should be applied is wrong --- lib/OpenLayers/Layer/Grid.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index eba00f5e4d..df9bafe49e 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -285,14 +285,12 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { // an ill-positioned image will be visible during the zoom // transition. - if(lastResolution !== serverResolution && - this.transitionEffect !== 'resize') { + if(zoomChanged && this.transitionEffect !== 'resize') { this.removeBackBuffer(); } - if(lastResolution === serverResolution || - (lastResolution && - this.transitionEffect === 'resize')) { + if(!zoomChanged || (lastResolution && + this.transitionEffect === 'resize')) { this.applyBackBuffer(serverResolution); } @@ -325,9 +323,8 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } if(forceReTile) { - if(this.transitionEffect === 'resize' && - (lastResolution && - (lastResolution !== serverResolution))) { + if(zoomChanged && this.transitionEffect === 'resize' && + lastResolution) { this.applyBackBuffer(serverResolution); } this.initGriddedTiles(bounds); From c0d210ef0571332bfe46e963bcc3c2d61db5bf09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Sat, 29 Oct 2011 21:11:14 +0200 Subject: [PATCH 27/44] just skip tiles that are currently loading when creating the back buffer --- lib/OpenLayers/Layer/Grid.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index df9bafe49e..22075ad44a 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -472,7 +472,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { for(var j=0, lenJ=this.grid[i].length; j Date: Sun, 30 Oct 2011 23:20:42 +0100 Subject: [PATCH 28/44] correct bug where the value stored for the top-left corner of the back buffer may be incorrect, thanks @ahocevar for catching the issue --- lib/OpenLayers/Layer/Grid.js | 90 +++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/lib/OpenLayers/Layer/Grid.js b/lib/OpenLayers/Layer/Grid.js index 22075ad44a..ce6332a3c9 100644 --- a/lib/OpenLayers/Layer/Grid.js +++ b/lib/OpenLayers/Layer/Grid.js @@ -118,15 +118,26 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { backBuffer: null, /** - * Property: backBufferData - * {Object} An object containing states necessary for the back buffer. It - * includes two state properties: - * - *resolution* the last resolution of the tiles. Used as the "from - * resolution" when transitioning. - * - *lonlat* the geographic coordinates of the tiles grid's top-left - * corner. + * Property: gridResolution + * {Number} The resolution of the current grid. Used for backbuffering. + * This property is updated each the grid is initialized. */ - backBufferData: null, + gridResolution: null, + + /** + * Property: backBufferResolution + * {Number} The resolution of the current back buffer. This property is + * updated each time a back buffer is created. + */ + backBufferResolution: null, + + /** + * Property: backBufferLonLat + * {Object} The top-left corner of the current back buffer. Includes lon + * and lat properties. This object is updated each time a back buffer + * is created. + */ + backBufferLonLat: null, /** * Constructor: OpenLayers.Layer.Grid @@ -150,7 +161,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.events.addEventType("tileloaded"); this.grid = []; - this.backBufferData = {}; this._moveGriddedTiles = OpenLayers.Function.bind( this.moveGriddedTiles, this @@ -177,9 +187,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { */ destroy: function() { this.clearGrid(); + // clearGrid should remove any back buffer from the layer, + // so no need to call removeBackBuffer here + this.grid = null; this.tileSize = null; - this.backBufferData = null; OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this, arguments); }, @@ -199,6 +211,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } } this.grid = []; + this.gridResolution = null; } }, @@ -231,6 +244,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { // we do not want to copy reference to grid, so we make a new array obj.grid = []; + obj.gridResolution = null; return obj; }, @@ -266,9 +280,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { // the server-supported resolution for the new map resolution var serverResolution = this.getServerResolution(resolution); - // the last resolution of the tiles - var lastResolution = this.backBufferData.resolution; - if (this.singleTile) { // We want to redraw whenever even the slightest part of the @@ -289,8 +300,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { this.removeBackBuffer(); } - if(!zoomChanged || (lastResolution && - this.transitionEffect === 'resize')) { + if(!zoomChanged || this.transitionEffect === 'resize') { this.applyBackBuffer(serverResolution); } @@ -323,8 +333,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } if(forceReTile) { - if(zoomChanged && this.transitionEffect === 'resize' && - lastResolution) { + if(zoomChanged && this.transitionEffect === 'resize') { this.applyBackBuffer(serverResolution); } this.initGriddedTiles(bounds); @@ -432,18 +441,28 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { } this.div.insertBefore(backBuffer, this.div.firstChild); this.backBuffer = backBuffer; + + // set some information in the instance for subsequent + // calls to applyBackBuffer where the same back buffer + // is reused + var topLeftTileBounds = this.grid[0][0].bounds; + this.backBufferLonLat = { + lon: topLeftTileBounds.left, + lat: topLeftTileBounds.top + }; + this.backBufferResolution = this.gridResolution; } var style = backBuffer.style; // scale the back buffer - var ratio = this.backBufferData.resolution / resolution; + var ratio = this.backBufferResolution / resolution; style.width = 100 * ratio + '%'; style.height = 100 * ratio + '%'; // and position it (based on the grid's top-left corner) var position = this.getViewPortPxFromLonLat( - this.backBufferData.lonlat, resolution); + this.backBufferLonLat, resolution); var leftOffset = parseInt(this.map.layerContainerDiv.style.left, 10); var topOffset = parseInt(this.map.layerContainerDiv.style.top, 10); backBuffer.style.left = (position.x - leftOffset) + '%'; @@ -452,12 +471,11 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { /** * Method: createBackBuffer - * Create a back buffer. We apply a best effort strategy here - if for any - * reason we cannot clone a tile's markup we give up right away. + * Create a back buffer. * * Returns: * {DOMElement} The DOM element for the back buffer, undefined if the - * back buffer couldn't have been created. + * grid isn't initialized yet. */ createBackBuffer: function() { var backBuffer; @@ -493,26 +511,7 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { if(this.backBuffer && this.backBuffer.parentNode) { this.div.removeChild(this.backBuffer); this.backBuffer = null; - } - }, - - /** - * Method: updateBackBufferData - * Upstate states in the backBufferData property - */ - updateBackBufferData: function() { - // updateBackBufferData is called asynchronously when tiles are - // received, so we need to check that the map is still there - if(this.map) { - var resolution = this.map.getResolution(); - this.backBufferData.resolution = this.getServerResolution(resolution); - } - // the top left tile might have been destroyed, so its bounds - // property may be null - var topLeftTile = this.grid[0][0]; - if(topLeftTile.bounds) { - this.backBufferData.lonlat = {lon: topLeftTile.bounds.left, - lat: topLeftTile.bounds.top}; + this.backBufferResolution = null; } }, @@ -645,6 +644,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { //remove all but our single tile this.removeExcessTiles(1,1); + + // store the resolution of the grid + this.gridResolution = this.getServerResolution(); }, /** @@ -805,6 +807,9 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { //shave off exceess rows and colums this.removeExcessTiles(rowidx, colidx); + // store the resolution of the grid + this.gridResolution = this.getServerResolution(); + //now actually draw the tiles this.spiralTileLoad(); }, @@ -936,7 +941,6 @@ OpenLayers.Layer.Grid = OpenLayers.Class(OpenLayers.Layer.HTTPRequest, { if (this.numLoadingTiles == 0) { this.events.triggerEvent("loadend"); this.removeBackBuffer(); - this.updateBackBufferData(); } }; tile.events.register("loadend", this, tile.onLoadEnd); From 896c2c058044bb0260663771dd1c2999d8ad3eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Sun, 30 Oct 2011 23:21:00 +0100 Subject: [PATCH 29/44] fix tests, and add new ones --- tests/Layer/Grid.html | 156 ++++++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 74 deletions(-) diff --git a/tests/Layer/Grid.html b/tests/Layer/Grid.html index 3a0b610105..6f78cd45dd 100644 --- a/tests/Layer/Grid.html +++ b/tests/Layer/Grid.html @@ -21,14 +21,13 @@ function test_Layer_Grid_constructor (t) { - t.plan( 6 ); + t.plan( 5 ); layer = new OpenLayers.Layer.Grid(name, url, params, null); t.ok( layer instanceof OpenLayers.Layer.Grid, "returns OpenLayers.Layer.Grid object" ); t.eq( layer.buffer, 0, "buffer default is 0"); t.eq( layer.ratio, 1.5, "ratio default is 1.5"); t.eq( layer.numLoadingTiles, 0, "numLoadingTiles starts at 0"); - t.eq( layer.backBufferData, {}, "backBufferData set to empty object"); var obj = {}; var func = function() {}; @@ -50,7 +49,7 @@ } function test_Layer_Grid_clearTiles (t) { - t.plan(3); + t.plan(4); var map = new OpenLayers.Map('map'); layer = new OpenLayers.Layer.WMS(name, url, params); @@ -86,6 +85,7 @@ t.ok( layer.grid != null, "layer.grid does not get nullified" ); t.eq(tilesDeleted, numTiles, "all tiles destroy()ed properly"); t.ok(allTilesUnhooked, "all tiles unhooked before being destroyed"); + t.eq(layer.gridResolution, null, "gridResolution set to null"); OpenLayers.Tile.Image.prototype.destroy = OpenLayers.Tile.Image.prototype._destroy; @@ -168,6 +168,7 @@ var map = new OpenLayers.Map('map'); layer = new OpenLayers.Layer.WMS(name, url, params); layer.destroy = function() {}; //we're going to do funky things with the grid + layer.applyBackBuffer = function() {}; // backbuffering isn't under test here map.addLayer(layer); //make sure null bounds doesnt cause script error. @@ -391,6 +392,8 @@ getLayerPxFromLonLat: function(ul) { t.ok(ul.equals(desiredUL), "correct ul passed to translation"); return translatedPX; + }, + getResolution: function() { } } @@ -588,7 +591,7 @@ function test_Layer_Grid_destroy (t) { - t.plan( 9 ); + t.plan( 10 ); var map = new OpenLayers.Map('map'); layer = new OpenLayers.Layer.Grid(name, url, params); @@ -605,17 +608,21 @@ map.setCenter(new OpenLayers.LonLat(0,0), 10); map.setCenter(new OpenLayers.LonLat(1,1)); - //grab a reference to one of the tiles var tile = layer.grid[1][1]; t.eq( tile.imgDiv.className, "olTileImage", "Tile has an image" ); + // add a fake back buffer to the layer + var backBuffer = document.createElement('div'); + layer.backBuffer = backBuffer + layer.div.appendChild(backBuffer); + layer.destroy(); t.eq( tile.imgDiv, null, "Tile destroyed" ); t.eq( layer.timerId, null, "Tile loading timeout cleared"); - t.ok( layer.grid == null, "tiles appropriately destroyed") - t.eq( layer.backBufferData, null, "backBufferData set to null"); + t.ok( backBuffer.parentNode === layer.div, "back buffer removed"); + t.eq( layer.backBuffer, null, "backBuffer set not null in the layer"); // destroy after remove from map layer = new OpenLayers.Layer.WMS(name, url, params); @@ -782,23 +789,20 @@ // initial resolution is 0.025 resolution = undefined; map.setCenter(new OpenLayers.LonLat(0, 0), 2); - t.eq(resolution, undefined, + t.eq(resolution, 0.025, 'applyBackBuffer not called on first moveTo'); - layer.backBufferData.resolution = 0.025; // move to (-90, 45) resolution = undefined; map.setCenter(new OpenLayers.LonLat(-90, 45)); t.eq(resolution, 0.025, 'applyBackBuffer called when map is moved'); - layer.backBufferData.resolution = 0.025; // change to resolution 1 resolution = undefined; map.zoomTo(0); t.eq(resolution, 1, 'applyBackBuffer called when map is zoomed out'); - layer.backBufferData.resolution = 1; // change to resolution 0.5 resolution = undefined; @@ -828,23 +832,20 @@ // initial resolution is 0.025 resolution = undefined; map.setCenter(new OpenLayers.LonLat(0, 0), 2); - t.eq(resolution, undefined, + t.eq(resolution, 0.025, 'applyBackBuffer not called on first moveTo'); - layer.backBufferData.resolution = 0.025; // move to (-90, 45) resolution = undefined; map.setCenter(new OpenLayers.LonLat(-90, 45)); t.eq(resolution, undefined, 'applyBackBuffer not called when map is moved'); - layer.backBufferData.resolution = 0.025; // change to resolution 1 resolution = undefined; map.zoomTo(0); t.eq(resolution, 1, 'applyBackBuffer called when map is zoomed out'); - layer.backBufferData.resolution = 1; // change to resolution 0.5 map.zoomTo(1); @@ -853,6 +854,7 @@ map.destroy(); } + function test_transformDiv(t) { t.plan(8); @@ -933,7 +935,8 @@ backBuffer = document.createElement('div'); return backBuffer; }; - layer.backBufferData = {resolution: 32, lonlat: map.getCenter()}; + layer.gridResolution = 32; + layer.grid[0][0].bounds = new OpenLayers.Bounds(0, 1, 1, 0); layer.applyBackBuffer(2); t.ok(layer.backBuffer === backBuffer, 'back buffer set in layer'); @@ -953,7 +956,8 @@ backBuffer = document.createElement('div'); return backBuffer; }; - layer.backBufferData = {resolution: 32, lonlat: map.getCenter()}; + layer.gridResolution = 32; + layer.grid[0][0].bounds = new OpenLayers.Bounds(0, 1, 1, 0); map.layerContainerDiv.style.left = '20px'; map.layerContainerDiv.style.top = '-20px'; layer.applyBackBuffer(2); @@ -974,7 +978,7 @@ } function test_createBackBuffer(t) { - t.plan(6); + t.plan(7); var map = new OpenLayers.Map('map'); var layer = new OpenLayers.Layer.WMS('', '', {}, { @@ -991,8 +995,10 @@ return; }; backBuffer = layer.createBackBuffer(); - t.eq(backBuffer, undefined, - 'createBackBuffer returns undefined if createBackBuffer returns undefined'); + t.ok(backBuffer != undefined, + 'createBackBuffer returns a back buffer'); + t.eq(backBuffer.childNodes.length, 0, + 'returned back buffer has no child nodes'); OpenLayers.Tile.Image.prototype.createBackBuffer = function() { return document.createElement('div'); @@ -1013,22 +1019,25 @@ OpenLayers.Tile.Image.prototype.createBackBuffer = createBackBuffer; } - function test_updateBackBufferData(t) { - t.plan(1); + function test_removeBackBuffer(t) { + t.plan(3); - var map = new OpenLayers.Map('map', { - resolutions: [32, 16] - }); - var layer = new OpenLayers.Layer.WMS('', '', {}, { - isBaseLayer: true - }); + var map = new OpenLayers.Map('map'); + var layer = new OpenLayers.Layer.WMS('', '', {}, {isBaseLayer: true}); map.addLayer(layer); - map.setCenter(new OpenLayers.LonLat(0, 0), 0); - layer.backBufferData = {}; - layer.updateBackBufferData(); - t.eq(layer.backBufferData.resolution, 32, - 'backBufferData has correct resolution'); + // add a fake back buffer + var backBuffer = document.createElement('div'); + layer.backBuffer = backBuffer; + layer.div.appendChild(backBuffer); + layer.backBufferResolution = 32; + + layer.removeBackBuffer(); + t.eq(layer.backBuffer, null, 'backBuffer set to null in layer'); + t.eq(layer.backBufferResolution, null, + 'backBufferResolution set to null in layer'); + t.ok(backBuffer.parentNode !== layer.div, + 'back buffer removed from layer'); map.destroy(); } @@ -1054,11 +1063,6 @@ map.addLayer(layer); map.setCenter(new OpenLayers.LonLat(0, 0), 0); - // pretend the image has been loaded - layer.updateBackBufferData(); - layer.grid[0][0].isLoading = false; // this is to be able to create - // a back buffer - // move map.setCenter(new OpenLayers.LonLat(10, 10)); t.ok(layer.backBuffer && layer.backBuffer.parentNode === layer.div, @@ -1073,7 +1077,7 @@ } function test_backbuffer_scaled_layer(t) { - t.plan(15); + t.plan(12); // // set up @@ -1090,14 +1094,20 @@ ); layer.serverResolutions = [32, 16, 8]; - layer.createBackBuffer = function() { - return document.createElement('div'); - }; map.addLayer(layer); map.setCenter(new OpenLayers.LonLat(0, 0), 2); - layer.updateBackBufferData(); + layer.createBackBuffer = function() { + return document.createElement('div'); + }; + + // we want to control when the back buffer is removed + var removeBackBuffer = OpenLayers.Function.bind( + layer.removeBackBuffer, layer); + layer.removeBackBuffer = function() {}; + + // layer.updateBackBufferData(); // // test @@ -1105,65 +1115,63 @@ // change resolution from 8 to 4 map.zoomTo(3); - t.ok(layer.backBuffer == undefined, - '[8->4] back buffer not applied'); - layer.updateBackBufferData(); + t.eq(layer.backBuffer.style.width, '100%', + '[8->4] back buffer not scaled'); + removeBackBuffer(); // change resolution from 8 to 2 - map.zoomTo(2); layer.updateBackBufferData(); map.zoomTo(4); - t.ok(layer.backBuffer == undefined, - '[8->2] back buffer not applies'); - layer.updateBackBufferData(); + map.zoomTo(2); removeBackBuffer(); map.zoomTo(4); + t.eq(layer.backBuffer.style.width, '100%', + '[8->2] back buffer not scaled'); + removeBackBuffer(); // change resolution from 16 to 4 - map.zoomTo(1); layer.updateBackBufferData(); map.zoomTo(3); - t.ok(layer.backBuffer != undefined, - '[16->4] back buffer applied'); + map.zoomTo(1); removeBackBuffer(); map.zoomTo(3); t.eq(layer.backBuffer.style.width, '200%', '[16->4] back buffer width is as expected'); t.eq(layer.backBuffer.style.width, '200%', '[16->4] back buffer height is as expected'); - layer.updateBackBufferData(); + removeBackBuffer(); // change resolution from 32 to 1 - map.zoomTo(0); layer.updateBackBufferData(); map.zoomTo(5); - t.ok(layer.backBuffer != undefined, - '[32->1] back buffer applied'); + map.zoomTo(0); removeBackBuffer(); map.zoomTo(5); t.eq(layer.backBuffer.style.width, '400%', '[32->1] back buffer width is as expected'); t.eq(layer.backBuffer.style.width, '400%', '[32->1] back buffer height is as expected'); - layer.updateBackBufferData(); + removeBackBuffer(); // change resolution from 4 to 2 - map.zoomTo(3); layer.updateBackBufferData(); map.zoomTo(4); - t.ok(layer.backBuffer == undefined, - '[4->2] back buffer not applied'); - layer.updateBackBufferData(); + map.zoomTo(3); removeBackBuffer(); map.zoomTo(4); + t.eq(layer.backBuffer.style.width, '100%', + '[4->2] back buffer not scaled'); + removeBackBuffer(); // change resolution from 4 to 1 - map.zoomTo(3); layer.updateBackBufferData(); map.zoomTo(5); - t.ok(layer.backBuffer == undefined, - '[4->1] back buffer not applied'); + map.zoomTo(3); removeBackBuffer(); map.zoomTo(5); + t.eq(layer.backBuffer.style.width, '100%', + '[4->1] back buffer not scaled'); + removeBackBuffer(); // change resolution from 1 to 4 - map.zoomTo(5); layer.updateBackBufferData(); map.zoomTo(3); - t.ok(layer.backBuffer == undefined, - '[1->4] back buffer not applied'); + map.zoomTo(5); removeBackBuffer(); map.zoomTo(3); + t.eq(layer.backBuffer.style.width, '100%', + '[1->4] back buffer not scaled'); + removeBackBuffer(); // change resolution from 4 to 8 - map.zoomTo(3); layer.updateBackBufferData(); map.zoomTo(2); - t.ok(layer.backBuffer == undefined, - '[4->8] back buffer not applied'); + map.zoomTo(3); removeBackBuffer(); map.zoomTo(2); + t.eq(layer.backBuffer.style.width, '100%', + '[4->8] back buffer not scaled'); + removeBackBuffer(); // change resolution from 4 to 16 - map.zoomTo(3); layer.updateBackBufferData(); map.zoomTo(1); - t.ok(layer.backBuffer != undefined, - '[4->16] back buffer applied'); + map.zoomTo(3); removeBackBuffer(); map.zoomTo(1); t.eq(layer.backBuffer.style.width, '50%', '[4->16] back buffer width is as expected'); t.eq(layer.backBuffer.style.width, '50%', '[4->16] back buffer height is as expected'); + removeBackBuffer(); // // tear down From 82bf97381c281c6a28942c1423fcea00301bbb88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Sun, 30 Oct 2011 23:26:23 +0100 Subject: [PATCH 30/44] remove commented line in a test --- tests/Layer/Grid.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Layer/Grid.html b/tests/Layer/Grid.html index 6f78cd45dd..eee963b72e 100644 --- a/tests/Layer/Grid.html +++ b/tests/Layer/Grid.html @@ -1107,8 +1107,6 @@ layer.removeBackBuffer, layer); layer.removeBackBuffer = function() {}; - // layer.updateBackBufferData(); - // // test // From c65471c35b345ca6ec6acb61b836380521e09dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Sun, 30 Oct 2011 23:34:52 +0100 Subject: [PATCH 31/44] Grid tests - do no test the same thing twice --- tests/Layer/Grid.html | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/Layer/Grid.html b/tests/Layer/Grid.html index eee963b72e..afeb1ec850 100644 --- a/tests/Layer/Grid.html +++ b/tests/Layer/Grid.html @@ -591,7 +591,7 @@ function test_Layer_Grid_destroy (t) { - t.plan( 10 ); + t.plan( 9 ); var map = new OpenLayers.Map('map'); layer = new OpenLayers.Layer.Grid(name, url, params); @@ -612,17 +612,16 @@ var tile = layer.grid[1][1]; t.eq( tile.imgDiv.className, "olTileImage", "Tile has an image" ); - // add a fake back buffer to the layer - var backBuffer = document.createElement('div'); - layer.backBuffer = backBuffer - layer.div.appendChild(backBuffer); + var removeBackBufferCalled = false; + layer.removeBackBuffer = function() { + removeBackBufferCalled = true; + }; layer.destroy(); t.eq( tile.imgDiv, null, "Tile destroyed" ); t.eq( layer.timerId, null, "Tile loading timeout cleared"); t.ok( layer.grid == null, "tiles appropriately destroyed") - t.ok( backBuffer.parentNode === layer.div, "back buffer removed"); - t.eq( layer.backBuffer, null, "backBuffer set not null in the layer"); + t.ok( removeBackBufferCalled, "destroy calls removeBackBuffer"); // destroy after remove from map layer = new OpenLayers.Layer.WMS(name, url, params); From 8b1f684cbdfcaff5ef3f59297ea0c7d28a001bbe Mon Sep 17 00:00:00 2001 From: Frederic Junod Date: Mon, 7 Nov 2011 10:48:52 +0100 Subject: [PATCH 32/44] Remove semicolons from viewport meta tag --- examples/bing-tiles-restrictedzoom.html | 2 +- examples/canvas-hit-detection.html | 2 +- examples/draw-undo-redo.html | 2 +- examples/editing-methods.html | 2 +- examples/point-grid.html | 2 +- examples/snap-grid.html | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/bing-tiles-restrictedzoom.html b/examples/bing-tiles-restrictedzoom.html index 992bd143ab..afbd6a9fb6 100644 --- a/examples/bing-tiles-restrictedzoom.html +++ b/examples/bing-tiles-restrictedzoom.html @@ -2,7 +2,7 @@ - + Basic Bing Tiles with a Subset of Resolutions Example diff --git a/examples/canvas-hit-detection.html b/examples/canvas-hit-detection.html index 5148b70633..2f86ea739b 100644 --- a/examples/canvas-hit-detection.html +++ b/examples/canvas-hit-detection.html @@ -3,7 +3,7 @@ OpenLayers Canvas Hit Detection Example - + diff --git a/examples/draw-undo-redo.html b/examples/draw-undo-redo.html index 40ad3e2995..6d5fa720ea 100644 --- a/examples/draw-undo-redo.html +++ b/examples/draw-undo-redo.html @@ -3,7 +3,7 @@ OpenLayers Undo/Redo Drawing Methods - + diff --git a/examples/editing-methods.html b/examples/editing-methods.html index eeab9166de..5a28710407 100644 --- a/examples/editing-methods.html +++ b/examples/editing-methods.html @@ -3,7 +3,7 @@ OpenLayers Editing Methods - + diff --git a/examples/point-grid.html b/examples/point-grid.html index 4cff89d85b..8508fdb473 100644 --- a/examples/point-grid.html +++ b/examples/point-grid.html @@ -1,7 +1,7 @@ - + OpenLayers Point Grid Example diff --git a/examples/snap-grid.html b/examples/snap-grid.html index b6b592d23e..9d0604bd69 100644 --- a/examples/snap-grid.html +++ b/examples/snap-grid.html @@ -1,7 +1,7 @@ - + OpenLayers Snap Grid Example From 797c479b6ec9c4261a063568dd071ab7ac08c856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89ric=20Lemoine?= Date: Mon, 7 Nov 2011 12:29:16 +0100 Subject: [PATCH 33/44] make OWSCommon v1 support constraints in Get and Post nodes --- lib/OpenLayers/Format/OWSCommon/v1.js | 20 ++++++++++++++++++++ tests/Format/WMTSCapabilities/v1_0_0.html | 11 ++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/lib/OpenLayers/Format/OWSCommon/v1.js b/lib/OpenLayers/Format/OWSCommon/v1.js index 7ee97593ce..0202dc2277 100644 --- a/lib/OpenLayers/Format/OWSCommon/v1.js +++ b/lib/OpenLayers/Format/OWSCommon/v1.js @@ -173,10 +173,22 @@ OpenLayers.Format.OWSCommon.v1 = OpenLayers.Class(OpenLayers.Format.XML, { "Get": function(node, http) { http.get = this.getAttributeNS(node, this.namespaces.xlink, "href"); + if (!http.constraints) { + http.constraints = {}; + } + var obj = {}; + this.readChildNodes(node, obj); + http.constraints.get = obj.constraints; }, "Post": function(node, http) { http.post = this.getAttributeNS(node, this.namespaces.xlink, "href"); + if (!http.constraints) { + http.constraints = {}; + } + var obj = {}; + this.readChildNodes(node, obj); + http.constraints.post = obj.constraints; }, "Parameter": function(node, operation) { if (!operation.parameters) { @@ -186,6 +198,14 @@ OpenLayers.Format.OWSCommon.v1 = OpenLayers.Class(OpenLayers.Format.XML, { operation.parameters[name] = {}; this.readChildNodes(node, operation.parameters[name]); }, + "Constraint": function(node, obj) { + if (!obj.constraints) { + obj.constraints = {}; + } + var name = node.getAttribute("name"); + obj.constraints[name] = {}; + this.readChildNodes(node, obj.constraints[name]); + }, "Value": function(node, allowedValues) { allowedValues[this.getChildValue(node)] = true; }, diff --git a/tests/Format/WMTSCapabilities/v1_0_0.html b/tests/Format/WMTSCapabilities/v1_0_0.html index 9ed58b3580..ff30f51998 100644 --- a/tests/Format/WMTSCapabilities/v1_0_0.html +++ b/tests/Format/WMTSCapabilities/v1_0_0.html @@ -4,7 +4,7 @@ + + +

    City of Vienna WMTS for Desktop and Mobile Devices

    +
    + mobile, vienna, ogdwien, rest, restful, wmts, geolocate, permalink +
    +

    + A full-screen map for both desktop and mobile devices. Uses + language dependent CSS content and the WMTSCapabilities format to + retrieve layers from the ogdwien open data initiative of the City + of Vienna. Also has a lightweight custom anchor permalink + functionality and uses the Geolocate control. +

    +
    + + + diff --git a/examples/mobile-wmts-vienna.js b/examples/mobile-wmts-vienna.js new file mode 100644 index 0000000000..595897051f --- /dev/null +++ b/examples/mobile-wmts-vienna.js @@ -0,0 +1,230 @@ +var map; + +(function() { + OpenLayers.ProxyHost = "proxy.cgi?url="; + + // Set document language for css content + document.documentElement.lang = (navigator.userLanguage || navigator.language).split("-")[0]; + + // A panel for switching between Aerial and Map, and for turning labels + // on and off. + var layerPanel = new OpenLayers.Control.Panel({ + displayClass: "layerPanel", + autoActivate: true + }); + var aerialButton = new OpenLayers.Control({ + type: OpenLayers.Control.TYPE_TOOL, + displayClass: "aerialButton", + eventListeners: { + activate: function() { + if (aerial) {map.setBaseLayer(aerial);} + } + } + }); + var mapButton = new OpenLayers.Control({ + type: OpenLayers.Control.TYPE_TOOL, + displayClass: "mapButton", + eventListeners: { + activate: function() { + if (fmzk) {map.setBaseLayer(fmzk);} + } + } + }); + var labelButton = new OpenLayers.Control({ + type: OpenLayers.Control.TYPE_TOGGLE, + displayClass: "labelButton", + eventListeners: { + activate: function() { + if (labels) {labels.setVisibility(true);} + }, + deactivate: function() { + if (labels) {labels.setVisibility(false);} + } + } + }); + layerPanel.addControls([aerialButton, mapButton, labelButton]); + + var zoomPanel = new OpenLayers.Control.ZoomPanel(); + + // Geolocate control for the Locate button - the locationupdated handler + // draws a cross at the location and a circle showing the accuracy radius. + zoomPanel.addControls([ + new OpenLayers.Control.Geolocate({ + type: OpenLayers.Control.TYPE_TOGGLE, + geolocationOptions: { + enableHighAccuracy: false, + maximumAge: 0, + timeout: 7000 + }, + eventListeners: { + activate: function() { + map.addLayer(vector); + }, + deactivate: function() { + map.removeLayer(vector); + vector.removeAllFeatures(); + }, + locationupdated: function(e) { + vector.removeAllFeatures(); + vector.addFeatures([ + new OpenLayers.Feature.Vector(e.point, null, { + graphicName: 'cross', + strokeColor: '#f00', + strokeWidth: 2, + fillOpacity: 0, + pointRadius: 10 + }), + new OpenLayers.Feature.Vector( + OpenLayers.Geometry.Polygon.createRegularPolygon( + new OpenLayers.Geometry.Point(e.point.x, e.point.y), + e.position.coords.accuracy / 2, 50, 0 + ), null, { + fillOpacity: 0.1, + fillColor: '#000', + strokeColor: '#f00', + strokeOpacity: 0.6 + } + ) + ]); + map.zoomToExtent(vector.getDataExtent()); + } + } + }) + ]); + + // Map with navigation controls optimized for touch devices + map = new OpenLayers.Map({ + div: "map", + theme: null, + projection: "EPSG:3857", + units: "m", + maxExtent: new OpenLayers.Bounds( + -20037508.34, -20037508.34, 20037508.34, 20037508.34 + ), + maxResolution: 156543.0339, + numZoomLevels: 20, + controls: [ + new OpenLayers.Control.TouchNavigation({ + mouseWheelOptions: { + cumulative: false, + interval: 20 + }, + dragPanOptions: { + enableKinetic: { + deceleration: 0.02 + } + }, + zoomBoxEnabled: false + }), + new OpenLayers.Control.Attribution(), + zoomPanel, + layerPanel + ], + eventListeners: { + moveend: function() { + // update anchor for permalinks + var ctr = map.getCenter(); + window.location.hash = "x="+ctr.lon+"&y="+ctr.lat+"&z="+map.getZoom(); + } + } + }); + layerPanel.activateControl(mapButton); + layerPanel.activateControl(labelButton); + + // Vector layer for the location cross and circle + var vector = new OpenLayers.Layer.Vector("Vector Layer"); + + // The WMTS layers we're going to add + var fmzk, aerial, labels; + + // The WMTSCapabilities format and the default options for the layers + var format = new OpenLayers.Format.WMTSCapabilities(), defaults = { + requestEncoding: "REST", + matrixSet: "google3857", + transitionEffect: "resize", + tileLoadingDelay: 0, + attribution: 'Datenquelle: Stadt Wien - data.wien.gv.at' + }; + + // Request capabilities and create layers + OpenLayers.Request.GET({ + url: "http://maps.wien.gv.at/wmts/1.0.0/WMTSCapabilities.xml", + success: function(request) { + var doc = request.responseText, + caps = format.read(doc); + fmzk = format.createLayer(caps, OpenLayers.Util.applyDefaults( + {layer:"fmzk", requestEncoding:"REST"}, defaults + )); + aerial = format.createLayer(caps, OpenLayers.Util.applyDefaults( + {layer:"lb", requestEncoding:"REST"}, defaults + )); + labels = format.createLayer(caps, OpenLayers.Util.applyDefaults( + {layer:"beschriftung", requestEncoding:"REST", isBaseLayer: false}, + defaults + )); + map.addLayers([fmzk, aerial, labels]); + + // zoom to initial extent or restore position from permalink + var extent = fmzk.tileFullExtent, + ctr = extent.getCenterLonLat(), + zoom = map.getZoomForExtent(extent, true), + params = OpenLayers.Util.getParameters("?"+window.location.hash.substr(1)); + OpenLayers.Util.applyDefaults(params, {x:ctr.lon, y:ctr.lat, z:zoom}); + map.setCenter(new OpenLayers.LonLat(params.x, params.y), params.z); + } + }); +})(); + +// Reliably hide the address bar on Android and iOS devices. From +// http://blog.nateps.com/how-to-hide-the-address-bar-in-a-full-screen +(function() { + var page = document.getElementById("map"), + ua = navigator.userAgent, + iphone = ~ua.indexOf('iPhone') || ~ua.indexOf('iPod'), + ipad = ~ua.indexOf('iPad'), + ios = iphone || ipad, + // Detect if this is running as a fullscreen app from the homescreen + fullscreen = window.navigator.standalone, + android = ~ua.indexOf('Android'), + lastWidth = 0; + + if (android) { + // Android's browser adds the scroll position to the innerHeight, just to + // make this really fucking difficult. Thus, once we are scrolled, the + // page height value needs to be corrected in case the page is loaded + // when already scrolled down. The pageYOffset is of no use, since it always + // returns 0 while the address bar is displayed. + window.onscroll = function() { + page.style.height = window.innerHeight + 'px'; + }; + } + var setupScroll = window.onload = function() { + // Start out by adding the height of the location bar to the width, so that + // we can scroll past it + if (ios) { + // iOS reliably returns the innerWindow size for documentElement.clientHeight + // but window.innerHeight is sometimes the wrong value after rotating + // the orientation + var height = document.documentElement.clientHeight; + // Only add extra padding to the height on iphone / ipod, since the ipad + // browser doesn't scroll off the location bar. + if (iphone && !fullscreen) height += 60; + page.style.height = height + 'px'; + } else if (android) { + // The stock Android browser has a location bar height of 56 pixels, but + // this very likely could be broken in other Android browsers. + page.style.height = (window.innerHeight + 56) + 'px'; + } + // Scroll after a timeout, since iOS will scroll to the top of the page + // after it fires the onload event + setTimeout(scrollTo, 0, 0, 1); + }; + (window.onresize = function() { + var pageWidth = page.offsetWidth; + // Android doesn't support orientation change, so check for when the width + // changes to figure out when the orientation changes + if (lastWidth == pageWidth) return; + lastWidth = pageWidth; + setupScroll(); + })(); +})(); diff --git a/examples/proxy.cgi b/examples/proxy.cgi index c668218c48..4358e2ca03 100755 --- a/examples/proxy.cgi +++ b/examples/proxy.cgi @@ -21,7 +21,8 @@ allowedHosts = ['www.openlayers.org', 'openlayers.org', 'sigma.openplans.org', 'demo.opengeo.org', 'www.openstreetmap.org', 'sample.azavea.com', 'v2.suite.opengeo.org', 'v-swe.uni-muenster.de:8080', - 'vmap0.tiles.osgeo.org', 'www.openrouteservice.org'] + 'vmap0.tiles.osgeo.org', 'www.openrouteservice.org', + 'maps.wien.gv.at'] method = os.environ["REQUEST_METHOD"]