[OpenLayers-Commits] r3189 - in sandbox/emanuel: . animatedZooming_final/examples animatedZooming_final/lib/OpenLayers animatedZooming_final/lib/OpenLayers/Control animatedZooming_final/lib/OpenLayers/Layer animatedZooming_final/lib/OpenLayers/Layer/WMS animatedZooming_final/lib/OpenLayers/Tile animatedZooming_final/tests animatedZooming_final/tests/Control animatedZooming_final/tests/Layer animatedZooming_final/tests/Marker

commits at openlayers.org commits at openlayers.org
Sat May 26 15:11:06 EDT 2007


Author: emanuel
Date: 2007-05-26 15:11:05 -0400 (Sat, 26 May 2007)
New Revision: 3189

Added:
   sandbox/emanuel/animatedZooming_final/
Modified:
   sandbox/emanuel/animatedZooming_final/examples/controls.html
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/MouseDefaults.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/MouseToolbar.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/OverviewMap.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/PanZoom.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/PanZoomBar.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/Grid.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/Image.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/WMS.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/WMS/Untiled.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Map.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Tile/Image.js
   sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Util.js
   sandbox/emanuel/animatedZooming_final/tests/Control/test_MouseToolbar.html
   sandbox/emanuel/animatedZooming_final/tests/Control/test_OverviewMap.html
   sandbox/emanuel/animatedZooming_final/tests/Control/test_PanZoom.html
   sandbox/emanuel/animatedZooming_final/tests/Control/test_PanZoomBar.html
   sandbox/emanuel/animatedZooming_final/tests/Control/test_Permalink.html
   sandbox/emanuel/animatedZooming_final/tests/Control/test_Scale.html
   sandbox/emanuel/animatedZooming_final/tests/Layer/test_Grid.html
   sandbox/emanuel/animatedZooming_final/tests/Layer/test_Image.html
   sandbox/emanuel/animatedZooming_final/tests/Layer/test_MapServer.html
   sandbox/emanuel/animatedZooming_final/tests/Layer/test_MapServer_Untiled.html
   sandbox/emanuel/animatedZooming_final/tests/Layer/test_WMS.html
   sandbox/emanuel/animatedZooming_final/tests/Marker/test_Box.html
   sandbox/emanuel/animatedZooming_final/tests/test_Feature.html
   sandbox/emanuel/animatedZooming_final/tests/test_Map.html
   sandbox/emanuel/animatedZooming_final/tests/test_Marker.html
   sandbox/emanuel/animatedZooming_final/tests/test_Util.html
Log:
OL 2.4 RC5 with animated zooming and panning



Copied: sandbox/emanuel/animatedZooming_final (from rev 3182, trunk/openlayers)

Modified: sandbox/emanuel/animatedZooming_final/examples/controls.html
===================================================================
--- trunk/openlayers/examples/controls.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/examples/controls.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -14,7 +14,7 @@
             var map = new OpenLayers.Map('map', { controls: [] });
 
             map.addControl(new OpenLayers.Control.PanZoomBar());
-            map.addControl(new OpenLayers.Control.MouseToolbar());
+            map.addControl(new OpenLayers.Control.MouseDefaults());
             map.addControl(new OpenLayers.Control.LayerSwitcher({'ascending':false}));
             map.addControl(new OpenLayers.Control.Permalink());
             map.addControl(new OpenLayers.Control.Permalink('permalink'));

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/MouseDefaults.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Control/MouseDefaults.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/MouseDefaults.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -101,10 +101,21 @@
     * @param {Event} evt
     */
     defaultDblClick: function (evt) {
-        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); 
-        this.map.setCenter(newCenter, this.map.zoom + 1);
-        OpenLayers.Event.stop(evt);
-        return false;
+        if (!this.map.zoomanimationActive){
+            // convert the (old) center of the map in pixel
+            var centerPx = this.map.getPixelFromLonLat(this.map.getCenter());
+            
+            // pan to new center   
+            var deltaX = evt.xy.x - centerPx.x; 
+            var deltaY = evt.xy.y - centerPx.y; 
+            this.map.pan(deltaX, deltaY,true);
+
+            // zoom to new level 
+            this.map.zoomIn(); 
+
+            OpenLayers.Event.stop(evt);
+            return false;
+        }
     },
 
     /**
@@ -203,8 +214,28 @@
      */
     defaultWheelUp: function(evt) {
         if (this.map.getZoom() <= this.map.getNumZoomLevels()) {
-            this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),
-                               this.map.getZoom() + 1);
+            if (!this.map.zoomanimationActive) {
+                // convert the current center of the map in pixel
+                var centerPx = this.map.getPixelFromLonLat(this.map.getCenter());
+
+                // determine lonlat from target (mouse position)
+                var targetLonLat = this.map.getLonLatFromViewPortPx( evt.xy ); 
+
+                // determine offset target-center in pixel
+                var offset = new OpenLayers.Pixel();
+                offset.x = evt.xy.x - centerPx.x;
+                offset.y = evt.xy.y - centerPx.y;
+
+                // convert offset of zoomlevel n to zoomlevel n+1
+                offset.x = offset.x / 2;
+                offset.y = offset.y / 2;
+
+                // pan to new center   
+                this.map.pan(offset.x, offset.y, true);
+
+                // zoom to new level 
+                this.map.zoomIn();
+            }
         }
     },
 
@@ -213,8 +244,28 @@
      */
     defaultWheelDown: function(evt) {
         if (this.map.getZoom() > 0) {
-            this.map.setCenter(this.map.getLonLatFromPixel(evt.xy),
-                               this.map.getZoom() - 1);
+            if (!this.map.zoomanimationActive) {
+                // convert the current center of the map in pixel
+                var centerPx = this.map.getPixelFromLonLat(this.map.getCenter());
+
+                // determine lonlat from target (mouse position)
+                var targetLonLat = this.map.getLonLatFromViewPortPx( evt.xy ); 
+
+                // determine offset target-center in pixel...
+                var offset = new OpenLayers.Pixel();
+                offset.x = evt.xy.x - centerPx.x;
+                offset.y = evt.xy.y - centerPx.y;
+
+                // convert offset of zoomlevel n to zoomlevel n-1
+                offset.x = -offset.x;
+                offset.y = -offset.y;
+
+                // pan to new center   
+                this.map.pan(offset.x, offset.y, true);
+
+                // zoom to new level 
+                this.map.zoomOut();
+            }
         }
     },
 
@@ -223,25 +274,31 @@
      */
     zoomBoxEnd: function(evt) {
         if (this.mouseDragStart != null) {
-            if (Math.abs(this.mouseDragStart.x - evt.xy.x) > 5 ||    
-                Math.abs(this.mouseDragStart.y - evt.xy.y) > 5) {   
-                var start = this.map.getLonLatFromViewPortPx( this.mouseDragStart ); 
-                var end = this.map.getLonLatFromViewPortPx( evt.xy );
-                var top = Math.max(start.lat, end.lat);
-                var bottom = Math.min(start.lat, end.lat);
-                var left = Math.min(start.lon, end.lon);
-                var right = Math.max(start.lon, end.lon);
-                var bounds = new OpenLayers.Bounds(left, bottom, right, top);
-                this.map.zoomToExtent(bounds);
-            } else {
-                var end = this.map.getLonLatFromViewPortPx( evt.xy );
-                this.map.setCenter(new OpenLayers.LonLat(
-                  (end.lon),
-                  (end.lat)
-                 ), this.map.getZoom() + 1);
-            }    
+            if (!this.map.zoomanimationActive) {
+                if (Math.abs(this.mouseDragStart.x - evt.xy.x) > 5 ||    
+                    Math.abs(this.mouseDragStart.y - evt.xy.y) > 5) {   
+                    var start = this.map.getLonLatFromViewPortPx( this.mouseDragStart ); 
+                    var end = this.map.getLonLatFromViewPortPx( evt.xy );
+                    var top = Math.max(start.lat, end.lat);
+                    var bottom = Math.min(start.lat, end.lat);
+                    var left = Math.min(start.lon, end.lon);
+                    var right = Math.max(start.lon, end.lon);
+                    var bounds = new OpenLayers.Bounds(left, bottom, right, top);
+                    this.map.zoomToExtent(bounds);
+                } else {
+                    // convert the (old) center of the map in pixel
+                    var centerPx = this.map.getPixelFromLonLat(this.map.getCenter())
+                    // pan to new center   
+                    var deltaX = evt.xy.x - centerPx.x; 
+                    var deltaY = evt.xy.y - centerPx.y; 
+                    this.map.pan(deltaX, deltaY,true);
+
+                    // zoom to new level 
+                    this.map.zoomIn();        
+                }    
+            }
             this.removeZoomBox();
-       }
+        }
     },
 
     /**

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/MouseToolbar.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Control/MouseToolbar.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/MouseToolbar.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -123,12 +123,24 @@
     * @param {Event} evt
     */
     defaultDblClick: function (evt) {
-        this.switchModeTo("pan");
-        this.performedDrag = false;
-        var newCenter = this.map.getLonLatFromViewPortPx( evt.xy ); 
-        this.map.setCenter(newCenter, this.map.zoom + 1);
-        OpenLayers.Event.stop(evt);
-        return false;
+        if (!this.map.zoomanimationActive){
+            this.switchModeTo("pan");
+            this.performedDrag = false;
+
+            // convert the (old) center of the map in pixel
+            var centerPx = this.map.getPixelFromLonLat(this.map.getCenter());
+
+            // pan to new center   
+            var deltaX = evt.xy.x - centerPx.x; 
+            var deltaY = evt.xy.y - centerPx.y; 
+            this.map.pan(deltaX, deltaY,true);
+
+            // zoom to new level 
+            this.map.zoomIn();
+
+            OpenLayers.Event.stop(evt);
+            return false;
+        }
     },
 
     /**

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/OverviewMap.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Control/OverviewMap.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/OverviewMap.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -164,9 +164,10 @@
 
         this.div.appendChild(this.element);
 
-        this.map.events.register('moveend', this, this.update);
+        // update overviewmap during map is panning
+        this.map.events.register('move', this, this.update);
         
-        // Set up events.  The image div recenters the map on click.
+        // Set up events.  The image div recenters the map on doubleclick.
         // The extent rectangle can be dragged to recenter the map.
         // If the mousedown happened elsewhere, then mousemove and mouseup
         // should slip through.
@@ -189,9 +190,8 @@
         this.rectEvents.register('click', this, function(e) {
             OpenLayers.Event.stop(e);
         });
-        this.rectEvents.register('dblclick', this, this.rectDblClick );
         this.mapDivEvents = new OpenLayers.Events(this, this.mapDiv);
-        this.mapDivEvents.register('click', this, this.mapDivClick);
+        this.mapDivEvents.register('dblclick', this, this.mapDivDblClick);
 
         // Optionally add min/max buttons if the control will go in the
         // map viewport.
@@ -329,19 +329,11 @@
         this.rectDragStart = null;
     },
     
-    /**
-    * @param {OpenLayers.Event} evt
-    */
-    rectDblClick: function(evt) {
-        this.performedRectDrag = false;
-        OpenLayers.Event.stop(evt);
-        this.updateOverview();
-    },
 
     /**
     * @param {OpenLayers.Event} evt
     */
-    mapDivClick: function(evt) {
+    mapDivDblClick: function(evt) {
         var pxBounds = this.getRectPxBounds();
         var pxCenter = pxBounds.getCenterPixel();
         var deltaX = evt.xy.x - pxCenter.x;
@@ -354,11 +346,11 @@
         newTop = Math.min(newTop, this.ovmap.size.h - height);
         var newLeft = Math.max(0, (left + deltaX));
         newLeft = Math.min(newLeft, this.ovmap.size.w - width);
-        this.setRectPxBounds(new OpenLayers.Bounds(newLeft,
+        pxBounds = new OpenLayers.Bounds(newLeft,
                                                    newTop + height,
                                                    newLeft + width,
-                                                   newTop));
-        this.updateMapToRect();
+                                                   newTop);
+        this.updateMapToRect(pxBounds);
         OpenLayers.Event.stop(evt);
     },
 
@@ -406,15 +398,17 @@
         if(this.ovmap == null) {
             this.createMap();
         }
-        
+
         if(!this.isSuitableOverview()) {
             this.updateOverview();
         }
-        
+
         // update extent rectangle
         this.updateRectToMap();
+
+        this.updateOverview();
     },
-    
+
     /**
      * Determines if the overview map is suitable given the extent and
      * resolution of the main map.
@@ -426,15 +420,26 @@
                                 Math.max(mapExtent.left, maxExtent.left),
                                 Math.max(mapExtent.bottom, maxExtent.bottom),
                                 Math.min(mapExtent.right, maxExtent.right),
-                                Math.min(mapExtent.top, maxExtent.top));        
+                                Math.min(mapExtent.top, maxExtent.top));
         var resRatio = this.ovmap.getResolution() / this.map.getResolution();
         return ((resRatio > this.minRatio) &&
                 (resRatio <= this.maxRatio) &&
                 (this.ovmap.getExtent().containsBounds(testExtent)));
     },
-    
-    updateOverview: function() {
-        var mapRes = this.map.getResolution();
+
+    /* 
+     * Updates the overview map. If the map is scaling (by zooming) the parameters
+     * define the values of the new resolution and bounds.
+     *
+     * @param {float} newResolution
+     * @param {OpenLayers.Bounds} bounds
+     */    
+    updateOverview: function(newResolution, bounds) {
+        //set new map resolution only by scaling
+        if (newResolution)
+            var mapRes = newResolution;
+        else
+            var mapRes = this.map.getResolution();
         var targetRes = this.ovmap.getResolution();
         var resRatio = targetRes / mapRes;
         if(resRatio > this.maxRatio) {
@@ -446,7 +451,7 @@
         }
         this.ovmap.setCenter(this.map.center,
                             this.ovmap.getZoomForResolution(targetRes));
-        this.updateRectToMap();
+        this.updateRectToMap(bounds);
     },
     
     createMap: function() {
@@ -470,9 +475,13 @@
     },
         
     /**
-     * Updates the extent rectangle position and size to match the map extent
+     * Updates the extent rectangle position and size to match the map extent  
+     * If the map is scaling (by zooming) the parameter defines the
+     * new bounds of the current map
+     *
+     * @param {OpenLayers.Bounds} bounds
      */
-    updateRectToMap: function() {
+    updateRectToMap: function(bounds) {
         // The base layer for overview map needs to be in the same projection
         // as the base layer for the main map.  This should be made more robust.
         if(this.map.units != 'degrees') {
@@ -480,7 +489,10 @@
                 alert('The overview map only works when it is in the same projection as the main map');
             }
         }
-        var pxBounds = this.getRectBoundsFromMapBounds(this.map.getExtent());
+
+        if (!bounds)
+            bounds=this.map.getExtent();
+        var pxBounds = this.getRectBoundsFromMapBounds(bounds);
         if (pxBounds) {
           this.setRectPxBounds(pxBounds);
         }
@@ -489,10 +501,22 @@
     /**
      * Updates the map extent to match the extent rectangle position and size
      */
-    updateMapToRect: function() {
-        var pxBounds = this.getRectPxBounds();
+    updateMapToRect: function(pxBounds) {
+        if (!pxBounds)
+            var pxBounds = this.getRectPxBounds();
         var lonLatBounds = this.getMapBoundsFromRectBounds(pxBounds);
-        this.map.setCenter(lonLatBounds.getCenterLonLat(), this.map.zoom);
+
+        var centerPx = this.map.getViewPortPxFromLonLat(lonLatBounds.getCenterLonLat());
+
+        var resolution = this.map.getResolution();
+        
+        var width = lonLatBounds.getWidth();
+        width = width / resolution;
+        var height = lonLatBounds.getHeight();
+        height = height / resolution;
+
+        // pan to recenter rectangle
+        this.map.pan(centerPx.x-width/2,centerPx.y-height/2);
     },
     
     /**

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/PanZoom.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Control/PanZoom.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/PanZoom.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -15,7 +15,7 @@
   OpenLayers.Class.inherit( OpenLayers.Control, {
 
     /** @type int */
-    slideFactor: 50,
+    slideFactor: 75,
 
     /** @type Array of Button Divs */
     buttons: null,
@@ -133,16 +133,16 @@
 
         switch (this.action) {
             case "panup": 
-                this.map.pan(0, -50);
+                this.map.pan(0, -this.slideFactor);
                 break;
             case "pandown": 
-                this.map.pan(0, 50);
+                this.map.pan(0, this.slideFactor);
                 break;
             case "panleft": 
-                this.map.pan(-50, 0);
+                this.map.pan(-this.slideFactor, 0);
                 break;
             case "panright": 
-                this.map.pan(50, 0);
+                this.map.pan(this.slideFactor, 0);
                 break;
             case "zoomin": 
                 this.map.zoomIn(); 

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/PanZoomBar.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Control/PanZoomBar.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Control/PanZoomBar.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -180,7 +180,10 @@
         var y = evt.xy.y;
         var top = OpenLayers.Util.pagePosition(evt.object)[1];
         var levels = Math.floor((y - top)/this.zoomStopHeight);
-        this.map.zoomTo((this.map.getNumZoomLevels() -1) -  levels);
+
+        if (!this.map.zoomanimationActive)
+            this.map.zoomTo((this.map.getNumZoomLevels() -1) -  levels);
+
         OpenLayers.Event.stop(evt);
     },
     
@@ -193,8 +196,12 @@
         this.map.events.register("mousemove", this, this.passEventToSlider);
         this.map.events.register("mouseup", this, this.passEventToSlider);
         this.mouseDragStart = evt.xy.clone();
-        this.zoomStart = evt.xy.clone();
+        this.map.zoomStart = evt.xy.clone();
         this.div.style.cursor = "move";
+
+        // get and set some settings for zoom animation 
+        this.map.prepareZoomAnimation();
+        
         // reset the div offsets just in case the div moved
         this.zoombarDiv.offsets = null; 
         OpenLayers.Event.stop(evt);
@@ -216,6 +223,13 @@
                 this.slider.style.top = newTop+"px";
             }
             this.mouseDragStart = evt.xy.clone();
+           
+            // set current slider position
+            var sliderPosition = new OpenLayers.Pixel(evt.xy.x, evt.xy.y); 
+
+            // run zoom animation -> scale tile(s)
+            this.map.runZoomAnimation(this.zoomStopHeight, sliderPosition);
+      
             OpenLayers.Event.stop(evt);
         }
     },
@@ -227,12 +241,18 @@
      */
     zoomBarUp:function(evt) {
         if (!OpenLayers.Event.isLeftClick(evt)) return;
-        if (this.zoomStart) {
+        if (this.map.zoomStart) {
             this.div.style.cursor="";
             this.map.events.unregister("mouseup", this, this.passEventToSlider);
             this.map.events.unregister("mousemove", this, this.passEventToSlider);
-            var deltaY = this.zoomStart.y - evt.xy.y
-            this.map.zoomTo(this.map.zoom + Math.round(deltaY/this.zoomStopHeight));
+            var deltaY = this.map.zoomStart.y - evt.xy.y;
+
+            // zoom map to new zoomlevel
+            var finalZoomlevel = this.map.zoom + Math.round(deltaY/this.zoomStopHeight);
+
+            // finish zoom animation
+            this.map.finishZoomAnimation(finalZoomlevel);
+
             this.moveZoomBar();
             this.mouseDragStart = null;
             OpenLayers.Event.stop(evt);
@@ -241,10 +261,17 @@
     
     /* 
     * Change the location of the slider to match the current zoom level.
+    *
+    * @param {float} zoomlevel
     */
-    moveZoomBar:function() {
-        var newTop = 
-            ((this.map.getNumZoomLevels()-1) - this.map.getZoom()) * 
+    moveZoomBar:function(zoomlevel) {
+        // check if zoomlevel is not a number
+        if (isNaN(zoomlevel)) {
+            zoomlevel = this.map.getZoom();
+        }
+
+        // set new top position
+        var newTop = ((this.map.getNumZoomLevels()-1) - zoomlevel) *
             this.zoomStopHeight + this.startTop + 1;
         this.slider.style.top = newTop + "px";
     },    

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/Grid.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/Grid.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/Grid.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -23,6 +23,12 @@
     /** @type Integer */
     buffer: 2,
 
+    /** @type Integer */
+    centerRow: null,
+
+    /** @type Integer */
+    centerCol: null,
+
     /**
      * @constructor
      * 
@@ -290,6 +296,8 @@
      *   Once all the grid's tiles have been added to the queue, we go back 
      *    and iterate through the queue (thus reversing the spiral order from 
      *    outside-in to inside-out), calling draw() on each tile. 
+     *
+     *   Fires loadend event after all tiles in viewport loaded.
      */
     spiralTileLoad: function() {
         var tileQueue = new Array();
@@ -344,16 +352,72 @@
                 directionsTried++;
             }
         } 
-        
+
+        // fire loadstart event
+        this.events.triggerEvent("loadstart");
+        this.doneLoading = false;
+    
+        // set tileQueue temporary as class parameter;
+        // necessaray to get values also in onload event function
+        this.tileQueue = tileQueue;
+
         // now we go through and draw the tiles in forward order
         for(var i=0; i < tileQueue.length; i++) {
-            var tile = tileQueue[i]
-            tile.draw();
-            //mark tile as unqueued for the next time (since tiles are reused)
-            tile.queued = false;       
+            var drawn = tileQueue[i].draw();
+            // mark tile as unqueued for the next time (since tiles are reused)
+            tileQueue[i].queued = false; 
+
+
+            // onload event function; 
+            // it calls automatically when image fires onload event
+            var onload = function() { 
+                // get object array
+                var tile = this[0];
+                var layer = this[1];
+                if (layer.map.div.id == "map") { 
+                    // default assumption: every images in extent are loaded
+                    var stillLoading = false;
+                   
+                    // set internal alt message after image loaded
+                    if (tile.imgDiv)
+                        tile.imgDiv.alt = "loaded";
+
+                    // check if all visible tiles are loaded
+                    for (var j=0; j < layer.tileQueue.length; j++) {
+                        if (layer.tileQueue[j].imgDiv){
+                            if((layer.tileQueue[j].bounds.intersectsBounds(
+                                                layer.map.getExtent(),false))
+                              && (layer.tileQueue[j].imgDiv.alt != "loaded")){
+                                // at least one image tile is still loading
+                                stillLoading = true;
+                            }
+                        }
+                    }
+
+                    // any visible images loaded? -> fire loadend event
+                    if ((!stillLoading) && (!layer.map.baseLayer.doneLoading)) {
+                        layer.map.baseLayer.doneLoading = true;
+                        layer.events.triggerEvent("loadend"); 
+                    }
+                }
+            }
+            
+
+            // if tile is start drawing (imgDiv exists)...
+            if (drawn){
+                // create an object with current tile and layer for onload event 
+                var object = new Array();
+                object[0] = tileQueue[i];
+                object[1] = this;
+
+                // start onload event listener
+                OpenLayers.Event.observe(tileQueue[i].imgDiv, 'load',
+                                     onload.bindAsEventListener(object));
+            }
         }
     },
 
+
     /**
      * addTile gives subclasses of Grid the opportunity to create an 
      * OpenLayer.Tile of their choosing. The implementer should initialize 
@@ -447,7 +511,193 @@
             }
         }
     },
+
+
+
+    /********************************************************/
+    /*                                                      */
+    /*       Baselayer Functions for zooming/scaling        */
+    /*                                                      */
+    /********************************************************/    
+
+    /** 
+     * Initializes zoomOut tile and sets a x-times bigger tile size.
+     *
+     * @returns true after zoomOutTile is set
+     * @type Boolean
+     */
+    setZoomOutTile:function() {
+        this.setZoomOutTile_share();
+        return true;
+    },
+
+    /** 
+     * Gets the current tile size of the layer.
+     *  
+     * @returns the current map tile size
+     * @type OpenLayers.Size
+     */
+    getTileSize:function() {
+        return this.map.getTileSize();
+    },
+
+    /** 
+     * Gets tile, which contains the center of the viewport.
+     *
+     * @returns the tile, which contains the center of the viewport
+     * @type OpenLayers.Tile
+     */
+    getCenterTile:function() {
+        var center = this.map.getCenter();
+
+        if (this.grid) {
+            for (var iRow=0; iRow < this.grid.length; iRow++) {
+                for (var iCol=0; iCol < this.grid[iRow].length; iCol++) {
+                    var tileBounds = this.grid[iRow][iCol].bounds;
+                    if (tileBounds.containsLonLat(center, true)) {
+                        this.centerRow = iRow;
+                        this.centerCol = iCol;
+                        return this.grid[iRow][iCol];                    
+                    }
+                }
+            }
+        }
+        return false;   // something runs fail!
+    },
     
+
+    /** 
+     * Sets all tiles outside the viewport invisible. 
+     * Only for baselayers with a grid of tiles.
+     * 
+     * @returns true if tiles are set invisible
+     * @type Boolean
+     */
+    setTilesOutsideInvisible:function() {
+        var extent = this.map.getExtent();
+        var layerGrid = this.map.baseLayer.grid;
+
+        // go through the whole grid
+        for (var iRow=0; iRow < layerGrid.length; iRow++) {
+            for (var iCol=0; iCol < layerGrid[iRow].length; iCol++) {                         
+                var tile = layerGrid[iRow][iCol];
+                if (tile.imgDiv) {
+                    // scale all (visible) tiles within the viewport
+                    if (!extent.containsBounds(tile.bounds,true, false))
+                        tile.imgDiv.style.display = "none";
+                }
+            }
+        }                
+        return true;
+    },
+
+
+    /**
+     * Scales all tiles of a grid to the new tile size 
+     * (changes size and position).
+     * 
+     * @param {OpenLayers.Tile} centerTile
+     * @param {OpenLayers.Size} newTileSize
+     *
+     * @returns true after the grid is scaled
+     * @type Boolean
+     */
+    scaleTilesOfGrid:function(centerTile, newTileSize) {
+
+        var extent = this.map.getExtent();
+
+        // reposition and resize all _visible_ tiles of the active baselayer
+        var layerGrid = this.map.baseLayer.grid;
+
+        // go through the whole grid
+        for (var iRow=0; iRow < layerGrid.length; iRow++) {
+            for (var iCol=0; iCol < layerGrid[iRow].length; iCol++) {                         
+                var tile = layerGrid[iRow][iCol];
+                if (tile.imgDiv) {
+                    if ((newTileSize.w < Math.pow(2,15)) &&
+                        (newTileSize.h < Math.pow(2,15)) ){
+
+                        // scale all (visible) tiles within the viewport
+                        if (extent.containsBounds(tile.bounds,true, false)) {
+                            //define the factors for rows and columns
+                            //(relates to the center tile)
+                            var deltaRow = iRow - this.centerRow;
+                            var deltaCol = iCol - this.centerCol;
+                            
+                            //set new left position
+                            var newLeftPos = parseInt(centerTile.imgDiv.style.left)
+                              + deltaCol * newTileSize.w ;
+                            tile.imgDiv.style.left = Math.round(newLeftPos) + "px";
+
+                            //set new top position
+                            var newTopPos = parseInt(centerTile.imgDiv.style.top)
+                              + deltaRow * newTileSize.h ;
+                            tile.imgDiv.style.top = Math.round(newTopPos) + "px";
+
+                            //set new width and height
+                            tile.imgDiv.style.width = Math.round(newTileSize.w) + "px";
+                            tile.imgDiv.style.height = Math.round(newTileSize.h) + "px";
+                        }
+                    }
+                }
+            }
+        }
+        return true;
+    },
+    
+    /**
+     * Reposition and resize the zoomOut tile to prevent a white frame
+     * during zoomOut.
+     * share scale algorithm with other baselayers
+     *
+     * @param {float} newZoomlevel
+     * @param {float} newResolution
+     *
+     * @returns true if zoomOutTile is scaled, otherwise false
+     * @type Boolean
+     */
+    scaleZoomOutTile: function(newZoomlevel, newResolution) {
+        if (this.zoomOutTile) {
+            this.scaleZoomOutTile_share(newZoomlevel, newResolution);
+            return true;
+        }
+        else { 
+            return false;
+        }
+    },
+
+    /** 
+     * Clones layerContainer for "smooth tile update". 
+     * So, it gets no blank map while map is loading in new zoomlevel.
+     *
+     * @returns true after layerContainer is cloned
+     * @type Boolean
+     */
+    cloneBaseLayerDiv:function() {
+        // share clone algorithm with other baselayers
+        this.cloneBaseLayerDiv_share();
+
+        // remove all old imgDiv tiles 
+        // (so it doesn't becomes complicate with the same imgDivs of the
+        // cloned layerContainerDiv)
+        for (iRow=0; iRow<this.grid.length; iRow++){
+            for (iCol=0; iCol<this.grid[iRow].length; iCol++){
+                var tile = this.grid[iRow][iCol];
+                if (tile.imgDiv)
+                    this.div.removeChild(tile.imgDiv);
+            }
+        }       
+        //reset grid array
+        this.grid = new Array();
+
+        //this.clearGrid();
+        //this.grid = new Array();
+        
+        return true;
+    },
+
+
+     
     /** @final @type String */
     CLASS_NAME: "OpenLayers.Layer.Grid"
 });

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/Image.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/Image.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/Image.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -178,6 +178,64 @@
         return this.url;
     },
         
+
+
+    /********************************************************/
+    /*                                                      */
+    /*       Baselayer Functions for zooming/scaling        */
+    /*                                                      */
+    /********************************************************/
+
+
+    /** 
+     * Gets tile (image) size.
+     *  
+     * @returns the image size if tile exists; otherwise
+     * null
+     * @type {OpenLayers.Size}
+     */
+    getTileSize:function() {
+        if (this.tile) 
+            return this.tile.size;
+        else
+            return null;
+    },
+
+    /** 
+     * Gets the tile of this image layer. 
+     *
+     * @returns the only tile of the layer
+     * @type {OpenLayers.Tile}
+     */
+    getCenterTile:function() {   
+        if (this.tile)
+            return this.tile; 
+        else
+            return null;
+    },
+
+    /** 
+     * Clones layerContainer for "smooth tile update". 
+     * So, it gets no blank map while map is loading in new zoomlevel.
+     *
+     * @returns true after layerContainer is cloned
+     * @type Boolean
+     */
+    cloneBaseLayerDiv:function() {
+        // share clone algorithm with other baselayers
+        this.cloneBaseLayerDiv_share();
+
+        // remove the old imgDiv tile 
+        // (so it doesn't becomes complicate with the same imgDiv of the
+        // cloned layerContainerDiv)
+        if (this.tile)
+            this.div.removeChild(this.tile.imgDiv);
+        
+        this.tile = null;        
+
+        return true;
+    },
+
     /** @final @type String */
     CLASS_NAME: "OpenLayers.Layer.Image"
 });

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/WMS/Untiled.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/WMS/Untiled.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/WMS/Untiled.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -31,9 +31,6 @@
     /** @type OpenLayers.Tile.Image */
     tile: null,
 
-    /** did the image finish loading before a new draw was initiated?
-     * @type Boolean */
-    doneLoading: false,
 
     /**
     * @constructor
@@ -177,6 +174,7 @@
                 this.tile = null;
             }
 
+            // fire loadstart event
             this.events.triggerEvent("loadstart");
             this.doneLoading = false;
             if (!this.tile) {
@@ -195,11 +193,16 @@
     
         }
     },
-    
-    getURL: function(bounds) {
+
+    getURL: function(bounds, tileSize) {
+        if (!tileSize) {
+            var tileSize = this.map.getSize();
+            tileSize.w = tileSize.w * this.ratio;
+            tileSize.h = tileSize.h * this.ratio;
+        }
         return this.getFullRequestString( {'BBOX': bounds.toBBOX(),
-                                                  'WIDTH': this.tileSize.w,
-                                                  'HEIGHT': this.tileSize.h} );
+                                                  'WIDTH': tileSize.w,
+                                                  'HEIGHT': tileSize.h} );
     },
  
     
@@ -240,7 +243,98 @@
         return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(
                                                     this, arguments);
     },
-    
+   
+
+    /********************************************************/
+    /*                                                      */
+    /*       Baselayer Functions for zooming/scaling        */
+    /*                                                      */
+    /********************************************************/    
+
+    /** 
+     * Initializes zoomOut tile and sets a x-times bigger tile size.
+     *
+     * Default function; will override from subclasses,
+     * otherwise it returns false
+     * 
+     * @returns true after zoomOutTile is set
+     */
+    setZoomOutTile:function() {
+        this.setZoomOutTile_share();
+        return true
+    },
+
+
+    /** 
+     * Gets tile size.
+     *  
+     * @returns the current map tile size if tile exists; otherwise
+     * null
+     * @type {OpenLayers.Size}
+     */
+    getTileSize:function() {
+        if (this.tile) 
+            return this.tile.size;
+        else
+            return null;
+    },
+
+    /** 
+     * Gets the center tile.
+     *
+     * @returns the only tile of the layer if tile exists; otherwise
+     * null
+     * @type {OpenLayers.Tile}
+     */
+    getCenterTile:function() {   
+        if (this.tile)
+            return this.tile; 
+        else
+            return null;
+    },
+
+    /**
+     * Reposition and resize the zoomOut tile to prevent a white frame
+     * during zoomOut.
+     * share scale algorithm with other baselayers
+     *
+     * @param {float} newZoomlevel
+     * @param {float} newResolution
+     *
+     * @returns true after the zoomOutTile is scaled, otherwise false
+     */
+    scaleZoomOutTile: function(newZoomlevel, newResolution) {
+        if (this.zoomOutTile) {
+            this.scaleZoomOutTile_share(newZoomlevel, newResolution);
+            return true;
+        }
+        else
+            return false;
+    },
+
+    /** 
+     * Clones layerContainer for "smooth tile update". 
+     * So, it gets no blank map while map is loading in new zoomlevel.
+     *
+     * @returns true after layerContainer is cloned
+     * @type Boolean
+     */
+    cloneBaseLayerDiv:function() {
+        // share clone algorithm with other baselayers
+        this.cloneBaseLayerDiv_share();
+
+        // remove the old imgDiv tile 
+        // (so it doesn't becomes complicate with the same imgDiv of the
+        // cloned layerContainerDiv)
+        if (this.tile)
+            this.div.removeChild(this.tile.imgDiv);
+        
+        this.tile = null;        
+
+        return true;
+    },
+
+ 
     /** @final @type String */
     CLASS_NAME: "OpenLayers.Layer.WMS.Untiled"
 });

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/WMS.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer/WMS.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer/WMS.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -86,20 +86,24 @@
     
     /**
      * @param {OpenLayers.Bounds} bounds
+     * @param {OpenLayers.Size} tileSize
      * 
      * @returns A string with the layer's url and parameters and also the 
      *           passed-in bounds and appropriate tile size specified as 
      *           parameters
      * @type String
      */
-    getURL: function (bounds) {
+    getURL: function (bounds, tileSize) {
+        if (!tileSize) {
+            var tileSize = this.tileSize;
+        }
         if(this.gutter) {
             bounds = this.adjustBoundsByGutter(bounds);
         }
         return this.getFullRequestString(
                      {BBOX:bounds.toBBOX(),
-                      WIDTH:this.imageSize.w,
-                      HEIGHT:this.imageSize.h});
+                      WIDTH:tileSize.w,
+                      HEIGHT:tileSize.h});
     },
 
     /**

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Layer.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Layer.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -140,7 +140,14 @@
     /** @type Boolean */
     displayOutsideMaxExtent: false,
     
-    
+    /** did the image finish loading before a new draw was initiated?
+     * @type Boolean */
+    doneLoading: false,
+
+    /** @type Boolen */
+    firstCall: true, 
+
+
     /**
      * @constructor
      * 
@@ -164,7 +171,9 @@
 
             this.events = new OpenLayers.Events(this, this.div, 
                                                 this.EVENT_TYPES);
+            this.events.register("loadend", this, this.setLoadendVisibility);
         }
+        
     },
     
     /**
@@ -545,6 +554,8 @@
      */
     getResolution: function() {
         var zoom = this.map.getZoom();
+        if (zoom >= this.map.getNumZoomLevels())
+            zoom = this.map.getNumZoomLevels() - 1;
         return this.resolutions[zoom];
     },
 
@@ -610,9 +621,10 @@
             var center = this.map.getCenter();
             if (center) {
                 var res  = this.map.getResolution();
-        
-                var delta_x = viewPortPx.x - (size.w / 2);
-                var delta_y = viewPortPx.y - (size.h / 2);
+
+                var delta_x = viewPortPx.x - Math.ceil(size.w / 2);
+                var delta_y = viewPortPx.y - Math.ceil(size.h / 2);
+
             
                 lonlat = new OpenLayers.LonLat(center.lon + delta_x * res ,
                                              center.lat - delta_y * res); 
@@ -628,10 +640,11 @@
      *          translated into view port pixels
      * @type OpenLayers.Pixel
      */
-    getViewPortPxFromLonLat: function (lonlat) {
+    getViewPortPxFromLonLat: function (lonlat, resolution) {
         var px = null; 
         if (lonlat != null) {
-            var resolution = this.map.getResolution();
+            if (!resolution)
+                resolution = this.map.getResolution();
             var extent = this.map.getExtent();
             px = new OpenLayers.Pixel(
                            Math.round(1/resolution * (lonlat.lon - extent.left)),
@@ -666,7 +679,7 @@
         if (opacity != this.opacity) {
             this.opacity = opacity;
             for(var i=0; i<this.div.childNodes.length; ++i) {
-                var element = this.div.childNodes[i].firstChild;
+                var element = this.div.childNodes[i];
                 OpenLayers.Util.modifyDOMElement(element, null, null, null, 
                                                  null, null, null, opacity);
             }
@@ -681,6 +694,369 @@
         this.div.style.zIndex = zIdx;
     },
 
+
+
+
+    /********************************************************/
+    /*                                                      */
+    /*       Baselayer Functions for zooming/scaling        */
+    /*                                                      */
+    /********************************************************/
+
+    /** 
+     * Initializes zoomOut tile and sets a x-times bigger tile size.
+     *
+     * Default function; will override in subclasses,
+     * otherwise it returns false
+     * 
+     * @returns false if no zoomOutTile is set
+     * @type Boolean
+     */
+    setZoomOutTile:function() {
+        return false;
+    },
+
+    /**
+     * Initializes zoomOut tile and sets a x-times bigger tile size.
+     * 
+     * special function; shares with some baselayers; calls from subclasses
+     *
+     */
+    setZoomOutTile_share:function() {
+        if (!this.zoomOutTile) {
+            var bounds = this.map.getMaxExtent();
+            var resolution = this.resolutions[0]; 
+
+            // calculate tile bounds
+            var n = 0;
+            do {
+                resolution = resolution * Math.pow(2, n);
+                
+                var tilelon = resolution * this.map.tileSize.w;
+                var tilelat = resolution * this.map.tileSize.h;
+            
+                var tileoffsetlon = bounds.left;
+                var tileoffsetlat = bounds.bottom;
+                
+                var tileBounds = new OpenLayers.Bounds(tileoffsetlon, 
+                                                       tileoffsetlat, 
+                                                       tileoffsetlon + tilelon,
+                                                       tileoffsetlat + tilelat);
+                n++;
+            }
+            while (!tileBounds.containsBounds(bounds, false, true));
+
+            var tileSize = new OpenLayers.Size();
+            tileSize.w = this.map.zoomOutTileSizeFactor * this.map.tileSize.w;
+            tileSize.h = this.map.zoomOutTileSizeFactor * this.map.tileSize.h;
+
+            // formulate request url string
+            var url = this.getURL(tileBounds, tileSize); 
+            // default start position
+            var pos = new OpenLayers.Pixel (0,0); 
+            // default start size
+            var tilesize = new OpenLayers.Size(0,0);
+
+            this.zoomOutTile = new OpenLayers.Tile.Image(this, pos, tileBounds, 
+                                                        url, tileSize);
+
+            // draw tile -> sets imgDiv
+            this.zoomOutTile.draw();
+
+            // resize zoomOutTile
+            this.zoomOutTile.imgDiv.style.width = 0;
+            this.zoomOutTile.imgDiv.style.height = 0;
+            
+            // set zoomOut tile invisible 
+            if (this.map.baseLayer.zoomOutTile)
+                this.map.baseLayer.zoomOutTile.imgDiv.style.display = "none";
+        }
+    },
+ 
+    /** 
+     * Gets the current tile size of the layer.
+     *
+     * Default function; will override in subclasses,
+     * otherwise it returns false - that means: no scaling possible!
+     * 
+     * @returns null if no tile size set
+     * @type OpenLayers.Size
+     */
+    getTileSize:function() {
+        return null;
+    },
+
+
+    /** 
+     * Gets tile, which contains the center of the viewport.
+     *
+     * Default function; will override in subclasses,
+     * otherwise it returns null - that means: no scaling possible!
+     * 
+     * @returns returns null if no center tile set
+     * @type OpenLayers.Tile
+     */
+    getCenterTile:function() {
+        return null;
+    },
+
+
+    /** 
+     * Sets all tiles outside the viewport invisible. 
+     * Only for baselayers with a grid of tiles.
+     *
+     * Default function; will override in subclasses,
+     * otherwise it returns false
+     * 
+     * @returns false if baselayer has no grid
+     * @type Boolean
+     */
+    setTilesOutsideInvisible:function() {
+        return false;
+    },
+
+    /**
+     * Scales tile to the new tile size (changes size and position).
+     * If you have a grid, the tile is the center tile. Otherwise it's
+     * the only one.
+     * 
+     * @param {OpenLayers.Tile} tile
+     * @param {OpenLayers.Size} newTileSize
+     * 
+     * @returns true if tile is scaled, otherwise false
+     * @type Boolean
+     */
+    scaleTileTo:function(tile, newTileSize) {
+        //convert the center of the map in pixel
+        var centerPx = this.map.getPixelFromLonLat(this.map.getCenter());
+
+        //reposition and resize the tile 
+        if (tile) {
+            if ((newTileSize.w < Math.pow(2,15)) &&
+                (newTileSize.h < Math.pow(2,15)) ){
+
+                // set real start position of centerTile
+                var startPosX = (tile.position.x +
+                  parseInt(this.map.layerContainerDiv.style.left));
+                // set new left position
+                var leftOffset = newTileSize.w / tile.size.w
+                  * (centerPx.x - startPosX);
+                leftOffset = Math.round(leftOffset);
+                var newLeftPos = centerPx.x - leftOffset
+                  - parseInt(this.map.layerContainerDiv.style.left);
+                tile.imgDiv.style.left = Math.round(newLeftPos) + "px";
+
+                // set real start position of centerTile
+                var startPosY = (tile.position.y +
+                  parseInt(this.map.layerContainerDiv.style.top));
+                //set new top position
+                var topOffset = newTileSize.h / tile.size.h
+                  * (centerPx.y - startPosY);
+                topOffset = Math.round(topOffset);
+                var newTopPos = centerPx.y - topOffset 
+                  - parseInt(this.map.layerContainerDiv.style.top);
+                tile.imgDiv.style.top = Math.round(newTopPos) + "px";
+
+                //set new width and height
+                tile.imgDiv.style.width = Math.round(newTileSize.w) + "px";
+                tile.imgDiv.style.height = Math.round(newTileSize.h) + "px";
+            }
+            return true;
+        }
+        else {
+            return false;
+        }
+    }, 
+
+    /** 
+     * Scales all tiles of a grid to the new tile size 
+     * (changes size and position).
+     *
+     * Default function; will override in subclasses,
+     * otherwise it returns false
+     * 
+     * @param {OpenLayers.Tile} centerTile
+     * @param {OpenLayers.Size} newTileSize
+     *
+     * @returns false if no grid is scaled
+     * @type Boolean
+     */
+    scaleTilesOfGrid:function(centertile, newTileSize) {
+        return false;
+    },
+
+
+    /**
+     * Reposition and resize the zoomOut tile to prevent a white frame
+     * during zoomOut.
+     *
+     * @param {float} newZoomlevel
+     * @param {float} newResolution
+     *
+     * @returns false if no zoomOutTile scaled
+     * @type Boolean
+     */
+    scaleZoomOutTile: function(newZoomlevel, newResolution) {
+        return false;
+    },
+
+    /**
+     * The actual zoomOutTile scale function:
+     * Reposition and resize the zoomOut tile to prevent a white frame
+     * during zoomOut.
+     *
+     * special function; shares with some baselayers; calls from subclasses
+     *
+     * @param {float} newZoomlevel
+     * @param {float} newResolution
+     *
+     * @returns true after the zoomOutTile is scaled
+     * @type Boolean
+     */
+    scaleZoomOutTile_share: function(newZoomlevel, newResolution) {
+
+        //convert the current center of the map in pixel
+        var centerPx = this.map.getPixelFromLonLat(this.map.getCenter());
+
+
+        var newTileSize = new OpenLayers.Size();
+        newTileSize.w = Math.round(this.map.tileSize.w * Math.pow(2, newZoomlevel));
+        newTileSize.h = Math.round(this.map.tileSize.h * Math.pow(2, newZoomlevel));
+
+        // handles bug in ie: 
+        // turn zoomOut tile scale off, if tileSize > 2^15 
+        var ieBug;
+        if (navigator.appName == "Microsoft Internet Explorer"){ 
+            if ((newTileSize.w > Math.pow(2,15)) &&
+                (newTileSize.h > Math.pow(2,15)) ){
+                ieBug = true;
+                this.map.baseLayer.zoomOutTile.imgDiv.style.display = "none";
+            }
+            else {
+                ieBug = false;
+            }
+        }
+        else {
+            ieBug = false;
+        }
+
+        if (!ieBug && !this.firstCall) {
+            //set new size (width and height)
+            this.zoomOutTile.imgDiv.style.width = newTileSize.w + "px";          
+            this.zoomOutTile.imgDiv.style.height = newTileSize.h + "px";
+
+            //set new position (top and left)
+            var bounds = this.zoomOutTile.bounds;
+            var extent = this.map.getExtent();
+            var maxExtent = this.map.getMaxExtent();
+
+            var resolution = this.map.getMaxResolution();
+            var centerLonLat = extent.getCenterLonLat();
+             
+            var offsetlon = bounds.left - centerLonLat.lon;
+            var offsetlat = -bounds.top + centerLonLat.lat;
+            
+            var offsetx = offsetlon / newResolution
+              - parseInt(this.map.layerContainerDiv.style.left);
+            var offsety = offsetlat / newResolution
+              - parseInt(this.map.layerContainerDiv.style.top);
+            
+            this.zoomOutTile.imgDiv.style.left = 
+                Math.round(centerPx.x + offsetx) + "px";  
+            this.zoomOutTile.imgDiv.style.top = 
+                Math.round(centerPx.y + offsety) + "px";
+        
+            
+            this.map.baseLayer.zoomOutTile.imgDiv.style.display = "block";
+        }
+        
+        return true;
+    },
+
+    /** 
+     * Clones layerContainer for "smooth tile update".
+     * So, it gets no blank map while map is loading in new zoomlevel.
+     *
+     * Default function; will override in subclasses,
+     * otherwise it returns false
+     * 
+     * @returns false if no layerContainer cloned
+     * @type Boolean
+     */
+    cloneBaseLayerDiv:function() {
+        return false;
+    },
+
+    /** 
+     * The actual clone function:
+     * Hold scaled map while tiles are loading successive.
+     *  
+     * special function; shares with some baselayers; calls from subclasses
+     *
+     */
+    cloneBaseLayerDiv_share:function() {
+        // function for map only; not for overviewmap!
+        if (this.map.div.id == "map") {  
+            
+            // 1. clone baseLayerDiv with all childs (replace, if already exist)
+            if (this.map.baseLayerDivClone){
+                this.map.layerContainerDiv.removeChild(this.map.baseLayerDivClone);
+                this.map.baseLayerDivClone = null;
+            }
+            this.map.baseLayerDivClone = this.map.baseLayer.div.cloneNode(true);
+            this.map.baseLayerDivClone.id =
+                this.map.baseLayer.div.id + "_clone";
+                    
+    
+            // 2. append baseLayerDivClone to layerContainer
+            // (now the cloned div is above the original; it hides the original)
+            this.map.layerContainerDiv.appendChild(this.map.baseLayerDivClone);
+
+            // 3. set zIndex 
+            this.map.baseLayerDivClone.style.zIndex--; 
+                
+            // 4. set zoomOut tile (of original div) invisible 
+            if (this.map.baseLayer.zoomOutTile)
+                this.map.baseLayer.zoomOutTile.imgDiv.style.display = "none";
+
+            // 5. adjust left and top position 
+            // (if map is panning before, layerContainer is displaced)
+            if (this.map.layerContainerDiv.style.left != "")
+                this.map.baseLayerDivClone.style.left += 
+                    parseInt(this.map.layerContainerDiv.style.left);
+            if (this.map.layerContainerDiv.style.top != "")
+                this.map.baseLayerDivClone.style.top += 
+                    parseInt(this.map.layerContainerDiv.style.top);           
+        }
+    },
+
+
+    /**
+     * Sets visibility of map after zoomend/loadend:
+     * - freezed/cloned layerContainer invisible
+     * 
+     * Calls automatically after fire loadend event. 
+     */
+    setLoadendVisibility: function() {
+        // set flag that zoom animation finished
+        this.map.zoomanimationActive = false;
+
+        // function for map only; not for overviewmap!
+        if (this.map.div.id == "map") {        
+            // remove cloned baseLayerDiv
+            if (this.map.baseLayerDivClone){
+                this.map.layerContainerDiv.removeChild(this.map.baseLayerDivClone);
+                this.map.baseLayerDivClone = null;
+            }
+        }
+        
+        // after map is loaded the first time the flag sets to false
+        // (reason: zoomOutTile shouldn't visible by first zoom/scale)
+        if (this.firstCall)
+            this.firstCall = false;
+    },
+
+
     /** @final @type String */
     CLASS_NAME: "OpenLayers.Layer"
 };

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Map.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Map.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Map.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -62,6 +62,9 @@
     /** @type HTMLDivElement */
     layerContainerDiv: null,
 
+    /** @type HTMLDivElement */
+    baseLayerDivClone: null, 
+
     /** ordered list of layers in the map
      * 
      * @type Array(OpenLayers.Layer)
@@ -136,6 +139,81 @@
     /** @type string */
     theme: null,
 
+
+    //ANIMATION
+    
+    /** @type Boolean */
+    animated: true,
+
+    /** steps in the slide
+     * 
+     * @type int */
+    slideSteps: 4,	
+    
+    /** millisecondss between each step
+     * 
+     * @type int */
+    slideWait: 1,
+
+    /** power used to calculate width of slide steps
+     * 
+     * @type float*/
+    slidePower: 0.7,
+
+    /** @type int */
+    animatedPanningIntervalID: null,
+
+
+    //ANIMATION
+    
+    /** @type Boolean */
+    animated: true,
+
+    /** steps in the slide
+     * 
+     * @type int */
+    slideSteps: 4,	
+    
+    /** millisecondss between each step
+     * 
+     * @type int */
+    slideWait: 1,
+
+    /** power used to calculate width of slide steps
+     * 
+     * @type float*/
+    slidePower: 0.7,
+
+
+    /** @type int */
+    animatedZoomingIntervalID: null,
+
+
+    /** @type boolean */
+    zoomanimationActive: false,
+
+    /** @type int */
+    zoomOutTileSizeFactor: 4,
+
+	/** @type int */
+    zoomlevel_startScale: null,	 
+	
+	/** @type float */
+    zoomlevel_scale: null,	 
+	 
+    /** @type OpenLayers.Size */
+    tileSize_startScale: null, 
+    
+    /** @type OpenLayers.Size */
+    tileSize_scale: null,
+ 
+    /** @type OpenLayers.Tile */
+    centerTile: null,
+    
+    /** @type float */
+    resolution_scale: null,
+
+
     /** Should OpenLayers allow events on the map to fall through to other
      *   elements on the page, or should it swallow them? (#457)
      * 
@@ -181,11 +259,13 @@
         this.events = new OpenLayers.Events(this, div, this.EVENT_TYPES, this.fallThrough);
         this.updateSize();
  
+
         // update the map size and location before the map moves
         this.events.register("movestart", this, this.updateSize);
 
         // Because Mozilla does not support the "resize" event for elements other
         // than "window", we need to put a hack here. 
+
         if (navigator.appName.contains("Microsoft")) {
             // If IE, register the resize on the div
             this.events.register("resize", this, this.updateSize);
@@ -244,7 +324,9 @@
 
         // always call map.destroy()
         OpenLayers.Event.observe(window, 'unload', this.unloadDestroy);
-
+        
+        // set tile size for scaling
+        this.tileSize_scale = new OpenLayers.Size();
     },
 
     /**
@@ -530,11 +612,18 @@
 
                 // set new baselayer and make it visible
                 this.baseLayer = newBaseLayer;
+
+                // preload a bigger tile for zooming out (not supported
+                // for every baselayer! for map only; not for ovmap!)
+                if (this.div.id == "map")
+                    this.baseLayer.setZoomOutTile(); 
                 
                 // Increment viewRequestID since the baseLayer is 
                 // changing. This is used by tiles to check if they should 
                 // draw themselves.
                 this.viewRequestID++;
+
+                // make new baselayer visible
                 this.baseLayer.setVisibility(true, noEvent);
 
                 //redraw all layers
@@ -624,6 +713,22 @@
         popup.map = null;
     },
 
+    /** Sets the map resolution during zooming/scaling.
+     * 
+     * @param {float} newResolution
+     */ 
+    setScaleResolution: function (newResolution) {
+        //calculate the current bounds of the new viewport
+        var newScaleBounds = this.calculateBounds(this.getCenter(), newResolution);
+        
+        //update the overviewMap
+        for (i=0; i<this.controls.length; i++) {
+            if (this.controls[i].CLASS_NAME == "OpenLayers.Control.OverviewMap") 
+                this.controls[i].updateOverview(newResolution, newScaleBounds);
+        }          
+    },
+
+
   /********************************************************/
   /*                                                      */
   /*              Container Div Functions                 */
@@ -677,7 +782,11 @@
                 var centerLL = this.getLonLatFromViewPortPx(center);
                 var zoom = this.getZoom();
                 this.zoom = null;
-                this.setCenter(this.getCenter(), zoom);
+                this.setCenter(this.getCenter(), zoom);  
+              
+                // reposition zoomOutTile (only if tile visible)
+                if(this.baseLayer.zoomOutTile.imgDiv.style.display != "none")
+                    this.baseLayer.scaleZoomOutTile(zoom,this.getResolution());
             }
 
         }
@@ -771,20 +880,30 @@
      * @param {int} dx
      * @param {int} dy
      */
-    pan: function(dx, dy) {
+    pan: function(dx, dy, animated) {
+        if (animated == null) { 
+ 	        animated = this.animated; 
+ 	    } 
+        
+        if (animated) {
+            this.panSlide(dx, dy, 
+                          this.slideSteps, 
+                          this.slideWait, 
+                          this.slidePower);
+        } else {
 
-        // getCenter
-        var centerPx = this.getViewPortPxFromLonLat(this.getCenter());
+            // getCenter
+            var centerPx = this.getViewPortPxFromLonLat(this.getCenter());
 
-        // adjust
-        var newCenterPx = centerPx.add(dx, dy);
-        
-        // only call setCenter if there has been a change
-        if (!newCenterPx.equals(centerPx)) {
-            var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
-            this.setCenter(newCenterLonLat);
+            // adjust
+            var newCenterPx = centerPx.add(dx, dy);
+            
+            // only call setCenter if there has been a change
+            if (!newCenterPx.equals(centerPx)) {
+                var newCenterLonLat = this.getLonLatFromViewPortPx(newCenterPx);
+                this.setCenter(newCenterLonLat);
+            }
         }
-
    },
 
     /**
@@ -900,7 +1019,92 @@
             this.layerContainerDiv.style.top  = (originPx.y - newPx.y) + "px";
         }
     },
+    /** Position changer with Memory by www.hesido.com
+     *  modified by dncpax for OpenLayers
+     * 
+     * @param {int} slideX
+     * @param {int} slideY
+     * @param {int} totalSteps
+     * @param {int} intervals
+     * @param {float} power 
+     */
+    panSlide: function( slideX, slideY, totalSteps, interval, power) {
+        if (this.animatedPanningIntervalID) {
+            window.clearInterval(this.animatedPanningIntervalID);
+            this.animatedPanningIntervalID = null;
+        }
+        var context = {
+            'map': this,
+            'slideX': slideX,
+            'slideY': slideY,
+            'totalSteps': totalSteps,
+            'step': 0,
+            'power': power
+        };
+        var move = function() {
+            var dx = OpenLayers.Util.easeInOutPan(this.slideX, 
+                                                this.totalSteps, 
+                                                this.step, 
+                                                this.power);
+            var dy = OpenLayers.Util.easeInOutPan(this.slideY,
+                                                this.totalSteps, 
+                                                this.step, 
+                                                this.power);
+            this.map.pan(dx, dy, false);
+            this.step++;
+            if (this.step > this.totalSteps) {
+                window.clearInterval(this.map.animatedPanningIntervalID);
+                this.map.animatedPanningIntervalID = null;
+            }
+        };
 
+        this.animatedPanningIntervalID = 
+            window.setInterval(move.bindAsEventListener(context), 
+                               interval);
+    },
+
+
+    /** Position changer with Memory by www.hesido.com
+     *  modified by dncpax for OpenLayers
+     * 
+     * @param {int} slideZoom
+     * @param {int} totalSteps
+     * @param {int} intervals
+     * @param {float} power 
+     */
+    zoomSlide: function( slideZoom, totalSteps, interval, power) {
+        if (this.animatedZoomingIntervalID) {
+            window.clearInterval(this.animatedZoomingIntervalID);
+            this.animatedZoomingIntervalID = null;
+        }
+        var context = {
+            'map': this,
+            'slideZoom': slideZoom,
+            'totalSteps': totalSteps,
+            'step': 0,
+            'power': power
+        };
+        var move = function() {
+            var delta = this.slideZoom - this.map.zoom;
+            var dZoom = OpenLayers.Util.easeInOutZoom(delta, 
+                                                this.totalSteps, 
+                                                this.step, 
+                                                this.power);
+
+            this.map.zoomTo(this.map.zoom + dZoom, false, this.step);
+            this.step++;
+            if (this.step > this.totalSteps) {
+                window.clearInterval(this.map.animatedZoomingIntervalID);
+                this.map.animatedZoomingIntervalID = null;
+            }
+        };
+
+        this.animatedZoomingIntervalID = 
+            window.setInterval(move.bindAsEventListener(context), 
+                               interval);
+    },
+
+
     /**
      * @private 
      * 
@@ -935,6 +1139,7 @@
         return valid;
     },
 
+
   /********************************************************/
   /*                                                      */
   /*                 Layer Options                        */
@@ -1087,26 +1292,67 @@
   
     /** Zoom to a specific zoom level
      * 
-     * @param {int} zoom
+     * @param {float} zoom
+     * @param {Boolean} animated 
+     * @param {int} step
+     * 
      */
-    zoomTo: function(zoom) {
+    zoomTo: function(zoom, animated, step) {
         if (this.isValidZoomLevel(zoom)) {
-            this.setCenter(null, zoom);
+            if (animated == null) { 
+                animated = this.animated; 
+            } 
+
+            if (animated) {
+                this.zoomSlide(zoom, 
+                              this.slideSteps, 
+                              this.slideWait, 
+                              this.slidePower);
+                
+                // prepare zoom animation
+                this.prepareZoomAnimation();
+            } else {
+                
+                if (step <= this.slideSteps ) {
+
+                    // set new zoomlevel from zoomSlide function
+                    this.zoomlevel_scale = zoom;
+
+                    // run zoom animation -> scale tile(s)
+                    this.runZoomAnimation(null,null);
+                }
+
+                // finish scaling -> redraw map in new zoomlevel
+                // or no animation set
+                if ( (step == this.slideSteps)
+                  || ((step == null)&&(!animated)) ){
+ 
+                    this.finishZoomAnimation(zoom);
+                }
+            }
         }
     },
     
     /**
      * @param {int} zoom
      */
-    zoomIn: function() {
-        this.zoomTo(this.getZoom() + 1);
+    zoomIn: function(animated) {
+        if (animated==null)
+            animated = true;
+
+        if (!this.zoomanimationActive)
+            this.zoomTo(this.getZoom() + 1,animated, null);
     },
     
     /**
      * @param {int} zoom
      */
-    zoomOut: function() {
-        this.zoomTo(this.getZoom() - 1);
+    zoomOut: function(animated) {
+        if (animated==null)
+            animated = true;
+
+        if (!this.zoomanimationActive)
+            this.zoomTo(this.getZoom() - 1,animated, null);
     },
 
     /** Zoom to the passed in bounds, recenter
@@ -1114,8 +1360,14 @@
      * @param {OpenLayers.Bounds} bounds
      */
     zoomToExtent: function(bounds) {
-        this.setCenter(bounds.getCenterLonLat(), 
-                       this.getZoomForExtent(bounds));
+        // recenter map to new center of bounds (in OLD zoom level)
+        this.setCenter(bounds.getCenterLonLat(), this.getZoom());
+        
+        // determine new zoomlevel 
+        var newZoomlevel = this.getZoomForExtent(bounds);
+        
+        // zoom to new zoomlevel
+        this.zoomTo(newZoomlevel);
     },
 
     /** Zoom to the full extent and recenter.
@@ -1142,7 +1394,167 @@
                                            center.lat + h_deg / 2);
         this.zoomToExtent(extent);
     },
+ 
     
+    /**
+     * get and set some settings for zoom animation
+     *
+     *
+     */
+    prepareZoomAnimation:function() {
+        // begin zoom animation -> set flag
+        this.zoomanimationActive = true;
+        
+        // get current zoomlevel
+        this.zoomlevel_startScale = this.zoom;
+
+        // get current tile size (it's the base for scaling)
+        this.tileSize_startScale = this.baseLayer.getTileSize();
+      
+        // get tile, which contains the center of the viewport
+        this.centerTile = this.baseLayer.getCenterTile();   
+
+        // set all active overlays temporarily invisible
+        for (var i = 0; i < this.layers.length; i++) {
+            var layer = this.layers[i];
+            if (!layer.isBaseLayer) {
+                this.layers[i].div.style.display = "none";
+            }
+        }       
+
+        // set all tiles outside the viewport invisible
+        // (only for baselayers with grid of tiles)
+        this.baseLayer.setTilesOutsideInvisible();
+    },
+
+    /**
+     * run zoom animation -> scale tile(s)   
+     *
+     * @param {int} zoomStopHeight
+     * @param {OpenLayers.Pixel} sliderPosition
+     */
+    runZoomAnimation:function(zoomStopHeight, sliderPosition) {
+        // scale baselayer if tileSize and centerTile is set
+        if ( this.tileSize_startScale && this.centerTile ) {
+
+            // determine zoomlevel (only if slider used ->zoomStopHeight exists)
+            if (zoomStopHeight && sliderPosition )
+                this.calculateNewZoomlevel(zoomStopHeight,sliderPosition);
+           
+            // determine tile size and map resolution
+            this.calculateNewTileSize();
+
+            // get tile, which contains the center of the viewport again
+            // (it's necessary for synchronous animated panning and zooming)
+            if (!zoomStopHeight)
+                this.centerTile = this.baseLayer.getCenterTile();  
+
+            // scale (center) tile to new scaled size	
+            this.baseLayer.scaleTileTo(this.centerTile, 
+                                            this.tileSize_scale);
+            
+            // scale all tiles to new scaled size (if there
+            // are more than one tile)
+            this.baseLayer.scaleTilesOfGrid(this.centerTile, 
+                                            this.tileSize_scale);
+
+            // scale zoomOut tile (to prevent a white frame during zoomOut)
+            this.baseLayer.scaleZoomOutTile(this.zoomlevel_scale, 
+                                            this.resolution_scale);
+
+            // set new scaled map resolution (important for overviewmap)
+            this.setScaleResolution(this.resolution_scale);
+
+            // update zoom slider position (only if slider NOT used ->
+            // zoomStopHeight not exisits)
+            if (!zoomStopHeight){
+                for (i=0; i<this.controls.length; i++) {
+                    if (this.controls[i].CLASS_NAME == "OpenLayers.Control.PanZoomBar") 
+                        this.controls[i].moveZoomBar(this.zoomlevel_scale);
+                }  
+            }
+        }
+    },
+
+     /**
+     * finish zoom animation
+     * 
+     * @param {int} finalZoomlevel
+     */
+    finishZoomAnimation:function(finalZoomlevel) {
+        // clone layerContainer for "smooth tile update" without blank map
+        this.baseLayer.cloneBaseLayerDiv();
+       
+        // zooom to final zoomlevel 
+        if (this.isValidZoomLevel(finalZoomlevel))
+            this.setCenter(null, finalZoomlevel);
+
+        // call loadend event function _manually_ 
+        // (only for baselayers without onimageload events, f.e. imagelayer
+        // and for ie, where the loadend event doesn't works correctly);
+        // for all other layers it calls automatically from
+        // loadendevent in layers.js
+        if (this.baseLayer.CLASS_NAME.match("OpenLayers.Layer.Image") ||
+            (navigator.appName == "Microsoft Internet Explorer") ){
+            this.baseLayer.setLoadendVisibility();
+        }
+    },
+
+
+    /**
+     * Calculates new zoomlevel of current zoomslider position.
+     * 
+     * @param {int} zoomStopHeight
+     * @param {OpenLayers.Pixel} sliderPosition
+     */
+    calculateNewZoomlevel:function(zoomStopHeight, sliderPosition) {
+        // convert current sliderposition to new zoomlevel
+        var deltaY_zoomlevel = this.zoomStart.y - sliderPosition.y;
+        this.zoomlevel_scale = this.zoomlevel_startScale + 
+          deltaY_zoomlevel/zoomStopHeight;
+       
+        // check zoomlevel validity	
+        if (this.zoomlevel_scale < 0) {
+            this.zoomlevel_scale = 0; 
+        } 
+        if (this.zoomlevel_scale > (this.getNumZoomLevels()- 1)) { 
+            this.zoomlevel_scale = this.getNumZoomLevels() - 1; 
+        }
+    },
+
+
+    /**
+     * Calculates new tile size and map resolution of current zoomlevel.
+     *
+     */
+    calculateNewTileSize:function() {
+        // calculate new tile size for...
+        // ...zoomIn
+        if (this.zoomlevel_startScale < this.zoomlevel_scale) {
+            this.tileSize_scale.w = Math.pow(2,(this.zoomlevel_scale -
+              this.zoomlevel_startScale)) * this.tileSize_startScale.w;
+            this.tileSize_scale.h = Math.pow(2,(this.zoomlevel_scale -
+              this.zoomlevel_startScale)) * this.tileSize_startScale.h;
+
+            // set new map resolution
+            this.resolution_scale = 1/(Math.pow(2,(this.zoomlevel_scale - 
+              this.zoomlevel_startScale))) *  this.getResolution();    
+        }
+        // ...zoomOut / no zoom changes
+        if (this.zoomlevel_startScale >= this.zoomlevel_scale) {             
+            this.tileSize_scale.w = 1/(Math.pow(2,(this.zoomlevel_startScale -
+              this.zoomlevel_scale))) * this.tileSize_startScale.w;
+            this.tileSize_scale.h = 1/(Math.pow(2,(this.zoomlevel_startScale - 
+              this.zoomlevel_scale))) * this.tileSize_startScale.h;
+
+            // set new map resolution
+            this.resolution_scale = Math.pow(2,(this.zoomlevel_startScale - 
+              this.zoomlevel_scale)) * this.getResolution(); 
+        }
+    },
+
+
+
   /********************************************************/
   /*                                                      */
   /*             Translation Functions                    */

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Tile/Image.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Tile/Image.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Tile/Image.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -11,24 +11,11 @@
 OpenLayers.Tile.Image = OpenLayers.Class.create();
 OpenLayers.Tile.Image.prototype = 
   OpenLayers.Class.inherit( OpenLayers.Tile, {
-
-    /** @type String */
-    url: null,
     
     /** @type DOMElement img */
     imgDiv: null,
 
-    /**
-     * The image element is appended to the frame.  Any gutter on the image 
-     * will be hidden behind the frame. 
-     * 
-     * @type DOMElement div */ 
-    frame: null, 
-
-    /** TBD 3.0 - reorder the parameters to the init function to put URL 
-     *             as last, so we can continue to call tile.initialize() 
-     *             without changing the arguments. 
-     * 
+    /** 
     * @constructor
     *
     * @param {OpenLayers.Grid} layer
@@ -39,30 +26,17 @@
     */
     initialize: function(layer, position, bounds, url, size) {
         OpenLayers.Tile.prototype.initialize.apply(this, arguments);
-
-        this.url = url;
-
-        this.frame = document.createElement('div'); 
-        this.frame.style.overflow = 'hidden'; 
-        this.frame.style.position = 'absolute'; 
     },
 
     /**
      * 
      */
     destroy: function() {
-        if (this.imgDiv != null)  {
-            OpenLayers.Event.stopObservingElement(this.imgDiv.id);
-            if (this.imgDiv.parentNode == this.frame) {
-                this.frame.removeChild(this.imgDiv);
-                this.imgDiv.map = null;
-            }
+        if ((this.imgDiv != null) && (this.imgDiv.parentNode == this.layer.div)) {
+            this.layer.div.removeChild(this.imgDiv);
+            this.imgDiv.map = null;
         }
         this.imgDiv = null;
-        if ((this.frame != null) && (this.frame.parentNode == this.layer.div)) { 
-            this.layer.div.removeChild(this.frame); 
-        }
-        this.frame = null; 
         OpenLayers.Tile.prototype.destroy.apply(this, arguments);
     },
 
@@ -83,17 +57,14 @@
         this.imgDiv.viewRequestID = this.layer.map.viewRequestID;
         
         this.url = this.layer.getURL(this.bounds);
-        // position the frame 
-        OpenLayers.Util.modifyDOMElement(this.frame, 
-                                         null, this.position, this.size);   
-
+  
         if (this.layer.alpha) {
             OpenLayers.Util.modifyAlphaImageDiv(this.imgDiv,
-                    null, null, this.layer.imageSize, this.url);
+                    null, this.position, this.size, this.url);
         } else {
             this.imgDiv.src = this.url;
             OpenLayers.Util.modifyDOMElement(this.imgDiv,
-                    null, null, this.layer.imageSize) ;
+                    null, this.position, this.size) ;
         }
         this.drawn = true;
         return true;
@@ -128,20 +99,20 @@
     initImgDiv: function() {
         if (this.layer.alpha) {
             this.imgDiv = OpenLayers.Util.createAlphaImageDiv(null,
-                                                           this.layer.imageOffset,
-                                                           this.layer.imageSize,
+                                                           this.position,
+                                                           this.size,
                                                            null,
-                                                           "relative",
+                                                           "absolute",
                                                            null,
                                                            null,
                                                            null,
                                                            true);
         } else {
             this.imgDiv = OpenLayers.Util.createImage(null,
-                                                      this.layer.imageOffset,
-                                                      this.layer.imageSize,
+                                                      this.position,
+                                                      this.size,
                                                       null,
-                                                      "relative",
+                                                      "absolute",
                                                       null,
                                                       null,
                                                       true);
@@ -157,9 +128,7 @@
         OpenLayers.Event.observe( this.imgDiv, "load",
                         this.checkImgURL.bindAsEventListener(this) );
         */
-        this.frame.appendChild(this.imgDiv); 
-        this.layer.div.appendChild(this.frame); 
-
+        this.layer.div.appendChild(this.imgDiv);
         if(this.layer.opacity != null) {
             
             OpenLayers.Util.modifyDOMElement(this.imgDiv, null, null, null,

Modified: sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Util.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Util.js	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/lib/OpenLayers/Util.js	2007-05-26 19:11:05 UTC (rev 3189)
@@ -966,3 +966,38 @@
     }
     return head;
 };
+
+
+/** Generic Animation Step Value Generator By www.hesido.com, slightly modified
+ * 
+ * 
+ * @param {int} delta
+ * @param {int} totalSteps
+ * @param {int} step
+ * @param {float} power
+ * 
+ * @returns The delta to the next position in the pan animation movement
+ * @type int
+ */
+OpenLayers.Util.easeInOutPan = function(delta, totalSteps, step, power) {
+    var prevStepVal = Math.pow(((1/totalSteps)*(step-1)),power) * delta;
+    var stepVal = Math.pow(((1/totalSteps)*step),power) * delta;
+    return Math.ceil(stepVal) - Math.ceil(prevStepVal);
+};
+
+
+/** Generic Animation Step Value Generator By www.hesido.com, slightly modified
+ * 
+ * 
+ * @param {int} delta
+ * @param {int} totalSteps
+ * @param {int} step
+ * @param {float} power
+ * 
+ * @returns The next zoomlevel in the zoom animation movement
+ * @type float
+ */
+OpenLayers.Util.easeInOutZoom = function(delta, totalSteps, step, power) {
+    var stepVal = Math.pow(((1/totalSteps)*step),power) * delta;
+    return stepVal; 
+};

Modified: sandbox/emanuel/animatedZooming_final/tests/Control/test_MouseToolbar.html
===================================================================
--- trunk/openlayers/tests/Control/test_MouseToolbar.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Control/test_MouseToolbar.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -45,7 +45,9 @@
             control.defaultMouseDown(evt);
             evt.xy = new OpenLayers.Size(15,15);
             control.defaultMouseUp(evt);
-            t.eq(map.getZoom(), 6, "Map zoom set correctly after zoombox");
+            t.delay_call( 1, function() {
+                t.eq(map.getZoom(), 6, "Map zoom set correctly after zoombox");
+            });
         } else {
             t.ok(true, "IE does not run this test.") 
         }

Modified: sandbox/emanuel/animatedZooming_final/tests/Control/test_OverviewMap.html
===================================================================
--- trunk/openlayers/tests/Control/test_OverviewMap.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Control/test_OverviewMap.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -3,13 +3,13 @@
   <script src="../../lib/OpenLayers.js"></script>
   <script type="text/javascript"><!--
     var map; 
-    function test_01_Control_PanZoom_constructor (t) {
+    function test_01_Control_OverviewMap_constructor (t) {
         t.plan( 1 );
     
         control = new OpenLayers.Control.OverviewMap();
         t.ok( control instanceof OpenLayers.Control.OverviewMap, "new OpenLayers.Control.OverviewMap returns object" );
     }
-    function test_02_Control_PanZoom_addControl (t) {
+    function test_02_Control_OverviewMap_addControl (t) {
         t.plan( 6 );
         map = new OpenLayers.Map('map');
         control = new OpenLayers.Control.OverviewMap();
@@ -23,7 +23,7 @@
 
         map.destroy();
     }
-    function test_03_Control_PanZoom_control_events (t) {
+    function test_03_Control_OverviewMap_control_events (t) {
         t.plan( 10 );
         var evt = {which: 1}; // control expects left-click
         map = new OpenLayers.Map('map');
@@ -44,30 +44,72 @@
         t.eq(overviewCenter.lat, 42, "Overviewmap center lat correct");
         t.eq(overviewZoom, 8, "Overviewmap zoomcorrect");
         
-        control.mapDivClick({'xy':new OpenLayers.Pixel(5,5)});
-        
-        var cent = map.getCenter();
-        t.eq(cent.lon, -71.3515625, "Clicking on the Overview Map has the correct effect on map lon");
-        t.eq(cent.lat, 42.17578125, "Clicking on the Overview Map has the correct effect on map lat");
+        control.mapDivDblClick({'xy':new OpenLayers.Pixel(5,5)});
+        t.delay_call(
+            1, function() {
+                var cent = map.getCenter();
+                t.eq(cent.lon, -71.3515625, "Clicking on the Overview Map has the correct effect on map lon");
+                t.eq(cent.lat, 42.17578125, "Clicking on the Overview Map has the correct effect on map lat");
 
-        control.rectMouseDown({'xy':new OpenLayers.Pixel(5,5), 'which':1});
-        control.rectMouseMove({'xy':new OpenLayers.Pixel(15,15), 'which':1});
-        control.rectMouseUp({'xy':new OpenLayers.Pixel(15,15), 'which':1});
-        
-        var cent = map.getCenter();
-        t.eq(cent.lon, -71.2734375, "Dragging on the Overview Map has the correct effect on map lon");
-        t.eq(cent.lat, 42.09765625, "Dragging on the Overview Map has the correct effect on map lat");
-        
-        map.setCenter(new OpenLayers.LonLat(0,0), 0);
-        var overviewCenter = control.ovmap.getCenter();
-        var overviewZoom = control.ovmap.getZoom();
-        t.eq(overviewCenter.lon, 0, "Overviewmap center lon correct -- second zoom");
-        t.eq(overviewCenter.lat, 0, "Overviewmap center lat correct -- second zoom");
-        t.eq(overviewZoom, 0, "Overviewmap zoomcorrect -- second zoom");
-        
-        map.destroy();
+                control.rectMouseDown({'xy':new OpenLayers.Pixel(5,5), 'which':1});
+                control.rectMouseMove({'xy':new OpenLayers.Pixel(15,15), 'which':1});
+                control.rectMouseUp({'xy':new OpenLayers.Pixel(15,15), 'which':1});
+            },
+            
+            1, function() {
+                var cent = map.getCenter();
+                t.eq(cent.lon, -71.27328491210938, "Dragging on the Overview Map has the correct effect on map lon");
+                t.eq(cent.lat, 42.09407043457031, "Dragging on the Overview Map has the correct effect on map lat");
+                
+                map.setCenter(new OpenLayers.LonLat(0,0), 0);
+                var overviewCenter = control.ovmap.getCenter();
+                var overviewZoom = control.ovmap.getZoom();
+                t.eq(overviewCenter.lon, 0, "Overviewmap center lon correct -- second zoom");
+                t.eq(overviewCenter.lat, 0, "Overviewmap center lat correct -- second zoom");
+                t.eq(overviewZoom, 0, "Overviewmap zoomcorrect -- second zoom");
+                map.destroy();
+           }
+        );
+    }
 
+    function test_04_Control_OverviewMap_updateRectToMap (t) {
+        t.plan( 4 );
+
+        map = new OpenLayers.Map('map');
+        var layer = new OpenLayers.Layer.WMS("Test Layer", 
+            "http://octo.metacarta.com/cgi-bin/mapserv?",
+            {map: "/mapdata/vmap_wms.map", layers: "basic"});
+        map.addLayer(layer);
+
+        control = new OpenLayers.Control.OverviewMap();
+        map.addControl(control, new OpenLayers.Pixel(20,20));
+        map.setCenter(new OpenLayers.LonLat(0,0), 5);
+        control.updateRectToMap();
+        t.eq(control.extentRectangle.style.left, "45px", "rectangle left position has been set correctly");
+        t.eq(control.extentRectangle.style.top, "23px", "rectangle top position has been set correctly");
+        t.eq(control.extentRectangle.style.width, "90px", "rectangle width position has been set correctly");
+        t.eq(control.extentRectangle.style.height, "45px", "rectangle height position has been set correctly");
     }
+
+    function test_05_Control_OverviewMap_updateMapToRect (t) {
+        t.plan( 4 );
+
+        map = new OpenLayers.Map('map');
+        var layer = new OpenLayers.Layer.WMS("Test Layer", 
+            "http://octo.metacarta.com/cgi-bin/mapserv?",
+            {map: "/mapdata/vmap_wms.map", layers: "basic"});
+        map.addLayer(layer);
+
+        control = new OpenLayers.Control.OverviewMap();
+        map.addControl(control, new OpenLayers.Pixel(20,20));
+        map.setCenter(new OpenLayers.LonLat(0,0), 5);
+        control.updateRectToMap();
+        t.eq(control.extentRectangle.style.left, "45px", "rectangle left position has been set correctly");
+        t.eq(control.extentRectangle.style.top, "23px", "rectangle top position has been set correctly");
+        t.eq(control.extentRectangle.style.width, "90px", "rectangle width position has been set correctly");
+        t.eq(control.extentRectangle.style.height, "45px", "rectangle height position has been set correctly");
+    }
+
   // -->
   </script>
 </head>

Modified: sandbox/emanuel/animatedZooming_final/tests/Control/test_PanZoom.html
===================================================================
--- trunk/openlayers/tests/Control/test_PanZoom.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Control/test_PanZoom.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -30,132 +30,12 @@
         t.eq( control2.div.style.top, "100px", "2nd control div is located correctly");
     }
 
-    function test_03_Control_PanZoom_control_events (t) {
 
-        if ( !window.document.createEvent ) {
-            //ie can't simulate mouseclicks
-            t.plan(0)
-        } else {
-            t.plan(35);
-            t.open_window( "Control/test_PanZoom.html", function( wnd ) {
-                t.delay_call( 3, function() {
-                    var flag;
-                    function setFlag(evt) {
-                        flag[evt.type] = true;
-                    }
-                    function resetFlags() {
-                        flag = {
-                            mousedown: false,
-                            mouseup: false,
-                            click: false,
-                            dblclick: false
-                        };
-                    }
-                    resetFlags();
-                    
-                    wnd.mapper.events.register("mousedown", mapper, setFlag);
-                    wnd.mapper.events.register("mouseup", mapper, setFlag);
-                    wnd.mapper.events.register("click", mapper, setFlag);
-                    wnd.mapper.events.register("dblclick", mapper, setFlag);
-                    
-                    simulateClick(wnd, wnd.control.buttons[0]);
-                    t.ok( wnd.mapper.getCenter().lat > wnd.centerLL.lat, "Pan up works correctly" );
-                    t.ok(!flag.mousedown, "mousedown does not get to the map");
-                    t.ok(!flag.mouseup, "mouseup does not get to the map");
-                    t.ok(!flag.click, "click does not get to the map");
-                    t.ok(!flag.dblclick, "dblclick does not get to the map");
-                    resetFlags();
-
-                    simulateClick(wnd, wnd.control.buttons[1]);
-                    t.ok( wnd.mapper.getCenter().lon < wnd.centerLL.lon, "Pan left works correctly" );
-                    t.ok(!flag.mousedown, "mousedown does not get to the map");
-                    t.ok(!flag.mouseup, "mouseup does not get to the map");
-                    t.ok(!flag.click, "click does not get to the map");
-                    t.ok(!flag.dblclick, "dblclick does not get to the map");
-                    resetFlags();
-
-                    simulateClick(wnd, wnd.control.buttons[2]);
-                    t.ok( wnd.mapper.getCenter().lon == wnd.centerLL.lon, "Pan right works correctly" );
-                    t.ok(!flag.mousedown, "mousedown does not get to the map");
-                    t.ok(!flag.mouseup, "mouseup does not get to the map");
-                    t.ok(!flag.click, "click does not get to the map");
-                    t.ok(!flag.dblclick, "dblclick does not get to the map");
-                    resetFlags();
-
-                    simulateClick(wnd, wnd.control.buttons[3]);
-                    t.ok( wnd.mapper.getCenter().lat == wnd.centerLL.lat, "Pan down works correctly" );
-                    t.ok(!flag.mousedown, "mousedown does not get to the map");
-                    t.ok(!flag.mouseup, "mouseup does not get to the map");
-                    t.ok(!flag.click, "click does not get to the map");
-                    t.ok(!flag.dblclick, "dblclick does not get to the map");
-                    resetFlags();
-
-                    simulateClick(wnd, wnd.control.buttons[4]);
-                    t.eq( wnd.mapper.getZoom(), 6, "zoomin works correctly" );
-                    t.ok(!flag.mousedown, "mousedown does not get to the map");
-                    t.ok(!flag.mouseup, "mouseup does not get to the map");
-                    t.ok(!flag.click, "click does not get to the map");
-                    t.ok(!flag.dblclick, "dblclick does not get to the map");
-                    resetFlags();
-
-                    simulateClick(wnd, wnd.control.buttons[6]);
-                    t.eq( wnd.mapper.getZoom(), 5, "zoomout works correctly" );
-                    t.ok(!flag.mousedown, "mousedown does not get to the map");
-                    t.ok(!flag.mouseup, "mouseup does not get to the map");
-                    t.ok(!flag.click, "click does not get to the map");
-                    t.ok(!flag.dblclick, "dblclick does not get to the map");
-                    resetFlags();
-
-                    simulateClick(wnd, wnd.control.buttons[5]);
-                    t.eq( wnd.mapper.getZoom(), 2, "zoomworld works correctly" );
-                    t.ok(!flag.mousedown, "mousedown does not get to the map");
-                    t.ok(!flag.mouseup, "mouseup does not get to the map");
-                    t.ok(!flag.click, "click does not get to the map");
-                    t.ok(!flag.dblclick, "dblclick does not get to the map");
-                    resetFlags();
-                    
-                });
-            });
-        }
-    }
-
-    function simulateClick(wnd, elem) {
-      var evt = wnd.document.createEvent("MouseEvents");
-      evt.initMouseEvent("mousedown", true, true, wnd, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-      elem.dispatchEvent(evt);
-
-      evt = wnd.document.createEvent("MouseEvents");
-      evt.initMouseEvent("mouseup", true, true, wnd, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-      elem.dispatchEvent(evt);
-
-      evt = wnd.document.createEvent("MouseEvents");
-      evt.initMouseEvent("click", true, true, wnd, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-      elem.dispatchEvent(evt);
-
-      evt = wnd.document.createEvent("MouseEvents");
-      evt.initMouseEvent("dblclick", true, true, wnd, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
-      elem.dispatchEvent(evt);
-    }
-
-    function loader() {
-        control = new OpenLayers.Control.PanZoom();
-    
-        mapper = new OpenLayers.Map('map', { controls: [control]});
         
-    
-        var layer = new OpenLayers.Layer.WMS("Test Layer", 
-            "http://octo.metacarta.com/cgi-bin/mapserv?",
-            {map: "/mapdata/vmap_wms.map", layers: "basic"});
-        mapper.addLayer(layer);
-    
-        centerLL = new OpenLayers.LonLat(0,0); 
-        mapper.setCenter(centerLL, 5);
-    }
-        
   // -->
   </script>
 </head>
-<body onload="loader()">
+<body >
     <div id="map" style="width: 1024px; height: 512px;"/>
 </body>
 </html>

Modified: sandbox/emanuel/animatedZooming_final/tests/Control/test_PanZoomBar.html
===================================================================
--- trunk/openlayers/tests/Control/test_PanZoomBar.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Control/test_PanZoomBar.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -32,6 +32,48 @@
         map.addControl(control2, new OpenLayers.Pixel(100,100));
         t.eq( control2.div.style.top, "100px", "2nd control div is located correctly");
     }
+
+    function test_03_Control_PanZoomBar_control_events (t) {
+        t.plan( 3 );
+
+        var evt = {which: 1}; // control expects left-click
+        map = new OpenLayers.Map('map');
+        var layer = new OpenLayers.Layer.WMS("Test Layer", 
+            "http://octo.metacarta.com/cgi-bin/mapserv?",
+            {map: "/mapdata/vmap_wms.map", layers: "basic"});
+        map.addLayer(layer);
+        control = new OpenLayers.Control.PanZoomBar();
+        map.addControl(control);
+        var centerLL = new OpenLayers.LonLat(0,0); 
+        map.setCenter(centerLL, 0);
+
+        evt.xy = new OpenLayers.Pixel(10,115); 
+        evt.object = control;
+        control.divClick(evt);
+        t.delay_call(
+            1, function() {
+                t.eq(map.zoom, 5, 
+                    "Clicking on the zoombar has the correct effect on zoomlevel");
+
+                control.zoomBarDown(evt);
+                evt.xy.y -= 30;  
+                control.zoomBarDrag(evt);
+
+                control.zoomBarUp(evt);
+            },
+            1, function() {
+                t.eq(map.zoom, 8, 
+                    "Dragging the zoomslider works correctly");
+                t.eq(control.slider.style.top, "159px", 
+                    "Zoomslider top position has been set correctly");
+            }
+
+        );
+        
+
+
+    }
+
   // -->
   </script>
 </head>

Modified: sandbox/emanuel/animatedZooming_final/tests/Control/test_Permalink.html
===================================================================
--- trunk/openlayers/tests/Control/test_Permalink.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Control/test_Permalink.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -17,14 +17,16 @@
         map = new OpenLayers.Map('map');
         layer = new OpenLayers.Layer.WMS('Test Layer', "http://octo.metacarta.com/cgi-bin/mapserv", {map: '/mapdata/vmap_wms.map', layers: 'basic', format: 'image/jpeg'});
         map.addLayer(layer);
-        if (!map.getCenter())  map.zoomToMaxExtent();
+        if (!map.getCenter())  map.setCenter(0,0);
         map.addControl(control);
         map.pan(5, 0);
-        if (/MSIE/.test(navigator.userAgent)) {
-            t.eq(OpenLayers.Util.getElement('permalink').href, "?lat=0&lon=1.75781&zoom=2&layers=B", "Panning sets permalink");
-        } else {
-            t.eq(OpenLayers.Util.getElement('permalink').href, location+"?lat=0&lon=1.75781&zoom=2&layers=B", "Panning sets permalink");
-        }
+        t.delay_call( 1, function() {
+            if (/MSIE/.test(navigator.userAgent)) {
+                t.eq(OpenLayers.Util.getElement('permalink').href, "?lat=0&lon=7.03125&zoom=0&layers=B", "Panning sets permalink");
+            } else {
+                t.eq(OpenLayers.Util.getElement('permalink').href, location+"?lat=0&lon=7.03125&zoom=0&layers=B", "Panning sets permalink");
+            }
+        });
     }
     function test_03_Control_Permalink_updateLinksBase (t) {
         t.plan( 2 );
@@ -37,8 +39,10 @@
         if (!map.getCenter())  map.zoomToMaxExtent();
         map.addControl(control);
         map.pan(5, 0);
-        OpenLayers.Util.getElement('edit_permalink').href = './edit.html?lat=0&lon=1.75781&zoom=2&layers=B';
-        t.eq(OpenLayers.Util.getElement('permalink').href, OpenLayers.Util.getElement('edit_permalink').href, "Panning sets permalink with base");
+        t.delay_call( 1, function() {
+            OpenLayers.Util.getElement('edit_permalink').href = './edit.html?lat=0&lon=7.03125&zoom=2&layers=B';
+            t.eq(OpenLayers.Util.getElement('permalink').href, OpenLayers.Util.getElement('edit_permalink').href, "Panning sets permalink with base");
+        });
   }
   function test_04_Control_Permalink_noElement (t) {
         t.plan( 2 );

Modified: sandbox/emanuel/animatedZooming_final/tests/Control/test_Scale.html
===================================================================
--- trunk/openlayers/tests/Control/test_Scale.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Control/test_Scale.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -18,13 +18,28 @@
         layer = new OpenLayers.Layer.WMS('Test Layer', "http://octo.metacarta.com/cgi-bin/mapserv", {map: '/mapdata/vmap_wms.map', layers: 'basic', format: 'image/jpeg'});
         map.addLayer(layer);
         map.zoomTo(0);
-        map.addControl(control);
-        t.eq(OpenLayers.Util.getElement('scale').innerHTML, "Scale = 1 : 443M", "Scale set by default."  );
-        map.zoomIn();
-        t.eq(OpenLayers.Util.getElement('scale').innerHTML, "Scale = 1 : 221M", "Zooming in changes scale"  );
-        map.baseLayer.resolutions = [OpenLayers.Util.getResolutionFromScale(110)];
-        map.zoomTo(0);
-        t.eq(OpenLayers.Util.getElement('scale').innerHTML, "Scale = 1 : 110", "Scale of 100 isn't rounded"  );
+        t.delay_call( 
+            1, function() {
+                map.addControl(control);
+                t.eq(OpenLayers.Util.getElement('scale').innerHTML, "Scale = 1 : 443M", "Scale set by default."  );
+                // set zoomanimation flag manually, 
+                // reason: loadend event in layers.js will not achieved in unittests
+                map.zoomanimationActive = false;
+                map.zoomIn();
+            },
+            1, function() {
+                t.eq(OpenLayers.Util.getElement('scale').innerHTML, "Scale = 1 : 221M", "Zooming in changes scale"  );
+                
+                // set zoomanimation flag manually, 
+                // reason: loadend event in layers.js will not achieved in unittests
+                map.zoomanimationActive = false;
+                map.baseLayer.resolutions = [OpenLayers.Util.getResolutionFromScale(110)];
+                map.zoomTo(0,false);
+            },
+            1, function() {
+                t.eq(OpenLayers.Util.getElement('scale').innerHTML, "Scale = 1 : 110", "Scale of 100 isn't rounded"  );
+            }
+        );
     }
     function test_03_Control_Scale_internalScale (t) {
         t.plan(2);

Modified: sandbox/emanuel/animatedZooming_final/tests/Layer/test_Grid.html
===================================================================
--- trunk/openlayers/tests/Layer/test_Grid.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Layer/test_Grid.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -3,6 +3,7 @@
   <script src="../../lib/OpenLayers.js"></script>
   <script type="text/javascript"><!--
     var isMozilla = (navigator.userAgent.indexOf("compatible") == -1);
+    var map;
     var layer; 
 
     var name = 'Test Layer';
@@ -32,7 +33,7 @@
 
     function test_02_Layer_Grid_inittiles (t) {
         t.plan( 2 );
-        var map = new OpenLayers.Map('map');
+        map = new OpenLayers.Map('map');
         layer = new OpenLayers.Layer.WMS(name, url, params);
         map.addLayer(layer);
         map.setCenter(new OpenLayers.LonLat(0,0),5);
@@ -43,7 +44,7 @@
 
     function test_03_Layer_Grid_clearTiles (t) {
         t.plan(1);
-        var map = new OpenLayers.Map('map');
+        map = new OpenLayers.Map('map');
         layer = new OpenLayers.Layer.WMS(name, url, params);
         map.addLayer(layer);
 
@@ -81,7 +82,7 @@
     function test_05_Layer_Grid_getResolution(t) {
         t.plan( 1 );
 
-        var map = new OpenLayers.Map('map');
+        map = new OpenLayers.Map('map');
         layer = new OpenLayers.Layer.WMS(name, url, params);
         map.addLayer(layer);
 
@@ -94,7 +95,7 @@
         t.plan( 2 );
         var bounds, zoom;
 
-        var map = new OpenLayers.Map('map');
+        map = new OpenLayers.Map('map');
         layer = new OpenLayers.Layer.WMS(name, url, params);
         map.addLayer(layer);
 
@@ -132,7 +133,7 @@
         t.plan(5);
         
         var options = {tileSize: new OpenLayers.Size(500,50)};
-        var map = new OpenLayers.Map('map', options);
+        map = new OpenLayers.Map('map', options);
         layer = new OpenLayers.Layer.Grid(name, url, params);
         map.addLayer(layer);
 
@@ -156,11 +157,10 @@
     }
 
     function test_11_Layer_Grid_setMap(t) {
-
         t.plan(2);
         
         var options = {tileSize: new OpenLayers.Size(500,50)};
-        var map = new OpenLayers.Map('map', options);
+        map = new OpenLayers.Map('map', options);
         layer = new OpenLayers.Layer.Grid(name, url, params);
 
 
@@ -171,11 +171,154 @@
     }
 
 
+
+    /*** animated zooming test functions ***/
+
+    function test_12_Layer_Grid_setZoomOutTile (t) {
+        t.plan(5);
+        
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.WMS(name, url, params);
+        map.addLayer(layer);
+        map.tileSize = new OpenLayers.Size(256,256); 
+        map.zoomOutTileFactor = 4;
+        var tile = map.baseLayer.zoomOutTile;
+
+        t.ok( tile instanceof OpenLayers.Tile.Image, 
+                "zoomOutTile is a Tile.Image object");
+        
+        var firstChild = map.baseLayer.div.firstChild;
+        t.eq( tile.imgDiv.id, firstChild.id, 
+                "zoomOutTile is first child of baseLayerDiv");
+
+        size = map.baseLayer.zoomOutTile.size;
+        t.eq( size.w, 1024, "zoomOutTile width is 1024px");
+        t.eq( size.h, 1024, "zoomOutTile height is 1024px");
+
+        t.ok( tile.imgDiv.style.display == "none", 
+                "zoomOutTile is invisible");
+    }
+
+
+    function test_13_Layer_Grid_getTileSize (t) {
+        t.plan(2);
+
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.WMS(name, url, params);
+        map.addLayer(layer);
+        map.tileSize = new OpenLayers.Size(256,256);  
+
+        size = map.baseLayer.getTileSize();
+        t.eq(size.w, 256, "tile width is correct"); 
+        t.eq(size.h, 256, "tile height is correct");
+    }
+
+    function test_14_Layer_Grid_getCenterTile (t) {
+        t.plan(1);
+
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.WMS(name, url, params);
+        map.addLayer(layer);
+        map.setCenter(new OpenLayers.LonLat(0,0));
+        
+        tile = map.baseLayer.getCenterTile(); 
+        t.ok(tile.bounds.contains(0,0,true), 
+                "center tile has been set correctly" );
+    }
+
+    function test_15_Layer_Grid_setTilesOutsideInvisible (t) {
+        t.plan(1);
+
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.WMS(name, url, params);
+        map.addLayer(layer);
+        map.setCenter(new OpenLayers.LonLat(0,0));
+        map.zoomTo(5,false);
+        map.baseLayer.setTilesOutsideInvisible();
+
+        var tileOutside = map.baseLayer.grid[0][0];
+        t.ok( tileOutside.imgDiv.style.display == "none", 
+                "tiles outside the viewport have been set invisible");
+
+    }
+
+    function test_16_Layer_Grid_scaleTilesOfGrid (t) {
+        t.plan(4);
+
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.WMS(name, url, params);
+        map.addLayer(layer);
+        map.setCenter(new OpenLayers.LonLat(0,0));
+        map.zoomTo(5,false);
+        
+        var tile = map.baseLayer.grid[3][2];
+        var centerTile = map.baseLayer.getCenterTile();
+        var newTileSize = new OpenLayers.Size(128,128);
+        map.baseLayer.scaleTileTo(centerTile,newTileSize);
+        map.baseLayer.scaleTilesOfGrid(centerTile,newTileSize);
+
+        t.eq( tile.imgDiv.style.width, "128px", 
+                "width of tiles has been set correctly");
+        t.eq( tile.imgDiv.style.height, "128px", 
+                "height of tiles has been set correctly");
+        t.eq( tile.imgDiv.style.top, "147px", 
+                "top position of tiles has been set correctly");
+        t.eq( tile.imgDiv.style.left, "122px", 
+                "left position of tiles has been set correctly");
+    }
+
+    function test_17_Layer_Grid_scaleZoomOutTile (t) {
+        t.plan(5);
+
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.WMS(name, url, params);
+        map.addLayer(layer);
+        map.setCenter(new OpenLayers.LonLat(0,0));
+        map.tileSize = new OpenLayers.Size(256,256);
+        map.zoomToMaxExtent();
+        var tile = map.baseLayer.zoomOutTile;
+        layer.firstCall = false; //set flag manually
+        map.baseLayer.scaleZoomOutTile(1,map.maxResolution/2);
+
+        t.eq( tile.imgDiv.style.width, "512px", 
+                "width of zoomOutTile has been set correctly");
+        t.eq( tile.imgDiv.style.height, "512px", 
+                "height of zoomOutTile has been set correctly");
+        t.eq( tile.imgDiv.style.top, "-109px", 
+                "top position of zoomOutTile has been set correctly");
+        t.eq( tile.imgDiv.style.left, "-6px", 
+                "left position of zoomOutTile has been set correctly");
+        t.ok( tile.imgDiv.style.display != "none", 
+                "zoomOutTile has been set visible");
+    }
+
+    function test_18_Layer_Grid_cloneBaseLayerDiv (t) {
+        t.plan(4);       
+
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.WMS(name, url, params);
+        map.addLayer(layer);
+        
+        map.baseLayer.cloneBaseLayerDiv();
+        var cloneDiv = map.baseLayerDivClone;
+        var originDiv = map.baseLayer.div; 
+        t.ok( cloneDiv instanceof HTMLDivElement, 
+                "cloned baseLayerDiv is a valid HTMLDivElement");
+        t.eq( cloneDiv.childNodes.length, originDiv.childNodes.length,
+                "cloned baseLayerDiv has the same number of childs");
+        t.eq( parseInt(cloneDiv.style.zIndex)+1, parseInt(originDiv.style.zIndex),
+                "zIndex has been set correctly");
+        t.ok( map.baseLayer.zoomOutTile.imgDiv.style.display == "none",
+                "zoomOutTile of original div has been set invisible");
+    }
+
+
+
     function test_99_Layer_Grid_destroy (t) {
 
         t.plan( 5 );
 
-        var map = new OpenLayers.Map('map');
+        map = new OpenLayers.Map('map');
         layer = new OpenLayers.Layer.Grid(name, url, params);
         map.addLayer(layer);
         layer.destroy();
@@ -183,7 +326,7 @@
         t.eq( layer.tileSize, null, "layer.tileSize is null after destroy" );
 
 
-    //test with tile creation
+        //test with tile creation
         layer = new OpenLayers.Layer.WMS(name, url, params);
         map.addLayer(layer);
 

Modified: sandbox/emanuel/animatedZooming_final/tests/Layer/test_Image.html
===================================================================
--- trunk/openlayers/tests/Layer/test_Image.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Layer/test_Image.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -38,7 +38,7 @@
         t.ok( layer.options instanceof Object, "layer.options correctly initialized as a non-null Object" );
     }
 
-    function test_50_Layer_Image_tileTests (t) {
+    function test_02_Layer_Image_tileTests (t) {
         t.plan(9);
         var map = new OpenLayers.Map('map');
         
@@ -77,15 +77,68 @@
  */
 
 
+/*** animated zooming test functions ***/
+    function test_03_Layer_Image_getTileSize (t) {
+        t.plan(2);
+
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.Image('Test Layer', 
+                'http://earthtrends.wri.org/images/maps/4_m_citylights_lg.gif',
+                new OpenLayers.Bounds(-180, -90, 180, 90),
+                new OpenLayers.Size(580, 288));
+        map.addLayer(layer);
+        map.setCenter(new OpenLayers.LonLat(0,0));
+
+        var size = map.baseLayer.getTileSize();
+        t.eq(size.w, 576, "tile width is correct");  
+        t.eq(size.h, 288, "tile height is correct");
+    }
+    function test_04_Layer_Image_getCenterTile (t) {
+        t.plan(1);
+
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.Image('Test Layer', 
+                'http://earthtrends.wri.org/images/maps/4_m_citylights_lg.gif',
+                new OpenLayers.Bounds(-180, -88.759, 180, 88.759),
+                new OpenLayers.Size(580, 288));
+        map.addLayer(layer);
+        map.setCenter(new OpenLayers.LonLat(0,0));
+
+        tile = map.baseLayer.getCenterTile(); 
+        t.ok(map.baseLayer.tile == tile, 
+                "center tile has been set correctly" );
+    }
+    function test_05_Layer_Image_cloneBaseLayerDiv (t) {
+        t.plan(3);
+
+        map = new OpenLayers.Map('map');
+        layer = new OpenLayers.Layer.Image('Test Layer', 
+                'http://earthtrends.wri.org/images/maps/4_m_citylights_lg.gif',
+                new OpenLayers.Bounds(-180, -88.759, 180, 88.759),
+                new OpenLayers.Size(580, 288));
+        map.addLayer(layer);
+        
+        map.baseLayer.cloneBaseLayerDiv();
+        var cloneDiv = map.baseLayerDivClone;
+        var originDiv = map.baseLayer.div; 
+        t.ok( cloneDiv instanceof HTMLDivElement, 
+                "cloned baseLayerDiv is a valid HTMLDivElement");
+        t.eq( cloneDiv.childNodes.length, originDiv.childNodes.length,
+                "cloned baseLayerDiv has the same number of childs");
+        t.eq( parseInt(cloneDiv.style.zIndex)+1, parseInt(originDiv.style.zIndex),
+                "zIndex has been set correctly");
+    }
+
+
     function test_99_Layer_Image_destroy (t) {
         t.plan( 4 );    
 
         var map = new OpenLayers.Map('map');
         
         layer = new OpenLayers.Layer.Image('Test Layer', 
-                                        'http://earthtrends.wri.org/images/maps/4_m_citylights_lg.gif',
-                                                                        new OpenLayers.Bounds(-180, -88.759, 180, 88.759),
-                                                                                                        new OpenLayers.Size(580, 288));
+                    'http://earthtrends.wri.org/images/maps/4_m_citylights_lg.gif',
+                    new OpenLayers.Bounds(-180, -88.759, 180, 88.759),
+                    new OpenLayers.Size(580, 288));
 
         map.addLayer(layer);
         map.zoomToMaxExtent();

Modified: sandbox/emanuel/animatedZooming_final/tests/Layer/test_MapServer.html
===================================================================
--- trunk/openlayers/tests/Layer/test_MapServer.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Layer/test_MapServer.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -1,8 +1,9 @@
 <html>
 <head>
     <script src='http://maps.google.com/maps?file=api&amp;v=2&amp;key=ABQIAAAAjpkAC9ePGem0lIq5XcMiuhR_wWLPFku8Ix9i2SXYRVK3e45q1BQUd_beF8dtzKET_EteAjPdGDwqpQ'></script>Z
-    
 
+
+
 <script src="../../lib/OpenLayers.js"></script>
   <script type="text/javascript"><!--
     var isMozilla = (navigator.userAgent.indexOf("compatible") == -1);
@@ -54,10 +55,13 @@
         t.eq( img.src,
              url + "?" + OpenLayers.Util.getParameterString(tParams).replace(/,/g, "+"),
              "image src is created correctly via addtile" );
-        t.eq( tile.frame.style.top, "6px", "image top is set correctly via addtile" );
-        t.eq( tile.frame.style.left, "5px", "image top is set correctly via addtile" );
+        t.eq( tile.imgDiv.style.top, "6px", "image top is set correctly via addtile" );
+        t.eq( tile.imgDiv.style.left, "5px", "image top is set correctly via addtile" );
 
-        var firstChild = layer.div.firstChild.firstChild;
+        
+        // get the 2nd child, because the 1st is a bigger zoomOutTile
+        var firstChild = layer.div.firstChild.nextSibling;
+
         if (!isMozilla)
             t.ok( true, "skipping element test outside of Mozilla");
         else
@@ -186,10 +190,10 @@
         map.addLayer(tLayer);
         map.zoomToMaxExtent();
         t.eq(tLayer.opacity, "0.5", "Opacity is set correctly");
-        t.eq(parseFloat(tLayer.div.firstChild.firstChild.style.opacity), 0.5, "Opacity on tile is correct");
+        t.eq(parseFloat(tLayer.div.firstChild.style.opacity), 0.5, "Opacity on tile is correct");
         tLayer.setOpacity("0.6");
         t.eq(tLayer.opacity, "0.6", "setOpacity works properly");
-        t.eq(parseFloat(tLayer.div.firstChild.firstChild.style.opacity), 0.6, "Opacity on tile is changed correctly");
+        t.eq(parseFloat(tLayer.div.firstChild.style.opacity), 0.6, "Opacity on tile is changed correctly");
         var pixel = new OpenLayers.Pixel(5,6);
         var tile = tLayer.addTile(new OpenLayers.Bounds(1,2,3,4), pixel);
         tile.draw();

Modified: sandbox/emanuel/animatedZooming_final/tests/Layer/test_MapServer_Untiled.html
===================================================================
--- trunk/openlayers/tests/Layer/test_MapServer_Untiled.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Layer/test_MapServer_Untiled.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -126,12 +126,12 @@
         var tLayer = new OpenLayers.Layer.MapServer.Untiled(name, tUrl, tParams, tOptions);
         map.addLayer(tLayer);
         map.zoomToMaxExtent();
+        
         t.eq(tLayer.opacity, "0.5", "Opacity is set correctly");
-        t.eq(parseFloat(tLayer.div.firstChild.firstChild.style.opacity), 0.5, "Opacity on tile is correct");
+        t.eq(parseFloat(tLayer.div.firstChild.style.opacity), 0.5, "Opacity on tile is correct");
         tLayer.setOpacity("0.6");
         t.eq(tLayer.opacity, "0.6", "setOpacity works properly");
-        t.eq(parseFloat(tLayer.div.firstChild.firstChild.style.opacity), 0.6, "Opacity on tile is changed correctly");
-
+        t.eq(parseFloat(tLayer.div.firstChild.style.opacity), 0.6, "Opacity on tile is changed correctly");
     }    
     
     function test_99_Layer_MapServer_Untiled_destroy (t) {

Modified: sandbox/emanuel/animatedZooming_final/tests/Layer/test_WMS.html
===================================================================
--- trunk/openlayers/tests/Layer/test_WMS.html	2007-05-25 12:49:27 UTC (rev 3182)
+++ sandbox/emanuel/animatedZooming_final/tests/Layer/test_WMS.html	2007-05-26 19:11:05 UTC (rev 3189)
@@ -26,7 +26,29 @@
 
     }
     
-    function test_02_Layer_WMS_addtile (t) {
+    function test_03_Layer_WMS_getURL (t) {
+        t.plan( 3 );
+    
+        var url = "http://octo.metacarta.com/cgi-bin/mapserv";
+        layer = new OpenLayers.Layer.WMS(name, url, params);
+        var map = new OpenLayers.Map('map');
+        map.addLayer(layer);
+
+        var bounds = new OpenLayers.Bounds(1,2,3,4);        
+        var url = map.baseLayer.getURL(bounds);
+        t.eq( url, "http://octo.metacarta.com/cgi-bin/mapserv?MAP=%2Fmapdata%2Fvmap_wms.map&LAYERS=basic&FORMAT=image%2Fpng&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&STYLES=&EXCEPTIONS=application%2Fvnd.ogc.se_inimage&SRS=EPSG%3A4326&BBOX=1%2C2%2C3%2C4&WIDTH=256&HEIGHT=256", 
+                "url has been set correctly");
+        
+        var tileSize = new OpenLayers.Size(512,512);
+        url = map.baseLayer.getURL(bounds,tileSize);        
+        t.ok( url.match("WIDTH=512"), 
+                "url with custom width has been set correctly");
+        t.ok( url.match("HEIGHT=512"), 
+                "url with custom height has been set correctly");
+
+    }
+
+    function test_03_Layer_WMS_addtile (t) {
         t.plan( 6 );
     
         var url = "http://octo.metacarta.com/cgi-bin/mapserv";
@@ -50,10 +72,12 @@
         t.eq( img.src,
              url + "?" + OpenLayers.Util.getParameterString(tParams),
              "image src is created correctly via addtile" );
-        t.eq( tile.frame.style.top, "6px", "image top is set correctly via addtile" );
-        t.eq( tile.frame.style.left, "5px", "image top is set correctly via addtile" );
+        t.eq( tile.imgDiv.style.top, "6px", "image top is set correctly via addtile" );
+        t.eq( tile.imgDiv.style.left, "5px", "image top is set correctly via addtile" );
 
-        var firstChild = layer.div.firstChild.firstChild;
+        // get the 2nd child, because the 1st is a bigger zoomOutTile
+        var firstChild = layer.div.firstChild.nextSibling;
+
         if (!isMozilla)
             t.ok( true, "skipping element test outside of Mozilla");
         else
@@ -65,7 +89,7 @@
         map.destroy();
     }
     
-    function test_03_Layer_WMS_inittiles (t) {
+    function test_04_Layer_WMS_inittiles (t) {
         t.plan( 2 );
         var map = new OpenLayers.Map('map');
         layer = new OpenLayers.Layer.WMS(name, url, params);
@@ -77,7 +101,7 @@
     }
 
 
-    function test_04_Layer_WMS_clone (t) {
+    function test_05_Layer_WMS_clone (t) {
         t.plan(4);
         
         var url = "http://octo.metacarta.com/cgi-bin/mapserv";
@@ -105,7 +129,7 @@
         map.destroy();
     }
 
-    function test_05_Layer_WMS_isBaseLayer(t) {
+    function test_06_Layer_WMS_isBaseLayer(t) {
         t.plan(3);
         
         var url = "http://octo.metacarta.com/cgi-bin/mapserv";
@@ -121,7 +145,7 @@
         t.ok( !layer.isBaseLayer, "baselayer is false when option is set to false" );
     }
 
-    function test_06_Layer_WMS_mergeNewParams (t) {
+    function test_07_Layer_WMS_mergeNewParams (t) {
         t.plan( 5 );
 
         var map = new OpenLayers.Map("map");
@@ -147,7 +171,7 @@
         map.destroy();
     }
 
-    function test_07_Layer_WMS_getFullR