From fdaa8dae948db928a4103d5e693a28960a5a03d0 Mon Sep 17 00:00:00 2001 From: x2605 <69812394+x2605@users.noreply.github.com> Date: Tue, 24 Mar 2026 11:04:15 +0900 Subject: [PATCH] fix cursor offset inside CSS zoom containers, add setZoom() API and demo --- demos/inside-css-zoom.html | 65 ++++++++++++++++++++++++++++++++++++++ src/uPlot.js | 21 ++++++++++-- 2 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 demos/inside-css-zoom.html diff --git a/demos/inside-css-zoom.html b/demos/inside-css-zoom.html new file mode 100644 index 00000000..7519e01c --- /dev/null +++ b/demos/inside-css-zoom.html @@ -0,0 +1,65 @@ + + + + + Inside CSS Zoom + + + + + + + +
+
+
+ +

+ + + + +

+ + + + + + diff --git a/src/uPlot.js b/src/uPlot.js index 9c875adc..fa864d7f 100644 --- a/src/uPlot.js +++ b/src/uPlot.js @@ -3093,6 +3093,17 @@ export default function uPlot(opts, data, then) { } let rect = null; + let cssZoom = 1; + + function getEffectiveZoom(el) { + let z = 1; + while (el) { + let s = getComputedStyle(el).zoom; + if (s && s !== 'normal') z *= parseFloat(s); + el = el.parentElement; + } + return z; + } Object.defineProperty(self, 'rect', { get() { @@ -3108,6 +3119,7 @@ export default function uPlot(opts, data, then) { rect = null; else { rect = over.getBoundingClientRect(); + cssZoom = getEffectiveZoom(over); fire("syncRect", rect); } } @@ -3139,8 +3151,8 @@ export default function uPlot(opts, data, then) { setCursorEvent(e); if (e != null) { - _l = e.clientX - rect.left; - _t = e.clientY - rect.top; + _l = (e.clientX - rect.left) / cssZoom; + _t = (e.clientY - rect.top) / cssZoom; } else { if (_l < 0 || _t < 0) { @@ -3408,6 +3420,11 @@ export default function uPlot(opts, data, then) { cursorPlots.add(self); self.syncRect = syncRect; + + // allows external code to notify uPlot when container CSS zoom changes, + // e.g. u.syncZoom() to auto-detect, or u.syncZoom(1.5) to set explicitly. + // avoids the performance cost of recalculating on every mousemove. + self.syncZoom = (z) => { cssZoom = z ?? getEffectiveZoom(over); }; } // external on/off