UNPKG

@antv/x6-react-components

Version:

React components for building x6 editors

193 lines (178 loc) 6.26 kB
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' }