Index: tests/test_Util.html
===================================================================
--- tests/test_Util.html	(Revision 2907)
+++ tests/test_Util.html	(Arbeitskopie)
@@ -563,13 +563,37 @@
         
  
     }
-    function test_Util_createUniqueIDSeq(t) {
+    function test_16_Util_createUniqueIDSeq(t) {
         t.plan(1);
         OpenLayers.Util.lastSeqID = 0;
         OpenLayers.Util.createDiv();
         OpenLayers.Util.createDiv();
         t.eq(OpenLayers.Util.createDiv().id, "OpenLayersDiv3", "Div created is sequential, starting at lastSeqID in Util.");
     }
+
+    function test_17_Util_easeInOutPan(t) {
+        t.plan(1);
+        var delta = 5; 
+        var totalSteps = 4;
+        var step = 1;
+        var power = 1;
+        var value = OpenLayers.Util.easeInOutPan(delta,totalSteps,step,power);
+        t.eq( value, 2, "calculation correct");
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
    // -->
   </script>
 </head>
Index: tests/test_Map.html
===================================================================
--- tests/test_Map.html	(Revision 2907)
+++ tests/test_Map.html	(Arbeitskopie)
@@ -316,7 +316,35 @@
         t.ok(map.getCenter().equals(new OpenLayers.LonLat(0,0)), "safely sets out-of-bounds lonlat");
     }
 
-    
+    /** animated panning **/
+    function test_08_Map_pan(t) {
+        t.plan(2);
+
+        map = new OpenLayers.Map('map');
+        var baseLayer = new OpenLayers.Layer.WMS("Test Layer", 
+            "http://octo.metacarta.com/cgi-bin/mapserv?",
+            {map: "/mapdata/vmap_wms.map", layers: "basic"},
+            {maxResolution: 'auto', maxExtent: new OpenLayers.Bounds(-10,-10,10,10)});
+        map.addLayer(baseLayer);
+        var ll = new OpenLayers.LonLat(0,0);
+        map.setCenter(ll, 0);
+
+        map.pan(0,3);
+        t.delay_call(
+            1, function() {    
+                var newCent = new OpenLayers.LonLat(0,-0.1);
+                t.ok( map.getCenter().equals(newCent), 
+                        "map center is correct after panning with animation");
+
+                map.pan(0,-3, false);
+                newCent = new OpenLayers.LonLat(0,0);
+                t.ok( map.getCenter().equals(newCent), 
+                        "map center is correct after panning without animation");
+            }
+        );
+    }
+
+
     function test_01_Map_defaultTheme(t) {
         t.plan(5);
         
Index: tests/Control/test_Permalink.html
===================================================================
--- tests/Control/test_Permalink.html	(Revision 2907)
+++ tests/Control/test_Permalink.html	(Arbeitskopie)
@@ -20,11 +20,13 @@
         if (!map.getCenter())  map.zoomToMaxExtent();
         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=2&layers=B", "Panning sets permalink");
+            } else {
+                t.eq(OpenLayers.Util.getElement('permalink').href, location+"?lat=0&lon=7.03125&zoom=2&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 );
Index: tests/Control/test_PanZoom.html
===================================================================
--- tests/Control/test_PanZoom.html	(Revision 2907)
+++ tests/Control/test_PanZoom.html	(Arbeitskopie)
@@ -42,26 +42,36 @@
         map.setCenter(centerLL, 5);
 
         control.buttons[0].onmousedown(evt);
-        t.ok( map.getCenter().lat > centerLL.lat, "Pan up works correctly" );
+        t.delay_call( 
+            1, function() {
+                t.ok( map.getCenter().lat > centerLL.lat, "Pan up works correctly" );
+                control.buttons[1].onmousedown(evt);
+            },
+            
+            1, function() {
+                t.ok( map.getCenter().lon < centerLL.lon, "Pan left works correctly" );
+                control.buttons[2].onmousedown(evt);
+            },
+            
+            1, function() {
+                t.ok( map.getCenter().lon == centerLL.lon, "Pan right works correctly" );
+                control.buttons[3].onmousedown(evt);
+            },
+            
+            1, function() {
+                t.ok( map.getCenter().lat == centerLL.lat, "Pan down works correctly" );
+                control.buttons[4].onmousedown(evt);
+                
+                t.eq( map.getZoom(), 6, "zoomin works correctly" );
 
-        control.buttons[1].onmousedown(evt);
-        t.ok( map.getCenter().lon < centerLL.lon, "Pan left works correctly" );
+                control.buttons[6].onmousedown(evt);
+                t.eq( map.getZoom(), 5, "zoomout works correctly" );
 
-        control.buttons[2].onmousedown(evt);
-        t.ok( map.getCenter().lon == centerLL.lon, "Pan right works correctly" );
+                control.buttons[5].onmousedown(evt);
+                t.eq( map.getZoom(), 2, "zoomworld works correctly" );
+            }
+        );
 
-        control.buttons[3].onmousedown(evt);
-        t.ok( map.getCenter().lat == centerLL.lat, "Pan down works correctly" );
-
-        control.buttons[4].onmousedown(evt);
-        t.eq( map.getZoom(), 6, "zoomin works correctly" );
-
-        control.buttons[6].onmousedown(evt);
-        t.eq( map.getZoom(), 5, "zoomout works correctly" );
-
-        control.buttons[5].onmousedown(evt);
-        t.eq( map.getZoom(), 2, "zoomworld works correctly" );
-
     }
   // -->
   </script>
Index: lib/OpenLayers/Control/PanZoom.js
===================================================================
--- lib/OpenLayers/Control/PanZoom.js	(Revision 2907)
+++ lib/OpenLayers/Control/PanZoom.js	(Arbeitskopie)
@@ -15,7 +15,7 @@
   OpenLayers.Class.inherit( OpenLayers.Control, {
 
     /** @type int */
-    slideFactor: 50,
+    slideFactor: 75,
 
     /** @type Array of Button Divs */
     buttons: null,
@@ -114,16 +114,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(); 
Index: lib/OpenLayers/Layer.js
===================================================================
--- lib/OpenLayers/Layer.js	(Revision 2907)
+++ lib/OpenLayers/Layer.js	(Arbeitskopie)
@@ -529,9 +529,9 @@
             var size = this.map.getSize();
             var center = this.map.getCenter();
             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); 
Index: lib/OpenLayers/Map.js
===================================================================
--- lib/OpenLayers/Map.js	(Revision 2907)
+++ lib/OpenLayers/Map.js	(Arbeitskopie)
@@ -136,6 +136,30 @@
     /** @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,
+
     /** Should OpenLayers allow events on the map to fall through to other
      *   elements on the page, or should it swallow them? (#457)
      * 
@@ -749,20 +773,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);
+            }
         }
-
    },
 
     /**
@@ -871,7 +905,50 @@
             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);
+    },
+
     /**
      * @private 
      * 
Index: lib/OpenLayers/Util.js
===================================================================
--- lib/OpenLayers/Util.js	(Revision 2907)
+++ lib/OpenLayers/Util.js	(Arbeitskopie)
@@ -965,3 +965,22 @@
     }
     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);
+};
+
