@@ -147,6 +147,119 @@ function tooltipPlugin({
147147 } ;
148148}
149149
150+ // Taken from https://leeoniya.github.io/uPlot/demos/zoom-wheel.html
151+ function wheelZoomPlugin ( opts ) {
152+ let factor = opts . factor || 0.75 ;
153+
154+ let xMin , xMax , yMin , yMax , xRange , yRange ;
155+
156+ function clamp ( nRange , nMin , nMax , fRange , fMin , fMax ) {
157+ if ( nRange > fRange ) {
158+ nMin = fMin ;
159+ nMax = fMax ;
160+ } else if ( nMin < fMin ) {
161+ nMin = fMin ;
162+ nMax = fMin + nRange ;
163+ } else if ( nMax > fMax ) {
164+ nMax = fMax ;
165+ nMin = fMax - nRange ;
166+ }
167+
168+ return [ nMin , nMax ] ;
169+ }
170+
171+ return {
172+ hooks : {
173+ ready : ( u ) => {
174+ xMin = u . scales . x . min ;
175+ xMax = u . scales . x . max ;
176+ yMin = u . scales . y . min ;
177+ yMax = u . scales . y . max ;
178+
179+ xRange = xMax - xMin ;
180+ yRange = yMax - yMin ;
181+
182+ let over = u . over ;
183+ let rect = over . getBoundingClientRect ( ) ;
184+
185+ // wheel drag pan
186+ over . addEventListener ( "mousedown" , ( e ) => {
187+ if ( e . button == 1 ) {
188+ // plot.style.cursor = "move";
189+ e . preventDefault ( ) ;
190+
191+ let left0 = e . clientX ;
192+ // let top0 = e.clientY;
193+
194+ let scXMin0 = u . scales . x . min ;
195+ let scXMax0 = u . scales . x . max ;
196+
197+ let xUnitsPerPx = u . posToVal ( 1 , "x" ) - u . posToVal ( 0 , "x" ) ;
198+
199+ function onmove ( e ) {
200+ e . preventDefault ( ) ;
201+
202+ let left1 = e . clientX ;
203+ // let top1 = e.clientY;
204+
205+ let dx = xUnitsPerPx * ( left1 - left0 ) ;
206+
207+ u . setScale ( "x" , {
208+ min : scXMin0 - dx ,
209+ max : scXMax0 - dx ,
210+ } ) ;
211+ }
212+
213+ function onup ( e ) {
214+ document . removeEventListener ( "mousemove" , onmove ) ;
215+ document . removeEventListener ( "mouseup" , onup ) ;
216+ }
217+
218+ document . addEventListener ( "mousemove" , onmove ) ;
219+ document . addEventListener ( "mouseup" , onup ) ;
220+ }
221+ } ) ;
222+
223+ // wheel scroll zoom
224+ over . addEventListener ( "wheel" , ( e ) => {
225+ e . preventDefault ( ) ;
226+
227+ let { left, top} = u . cursor ;
228+
229+ let leftPct = left / rect . width ;
230+ let btmPct = 1 - top / rect . height ;
231+ let xVal = u . posToVal ( left , "x" ) ;
232+ let yVal = u . posToVal ( top , "y" ) ;
233+ let oxRange = u . scales . x . max - u . scales . x . min ;
234+ let oyRange = u . scales . y . max - u . scales . y . min ;
235+
236+ let nxRange = e . deltaY < 0 ? oxRange * factor : oxRange / factor ;
237+ let nxMin = xVal - leftPct * nxRange ;
238+ let nxMax = nxMin + nxRange ;
239+ [ nxMin , nxMax ] = clamp ( nxRange , nxMin , nxMax , xRange , xMin , xMax ) ;
240+
241+ let nyRange = e . deltaY < 0 ? oyRange * factor : oyRange / factor ;
242+ let nyMin = yVal - btmPct * nyRange ;
243+ let nyMax = nyMin + nyRange ;
244+ [ nyMin , nyMax ] = clamp ( nyRange , nyMin , nyMax , yRange , yMin , yMax ) ;
245+
246+ u . batch ( ( ) => {
247+ u . setScale ( "x" , {
248+ min : nxMin ,
249+ max : nxMax ,
250+ } ) ;
251+
252+ u . setScale ( "y" , {
253+ min : nyMin ,
254+ max : nyMax ,
255+ } ) ;
256+ } ) ;
257+ } ) ;
258+ } ,
259+ } ,
260+ } ;
261+ }
262+
150263function genPlotOpts ( {
151264 width,
152265 height,
@@ -253,6 +366,7 @@ function genPlotOpts({
253366 isInterpolated,
254367 absoluteMode,
255368 } ) ,
369+ wheelZoomPlugin ( { factor : 0.75 } ) ,
256370 ] ,
257371 } ;
258372}
0 commit comments