Ticket #933: transition-resize-r6450.patch
| File transition-resize-r6450.patch, 17.5 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 * Internal function to actually initialize the image tile, 155 * position it correctly, and set its url. 156 */ 157 renderTile: function() { 149 158 if (this.imgDiv == null) { 150 159 this.initImgDiv(); 151 160 } … … 162 171 OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv, 163 172 null, null, imageSize, this.url); 164 173 } else { 165 this.imgDiv.src = this.url;166 174 OpenLayers.Util.modifyDOMElement(this.imgDiv, 167 175 null, null, imageSize) ; 176 this.imgDiv.src = this.url; 168 177 } 169 178 return true; 170 179 }, … … 176 185 */ 177 186 clear: function() { 178 187 if(this.imgDiv) { 179 this. imgDiv.style.display = "none";188 this.hide(); 180 189 if (OpenLayers.Tile.Image.useBlankTile) { 181 190 this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif"; 182 191 } … … 223 232 OpenLayers.Event.observe( this.imgDiv, "load", 224 233 OpenLayers.Function.bind(this.checkImgURL, this) ); 225 234 */ 235 this.frame.style.zIndex = this.isBackBuffer ? 0 : 1; 226 236 this.frame.appendChild(this.imgDiv); 227 237 this.layer.div.appendChild(this.frame); 228 238 … … 300 310 if (this.layer) { 301 311 var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src; 302 312 if (!OpenLayers.Util.isEquivalentUrl(loaded, this.url)) { 303 this. imgDiv.style.display = "none";313 this.hide(); 304 314 } 305 315 } 306 316 }, 317 318 /** 319 * Method: startTransition 320 * This method is invoked on tiles that are backBuffers for tiles in the 321 * grid. The grid tile is about to be cleared and a new tile source 322 * loaded. This is where the transition effect needs to be started 323 * to provide visual continuity. 324 */ 325 startTransition: function() { 326 // backBufferTile has to be valid and ready to use 327 if (!this.backBufferTile || !this.backBufferTile.imgDiv) { 328 return; 329 } 307 330 331 // calculate the ratio of change between the current resolution of the 332 // backBufferTile and the layer. If several animations happen in a 333 // row, then the backBufferTile will scale itself appropriately for 334 // each request. 335 var ratio = 1; 336 if (this.backBufferTile.resolution) { 337 ratio = this.backBufferTile.resolution / this.layer.getResolution(); 338 } 339 340 // if the ratio is not the same as it was last time (i.e. we are 341 // zooming), then we need to adjust the backBuffer tile 342 if (ratio != this.lastRatio) { 343 if (this.layer.transitionEffect == 'resize') { 344 // In this case, we can just immediately resize the 345 // backBufferTile. 346 var upperLeft = new OpenLayers.LonLat( 347 this.backBufferTile.bounds.left, 348 this.backBufferTile.bounds.top 349 ); 350 var size = new OpenLayers.Size( 351 this.backBufferTile.size.w * ratio, 352 this.backBufferTile.size.h * ratio 353 ); 354 355 var px = this.layer.map.getLayerPxFromLonLat(upperLeft); 356 OpenLayers.Util.modifyDOMElement(this.backBufferTile.frame, 357 null, px, size); 358 var imageSize = this.backBufferTile.imageSize; 359 imageSize = new OpenLayers.Size(imageSize.w * ratio, 360 imageSize.h * ratio); 361 var imageOffset = this.backBufferTile.imageOffset; 362 if(imageOffset) { 363 imageOffset = new OpenLayers.Pixel( 364 imageOffset.x * ratio, imageOffset.y * ratio 365 ); 366 } 367 368 OpenLayers.Util.modifyDOMElement( 369 this.backBufferTile.imgDiv, null, imageOffset, imageSize 370 ) ; 371 372 this.backBufferTile.show(); 373 } 374 } else { 375 // default effect is just to leave the existing tile 376 // until the new one loads if this is a singleTile and 377 // there was no change in resolution. Otherwise we 378 // don't bother to show the backBufferTile at all 379 if (this.layer.singleTile) { 380 this.backBufferTile.show(); 381 } else { 382 this.backBufferTile.hide(); 383 } 384 } 385 this.lastRatio = ratio; 386 387 }, 388 389 /** 390 * Method: show 391 * Show the tile by showing its frame. 392 */ 393 show: function() { 394 this.frame.style.display = ''; 395 // Force a reflow on gecko based browsers to actually show the element 396 // before continuing execution. 397 if (navigator.userAgent.toLowerCase().indexOf("gecko") != -1) { 398 this.frame.scrollLeft = this.frame.scrollLeft; 399 } 400 }, 401 402 /** 403 * Method: hide 404 * Hide the tile by hiding its frame. 405 */ 406 hide: function() { 407 this.frame.style.display = 'none'; 408 }, 409 308 410 CLASS_NAME: "OpenLayers.Tile.Image" 309 411 } 310 412 ); -
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: lastRatio 91 * {Float} Used in transition code only. This is the previous ratio 92 * of the back buffer tile resolution to the map resolution. Compared 93 * with the current ratio to determine if zooming occurred. 94 */ 95 lastRatio: 1, 96 97 /** 98 * Property: isFirstDraw 99 * {Boolean} Is this the first time the tile is being drawn? 100 * This is used to force resetBackBuffer to synchronize 101 * the backBufferTile with the foreground tile the first time 102 * the foreground tile loads so that if the user zooms 103 * before the layer has fully loaded, the backBufferTile for 104 * tiles that have been loaded can be used. 105 */ 106 isFirstDraw: true, 107 108 /** 109 * Property: backBufferTile 110 * {<OpenLayers.Tile>} A clone of the tile used to create transition 111 * effects when the tile is moved or changes resolution. 112 */ 113 backBufferTile: null, 114 83 115 /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor. 84 116 * there is no need for the base tile class to have a url. 85 117 * … … 111 143 * Nullify references to prevent circular references and memory leaks. 112 144 */ 113 145 destroy:function() { 146 if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, 147 this.layer.transitionEffect) != -1) { 148 this.layer.events.unregister("loadend", this, this.resetBackBuffer); 149 this.events.unregister('loadend', this, this.resetBackBuffer); 150 } else { 151 this.events.unregister('loadend', this, this.showTile); 152 } 114 153 this.layer = null; 115 154 this.bounds = null; 116 155 this.size = null; … … 118 157 119 158 this.events.destroy(); 120 159 this.events = null; 160 161 /* clean up the backBufferTile if it exists */ 162 if (this.backBufferTile) { 163 this.backBufferTile.destroy(); 164 this.backBufferTile = null; 165 } 121 166 }, 122 167 123 168 /** … … 156 201 * depend on the return to know if they should draw or not. 157 202 */ 158 203 draw: function() { 159 160 //clear tile's contents and mark as not drawn161 this.clear();162 163 204 var maxExtent = this.layer.maxExtent; 164 205 var withinMaxExtent = (maxExtent && 165 206 this.bounds.intersectsBounds(maxExtent, false)); 166 207 167 208 // The only case where we *wouldn't* want to draw the tile is if the 168 209 // tile is outside its layer's maxExtent. 169 return (withinMaxExtent || this.layer.displayOutsideMaxExtent); 210 var drawTile = (withinMaxExtent || this.layer.displayOutsideMaxExtent); 211 212 if (OpenLayers.Util.indexOf(this.layer.SUPPORTED_TRANSITIONS, this.layer.transitionEffect) != -1) { 213 if (drawTile) { 214 //we use a clone of this tile to create a double buffer for visual 215 //continuity. The backBufferTile is used to create transition 216 //effects while the tile in the grid is repositioned and redrawn 217 if (!this.backBufferTile) { 218 this.backBufferTile = this.clone(); 219 this.backBufferTile.hide(); 220 // this is important. It allows the backBuffer to place itself 221 // appropriately in the DOM. The Image subclass needs to put 222 // the backBufferTile behind the main tile so the tiles can 223 // load over top and display as soon as they are loaded. 224 this.backBufferTile.isBackBuffer = true; 225 226 // potentially end any transition effects when the tile loads 227 this.events.register('loadend', this, this.resetBackBuffer); 228 229 // clear transition back buffer tile only after all tiles in 230 // this layer have loaded to avoid visual glitches 231 this.layer.events.register("loadend", this, this.resetBackBuffer); 232 } 233 // run any transition effects 234 this.startTransition(); 235 } else { 236 // if we aren't going to draw the tile, then the backBuffer should 237 // be hidden too! 238 if (this.backBufferTile) { 239 this.backBufferTile.clear(); 240 } 241 } 242 } else { 243 if (drawTile && this.isFirstDraw) { 244 this.events.register('loadend', this, this.showTile); 245 this.isFirstDraw = false; 246 } 247 } 248 this.shouldDraw = drawTile; 249 250 //clear tile's contents and mark as not drawn 251 this.clear(); 252 253 return drawTile; 170 254 }, 171 255 172 256 /** … … 237 321 topLeft.lat); 238 322 return bounds; 239 323 }, 240 324 325 /** 326 * Method: startTransition 327 * Prepare the tile for a transition effect. To be 328 * implemented by subclasses. 329 */ 330 startTransition: function() {}, 331 332 /** 333 * Method: resetBackBuffer 334 * Triggered by two different events, layer loadend, and tile loadend. 335 * In any of these cases, we check to see if we can hide the 336 * backBufferTile yet and update its parameters to match the 337 * foreground tile. 338 * 339 * Basic logic: 340 * - If the backBufferTile hasn't been drawn yet, reset it 341 * - If layer is still loading, show foreground tile but don't hide 342 * the backBufferTile yet 343 * - If layer is done loading, reset backBuffer tile and show 344 * foreground tile 345 */ 346 resetBackBuffer: function() { 347 this.showTile(); 348 if (this.backBufferTile && 349 (this.isFirstDraw || !this.layer.numLoadingTiles)) { 350 this.isFirstDraw = false; 351 // check to see if the backBufferTile is within the max extents 352 // before rendering it 353 var maxExtent = this.layer.maxExtent; 354 var withinMaxExtent = (maxExtent && 355 this.bounds.intersectsBounds(maxExtent, false)); 356 if (withinMaxExtent) { 357 this.backBufferTile.position = this.position; 358 this.backBufferTile.bounds = this.bounds; 359 this.backBufferTile.size = this.size; 360 this.backBufferTile.imageSize = this.layer.imageSize || this.size; 361 this.backBufferTile.imageOffset = this.layer.imageOffset; 362 this.backBufferTile.resolution = this.layer.getResolution(); 363 this.backBufferTile.renderTile(); 364 } 365 } 366 }, 367 368 /** 369 * Method: showTile 370 * Show the tile only if it should be drawn. 371 */ 372 showTile: function() { 373 if (this.shouldDraw) { 374 this.show(); 375 } 376 }, 377 378 /** 379 * Method: show 380 * Show the tile. To be implemented by subclasses. 381 */ 382 show: function() { }, 383 384 /** 385 * Method: hide 386 * Hide the tile. To be implemented by subclasses. 387 */ 388 hide: function() { }, 389 241 390 CLASS_NAME: "OpenLayers.Tile" 242 391 }); -
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. 264 * 265 * There are currently two supported values: 266 * - *null* No transition effect (the default). 267 * - *resize* Existing tiles are resized on zoom to provide a visual 268 * effect of the zoom having taken place immediately. As the 269 * new tiles become available, they are drawn over top of the 270 * resized tiles. 271 */ 272 transitionEffect: null, 260 273 261 274 /** 275 * Property: SUPPORTED_TRANSITIONS 276 * {Array} An immutable (that means don't change it!) list of supported 277 * transitionEffect values. 278 */ 279 SUPPORTED_TRANSITIONS: ['resize'], 280 281 /** 262 282 * Constructor: OpenLayers.Layer 263 283 * 264 284 * Parameters: -
examples/transition.html
old new 1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title>OpenLayers Transitions Example</title> 4 <style type="text/css"> 5 #mapDiv { 6 width: 400px; 7 height: 400px; 8 border: 1px solid black; 9 } 10 </style> 11 <script src="../lib/OpenLayers.js"></script> 12 <script type="text/javascript"> 13 var map; 14 function init(){ 15 map = new OpenLayers.Map('mapDiv', {maxResolution: 'auto'}); 16 17 var single_default_effect = new OpenLayers.Layer.WMS( 18 "WMS untiled default", 19 "http://labs.metacarta.com/wms/vmap0?", 20 {layers: 'basic'}, 21 {singleTile: true} 22 ); 23 var single_resize_effect = new OpenLayers.Layer.WMS( 24 "WMS untiled resize", 25 "http://labs.metacarta.com/wms/vmap0?", 26 {layers: 'basic'}, 27 {singleTile: true, transitionEffect: 'resize'} 28 ); 29 var tiled_default_effect = new OpenLayers.Layer.WMS( 30 "WMS tiled default ", 31 "http://labs.metacarta.com/wms/vmap0?", 32 {layers: 'basic'} 33 ); 34 var tiled_resize_effect = new OpenLayers.Layer.WMS( 35 "WMS tiled resize", 36 "http://labs.metacarta.com/wms/vmap0?", 37 {layers: 'basic'}, 38 {transitionEffect: 'resize'} 39 ); 40 41 map.addLayers([single_default_effect, single_resize_effect, 42 tiled_default_effect, tiled_resize_effect]); 43 map.addControl(new OpenLayers.Control.LayerSwitcher()); 44 map.setCenter(new OpenLayers.LonLat(6.5, 40.5), 4); 45 } 46 </script> 47 </head> 48 <body onload="init()"> 49 <h1 id="title">Transition Example</h1> 50 <p id="shortdesc"> 51 Demonstrates the use of transition effects in tiled and untiled layers. 52 </p> 53 <div id="mapDiv"></div> 54 <div id="docs"> 55 There are two transitions that are currently implemented: null (the 56 default) and 'resize'. The default transition effect is used when no 57 transition is specified and is implemented as no transition effect except 58 for panning singleTile layers. The 'resize' effect resamples the current 59 tile and displays it stretched or compressed until the new tile is available. 60 <ul> 61 <li>The first layer is an untiled WMS layer with no transition effect.</li> 62 <li>The second layer is an untiled WMS layer with a 'resize' effect. </li> 63 <li>The third layer is a tiled WMS layer with no transition effect. </li> 64 <li>The fourth layer is a tiled WMS layer with a 'resize' effect. </li> 65 </ul> 66 </div> 67 </body> 68 </body> 69 </html>
