Ticket #933: tranny.patch
| File tranny.patch, 16.8 kB (added by tschaub, 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 (this.layer.transitionEffect) { 147 this.layer.events.unregister("loadend", this, this.resetBackBuffer); 148 this.events.unregister('loadend', this, this.resetBackBuffer); 149 } else { 150 this.events.unregister('loadend', this, this.showTile); 151 } 114 152 this.layer = null; 115 153 this.bounds = null; 116 154 this.size = null; … … 118 156 119 157 this.events.destroy(); 120 158 this.events = null; 159 160 /* clean up the backBufferTile if it exists */ 161 if (this.backBufferTile) { 162 this.backBufferTile.destroy(); 163 this.backBufferTile = null; 164 } 121 165 }, 122 166 123 167 /** … … 156 200 * depend on the return to know if they should draw or not. 157 201 */ 158 202 draw: function() { 159 160 //clear tile's contents and mark as not drawn161 this.clear();162 163 203 var maxExtent = this.layer.maxExtent; 164 204 var withinMaxExtent = (maxExtent && 165 205 this.bounds.intersectsBounds(maxExtent, false)); 166 206 167 207 // The only case where we *wouldn't* want to draw the tile is if the 168 208 // tile is outside its layer's maxExtent. 169 return (withinMaxExtent || this.layer.displayOutsideMaxExtent); 209 var drawTile = (withinMaxExtent || this.layer.displayOutsideMaxExtent); 210 211 if (this.layer.transitionEffect != null) { 212 if (drawTile) { 213 //we use a clone of this tile to create a double buffer for visual 214 //continuity. The backBufferTile is used to create transition 215 //effects while the tile in the grid is repositioned and redrawn 216 if (!this.backBufferTile) { 217 this.backBufferTile = this.clone(); 218 this.backBufferTile.hide(); 219 // this is important. It allows the backBuffer to place itself 220 // appropriately in the DOM. The Image subclass needs to put 221 // the backBufferTile behind the main tile so the tiles can 222 // load over top and display as soon as they are loaded. 223 this.backBufferTile.isBackBuffer = true; 224 225 // potentially end any transition effects when the tile loads 226 this.events.register('loadend', this, this.resetBackBuffer); 227 228 // clear transition back buffer tile only after all tiles in 229 // this layer have loaded to avoid visual glitches 230 this.layer.events.register("loadend", this, this.resetBackBuffer); 231 } 232 // run any transition effects 233 this.startTransition(); 234 } else { 235 // if we aren't going to draw the tile, then the backBuffer should 236 // be hidden too! 237 if (this.backBufferTile) { 238 this.backBufferTile.clear(); 239 } 240 } 241 } else { 242 if (drawTile && this.isFirstDraw) { 243 this.events.register('loadend', this, this.showTile); 244 this.isFirstDraw = false; 245 } 246 } 247 this.shouldDraw = drawTile; 248 249 //clear tile's contents and mark as not drawn 250 this.clear(); 251 252 return drawTile; 170 253 }, 171 254 172 255 /** … … 237 320 topLeft.lat); 238 321 return bounds; 239 322 }, 240 323 324 /** 325 * Method: startTransition 326 * Prepare the tile for a transition effect. To be 327 * implemented by subclasses. 328 */ 329 startTransition: function() {}, 330 331 /** 332 * Method: resetBackBuffer 333 * Triggered by two different events, layer loadend, and tile loadend. 334 * In any of these cases, we check to see if we can hide the 335 * backBufferTile yet and update its parameters to match the 336 * foreground tile. 337 * 338 * Basic logic: 339 * - If the backBufferTile hasn't been drawn yet, reset it 340 * - If layer is still loading, show foreground tile but don't hide 341 * the backBufferTile yet 342 * - If layer is done loading, reset backBuffer tile and show 343 * foreground tile 344 */ 345 resetBackBuffer: function() { 346 this.showTile(); 347 if (this.backBufferTile && 348 (this.isFirstDraw || !this.layer.numLoadingTiles)) { 349 this.isFirstDraw = false; 350 // check to see if the backBufferTile is within the max extents 351 // before rendering it 352 var maxExtent = this.layer.maxExtent; 353 var withinMaxExtent = (maxExtent && 354 this.bounds.intersectsBounds(maxExtent, false)); 355 if (withinMaxExtent) { 356 this.backBufferTile.position = this.position; 357 this.backBufferTile.bounds = this.bounds; 358 this.backBufferTile.size = this.size; 359 this.backBufferTile.imageSize = this.layer.imageSize || this.size; 360 this.backBufferTile.imageOffset = this.layer.imageOffset; 361 this.backBufferTile.resolution = this.layer.getResolution(); 362 this.backBufferTile.renderTile(); 363 } 364 } 365 }, 366 367 /** 368 * Method: showTile 369 * Show the tile only if it should be drawn. 370 */ 371 showTile: function() { 372 if (this.shouldDraw) { 373 this.show(); 374 } 375 }, 376 377 /** 378 * Method: show 379 * Show the tile. To be implemented by subclasses. 380 */ 381 show: function() { }, 382 383 /** 384 * Method: hide 385 * Hide the tile. To be implemented by subclasses. 386 */ 387 hide: function() { }, 388 241 389 CLASS_NAME: "OpenLayers.Tile" 242 390 }); -
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 /** 262 275 * Constructor: OpenLayers.Layer -
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>
