leeoniya / leeoniya/uPlot

wheel zoom plugin not work when I add point

Open
#725 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
10.5k
Forks
463
PR merge metrics
No merged PRs in 30d

Description

Hi,

I have a problem with the wheel zoom plugin. When I add new points, the zoom stay with only the first point. How can I "refresh" the zoom ?
Regards,
Lionel

Here is a demo of the problem :

<!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="../dist/uPlot.min.css">
	</head>
	<body>
        <button class="" id="add" title="Add point." onclick="doAdd()">Add point</button>
		<script src="../dist/uPlot.iife.js"></script>
		<script>
          
          
            function getSize() {
              return {
                  "width": window.innerWidth - 50,
                  "height": window.innerHeight - 100
              };
            }
          
			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 over = u.over;
							let rect = over.getBoundingClientRect();

							// wheel drag pan
							over.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 xUnitsPerPx = u.posToVal(1, 'x') - u.posToVal(0, 'x');

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

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

										let dx = xUnitsPerPx * (left1 - left0);

										u.setScale('x', {
											min: scXMin0 - dx,
											max: scXMax0 - dx,
										});
									}

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

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

							// wheel scroll zoom
							over.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,
									});
								});
							});
						}
					}
				};
			}

            let plot;
          
            let data = [
                [ 1, 2, 3, 4, 5, 6, 7],
                [40,43,60,65,71,73,80],
                [18,24,37,55,55,60,63],
            ];          
          
			function makeChart() {
				console.time('chart');

				let opts = {
					title: "Wheel Zoom & Drag",
					width: 600,
					height: 400,
					plugins: [
						wheelZoomPlugin({factor: 0.75})
					],
                    ...getSize(),                  
					scales: {
						x: {
							time: true,
						},
					//	y: {
					//		auto: false,
					//	}
					},
					series: [
						{},
						{
							label: "One",
							stroke: "red",
						},
						{
							label: "Two",
							stroke: "blue",
						},
					]
				};

				plot = new uPlot(opts, data, document.body);
              
                window.addEventListener("resize", e => {
                    plot.setSize(getSize());
                });

				console.timeEnd('chart');
			}
          
            function doAdd() {
              data[0].push(data[0].length+1);
              data[1].push(Math.random()*80);
              data[2].push(Math.random()*70);
              plot.setData(data);
            }

			makeChart();
		</script>
      
	</body>
</html>

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the embedded demo, focusing on wheelZoomPlugin's ready hook and its xMin/xMax/yMin/yMax bounds, then trace doAdd() through plot.setData(data). Reproduce the zoom behavior after adding a point and determine what the plugin should consider its updated bounds; done means the added point is handled by the zoom behavior without breaking existing wheel zoom and drag interactions.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
data-visualization
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.