Add Wheel Zoom plugin (#1313)

This commit is contained in:
Karol Piecuch 2023-09-26 13:15:36 +02:00 committed by GitHub
parent 4f9afdefe9
commit 26e5f28119
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 142 additions and 3 deletions

5
.gitattributes vendored Normal file
View File

@ -0,0 +1,5 @@
# automatically normalize line endings
* text=auto
# force bash scripts to always use LF line endings
*.sh text eol=lf

View File

@ -6,6 +6,7 @@ import UplotReact from 'uplot-react';
import { Colors } from '../../utils/colors';
import { colorHsl, formatNumberMs } from '../../utils/numbers';
import { isNumber } from '../../utils/tune/expression';
import mouseZoomPlugin from '../../utils/uPlot/mouseZoomPlugin';
import touchZoomPlugin from '../../utils/uPlot/touchZoomPlugin';
export interface SelectedField {
@ -144,7 +145,7 @@ const LogCanvas = ({
sync: { key: plotSyncKey },
points: { size: 7 },
},
plugins: [touchZoomPlugin()],
plugins: [touchZoomPlugin(), mouseZoomPlugin()],
},
};
},

View File

@ -3,6 +3,7 @@ import uPlot from 'uplot';
import UplotReact from 'uplot-react';
import { Colors } from '../../utils/colors';
import { CompositeLogEntry } from '../../utils/logs/TriggerLogsParser';
import mouseZoomPlugin from '../../utils/uPlot/mouseZoomPlugin';
import touchZoomPlugin from '../../utils/uPlot/touchZoomPlugin';
import LogsPagination from './LogsPagination';
@ -103,7 +104,7 @@ const CompositeCanvas = ({ data, width, height }: Props) => {
drag: { y: false },
points: { size: 7 },
},
plugins: [touchZoomPlugin()],
plugins: [touchZoomPlugin(), mouseZoomPlugin()],
});
}, [data, width, height, indexFrom, indexTo]);

View File

@ -3,6 +3,7 @@ import uPlot from 'uplot';
import UplotReact from 'uplot-react';
import { Colors } from '../../utils/colors';
import { EntryType, ToothLogEntry } from '../../utils/logs/TriggerLogsParser';
import mouseZoomPlugin from '../../utils/uPlot/mouseZoomPlugin';
import touchZoomPlugin from '../../utils/uPlot/touchZoomPlugin';
import LogsPagination from './LogsPagination';
@ -69,7 +70,7 @@ const ToothCanvas = ({ data, width, height }: Props) => {
drag: { y: false },
points: { size: 7 },
},
plugins: [touchZoomPlugin()],
plugins: [touchZoomPlugin(), mouseZoomPlugin()],
});
}, [data, width, height, indexFrom, indexTo]);

View File

@ -0,0 +1,131 @@
import uPlot from 'uplot';
import { Plugin } from 'uplot';
interface WheelZoomPluginOptions {
factor?: number;
animationDuration?: number;
}
function wheelZoomPlugin(options: WheelZoomPluginOptions = {}): Plugin {
const factor = options.factor || 0.9;
let xMin: number;
let xMax: number;
let yMin: number;
let yMax: number;
let xRange: number;
let yRange: number;
let over = null;
let rect: DOMRect;
function isCtrlPressed(e: MouseEvent): boolean {
return e.ctrlKey || e.metaKey;
}
function clamp(
nRange: number,
nMin: number,
nMax: number,
fRange: number,
fMin: number,
fMax: number,
): [number, number] {
let newNMin = nMin;
let newNMax = nMax;
if (nRange > fRange) {
newNMin = fMin;
newNMax = fMax;
} else if (nMin < fMin) {
newNMin = fMin;
newNMax = fMin + nRange;
} else if (nMax > fMax) {
newNMax = fMax;
newNMin = fMax - nRange;
}
return [newNMin, newNMax];
}
return {
hooks: {
ready(u: uPlot) {
xMin = u.scales.x.min ?? 0;
xMax = u.scales.x.max ?? 0;
yMin = u.scales.y.min ?? 0;
yMax = u.scales.y.max ?? 0;
xRange = xMax - xMin;
yRange = yMax - yMin;
over = u.over;
rect = over.getBoundingClientRect();
over.addEventListener('mousedown', (e: MouseEvent) => {
if (e.button === 1) {
e.preventDefault();
const left0 = e.clientX;
const scXMin0 = u.scales.x.min;
const scXMax0 = u.scales.x.max;
const xUnitsPerPx = u.valToPos(1, 'x') - u.valToPos(0, 'x');
function onMove(e: MouseEvent) {
e.preventDefault();
const left1 = e.clientX;
const dx = xUnitsPerPx * (left1 - left0);
u.setScale('x', {
min: (scXMin0 ?? 0) - dx,
max: (scXMax0 ?? 0) - dx,
});
}
document.addEventListener('mousemove', onMove);
}
});
over.addEventListener('wheel', (e: WheelEvent) => {
e.preventDefault();
if (!isCtrlPressed(e)) {
return;
}
const cursor = u.cursor;
const { left, top } = cursor;
const leftPct = (left || 0) / rect.width;
const btmPct = 1 - (top || 0) / rect.height;
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);
const oyRange = (u.scales.y.max || 0) - (u.scales.y.min || 0);
const 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);
const 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,
});
});
});
},
},
};
}
export default wheelZoomPlugin;