-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4f9afde
commit 26e5f28
Showing
5 changed files
with
142 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |