molstar
Version:
A comprehensive macromolecular library.
837 lines (836 loc) • 32.9 kB
JavaScript
/**
* Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
* @author David Sehnal <david.sehnal@gmail.com>
* @author Russell Parker <russell@benchling.com>
* @author Herman Bergwerf <post@hbergwerf.nl>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.InputObserver = exports.EmptyKeyInput = exports.ButtonsType = exports.ModifiersKeys = exports.DefaultInputObserverProps = void 0;
exports.getButtons = getButtons;
exports.getButton = getButton;
exports.getModifiers = getModifiers;
exports.normalizeWheel = normalizeWheel;
const rxjs_1 = require("rxjs");
const util_1 = require("../../mol-canvas3d/camera/util");
const linear_algebra_1 = require("../../mol-math/linear-algebra");
const mol_util_1 = require("../../mol-util");
function getButtons(event) {
if (typeof event === 'object') {
if ('buttons' in event) {
return event.buttons;
}
else if ('which' in event) {
const b = event.which; // 'any' to support older browsers
if (b === 2) {
return 4;
}
else if (b === 3) {
return 2;
}
else if (b > 0) {
return 1 << (b - 1);
}
}
}
return 0;
}
function getButton(event) {
if (typeof event === 'object') {
if ('button' in event) {
const b = event.button;
if (b === 1) {
return 4;
}
else if (b === 2) {
return 2;
}
else if (b >= 0) {
return 1 << b;
}
}
}
return 0;
}
function getModifiers(event) {
return {
alt: 'altKey' in event ? event.altKey : false,
shift: 'shiftKey' in event ? event.shiftKey : false,
control: 'ctrlKey' in event ? event.ctrlKey : false,
meta: 'metaKey' in event ? event.metaKey : false
};
}
exports.DefaultInputObserverProps = {
noScroll: true,
noMiddleClickScroll: true,
noContextMenu: true,
noPinchZoom: true,
noTextSelect: true,
preventGestures: false,
mask: (x, y) => true,
pixelScale: 1
};
var ModifiersKeys;
(function (ModifiersKeys) {
ModifiersKeys.None = create();
function areEqual(a, b) {
return a.shift === b.shift && a.alt === b.alt && a.control === b.control && a.meta === b.meta;
}
ModifiersKeys.areEqual = areEqual;
function areNone(a) {
return areEqual(a, ModifiersKeys.None);
}
ModifiersKeys.areNone = areNone;
function size(a) {
if (!a)
return 0;
let ret = 0;
if (!!a.shift)
ret++;
if (!!a.alt)
ret++;
if (!!a.control)
ret++;
if (!!a.meta)
ret++;
return ret;
}
ModifiersKeys.size = size;
function create(modifierKeys = {}) {
return {
shift: !!modifierKeys.shift,
alt: !!modifierKeys.alt,
control: !!modifierKeys.control,
meta: !!modifierKeys.meta
};
}
ModifiersKeys.create = create;
})(ModifiersKeys || (exports.ModifiersKeys = ModifiersKeys = {}));
var ButtonsType;
(function (ButtonsType) {
ButtonsType.has = mol_util_1.BitFlags.has;
ButtonsType.create = mol_util_1.BitFlags.create;
let Flag;
(function (Flag) {
/** No button or un-initialized */
Flag[Flag["None"] = 0] = "None";
/** Primary button (usually left) */
Flag[Flag["Primary"] = 1] = "Primary";
/** Secondary button (usually right) */
Flag[Flag["Secondary"] = 2] = "Secondary";
/** Auxilary button (usually middle or mouse wheel button) */
Flag[Flag["Auxilary"] = 4] = "Auxilary";
/** 4th button (typically the "Browser Back" button) */
Flag[Flag["Forth"] = 8] = "Forth";
/** 5th button (typically the "Browser Forward" button) */
Flag[Flag["Five"] = 16] = "Five";
})(Flag = ButtonsType.Flag || (ButtonsType.Flag = {}));
})(ButtonsType || (exports.ButtonsType = ButtonsType = {}));
exports.EmptyKeyInput = {
key: '',
code: '',
modifiers: ModifiersKeys.None,
x: -1,
y: -1,
pageX: -1,
pageY: -1,
preventDefault: mol_util_1.noop,
};
var DraggingState;
(function (DraggingState) {
DraggingState[DraggingState["Stopped"] = 0] = "Stopped";
DraggingState[DraggingState["Started"] = 1] = "Started";
DraggingState[DraggingState["Moving"] = 2] = "Moving";
})(DraggingState || (DraggingState = {}));
function createEvents() {
return {
drag: new rxjs_1.Subject(),
interactionEnd: new rxjs_1.Subject(),
click: new rxjs_1.Subject(),
move: new rxjs_1.Subject(),
wheel: new rxjs_1.Subject(),
pinch: new rxjs_1.Subject(),
gesture: new rxjs_1.Subject(),
resize: new rxjs_1.Subject(),
leave: new rxjs_1.Subject(),
enter: new rxjs_1.Subject(),
modifiers: new rxjs_1.Subject(),
key: new rxjs_1.Subject(),
keyUp: new rxjs_1.Subject(),
keyDown: new rxjs_1.Subject(),
lock: new rxjs_1.Subject(),
};
}
const AllowedNonPrintableKeys = ['Backspace', 'Delete'];
var InputObserver;
(function (InputObserver) {
function create(props = {}) {
const { noScroll, noContextMenu } = { ...exports.DefaultInputObserverProps, ...props };
return {
noScroll,
noContextMenu,
pointerLock: false,
width: 0,
height: 0,
pixelRatio: 1,
...createEvents(),
setPixelScale: mol_util_1.noop,
requestPointerLock: mol_util_1.noop,
exitPointerLock: mol_util_1.noop,
dispose: mol_util_1.noop
};
}
InputObserver.create = create;
function fromElement(element, props = {}) {
let { noScroll, noMiddleClickScroll, noContextMenu, noPinchZoom, noTextSelect, mask, pixelScale, preventGestures } = { ...exports.DefaultInputObserverProps, ...props };
let width = element.clientWidth * pixelRatio();
let height = element.clientHeight * pixelRatio();
let isLocked = false;
let lockedViewport = (0, util_1.Viewport)();
const pointerDown = (0, linear_algebra_1.Vec2)();
const pointerStart = (0, linear_algebra_1.Vec2)();
const pointerEnd = (0, linear_algebra_1.Vec2)();
const pointerDelta = (0, linear_algebra_1.Vec2)();
const rectSize = (0, linear_algebra_1.Vec2)();
const modifierKeys = {
shift: false,
alt: false,
control: false,
meta: false
};
const position = {
x: -1,
y: -1,
pageX: -1,
pageY: -1,
};
function pixelRatio() {
return window.devicePixelRatio * pixelScale;
}
function getModifierKeys() {
return { ...modifierKeys };
}
function getKeyOnElement(event) {
return event.target === document.body || event.target === element;
}
let dragging = DraggingState.Stopped;
let disposed = false;
let buttons = ButtonsType.create(ButtonsType.Flag.None);
let button = ButtonsType.Flag.None;
let isInside = false;
let hasMoved = false;
let resizeObserver;
if (typeof window.ResizeObserver !== 'undefined') {
resizeObserver = new window.ResizeObserver(onResize);
}
const events = createEvents();
const { drag, interactionEnd, wheel, pinch, gesture, click, move, leave, enter, resize, modifiers, key, keyUp, keyDown, lock } = events;
attach();
function attach() {
element.addEventListener('contextmenu', onContextMenu, false);
element.addEventListener('wheel', onMouseWheel, false);
element.addEventListener('mousedown', onMouseDown, false);
// for dragging to work outside canvas bounds,
// mouse move/up events have to be added to a parent, i.e. window
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('mouseup', onMouseUp, false);
element.addEventListener('touchstart', onTouchStart, false);
element.addEventListener('touchmove', onTouchMove, false);
element.addEventListener('touchend', onTouchEnd, false);
element.addEventListener('gesturechange', onGestureChange, false);
element.addEventListener('gesturestart', onGestureStart, false);
element.addEventListener('gestureend', onGestureEnd, false);
// reset buttons and modifier keys state when browser window looses focus
window.addEventListener('blur', handleBlur);
window.addEventListener('keyup', handleKeyUp, false);
window.addEventListener('keydown', handleKeyDown, false);
window.addEventListener('keypress', handleKeyPress, false);
document.addEventListener('pointerlockchange', onPointerLockChange, false);
document.addEventListener('pointerlockerror', onPointerLockError, false);
if (resizeObserver != null) {
resizeObserver.observe(element.parentElement);
}
else {
window.addEventListener('resize', onResize, false);
}
}
function dispose() {
if (disposed)
return;
disposed = true;
element.removeEventListener('contextmenu', onContextMenu, false);
element.removeEventListener('wheel', onMouseWheel, false);
element.removeEventListener('mousedown', onMouseDown, false);
window.removeEventListener('mousemove', onMouseMove, false);
window.removeEventListener('mouseup', onMouseUp, false);
element.removeEventListener('touchstart', onTouchStart, false);
element.removeEventListener('touchmove', onTouchMove, false);
element.removeEventListener('touchend', onTouchEnd, false);
element.removeEventListener('gesturechange', onGestureChange, false);
element.removeEventListener('gesturestart', onGestureStart, false);
element.removeEventListener('gestureend', onGestureEnd, false);
window.removeEventListener('blur', handleBlur);
window.removeEventListener('keyup', handleKeyUp, false);
window.removeEventListener('keydown', handleKeyDown, false);
window.removeEventListener('keypress', handleKeyPress, false);
document.removeEventListener('pointerlockchange', onPointerLockChange, false);
document.removeEventListener('pointerlockerror', onPointerLockError, false);
cross.remove();
if (resizeObserver != null) {
resizeObserver.unobserve(element.parentElement);
resizeObserver.disconnect();
}
else {
window.removeEventListener('resize', onResize, false);
}
}
function onPointerLockChange() {
if (element.ownerDocument.pointerLockElement === element) {
isLocked = true;
}
else {
isLocked = false;
}
toggleCross(isLocked);
lock.next(isLocked);
}
function onPointerLockError() {
console.error('Unable to use Pointer Lock API');
isLocked = false;
toggleCross(isLocked);
lock.next(isLocked);
}
function onContextMenu(event) {
if (!mask(event.clientX, event.clientY))
return;
if (noContextMenu) {
event.preventDefault();
}
}
function updateModifierKeys(event) {
modifierKeys.alt = event.altKey;
modifierKeys.shift = event.shiftKey;
modifierKeys.control = event.ctrlKey;
modifierKeys.meta = event.metaKey;
}
function handleBlur() {
if (buttons || modifierKeys.shift || modifierKeys.alt || modifierKeys.meta || modifierKeys.control) {
buttons = 0;
modifierKeys.shift = modifierKeys.alt = modifierKeys.control = modifierKeys.meta = false;
}
}
function handleKeyDown(event) {
let changed = false;
if (!modifierKeys.alt && event.altKey) {
changed = true;
modifierKeys.alt = true;
}
if (!modifierKeys.shift && event.shiftKey) {
changed = true;
modifierKeys.shift = true;
}
if (!modifierKeys.control && event.ctrlKey) {
changed = true;
modifierKeys.control = true;
}
if (!modifierKeys.meta && event.metaKey) {
changed = true;
modifierKeys.meta = true;
}
if (changed && isInside)
modifiers.next(getModifierKeys());
if (getKeyOnElement(event) && isInside) {
keyDown.next({
key: event.key,
code: event.code,
modifiers: getModifierKeys(),
...position,
preventDefault: () => event.preventDefault(),
});
}
}
function handleKeyUp(event) {
let changed = false;
if (modifierKeys.alt && !event.altKey) {
changed = true;
modifierKeys.alt = false;
}
if (modifierKeys.shift && !event.shiftKey) {
changed = true;
modifierKeys.shift = false;
}
if (modifierKeys.control && !event.ctrlKey) {
changed = true;
modifierKeys.control = false;
}
if (modifierKeys.meta && !event.metaKey) {
changed = true;
modifierKeys.meta = false;
}
if (changed && isInside)
modifiers.next(getModifierKeys());
if (AllowedNonPrintableKeys.includes(event.key))
handleKeyPress(event);
if (getKeyOnElement(event) && isInside) {
keyUp.next({
key: event.key,
code: event.code,
modifiers: getModifierKeys(),
...position,
preventDefault: () => event.preventDefault(),
});
}
}
function handleKeyPress(event) {
if (!getKeyOnElement(event) || !isInside)
return;
key.next({
key: event.key,
code: event.code,
modifiers: getModifierKeys(),
...position,
preventDefault: () => event.preventDefault(),
});
}
function getCenterTouch(ev) {
const t0 = ev.touches[0];
const t1 = ev.touches[1];
return {
clientX: (t0.clientX + t1.clientX) / 2,
clientY: (t0.clientY + t1.clientY) / 2,
pageX: (t0.pageX + t1.pageX) / 2,
pageY: (t0.pageY + t1.pageY) / 2,
target: ev.target
};
}
function getTouchDistance(ev) {
const dx = ev.touches[0].pageX - ev.touches[1].pageX;
const dy = ev.touches[0].pageY - ev.touches[1].pageY;
return Math.sqrt(dx * dx + dy * dy);
}
let singleTouchDistance = -1;
let lastSingleTouch = undefined;
const singleTouchPosition = (0, linear_algebra_1.Vec2)(), singleTouchTmp = (0, linear_algebra_1.Vec2)();
function updateSingleTouchDistance(ev) {
if (singleTouchDistance < 0)
return;
linear_algebra_1.Vec2.set(singleTouchTmp, ev.touches[0].pageX, ev.touches[0].pageY);
singleTouchDistance += linear_algebra_1.Vec2.distance(singleTouchPosition, singleTouchTmp);
linear_algebra_1.Vec2.copy(singleTouchPosition, singleTouchTmp);
}
const firstTouchStart = (0, linear_algebra_1.Vec2)();
let firstTouchStartSet = false;
let initialTouchDistance = 0, lastTouchFraction = 1;
function onTouchStart(ev) {
ev.preventDefault();
lastSingleTouch = undefined;
singleTouchDistance = -1;
if (ev.touches.length === 1) {
buttons = button = ButtonsType.Flag.Primary;
singleTouchDistance = 0;
linear_algebra_1.Vec2.set(singleTouchPosition, ev.touches[0].pageX, ev.touches[0].pageY);
lastSingleTouch = ev.touches[0];
onPointerDown(ev.touches[0]);
linear_algebra_1.Vec2.copy(firstTouchStart, pointerStart);
firstTouchStartSet = true;
}
else if (ev.touches.length === 2) {
buttons = ButtonsType.Flag.Secondary | ButtonsType.Flag.Auxilary;
button = ButtonsType.Flag.Secondary;
updateModifierKeys(ev);
lastTouchFraction = 1;
initialTouchDistance = getTouchDistance(ev);
const { pageX: centerPageX, pageY: centerPageY } = getPagePosition(getCenterTouch(ev));
if (!firstTouchStartSet) {
eventOffset(firstTouchStart, getCenterTouch(ev));
firstTouchStartSet = true;
}
pinch.next({
isStart: true,
distance: initialTouchDistance,
delta: 0,
fraction: lastTouchFraction,
fractionDelta: 0,
startX: firstTouchStart[0],
startY: firstTouchStart[1],
centerPageX,
centerPageY,
buttons,
button,
modifiers: getModifierKeys()
});
}
else if (ev.touches.length === 3) {
buttons = button = ButtonsType.Flag.Forth;
onPointerDown(getCenterTouch(ev));
}
}
function onTouchEnd(ev) {
endDrag();
if (lastSingleTouch && singleTouchDistance <= 4) {
const t = lastSingleTouch;
if (!mask(t.clientX, t.clientY))
return;
eventOffset(singleTouchTmp, t);
const { pageX, pageY } = getPagePosition(t);
const [x, y] = singleTouchTmp;
click.next({ x, y, pageX, pageY, buttons, button, modifiers: getModifierKeys() });
}
lastSingleTouch = undefined;
firstTouchStartSet = false;
}
function onTouchMove(ev) {
button = ButtonsType.Flag.None;
if (noPinchZoom) {
ev.preventDefault();
ev.stopPropagation();
if (ev.originalEvent) {
ev.originalEvent.preventDefault();
ev.originalEvent.stopPropagation();
}
}
lastSingleTouch = undefined;
if (ev.touches.length === 1) {
buttons = ButtonsType.Flag.Primary;
lastSingleTouch = ev.touches[0];
updateSingleTouchDistance(ev);
onPointerMove(ev.touches[0]);
}
else if (ev.touches.length === 2) {
buttons = ButtonsType.Flag.Secondary | ButtonsType.Flag.Auxilary;
button = ButtonsType.Flag.Secondary;
updateModifierKeys(ev);
const { pageX: centerPageX, pageY: centerPageY } = getPagePosition(getCenterTouch(ev));
const distance = getTouchDistance(ev);
const delta = initialTouchDistance - distance;
const fraction = initialTouchDistance / distance;
const fractionDelta = fraction - lastTouchFraction;
lastTouchFraction = fraction;
pinch.next({
isStart: false,
distance,
delta,
fraction,
fractionDelta,
startX: firstTouchStart[0],
startY: firstTouchStart[1],
centerPageX,
centerPageY,
buttons,
button,
modifiers: getModifierKeys()
});
}
else if (ev.touches.length === 3) {
buttons = ButtonsType.Flag.Forth;
onPointerMove(getCenterTouch(ev));
}
}
function onMouseDown(ev) {
updateModifierKeys(ev);
buttons = getButtons(ev);
button = getButton(ev);
if (noMiddleClickScroll && buttons === ButtonsType.Flag.Auxilary) {
ev.preventDefault;
}
onPointerDown(ev);
}
function onMouseMove(ev) {
updateModifierKeys(ev);
buttons = getButtons(ev);
button = ButtonsType.Flag.None;
onPointerMove(ev);
}
function onMouseUp(ev) {
updateModifierKeys(ev);
buttons = getButtons(ev);
button = getButton(ev);
onPointerUp(ev);
endDrag();
}
function endDrag() {
interactionEnd.next(void 0);
}
function onPointerDown(ev) {
if (!mask(ev.clientX, ev.clientY))
return;
eventOffset(pointerStart, ev);
linear_algebra_1.Vec2.copy(pointerDown, pointerStart);
if (insideBounds(pointerStart)) {
dragging = DraggingState.Started;
}
}
function onPointerUp(ev) {
dragging = DraggingState.Stopped;
if (!mask(ev.clientX, ev.clientY))
return;
eventOffset(pointerEnd, ev);
if (!hasMoved && linear_algebra_1.Vec2.distance(pointerEnd, pointerDown) < 4) {
const { pageX, pageY } = getPagePosition(ev);
const [x, y] = pointerEnd;
click.next({ x, y, pageX, pageY, buttons, button, modifiers: getModifierKeys() });
}
hasMoved = false;
}
function onPointerMove(ev) {
var _a;
eventOffset(pointerEnd, ev);
const { pageX, pageY } = getPagePosition(ev);
const [x, y] = pointerEnd;
const { movementX, movementY } = ev;
const inside = insideBounds(pointerEnd) && mask(ev.clientX, ev.clientY);
if (isInside && !inside) {
leave.next(void 0);
}
else if (!isInside && inside) {
enter.next(void 0);
}
isInside = inside;
position.x = x;
position.y = y;
position.pageX = pageX;
position.pageY = pageY;
move.next({ x, y, pageX, pageY, movementX, movementY, buttons, button, modifiers: getModifierKeys(), inside, onElement: ev.target === element });
if (dragging === DraggingState.Stopped)
return;
if (noTextSelect) {
(_a = ev.preventDefault) === null || _a === void 0 ? void 0 : _a.call(ev);
}
linear_algebra_1.Vec2.div(pointerDelta, linear_algebra_1.Vec2.sub(pointerDelta, pointerEnd, pointerStart), getClientSize(rectSize));
if (linear_algebra_1.Vec2.magnitude(pointerDelta) < linear_algebra_1.EPSILON)
return;
const isStart = dragging === DraggingState.Started;
if (isStart && !mask(ev.clientX, ev.clientY))
return;
if (linear_algebra_1.Vec2.distance(pointerEnd, pointerDown) >= 4) {
hasMoved = true;
}
const [dx, dy] = pointerDelta;
drag.next({ x, y, dx, dy, pageX, pageY, buttons, button, modifiers: getModifierKeys(), isStart });
linear_algebra_1.Vec2.copy(pointerStart, pointerEnd);
dragging = DraggingState.Moving;
}
function onMouseWheel(ev) {
if (!mask(ev.clientX, ev.clientY))
return;
eventOffset(pointerEnd, ev);
const { pageX, pageY } = getPagePosition(ev);
const [x, y] = pointerEnd;
if (noScroll) {
ev.preventDefault();
}
const normalized = normalizeWheel(ev);
buttons = button = ButtonsType.Flag.Auxilary;
if (normalized.dx || normalized.dy || normalized.dz) {
wheel.next({ x, y, pageX, pageY, ...normalized, buttons, button, modifiers: getModifierKeys() });
}
}
function tryPreventGesture(ev) {
var _a, _b;
// console.log(ev, preventGestures);
if (!preventGestures)
return;
ev.preventDefault();
(_a = ev.stopImmediatePropagation) === null || _a === void 0 ? void 0 : _a.call(ev);
(_b = ev.stopPropagation) === null || _b === void 0 ? void 0 : _b.call(ev);
}
let prevGestureScale = 0, prevGestureRotation = 0;
function onGestureStart(ev) {
tryPreventGesture(ev);
prevGestureScale = ev.scale;
prevGestureRotation = ev.rotation;
gesture.next({ scale: ev.scale, rotation: ev.rotation, deltaRotation: 0, deltaScale: 0, isStart: true });
}
function gestureDelta(ev, isEnd) {
gesture.next({
scale: ev.scale,
rotation: ev.rotation,
deltaRotation: prevGestureRotation - ev.rotation,
deltaScale: prevGestureScale - ev.scale,
isEnd
});
prevGestureRotation = ev.rotation;
prevGestureScale = ev.scale;
}
function onGestureChange(ev) {
tryPreventGesture(ev);
gestureDelta(ev);
}
function onGestureEnd(ev) {
tryPreventGesture(ev);
gestureDelta(ev, true);
}
function onResize() {
width = element.clientWidth * pixelRatio();
height = element.clientHeight * pixelRatio();
resize.next({});
}
function insideBounds(pos) {
if (element instanceof Window || element instanceof Document || element === document.body) {
return true;
}
else {
const rect = element.getBoundingClientRect();
return pos[0] >= 0 && pos[1] >= 0 && pos[0] < rect.width && pos[1] < rect.height;
}
}
function getClientSize(out) {
out[0] = element.clientWidth;
out[1] = element.clientHeight;
return out;
}
function eventOffset(out, ev) {
width = element.clientWidth * pixelRatio();
height = element.clientHeight * pixelRatio();
if (isLocked) {
const pr = pixelRatio();
out[0] = (lockedViewport.x + lockedViewport.width / 2) / pr;
out[1] = (height - (lockedViewport.y + lockedViewport.height / 2)) / pr;
}
else {
const rect = element.getBoundingClientRect();
out[0] = (ev.clientX || 0) - rect.left;
out[1] = (ev.clientY || 0) - rect.top;
}
return out;
}
function getPagePosition(ev) {
if (isLocked) {
return {
pageX: Math.round(window.innerWidth / 2) + lockedViewport.x,
pageY: Math.round(window.innerHeight / 2) + lockedViewport.y
};
}
else {
return {
pageX: ev.pageX,
pageY: ev.pageY
};
}
}
const crossWidth = 30;
const cross = addCross();
function addCross() {
var _a;
const cross = document.createElement('div');
const b = '30%';
const t = '10%';
const c = `#000 ${b}, #0000 0 calc(100% - ${b}), #000 0`;
const vline = `linear-gradient(0deg, ${c}) 50%/${t} 100% no-repeat`;
const hline = `linear-gradient(90deg, ${c}) 50%/100% ${t} no-repeat`;
const cdot = 'radial-gradient(circle at 50%, #000 5%, #0000 5%)';
Object.assign(cross.style, {
width: `${crossWidth}px`,
aspectRatio: 1,
background: `${vline}, ${hline}, ${cdot}`,
display: 'none',
zIndex: 1000,
position: 'absolute',
mixBlendMode: 'difference',
filter: 'invert(1)',
});
(_a = element.parentElement) === null || _a === void 0 ? void 0 : _a.appendChild(cross);
return cross;
}
function toggleCross(value) {
cross.style.display = value ? 'block' : 'none';
if (value) {
const pr = pixelRatio();
const offsetX = (lockedViewport.x + lockedViewport.width / 2) / pr;
const offsetY = (lockedViewport.y + lockedViewport.height / 2) / pr;
cross.style.width = `${crossWidth}px`;
cross.style.left = `calc(${offsetX}px - ${crossWidth / 2}px)`;
cross.style.bottom = `calc(${offsetY}px - ${crossWidth / 2}px)`;
}
}
return {
get noScroll() { return noScroll; },
set noScroll(value) { noScroll = value; },
get noContextMenu() { return noContextMenu; },
set noContextMenu(value) { noContextMenu = value; },
get width() { return width; },
get height() { return height; },
get pixelRatio() { return pixelRatio(); },
get pointerLock() { return isLocked; },
...events,
setPixelScale: (value) => {
pixelScale = value;
width = element.clientWidth * pixelRatio();
height = element.clientHeight * pixelRatio();
},
requestPointerLock: (viewport) => {
lockedViewport = viewport;
if (!isLocked) {
element.requestPointerLock();
}
},
exitPointerLock: () => {
if (isLocked) {
element.ownerDocument.exitPointerLock();
}
},
dispose
};
}
InputObserver.fromElement = fromElement;
})(InputObserver || (exports.InputObserver = InputObserver = {}));
// Adapted from https://stackoverflow.com/a/30134826
// License: https://creativecommons.org/licenses/by-sa/3.0/
function normalizeWheel(event) {
// Reasonable defaults
const PIXEL_STEP = 10;
const LINE_HEIGHT = 40;
const PAGE_HEIGHT = 800;
let spinX = 0, spinY = 0, dx = 0, dy = 0, dz = 0; // pixelX, pixelY, pixelZ
// Legacy
if ('detail' in event) {
spinY = event.detail;
}
if ('wheelDelta' in event) {
spinY = -event.wheelDelta / 120;
}
if ('wheelDeltaY' in event) {
spinY = -event.wheelDeltaY / 120;
}
if ('wheelDeltaX' in event) {
spinX = -event.wheelDeltaX / 120;
}
// side scrolling on FF with DOMMouseScroll
if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) {
spinX = spinY;
spinY = 0;
}
dx = spinX * PIXEL_STEP;
dy = spinY * PIXEL_STEP;
if ('deltaY' in event) {
dy = event.deltaY;
}
if ('deltaX' in event) {
dx = event.deltaX;
}
if ('deltaZ' in event) {
dz = event.deltaZ;
}
if ((dx || dy || dz) && event.deltaMode) {
if (event.deltaMode === 1) { // delta in LINE units
dx *= LINE_HEIGHT;
dy *= LINE_HEIGHT;
dz *= LINE_HEIGHT;
}
else { // delta in PAGE units
dx *= PAGE_HEIGHT;
dy *= PAGE_HEIGHT;
dz *= PAGE_HEIGHT;
}
}
// Fall-back if spin cannot be determined
if (dx && !spinX) {
spinX = (dx < 1) ? -1 : 1;
}
if (dy && !spinY) {
spinY = (dy < 1) ? -1 : 1;
}
return { spinX, spinY, dx, dy, dz };
}
;