@antv/x6-react-components
Version:
React components for building x6 editors
193 lines (178 loc) • 6.26 kB
text/typescript
import { UAParser } from 'ua-parser-js'
import { isEventSupported } from './isEventSupported'
const PIXEL_STEP = 10
const LINE_HEIGHT = 40
const PAGE_HEIGHT = 800
const uaParser = new UAParser()
const uaObject = uaParser.getResult()
const isFirefox = uaObject.browser.name === 'Firefox'
/**
* Mouse wheel (and 2-finger trackpad) support on the web sucks. It is
* complicated, thus this doc is long and (hopefully) detailed enough to answer
* your questions.
*
* If you need to react to the mouse wheel in a predictable way, this code is
* like your bestest friend. * hugs *
*
* As of today, there are 4 DOM event types you can listen to:
*
* 'wheel' -- Chrome(31+), FF(17+), IE(9+)
* 'mousewheel' -- Chrome, IE(6+), Opera, Safari
* 'MozMousePixelScroll' -- FF(3.5 only!) (2010-2013) -- don't bother!
* 'DOMMouseScroll' -- FF(0.9.7+) since 2003
*
* So what to do? The is the best:
*
* getEventType();
*
* In your event callback, use this code to get sane interpretation of the
* deltas. This code will return an object with properties:
*
* spinX -- normalized spin speed (use for zoom) - x plane
* spinY -- " - y plane
* pixelX -- normalized distance (to pixels) - x plane
* pixelY -- " - y plane
*
* Wheel values are provided by the browser assuming you are using the wheel to
* scroll a web page by a number of lines or pixels (or pages). Values can vary
* significantly on different platforms and browsers, forgetting that you can
* scroll at different speeds. Some devices (like trackpads) emit more events
* at smaller increments with fine granularity, and some emit massive jumps with
* linear speed or acceleration.
*
* This code does its best to normalize the deltas for you:
*
* - spin is trying to normalize how far the wheel was spun (or trackpad
* dragged). This is super useful for zoom support where you want to
* throw away the chunky scroll steps on the PC and make those equal to
* the slow and smooth tiny steps on the Mac. Key data: This code tries to
* resolve a single slow step on a wheel to 1.
*
* - pixel is normalizing the desired scroll delta in pixel units. You'll
* get the crazy differences between browsers, but at least it'll be in
* pixels!
*
* - positive value indicates scrolling DOWN/RIGHT, negative UP/LEFT. This
* should translate to positive value zooming IN, negative zooming OUT.
* This matches the newer 'wheel' event.
*
* Why are there spinX, spinY (or pixels)?
*
* - spinX is a 2-finger side drag on the trackpad, and a shift + wheel turn
* with a mouse. It results in side-scrolling in the browser by default.
*
* - spinY is what you expect -- it's the classic axis of a mouse wheel.
*
* - I dropped spinZ/pixelZ. It is supported by the DOM 3 'wheel' event and
* probably is by browsers in conjunction with fancy 3D controllers .. but
* you know.
*
* Implementation info:
*
* Examples of 'wheel' event if you scroll slowly (down) by one step with an
* average mouse:
*
* OS X + Chrome (mouse) - 4 pixel delta (wheelDelta -120)
* OS X + Safari (mouse) - N/A pixel delta (wheelDelta -12)
* OS X + Firefox (mouse) - 0.1 line delta (wheelDelta N/A)
* Win8 + Chrome (mouse) - 100 pixel delta (wheelDelta -120)
* Win8 + Firefox (mouse) - 3 line delta (wheelDelta -120)
*
* On the trackpad:
*
* OS X + Chrome (trackpad) - 2 pixel delta (wheelDelta -6)
* OS X + Firefox (trackpad) - 1 pixel delta (wheelDelta N/A)
*
* On other/older browsers.. it's more complicated as there can be multiple and
* also missing delta values.
*
* The 'wheel' event is more standard:
*
* http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents
*
* The basics is that it includes a unit, deltaMode (pixels, lines, pages), and
* deltaX, deltaY and deltaZ. Some browsers provide other values to maintain
* backward compatibility with older events. Those other values help us
* better normalize spin speed. Example of what the browsers provide:
*
* | event.wheelDelta | event.detail
* ------------------+------------------+--------------
* Safari v5/OS X | -120 | 0
* Safari v5/Win7 | -120 | 0
* Chrome v17/OS X | -120 | 0
* Chrome v17/Win7 | -120 | 0
* IE9/Win7 | -120 | undefined
* Firefox v4/OS X | undefined | 1
* Firefox v4/Win7 | undefined | 3
*
*/
export function normalizeWheel(e: any) {
let spinX = 0
let spinY = 0
let pixelX = 0
let pixelY = 0
// legacy
if ('detail' in e) {
spinY = e.detail
}
if ('wheelDelta' in e) {
spinY = -e.wheelDelta / 120
}
if ('wheelDeltaY' in e) {
spinY = -e.wheelDeltaY / 120
}
if ('wheelDeltaX' in e) {
spinX = -e.wheelDeltaX / 120
}
// side scrolling on FF with DOMMouseScroll
if ('axis' in e && e.axis === e.HORIZONTAL_AXIS) {
spinX = spinY
spinY = 0
}
pixelX = spinX * PIXEL_STEP
pixelY = spinY * PIXEL_STEP
if ('deltaY' in e) {
pixelY = e.deltaY
}
if ('deltaX' in e) {
pixelX = e.deltaX
}
if ((pixelX || pixelY) && e.deltaMode) {
if (e.deltaMode === 1) {
// delta in LINE units
pixelX *= LINE_HEIGHT
pixelY *= LINE_HEIGHT
} else {
// delta in PAGE units
pixelX *= PAGE_HEIGHT
pixelY *= PAGE_HEIGHT
}
}
// fall-back if spin cannot be determined
if (pixelX && !spinX) {
spinX = pixelX < 1 ? -1 : 1
}
if (pixelY && !spinY) {
spinY = pixelY < 1 ? -1 : 1
}
return {
spinX,
spinY,
pixelX,
pixelY,
}
}
/**
* The best combination if you prefer spinX + spinY normalization. It favors
* the older DOMMouseScroll for Firefox, as FF does not include wheelDelta with
* 'wheel' event, making spin speed determination impossible.
*/
export function getEventType(): string {
if (isFirefox) {
return 'DOMMouseScroll'
}
if (isEventSupported('wheel')) {
return 'wheel'
}
return 'mousewheel'
}