Synchronize graphs on zoom (#1315)
This commit is contained in:
parent
10b6150a7a
commit
f06382b5a1
|
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue