Changeset 6452
- Timestamp:
- 03/06/08 17:50:44 (6 months ago)
- Files:
-
- trunk/openlayers/examples/transition.html (added)
- trunk/openlayers/lib/OpenLayers/Layer.js (modified) (1 diff)
- trunk/openlayers/lib/OpenLayers/Tile.js (modified) (6 diffs)
- trunk/openlayers/lib/OpenLayers/Tile/Image.js (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/openlayers/lib/OpenLayers/Layer.js
r6447 r6452 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, 273 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'], 260 280 261 281 /** trunk/openlayers/lib/OpenLayers/Tile.js
r6313 r6452 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. … … 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; … … 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 … … 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 && … … 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 … … 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 }); trunk/openlayers/lib/OpenLayers/Tile/Image.js
r6068 r6452 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(); … … 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; … … 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"; … … 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); … … 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"; 304 } 305 } 306 }, 307 313 this.hide(); 314 } 315 } 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 } 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 }
