Synchronize graphs on zoom (#1315)

This commit is contained in:
Karol Piecuch 2023-09-29 13:32:31 +02:00 committed by GitHub
parent 10b6150a7a
commit f06382b5a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 29 deletions

View File

@ -6,6 +6,8 @@ interface WheelZoomPluginOptions {
animationDuration?: number;
}
const chartInstances: uPlot[] = [];
function wheelZoomPlugin(options: WheelZoomPluginOptions = {}): Plugin {
const factor = options.factor || 0.9;
@ -15,8 +17,8 @@ function wheelZoomPlugin(options: WheelZoomPluginOptions = {}): Plugin {
let yMax: number;
let xRange: number;
let yRange: number;
let over = null;
let rect: DOMRect;
let over: HTMLElement | null = null;
let rect: DOMRect | null = null;
function isCtrlPressed(e: MouseEvent): boolean {
return e.ctrlKey || e.metaKey;
@ -50,6 +52,8 @@ function wheelZoomPlugin(options: WheelZoomPluginOptions = {}): Plugin {
return {
hooks: {
ready(u: uPlot) {
chartInstances.push(u); // Add the current chart instance to the list
xMin = u.scales.x.min ?? 0;
xMax = u.scales.x.max ?? 0;
yMin = u.scales.y.min ?? 0;
@ -59,7 +63,7 @@ function wheelZoomPlugin(options: WheelZoomPluginOptions = {}): Plugin {
over = u.over;
rect = over.getBoundingClientRect();
over.addEventListener('mousedown', (e: MouseEvent) => {
over?.addEventListener('mousedown', (e: MouseEvent) => {
if (e.button === 1) {
e.preventDefault();
@ -84,7 +88,7 @@ function wheelZoomPlugin(options: WheelZoomPluginOptions = {}): Plugin {
}
});
over.addEventListener('wheel', (e: WheelEvent) => {
over?.addEventListener('wheel', (e: WheelEvent) => {
e.preventDefault();
if (!isCtrlPressed(e)) {
@ -94,8 +98,8 @@ function wheelZoomPlugin(options: WheelZoomPluginOptions = {}): Plugin {
const cursor = u.cursor;
const { left, top } = cursor;
const leftPct = (left || 0) / rect.width;
const btmPct = 1 - (top || 0) / rect.height;
const leftPct = (left || 0) / (rect?.width || 1);
const btmPct = 1 - (top || 0) / (rect?.height || 1);
const xVal = u.posToVal(left || 0, 'x');
const yVal = u.posToVal(top || 0, 'y');
const oxRange = (u.scales.x.max || 0) - (u.scales.x.min || 0);
@ -111,15 +115,18 @@ function wheelZoomPlugin(options: WheelZoomPluginOptions = {}): Plugin {
let nyMax = nyMin + nyRange;
[nyMin, nyMax] = clamp(nyRange, nyMin, nyMax, yRange, yMin, yMax);
u.batch(() => {
u.setScale('x', {
min: nxMin,
max: nxMax,
});
// Loop through all chart instances and apply the same zoom to each of them
chartInstances.forEach((chartInstance) => {
chartInstance.batch(() => {
chartInstance.setScale('x', {
min: nxMin,
max: nxMax,
});
u.setScale('y', {
min: nyMin,
max: nyMax,
chartInstance.setScale('y', {
min: nyMin,
max: nyMax,
});
});
});
});

View File

@ -8,6 +8,8 @@ interface Point {
dy: number;
}
const chartInstances: uPlot[] = [];
const touchZoomPlugin = () => {
const init = (u: uPlot, _opts: any, _data: any) => {
const { over } = u;
@ -56,17 +58,12 @@ const touchZoomPlugin = () => {
let rafPending = false;
const zoom = () => {
const zoomCharts = () => {
rafPending = false;
const left = to.x;
const top = to.y;
// non-uniform scaling
// let xFactor = fr.dx / to.dx;
// let yFactor = fr.dy / to.dy;
// uniform x/y scaling
const xFactor = fr.d! / to.d!;
const yFactor = fr.d! / to.d!;
@ -81,15 +78,18 @@ const touchZoomPlugin = () => {
const nyMin = yVal - btmPct * nyRange;
const nyMax = nyMin + nyRange;
u.batch(() => {
u.setScale('x', {
min: nxMin,
max: nxMax,
});
// Loop through all chart instances and apply the same zoom to each of them
chartInstances.forEach((chartInstance) => {
chartInstance.batch(() => {
chartInstance.setScale('x', {
min: nxMin,
max: nxMax,
});
u.setScale('y', {
min: nyMin,
max: nyMax,
chartInstance.setScale('y', {
min: nyMin,
max: nyMax,
});
});
});
};
@ -99,7 +99,7 @@ const touchZoomPlugin = () => {
if (!rafPending) {
rafPending = true;
requestAnimationFrame(zoom);
requestAnimationFrame(zoomCharts);
}
};
@ -128,6 +128,8 @@ const touchZoomPlugin = () => {
over.addEventListener('touchend', (_e: TouchEvent) => {
document.removeEventListener('touchmove', touchmove);
});
chartInstances.push(u); // Add the current chart instance to the list
};
return {