Ticket #933: transition-resize-r6439.patch
| File transition-resize-r6439.patch, 17.0 kB (added by pspencer, 10 months ago) |
|---|
-
lib/OpenLayers/Tile/Image.js
old new 146 146 this.events.triggerEvent("loadstart"); 147 147 } 148 148 149 return this.renderTile(); 150 }, 151 152 /** 153 * Method: renderTile 154 * 155 * internal function to actually initialize the image tile, 156 * position it correctly, and set its url 157 */ 158 renderTile: function() { 149 159 if (this.imgDiv == null) { 150 160 this.initImgDiv(); 151 161 } … … 162 172 OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv, 163 173 null, null, imageSize, this.url); 164 174 } else { 165 this.imgDiv.src = this.url;166 175 OpenLayers.Util.modifyDOMElement(this.imgDiv, 167 176 null, null, imageSize) ; 177 this.imgDiv.src = this.url; 168 178 } 169 179 return true; 170 180 }, … … 176 186 */ 177 187 clear: function() { 178 188 if(this.imgDiv) { 179 this. imgDiv.style.display = "none";189 this.hide(); 180 190 if (OpenLayers.Tile.Image.useBlankTile) { 181 191 this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif"; 182 192 } … … 223 233 OpenLayers.Event.observe( this.imgDiv, "load", 224 234 OpenLayers.Function.bind(this.checkImgURL, this) ); 225 235 */ 236 this.frame.style.zIndex = this.isBackBuffer ? 0 : 1; 226 237 this.frame.appendChild(this.imgDiv); 227 238 this.layer.div.appendChild(this.frame); 228 239 … … 300 311 if (this.layer) { 301 312 var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src; 302 313 if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) { 303 this. imgDiv.style.display = "none";314 this.hide(); 304 315 } 305 316 } 306 317 }, 318 319 /** 320 * Method: startTransition 321 * 322 * This method is invoked on tiles that are backBuffers for tiles in the 323 * grid. The grid tile is about to be cleared and a new tile source 324 * loaded. This is where the transition effect needs to be started 325 * to provide visual continuity. 326 */ 327 startTransition: function() { 328 // backBufferTile has to be valid and ready to use 329 if (!this.backBufferTile || !this.backBufferTile.imgDiv) { 330 return; 331 } 307 332 333 // show the backBufferTile and hide this tile 334 this.hide(); 335 336 // calculate the ratio of change between the current resolution of the 337 // backBufferTile and the layer. If several animations happen in a 338 // row, then the backBufferTile will scale itself appropriately for 339 // each request. 340 var ratio = 1; 341 if (this.backBufferTile.resolution) { 342 ratio = this.backBufferTile.resolution / this.layer.getResolution() ; 343 } 344 345 // if the ratio is not 1 (i.e. we are zooming), then we might be 346 // resizing the backBuffer tile ... 347 if (ratio != 1) { 348 if (this.layer.transitionEffect == 'resize') { 349 // In this case, we can just immediately resize the 350 // backBufferTile. 351 var upperLeft = 352 new OpenLayers.LonLat(this.backBufferTile.bounds.left, 353 this.backBufferTile.bounds.top); 354 var size = 355 new OpenLayers.Size(this.backBufferTile.size.w * ratio, 356 this.backBufferTile.size.h * ratio); 357 358 var px = this.layer.map.getLayerPxFromLonLat(upperLeft); 359 OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame, 360 null, px, size); 361 var imageSize = this.backBufferTile.size.clone(); 362 imageSize = new OpenLayers.Size(imageSize.w * ratio, 363 imageSize.h * ratio); 364 365 OpenLayers.Util.modifyDOMElement(this.backBufferTile.imgDiv, 366 null, null, imageSize) ; 367 368 this.backBufferTile.show(); 369 } 370 } else { 371 // default effect is just to leave the existing tile 372 // until the new one loads if this is a singleTile and 373 // there was no change in resolution. Otherwise we 374 // don't bother to show the backBufferTile at all 375 if (this.layer.singleTile && ratio == 1) { 376 this.backBufferTile.show(); 377 } else { 378 this.backBufferTile.hide(); 379 } 380 } 381 }, 382 383 /** 384 * Method: show 385 * 386 * show the tile by showing its frame. 387 */ 388 show: function() { 389 this.frame.style.display = ''; 390 }, 391 392 /** 393 * Method: hide 394 * 395 * hide the tile by hiding its frame. 396 */ 397 hide: function() { 398 this.frame.style.display = 'none'; 399 }, 400 308 401 CLASS_NAME: "OpenLayers.Tile.Image" 309 402 } 310 403 ); -
lib/OpenLayers/Tile.js
old new 80 80 */ 81 81 isLoading: false, 82 82 83 /** 84 * Property: isBackBuffer 85 * {Boolean} Is this tile a back buffer tile? 86 */ 87 isBackBuffer: false, 88 89 /** 90 * Property: isFirstDraw 91 * {Boolean} Is this the first time the tile is being drawn? 92 * This is used to force resetBackBuffer to synchronize 93 * the backBufferTile with the foreground tile the first time 94 * the foreground tile loads so that if the user zooms 95 * before the layer has fully loaded, the backBufferTile for 96 * tiles that have been loaded can be used. 97 */ 98 isFirstDraw: true, 99 100 /** 101 * Property: backBufferTile 102 * {<OpenLayers.Tile>} A clone of the tile used to create transition 103 * effects when the tile is moved or changes resolution. 104 */ 105 backBufferTile: null, 106 83 107 /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor. 84 108 * there is no need for the base tile class to have a url. 85 109 * … … 111 135 * Nullify references to prevent circular references and memory leaks. 112 136 */ 113 137 destroy:function() { 138 if (this.layer.transitionEffect) { 139 this.layer.events.unregister("loadend", this, this.resetBackBuffer); 140 this.events.unregister('loadend', this, this.resetBackBuffer); 141 } else { 142 this.events.unregister('loadend', this, this.showTile); 143 } 114 144 this.layer = null; 115 145 this.bounds = null; 116 146 this.size = null; … … 118 148 119 149 this.events.destroy(); 120 150 this.events = null; 151 152 /* clean up the backBufferTile if it exists */ 153 if (this.backBufferTile) { 154 this.backBufferTile.destroy(); 155 this.backBufferTile = null; 156 } 121 157 }, 122 158 123 159 /** … … 157 193 */ 158 194 draw: function() { 159 195 160 //clear tile's contents and mark as not drawn161 this.clear();162 163 196 var maxExtent = this.layer.maxExtent; 164 197 var withinMaxExtent = (maxExtent && 165 198 this.bounds.intersectsBounds(maxExtent, false)); 166 199 167 200 // The only case where we *wouldn't* want to draw the tile is if the 168 201 // tile is outside its layer's maxExtent. 169 return (withinMaxExtent || this.layer.displayOutsideMaxExtent); 202 var drawTile = (withinMaxExtent || this.layer.displayOutsideMaxExtent); 203 204 if (this.layer.transitionEffect != null) { 205 if (drawTile) { 206 //we use a clone of this tile to create a double buffer for visual 207 //continuity. The backBufferTile is used to create transition 208 //effects while the tile in the grid is repositioned and redrawn 209 if (!this.backBufferTile) { 210 this.backBufferTile = this.clone(); 211 this.backBufferTile.hide(); 212 // this is important. It allows the backBuffer to place itself 213 // appropriately in the DOM. The Image subclass needs to put 214 // the backBufferTile behind the main tile so the tiles can 215 // load over top and display as soon as they are loaded. 216 this.backBufferTile.isBackBuffer = true; 217 218 // potentially end any transition effects when the tile loads 219 this.events.register('loadend', this, this.resetBackBuffer); 220 221 // clear transition back buffer tile only after all tiles in 222 // this layer have loaded to avoid visual glitches 223 this.layer.events.register("loadend", this, this.resetBackBuffer); 224 } 225 // run any transition effects 226 this.startTransition(); 227 } else { 228 // if we aren't going to draw the tile, then the backBuffer should 229 // be hidden too! 230 if (this.backBufferTile) { 231 this.backBufferTile.clear(); 232 } 233 } 234 } else { 235 if (this.isFirstDraw) { 236 this.events.register('loadend', this, this.showTile); 237 this.isFirstDraw = false; 238 } 239 } 240 this.shouldDraw = drawTile; 241 242 //clear tile's contents and mark as not drawn 243 this.clear(); 244 245 return drawTile; 170 246 }, 171 247 172 248 /** … … 237 313 topLeft.lat); 238 314 return bounds; 239 315 }, 240 316 317 /** 318 * Method: startTransition 319 * 320 * prepare the tile for a transition effect. To be 321 * implemented by subclasses. 322 */ 323 startTransition: function() {}, 324 325 /** 326 * Method: resetBackBuffer 327 * 328 * triggered by two different events, layer loadend, and tile loadend. 329 * In any of these cases, we check to see if we can hide the 330 * backBufferTile yet and update its parameters to match the 331 * foreground tile. Basic logic: 332 * 333 * - If the backBufferTile hasn't been drawn yet, reset it 334 * - If layer is still loading, show foreground tile but don't hide 335 * the backBufferTile yet 336 * - If layer is done loading, reset backBuffer tile and show 337 * foreground tile 338 */ 339 resetBackBuffer: function(args) { 340 if (this.backBufferTile && 341 (this.isFirstDraw || !this.layer.numLoadingTiles)) { 342 this.backBufferTile.hide(); 343 this.isFirstDraw = false; 344 // check to see if the backBufferTile is within the max extents 345 // before rendering it 346 var maxExtent = this.layer.maxExtent; 347 var withinMaxExtent = (maxExtent && 348 this.bounds.intersectsBounds(maxExtent, false)); 349 if (withinMaxExtent) { 350 this.backBufferTile.position = this.position.clone(); 351 this.backBufferTile.bounds = this.bounds.clone(); 352 this.backBufferTile.size = this.size.clone(); 353 this.backBufferTile.resolution = this.layer.getResolution(); 354 this.backBufferTile.renderTile(); 355 } 356 } 357 this.showTile(); 358 }, 359 360 /** 361 * Method: showTile 362 * 363 * show the tile only if it should be drawn. 364 */ 365 showTile: function() { 366 if (this.shouldDraw) { 367 this.show(); 368 } 369 }, 370 371 /** 372 * Method: show 373 * 374 * show the tile. To be implemented by subclasses. 375 */ 376 show: function() { }, 377 378 /** 379 * Method: hide 380 * 381 * hide the tile. To be implemented by subclasses. 382 */ 383 hide: function() { }, 384 241 385 CLASS_NAME: "OpenLayers.Tile" 242 386 }); -
lib/OpenLayers/Layer.js
old new 257 257 */ 258 258 wrapDateLine: false, 259 259 260 /** 261 * APIProperty: transitionEffect 262 * {String} The transition effect to use when the map is panned or 263 * zoomed. There is currently two supported values: 264 * null - no transition effect (the default). 265 * keep - Keep tiles around. This uses double-buffering: this 266 * type of transition effect is only useful for singleTile layers, 267 * where the tile will be kept in place on drag. 268 * resize - existing tiles are resized on zoom to provide a visual 269 * effect of the zoom having taken place immediately. As the 270 * new tiles become available, they are drawn over top of the 271 * resized tiles. 272 */ 273 transitionEffect: null, 260 274 261 275 /** 262 276 * Constructor: OpenLayers.Layer -
lib/OpenLayers/Layer/Text.js
old new 173 173 // externalGraphic, because icon has no setOffset API Method. 174 174 if (feature.style.graphicXOffset 175 175 && feature.style.graphicYOffset) { 176 iconOffset = new OpenLayers. Pixel(176 iconOffset = new OpenLayers.Size( 177 177 feature.style.graphicXOffset, 178 178 feature.style.graphicYOffset); 179 179 } -
examples/transition.html
old new 1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <style type="text/css"> 4 #mapDiv { 5 width: 400px; 6 height: 400px; 7 border: 1px solid black; 8 } 9 </style> 10 <script src="../lib/OpenLayers.js"></script> 11 <script type="text/javascript"> 12 var map; 13 function init(){ 14 map = new OpenLayers.Map('mapDiv', {maxResolution: 'auto'}); 15 16 var single_default_effect = new OpenLayers.Layer.WMS( "WMS untiled default", 17 "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}, 18 { singleTile: true, isBaseLayer: true} ); 19 var single_resize_effect = new OpenLayers.Layer.WMS( "WMS untiled resize", 20 "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}, 21 { singleTile: true, isBaseLayer: true, transitionEffect: 'resize'} ); 22 var tiled_default_effect = new OpenLayers.Layer.WMS( "WMS tiled default ", 23 "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}, 24 { isBaseLayer: true} ); 25 var tiled_resize_effect = new OpenLayers.Layer.WMS( "WMS tiled resize", 26 "http://labs.metacarta.com/wms/vmap0?", {layers: 'basic'}, 27 { isBaseLayer: true, transitionEffect: 'resize'} ); 28 29 map.addLayers([single_default_effect, single_resize_effect, 30 tiled_default_effect, tiled_resize_effect]); 31 map.addControl(new OpenLayers.Control.LayerSwitcher()); 32 map.setCenter(new OpenLayers.LonLat(6.5, 40.5), 4); 33 } 34 </script> 35 </head> 36 <body onload="init()"> 37 <h1 id="title">Transition Example</h1> 38 <p id="shortdesc"> 39 Demonstrates the use of transition effects in tiled and untiled layers. There are two transitions that are currently implemented, 'default', 'resize'. The default transition effect is used when no transition is specified and is implemented as no transition effect except for panning singleTile layers. The 'resize' effect resamples the current tile and displays it stretched or compressed until the new tile is available.</p> 40 <p><em>Note: There is a small visual glitch that appears to affect singleTile layers with the resize effect in FireFox 2.0 with caching enabled (developers often disable their cache). The map has a noticable flash when panning. This appears to be a timing issue with showing and hiding the singleTile. It</em></p> 41 <div id="mapDiv"></div> 42 <p> The first layer is an untiled WMS layer with no transition effect. </p> 43 <p> The second layer is an untiled WMS layer with a 'resize' effect. </p> 44 <p> The third layer is a tiled WMS layer with no transition effect. </p> 45 <p> The fourth layer is a tiled WMS layer with a 'resize' effect. </p> 46 </body> 47 </html>
