OpenLayers OpenLayers

Changeset 6452

Show
Ignore:
Timestamp:
03/06/08 17:50:44 (6 months ago)
Author:
pagameba
Message:

Re #933. Apply transition effect patch to trunk, many thanks to Erik, Tim and Chris for support. r=crschmidt, tschaub.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/openlayers/lib/OpenLayers/Layer.js

    r6447 r6452  
    258258    wrapDateLine: false, 
    259259     
     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'], 
    260280     
    261281    /** 
  • trunk/openlayers/lib/OpenLayers/Tile.js

    r6313 r6452  
    8181    isLoading: false, 
    8282     
     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         
    83115    /** TBD 3.0 -- remove 'url' from the list of parameters to the constructor. 
    84116     *             there is no need for the base tile class to have a url. 
     
    112144     */ 
    113145    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        } 
    114153        this.layer  = null; 
    115154        this.bounds = null; 
     
    119158        this.events.destroy(); 
    120159        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        } 
    121166    }, 
    122167     
     
    157202     */ 
    158203    draw: function() { 
    159          
    160         //clear tile's contents and mark as not drawn 
    161         this.clear(); 
    162          
    163204        var maxExtent = this.layer.maxExtent; 
    164205        var withinMaxExtent = (maxExtent && 
     
    167208        // The only case where we *wouldn't* want to draw the tile is if the  
    168209        // 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; 
    170254    }, 
    171255     
     
    238322        return bounds; 
    239323    },         
    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     
    241390    CLASS_NAME: "OpenLayers.Tile" 
    242391}); 
  • trunk/openlayers/lib/OpenLayers/Tile/Image.js

    r6068 r6452  
    147147        } 
    148148         
     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() { 
    149158        if (this.imgDiv == null) { 
    150159            this.initImgDiv(); 
     
    163172                    null, null, imageSize, this.url); 
    164173        } else { 
    165             this.imgDiv.src = this.url; 
    166174            OpenLayers.Util.modifyDOMElement(this.imgDiv, 
    167175                    null, null, imageSize) ; 
     176            this.imgDiv.src = this.url; 
    168177        } 
    169178        return true; 
     
    177186    clear: function() { 
    178187        if(this.imgDiv) { 
    179             this.imgDiv.style.display = "none"
     188            this.hide()
    180189            if (OpenLayers.Tile.Image.useBlankTile) {  
    181190                this.imgDiv.src = OpenLayers.Util.getImagesLocation() + "blank.gif"; 
     
    224233            OpenLayers.Function.bind(this.checkImgURL, this) ); 
    225234        */ 
     235        this.frame.style.zIndex = this.isBackBuffer ? 0 : 1; 
    226236        this.frame.appendChild(this.imgDiv);  
    227237        this.layer.div.appendChild(this.frame);  
     
    301311            var loaded = this.layerAlphaHack ? this.imgDiv.firstChild.src : this.imgDiv.src; 
    302312            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     
    308410    CLASS_NAME: "OpenLayers.Tile.Image" 
    309411  }