<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Wheel Zoom &amp; Drag</title>
		<meta name="viewport" content="width=device-width, initial-scale=1">

		<link rel="stylesheet" href="https://leeoniya.github.io/uPlot/dist/uPlot.min.css">
	</head>
	<body>
		<script src="https://leeoniya.github.io/uPlot/dist/uPlot.iife.js"></script>
	</body>
</html>
function wheelZoomPlugin(opts) {
				let factor = opts.factor || 0.75;

				let xMin, xMax, yMin, yMax, xRange, yRange;

				function clamp(nRange, nMin, nMax, fRange, fMin, fMax) {
					if (nRange > fRange) {
						nMin = fMin;
						nMax = fMax;
					}
					else if (nMin < fMin) {
						nMin = fMin;
						nMax = fMin + nRange;
					}
					else if (nMax > fMax) {
						nMax = fMax;
						nMin = fMax - nRange;
					}

					return [nMin, nMax];
				}

				return {
					hooks: {
						ready: u => {
							xMin = u.scales.x.min;
							xMax = u.scales.x.max;
							yMin = u.scales.y.min;
							yMax = u.scales.y.max;

							xRange = xMax - xMin;
							yRange = yMax - yMin;

							let plot = u.root.querySelector(".u-over");
							let rect = plot.getBoundingClientRect();

							// wheel drag pan
							plot.addEventListener("mousedown", e => {
								if (e.button == 1) {
								  //plot.style.cursor = "move";
									e.preventDefault();

									let left0 = e.clientX;
								  let top0 = e.clientY;

									let scXMin0 = u.scales.x.min;
									let scXMax0 = u.scales.x.max;
									let scYMin0 = u.scales.y.min;
									let scYMax0 = u.scales.y.max;

									let xUnitsPerPx = u.posToVal(1, 'x') - u.posToVal(0, 'x');
									let yUnitsPerPx = u.posToVal(1, 'y') - u.posToVal(0, 'y');

									function onmove(e) {
										e.preventDefault();

										let left1 = e.clientX;
									  let top1 = e.clientY;

										let dx = xUnitsPerPx * (left1 - left0);
										let dy = yUnitsPerPx * (top1 - top0);

										u.batch(() => {
											u.setScale('x', {
												min: scXMin0 - dx,
												max: scXMax0 - dx,
											});
											u.setScale("y", {
												min: scYMin0 - dy,
												max: scYMax0 - dy,
											});
										});
									}

									function onup(e) {
										document.removeEventListener("mousemove", onmove);
										document.removeEventListener("mouseup", onup);
									}

									document.addEventListener("mousemove", onmove);
									document.addEventListener("mouseup", onup);
								}
							});

							// wheel scroll zoom
							plot.addEventListener("wheel", e => {
								e.preventDefault();

								let {left, top} = u.cursor;

								let leftPct = left/rect.width;
								let btmPct = 1 - top/rect.height;
								let xVal = u.posToVal(left, "x");
								let yVal = u.posToVal(top, "y");
								let oxRange = u.scales.x.max - u.scales.x.min;
								let oyRange = u.scales.y.max - u.scales.y.min;

								let nxRange = e.deltaY < 0 ? oxRange * factor : oxRange / factor;
								let nxMin = xVal - leftPct * nxRange;
								let nxMax = nxMin + nxRange;
								[nxMin, nxMax] = clamp(nxRange, nxMin, nxMax, xRange, xMin, xMax);

								let nyRange = e.deltaY < 0 ? oyRange * factor : oyRange / factor;
								let nyMin = yVal - btmPct * nyRange;
								let nyMax = nyMin + nyRange;
								[nyMin, nyMax] = clamp(nyRange, nyMin, nyMax, yRange, yMin, yMax);

								u.batch(() => {
									u.setScale("x", {
										min: nxMin,
										max: nxMax,
									});

									u.setScale("y", {
										min: nyMin,
										max: nyMax,
									});
								});
							});
						}
					}
				};
			}

			function makeChart() {
				console.time('chart');

				let opts = {
					title: "Wheel Zoom & Drag",
					width: 1000,
					height: 500,
					plugins: [
						wheelZoomPlugin({factor: 0.75})
					],
          cursor: {
            drag: {x: false, setScale: false}
          },
					scales: {
						x: {
							time: false,
						},
					    y: {
					        auto: false,
					        min: -2,
					        max: 2
					    }
					},
					series: [
						{},
						{
							label: "One",
							stroke: "red",
						},
						/*{
							label: "Two",
							stroke: "blue",
						},*/
					]
				};

				const data = [
					[ 1, 2, 3, 4, 5],
					[40,43,60,65,71],
					//[18,24,37,55,55],
				];
				for (var i = 0; i < 100000; i++) {
					data[0][i] = i;
					data[1][i] = Math.sin(i / 500);
					//data[2][i] = Math.cos(i / 500);
				}
				//data[1][0] = 2;
				//data[2][0] = -2;

				let u = new uPlot(opts, data, document.body);

				console.timeEnd('chart');
			}

			makeChart();

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.