Repository: chartjs/chartjs-plugin-zoom
Pull request #898 (2024-11-20 23:45:22)

Fix handling at canvas edge
This is a possible fix for #897. Further testing may be needed.

joshkel: @kurkle I have a test in my local branch at https://github.com/joshkel/chartjs-plugin-zoom/commit/c67c7b58ae1f279bdb05b9ec812bc8c752ffd75e. It depends on #896 being merged. I can wait for that PR, or, if you'd rather have one PR that combines these fixes, I can do that.

Patch:
diff --git a/src/handlers.js b/src/handlers.js
index 25ea441..97c716f 100644
--- a/src/handlers.js
+++ b/src/handlers.js
@@ -58,13 +58,14 @@ function keyDown(chart, event) {
 }
 
 function getPointPosition(event, chart) {
-  const point = getRelativePosition(event, chart);
-  const canvasArea = chart.canvas.getBoundingClientRect();
-  if (!_isPointInArea(event, canvasArea)) {
-    point.x = event.clientX - canvasArea.left;
-    point.y = event.clientY - canvasArea.top;
+  if (event.target !== chart.canvas) {
+    const canvasArea = chart.canvas.getBoundingClientRect();
+    return {
+      x: event.clientX - canvasArea.left,
+      y: event.clientY - canvasArea.top,
+    };
   }
-  return point;
+  return getRelativePosition(event, chart);
 }
 
 function zoomStart(chart, event, zoomOptions) {


Test patch:
diff --git a/test/specs/zoom.drag.spec.js b/test/specs/zoom.drag.spec.js
index 712f2b6..1ec51c4 100644
--- a/test/specs/zoom.drag.spec.js
+++ b/test/specs/zoom.drag.spec.js
@@ -450,6 +450,63 @@ describe('zoom with drag', function() {
       expect(scaleY.options.min).toBeCloseTo(1.2);
       expect(scaleY.options.max).toBeCloseTo(1.7);
     });
+
+    it('handles dragging off the right edge of the chart canvas', function() {
+      chart = window.acquireChart({
+        type: 'line',
+        data,
+        options: {
+          scales: {
+            xScale0: {
+              id: 'xScale0',
+              type: 'linear',
+              min: 0,
+              max: 4
+            },
+            yScale0: {
+              id: 'yScale0',
+              type: 'linear',
+              min: 0,
+              max: 4,
+            }
+          },
+          plugins: {
+            zoom: {
+              zoom: {
+                drag: {
+                  enabled: true
+                },
+                mode: 'xy'
+              }
+            }
+          }
+        }
+      }, {
+        wrapper: {style: 'position: absolute; left: 50px; top: 50px;'}
+      });
+
+      scaleX = chart.scales.xScale0;
+      scaleY = chart.scales.yScale0;
+
+      jasmine.triggerMouseEvent(chart, 'mousedown', {
+        x: scaleX.getPixelForValue(1.5),
+        y: scaleY.getPixelForValue(1.2)
+      });
+
+      const rect = chart.canvas.getBoundingClientRect();
+      document.documentElement.dispatchEvent(new MouseEvent('mouseup', {
+        clientX: rect.right,
+        clientY: rect.top + scaleY.getPixelForValue(1.7),
+        cancelable: true,
+        bubbles: true,
+        view: window
+      }));
+
+      expect(scaleX.options.min).toBeCloseTo(1.5);
+      expect(scaleX.options.max).toBeCloseTo(4);
+      expect(scaleY.options.min).toBeCloseTo(1.2);
+      expect(scaleY.options.max).toBeCloseTo(1.7);
+    });
   });
 
   describe('events', function() {