Skip to content

Commit

Permalink
Add Wheel Zoom plugin (#1313)
Browse files Browse the repository at this point in the history
  • Loading branch information
VillageR88 authored Sep 26, 2023
1 parent 4f9afde commit 26e5f28
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# automatically normalize line endings
* text=auto

# force bash scripts to always use LF line endings
*.sh text eol=lf
3 changes: 2 additions & 1 deletion src/components/Logs/LogCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -144,7 +145,7 @@ const LogCanvas = ({
sync: { key: plotSyncKey },
points: { size: 7 },
},
plugins: [touchZoomPlugin()],
plugins: [touchZoomPlugin(), mouseZoomPlugin()],
},
};
},
Expand Down
3 changes: 2 additions & 1 deletion src/components/TriggerLogs/CompositeCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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]);

Expand Down
3 changes: 2 additions & 1 deletion src/components/TriggerLogs/ToothCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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]);

Expand Down
131 changes: 131 additions & 0 deletions src/utils/uPlot/mouseZoomPlugin.ts
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 26e5f28

Please sign in to comment.