From 12de02938a29738dbf9dceff92eea962204aebb8 Mon Sep 17 00:00:00 2001
From: achu1998 <a1866320@adelaide.edu.au>
Date: Sat, 29 Mar 2025 13:33:25 +1030
Subject: [PATCH 1/4] Exposed Zoom In and Out methods for end users

---
 src/viewer.js | 117 +++++++++++++++++++++++++++++---------------------
 1 file changed, 68 insertions(+), 49 deletions(-)

diff --git a/src/viewer.js b/src/viewer.js
index 17c8184c..95c9e97f 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -2005,11 +2005,11 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
         //////////////////////////////////////////////////////////////////////////
         // Navigation Controls
         //////////////////////////////////////////////////////////////////////////
-        var beginZoomingInHandler   = $.delegate( this, beginZoomingIn ),
-            endZoomingHandler       = $.delegate( this, endZooming ),
-            doSingleZoomInHandler   = $.delegate( this, doSingleZoomIn ),
-            beginZoomingOutHandler  = $.delegate( this, beginZoomingOut ),
-            doSingleZoomOutHandler  = $.delegate( this, doSingleZoomOut ),
+        var beginZoomingInHandler   = $.delegate( this, this.beginZoomingIn ),
+            endZoomingHandler       = $.delegate( this, this.endZooming ),
+            doSingleZoomInHandler   = $.delegate( this, this.doSingleZoomIn ),
+            beginZoomingOutHandler  = $.delegate( this, this.beginZoomingOut ),
+            doSingleZoomOutHandler  = $.delegate( this, this.doSingleZoomOut ),
             onHomeHandler           = $.delegate( this, onHome ),
             onFullScreenHandler     = $.delegate( this, onFullScreen ),
             onRotateLeftHandler     = $.delegate( this, onRotateLeft ),
@@ -2625,6 +2625,69 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
     isAnimating: function () {
         return THIS[ this.hash ].animating;
     },
+
+    /**
+     * Starts continuous zoom-in animation (typically bound to mouse-down on the zoom-in button).
+     * @function
+     * @memberof OpenSeadragon.Viewer.prototype
+     */
+    beginZoomingIn: function () {
+        THIS[ this.hash ].lastZoomTime = $.now();
+        THIS[ this.hash ].zoomFactor = this.zoomPerSecond;
+        THIS[ this.hash ].zooming = true;
+        scheduleZoom( this );
+    },
+
+    /**
+     * Starts continuous zoom-out animation (typically bound to mouse-down on the zoom-out button).
+     * @function
+     * @memberof OpenSeadragon.Viewer.prototype
+     */
+    beginZoomingOut: function () {
+        THIS[ this.hash ].lastZoomTime = $.now();
+        THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond;
+        THIS[ this.hash ].zooming = true;
+        scheduleZoom( this );
+    },
+
+    /**
+     * Stops any continuous zoom animation (typically bound to mouse-up/leave events on a button).
+     * @function
+     * @memberof OpenSeadragon.Viewer.prototype
+     */
+    endZooming: function () {
+        THIS[ this.hash ].zooming = false;
+    },
+
+    /**
+     * Performs single-step zoom-in operation (typically bound to click/enter on the zoom-in button).
+     * @function
+     * @memberof OpenSeadragon.Viewer.prototype
+     */
+    doSingleZoomIn: function () {
+        if ( this.viewport ) {
+            THIS[ this.hash ].zooming = false;
+            this.viewport.zoomBy(
+                this.zoomPerClick / 1.0
+            );
+            this.viewport.applyConstraints();
+        }
+    },
+
+    /**
+     * Performs single-step zoom-out operation (typically bound to click/enter on the zoom-out button).
+     * @function
+     * @memberof OpenSeadragon.Viewer.prototype
+     */
+    doSingleZoomOut: function () {
+        if ( this.viewport ) {
+            THIS[ this.hash ].zooming = false;
+            this.viewport.zoomBy(
+                1.0 / this.zoomPerClick
+            );
+            this.viewport.applyConstraints();
+        }
+    },
 });
 
 
@@ -3957,28 +4020,6 @@ function resolveUrl( prefix, url ) {
 }
 
 
-
-function beginZoomingIn() {
-    THIS[ this.hash ].lastZoomTime = $.now();
-    THIS[ this.hash ].zoomFactor = this.zoomPerSecond;
-    THIS[ this.hash ].zooming = true;
-    scheduleZoom( this );
-}
-
-
-function beginZoomingOut() {
-    THIS[ this.hash ].lastZoomTime = $.now();
-    THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond;
-    THIS[ this.hash ].zooming = true;
-    scheduleZoom( this );
-}
-
-
-function endZooming() {
-    THIS[ this.hash ].zooming = false;
-}
-
-
 function scheduleZoom( viewer ) {
     $.requestAnimationFrame( $.delegate( viewer, doZoom ) );
 }
@@ -4002,28 +4043,6 @@ function doZoom() {
 }
 
 
-function doSingleZoomIn() {
-    if ( this.viewport ) {
-        THIS[ this.hash ].zooming = false;
-        this.viewport.zoomBy(
-            this.zoomPerClick / 1.0
-        );
-        this.viewport.applyConstraints();
-    }
-}
-
-
-function doSingleZoomOut() {
-    if ( this.viewport ) {
-        THIS[ this.hash ].zooming = false;
-        this.viewport.zoomBy(
-            1.0 / this.zoomPerClick
-        );
-        this.viewport.applyConstraints();
-    }
-}
-
-
 function lightUp() {
     if (this.buttonGroup) {
         this.buttonGroup.emulateEnter();

From 3550dfafd3128642ac956f9d67bb48f38f1aae96 Mon Sep 17 00:00:00 2001
From: achu1998 <a1866320@adelaide.edu.au>
Date: Sat, 29 Mar 2025 13:47:02 +1030
Subject: [PATCH 2/4] Refactored code to minimise the changes required

---
 src/viewer.js | 92 +++++++++++++++++++++++++++++++++------------------
 1 file changed, 59 insertions(+), 33 deletions(-)

diff --git a/src/viewer.js b/src/viewer.js
index 95c9e97f..059f326d 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -2005,11 +2005,11 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
         //////////////////////////////////////////////////////////////////////////
         // Navigation Controls
         //////////////////////////////////////////////////////////////////////////
-        var beginZoomingInHandler   = $.delegate( this, this.beginZoomingIn ),
-            endZoomingHandler       = $.delegate( this, this.endZooming ),
-            doSingleZoomInHandler   = $.delegate( this, this.doSingleZoomIn ),
-            beginZoomingOutHandler  = $.delegate( this, this.beginZoomingOut ),
-            doSingleZoomOutHandler  = $.delegate( this, this.doSingleZoomOut ),
+        var beginZoomingInHandler   = $.delegate( this, beginZoomingIn ),
+            endZoomingHandler       = $.delegate( this, endZooming ),
+            doSingleZoomInHandler   = $.delegate( this, doSingleZoomIn ),
+            beginZoomingOutHandler  = $.delegate( this, beginZoomingOut ),
+            doSingleZoomOutHandler  = $.delegate( this, doSingleZoomOut ),
             onHomeHandler           = $.delegate( this, onHome ),
             onFullScreenHandler     = $.delegate( this, onFullScreen ),
             onRotateLeftHandler     = $.delegate( this, onRotateLeft ),
@@ -2631,11 +2631,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    beginZoomingIn: function () {
-        THIS[ this.hash ].lastZoomTime = $.now();
-        THIS[ this.hash ].zoomFactor = this.zoomPerSecond;
-        THIS[ this.hash ].zooming = true;
-        scheduleZoom( this );
+    startZoomInNavButton: function () {
+        beginZoomingIn();
     },
 
     /**
@@ -2643,11 +2640,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    beginZoomingOut: function () {
-        THIS[ this.hash ].lastZoomTime = $.now();
-        THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond;
-        THIS[ this.hash ].zooming = true;
-        scheduleZoom( this );
+    startZoomOutNavButton: function () {
+        beginZoomingOut();
     },
 
     /**
@@ -2655,8 +2649,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    endZooming: function () {
-        THIS[ this.hash ].zooming = false;
+    endZoomNavButton: function () {
+        endZooming();
     },
 
     /**
@@ -2664,14 +2658,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    doSingleZoomIn: function () {
-        if ( this.viewport ) {
-            THIS[ this.hash ].zooming = false;
-            this.viewport.zoomBy(
-                this.zoomPerClick / 1.0
-            );
-            this.viewport.applyConstraints();
-        }
+    zoomInNavButton: function () {
+        doSingleZoomIn();
     },
 
     /**
@@ -2679,14 +2667,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    doSingleZoomOut: function () {
-        if ( this.viewport ) {
-            THIS[ this.hash ].zooming = false;
-            this.viewport.zoomBy(
-                1.0 / this.zoomPerClick
-            );
-            this.viewport.applyConstraints();
-        }
+    zoomOutNavButton: function () {
+        doSingleZoomOut();
     },
 });
 
@@ -4020,6 +4002,28 @@ function resolveUrl( prefix, url ) {
 }
 
 
+
+function beginZoomingIn() {
+    THIS[ this.hash ].lastZoomTime = $.now();
+    THIS[ this.hash ].zoomFactor = this.zoomPerSecond;
+    THIS[ this.hash ].zooming = true;
+    scheduleZoom( this );
+}
+
+
+function beginZoomingOut() {
+    THIS[ this.hash ].lastZoomTime = $.now();
+    THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond;
+    THIS[ this.hash ].zooming = true;
+    scheduleZoom( this );
+}
+
+
+function endZooming() {
+    THIS[ this.hash ].zooming = false;
+}
+
+
 function scheduleZoom( viewer ) {
     $.requestAnimationFrame( $.delegate( viewer, doZoom ) );
 }
@@ -4043,6 +4047,28 @@ function doZoom() {
 }
 
 
+function doSingleZoomIn() {
+    if ( this.viewport ) {
+        THIS[ this.hash ].zooming = false;
+        this.viewport.zoomBy(
+            this.zoomPerClick / 1.0
+        );
+        this.viewport.applyConstraints();
+    }
+}
+
+
+function doSingleZoomOut() {
+    if ( this.viewport ) {
+        THIS[ this.hash ].zooming = false;
+        this.viewport.zoomBy(
+            1.0 / this.zoomPerClick
+        );
+        this.viewport.applyConstraints();
+    }
+}
+
+
 function lightUp() {
     if (this.buttonGroup) {
         this.buttonGroup.emulateEnter();

From 2e3f0923f5c61a9d609e06568f4bb21eec902f91 Mon Sep 17 00:00:00 2001
From: achu1998 <a1866320@adelaide.edu.au>
Date: Sat, 29 Mar 2025 14:17:54 +1030
Subject: [PATCH 3/4] Explicitly bind 'this' to the Viewer instance

---
 src/viewer.js | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/viewer.js b/src/viewer.js
index 059f326d..3c6d3b62 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -2632,7 +2632,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @memberof OpenSeadragon.Viewer.prototype
      */
     startZoomInNavButton: function () {
-        beginZoomingIn();
+        beginZoomingIn.call(this);
     },
 
     /**
@@ -2641,7 +2641,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @memberof OpenSeadragon.Viewer.prototype
      */
     startZoomOutNavButton: function () {
-        beginZoomingOut();
+        beginZoomingOut.call(this);
     },
 
     /**
@@ -2650,7 +2650,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @memberof OpenSeadragon.Viewer.prototype
      */
     endZoomNavButton: function () {
-        endZooming();
+        endZooming.call(this);
     },
 
     /**
@@ -2659,7 +2659,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @memberof OpenSeadragon.Viewer.prototype
      */
     zoomInNavButton: function () {
-        doSingleZoomIn();
+        doSingleZoomIn.call(this);
     },
 
     /**
@@ -2668,7 +2668,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @memberof OpenSeadragon.Viewer.prototype
      */
     zoomOutNavButton: function () {
-        doSingleZoomOut();
+        doSingleZoomOut.call(this);
     },
 });
 

From 9e01a1e18b9b752e76832a90e33ffbb19506e68e Mon Sep 17 00:00:00 2001
From: achu1998 <a1866320@adelaide.edu.au>
Date: Tue, 1 Apr 2025 11:04:04 +1030
Subject: [PATCH 4/4] Made changes according to review.

---
 src/viewer.js | 92 ++++++++++++++++++---------------------------------
 1 file changed, 33 insertions(+), 59 deletions(-)

diff --git a/src/viewer.js b/src/viewer.js
index 3c6d3b62..41bed4ae 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -2005,11 +2005,11 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
         //////////////////////////////////////////////////////////////////////////
         // Navigation Controls
         //////////////////////////////////////////////////////////////////////////
-        var beginZoomingInHandler   = $.delegate( this, beginZoomingIn ),
-            endZoomingHandler       = $.delegate( this, endZooming ),
-            doSingleZoomInHandler   = $.delegate( this, doSingleZoomIn ),
-            beginZoomingOutHandler  = $.delegate( this, beginZoomingOut ),
-            doSingleZoomOutHandler  = $.delegate( this, doSingleZoomOut ),
+        var beginZoomingInHandler   = $.delegate( this, this.startZoomInAction ),
+            endZoomingHandler       = $.delegate( this, this.endZoomAction ),
+            doSingleZoomInHandler   = $.delegate( this, this.singleZoomInAction ),
+            beginZoomingOutHandler  = $.delegate( this, this.startZoomOutAction ),
+            doSingleZoomOutHandler  = $.delegate( this, this.singleZoomOutAction ),
             onHomeHandler           = $.delegate( this, onHome ),
             onFullScreenHandler     = $.delegate( this, onFullScreen ),
             onRotateLeftHandler     = $.delegate( this, onRotateLeft ),
@@ -2631,8 +2631,11 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    startZoomInNavButton: function () {
-        beginZoomingIn.call(this);
+    startZoomInAction: function () {
+        THIS[ this.hash ].lastZoomTime = $.now();
+        THIS[ this.hash ].zoomFactor = this.zoomPerSecond;
+        THIS[ this.hash ].zooming = true;
+        scheduleZoom( this );
     },
 
     /**
@@ -2640,8 +2643,11 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    startZoomOutNavButton: function () {
-        beginZoomingOut.call(this);
+    startZoomOutAction: function () {
+        THIS[ this.hash ].lastZoomTime = $.now();
+        THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond;
+        THIS[ this.hash ].zooming = true;
+        scheduleZoom( this );
     },
 
     /**
@@ -2649,8 +2655,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    endZoomNavButton: function () {
-        endZooming.call(this);
+    endZoomAction: function () {
+        THIS[ this.hash ].zooming = false;
     },
 
     /**
@@ -2658,8 +2664,14 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    zoomInNavButton: function () {
-        doSingleZoomIn.call(this);
+    singleZoomInAction: function () {
+        if ( this.viewport ) {
+            THIS[ this.hash ].zooming = false;
+            this.viewport.zoomBy(
+                this.zoomPerClick / 1.0
+            );
+            this.viewport.applyConstraints();
+        }
     },
 
     /**
@@ -2667,8 +2679,14 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
      * @function
      * @memberof OpenSeadragon.Viewer.prototype
      */
-    zoomOutNavButton: function () {
-        doSingleZoomOut.call(this);
+    singleZoomOutAction: function () {
+        if ( this.viewport ) {
+            THIS[ this.hash ].zooming = false;
+            this.viewport.zoomBy(
+                1.0 / this.zoomPerClick
+            );
+            this.viewport.applyConstraints();
+        }
     },
 });
 
@@ -4002,28 +4020,6 @@ function resolveUrl( prefix, url ) {
 }
 
 
-
-function beginZoomingIn() {
-    THIS[ this.hash ].lastZoomTime = $.now();
-    THIS[ this.hash ].zoomFactor = this.zoomPerSecond;
-    THIS[ this.hash ].zooming = true;
-    scheduleZoom( this );
-}
-
-
-function beginZoomingOut() {
-    THIS[ this.hash ].lastZoomTime = $.now();
-    THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond;
-    THIS[ this.hash ].zooming = true;
-    scheduleZoom( this );
-}
-
-
-function endZooming() {
-    THIS[ this.hash ].zooming = false;
-}
-
-
 function scheduleZoom( viewer ) {
     $.requestAnimationFrame( $.delegate( viewer, doZoom ) );
 }
@@ -4047,28 +4043,6 @@ function doZoom() {
 }
 
 
-function doSingleZoomIn() {
-    if ( this.viewport ) {
-        THIS[ this.hash ].zooming = false;
-        this.viewport.zoomBy(
-            this.zoomPerClick / 1.0
-        );
-        this.viewport.applyConstraints();
-    }
-}
-
-
-function doSingleZoomOut() {
-    if ( this.viewport ) {
-        THIS[ this.hash ].zooming = false;
-        this.viewport.zoomBy(
-            1.0 / this.zoomPerClick
-        );
-        this.viewport.applyConstraints();
-    }
-}
-
-
 function lightUp() {
     if (this.buttonGroup) {
         this.buttonGroup.emulateEnter();