Skip to content

Commit

Permalink
feat: add inputKey option to PanInput and WheelInput (#204)
Browse files Browse the repository at this point in the history
* feat: add inputKey option to PanInput and WheelInput

* fix: set passive of WheelInput to true

* chore: set WheelInput event listener passive to false

* test: add test case for no inputButton

* docs: add inputKey demo

* feat: separate any and none in the condition of inputKey

* docs: add documentation for trackpad

* chore: update package.json

* chore: apply lint

* docs: update inputKey option
  • Loading branch information
malangfox authored Oct 8, 2022
1 parent 93e7279 commit 1169aca
Show file tree
Hide file tree
Showing 17 changed files with 347 additions and 55 deletions.
2 changes: 1 addition & 1 deletion packages/axes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"sinon": "^4.1.4",
"string-replace-webpack-plugin": "0.1.3",
"sync-exec": "^0.6.2",
"ts-loader": "^8.0.6",
"ts-loader": "8.0.6",
"typescript": "^4.6.2",
"uglifyjs-webpack-plugin": "^1.1.6",
"webpack": "^3.10.0",
Expand Down
7 changes: 7 additions & 0 deletions packages/axes/src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ export const MOUSE_LEFT = "left";
export const MOUSE_RIGHT = "right";
export const MOUSE_MIDDLE = "middle";

export const ANY = "any";
export const NONE = "none";
export const SHIFT = "shift";
export const CTRL = "ctrl";
export const ALT = "alt";
export const META = "meta";

export const VELOCITY_INTERVAL = 16;

export const AXES_METHODS = [
Expand Down
47 changes: 45 additions & 2 deletions packages/axes/src/eventInput/EventInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@ import { ExtendedEvent, InputEventType, LatestInterval } from "../types";
import { getAngle } from "../utils";
import { window } from "../browser";
import {
ALT,
ANY,
CTRL,
META,
MOUSE_LEFT,
MOUSE_MIDDLE,
MOUSE_RIGHT,
NONE,
SHIFT,
VELOCITY_INTERVAL,
} from "../const";

Expand All @@ -17,6 +23,28 @@ export const SUPPORT_POINTER = "PointerEvent" in window;
export const SUPPORT_MSPOINTER = "MSPointerEvent" in window;
export const SUPPORT_POINTER_EVENTS = SUPPORT_POINTER || SUPPORT_MSPOINTER;

export const isValidKey = (
event: InputEventType | WheelEvent,
inputKey?: string[]
): boolean => {
if (
!inputKey ||
inputKey.indexOf(ANY) > -1 ||
(inputKey.indexOf(NONE) > -1 &&
!event.shiftKey &&
!event.ctrlKey &&
!event.altKey &&
!event.metaKey) ||
(inputKey.indexOf(SHIFT) > -1 && event.shiftKey) ||
(inputKey.indexOf(CTRL) > -1 && event.ctrlKey) ||
(inputKey.indexOf(ALT) > -1 && event.altKey) ||
(inputKey.indexOf(META) > -1 && event.metaKey)
) {
return true;
}
return false;
};

export abstract class EventInput {
public prevEvent: ExtendedEvent;
private _latestInterval: LatestInterval;
Expand All @@ -35,7 +63,11 @@ export abstract class EventInput {

public abstract onRelease(event: InputEventType): void;

public abstract getTouches(event: InputEventType, inputButton?: string[]): number;
public abstract getTouches(
event: InputEventType,
inputKey?: string[],
inputButton?: string[]
): number;

protected abstract _getScale(event: InputEventType): number;

Expand Down Expand Up @@ -112,13 +144,24 @@ export abstract class EventInput {
}

protected _isTouchEvent(event: InputEventType): event is TouchEvent {
return event.type.indexOf("touch") > -1;
return event.type && event.type.indexOf("touch") > -1;
}

protected _isValidButton(button: string, inputButton: string[]): boolean {
return inputButton.indexOf(button) > -1;
}

protected _isValidEvent(
event: InputEventType,
inputKey?: string[],
inputButton?: string[]
): boolean {
return (
(!inputKey || isValidKey(event, inputKey)) &&
(!inputButton || this._isValidButton(this._getButton(event), inputButton))
);
}

protected _preventMouseButton(event: InputEventType, button: string): void {
if (button === MOUSE_RIGHT) {
window.addEventListener("contextmenu", this._stopContextMenu);
Expand Down
9 changes: 4 additions & 5 deletions packages/axes/src/eventInput/MouseEventInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ export class MouseEventInput extends EventInput {

public onEventStart(
event: InputEventType,
inputKey?: string[],
inputButton?: string[]
): ExtendedEvent {
const button = this._getButton(event);
if (inputButton && !this._isValidButton(button, inputButton)) {
if (!this._isValidEvent(event, inputKey, inputButton)) {
return null;
}
this._preventMouseButton(event, button);
Expand All @@ -26,12 +27,10 @@ export class MouseEventInput extends EventInput {

public onEventMove(
event: InputEventType,
inputKey?: string[],
inputButton?: string[]
): ExtendedEvent {
if (
inputButton &&
!this._isValidButton(this._getButton(event), inputButton)
) {
if (!this._isValidEvent(event, inputKey, inputButton)) {
return null;
}
return this.extendEvent(event);
Expand Down
9 changes: 4 additions & 5 deletions packages/axes/src/eventInput/PointerEventInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ export class PointerEventInput extends EventInput {

public onEventStart(
event: InputEventType,
inputKey?: string[],
inputButton?: string[]
): ExtendedEvent {
const button = this._getButton(event);
if (inputButton && !this._isValidButton(button, inputButton)) {
if (!this._isValidEvent(event, inputKey, inputButton)) {
return null;
}
this._preventMouseButton(event, button);
Expand All @@ -32,12 +33,10 @@ export class PointerEventInput extends EventInput {

public onEventMove(
event: InputEventType,
inputKey?: string[],
inputButton?: string[]
): ExtendedEvent {
if (
inputButton &&
!this._isValidButton(this._getButton(event), inputButton)
) {
if (!this._isValidEvent(event, inputKey, inputButton)) {
return null;
}
this._updatePointerEvent(event as PointerEvent);
Expand Down
16 changes: 14 additions & 2 deletions packages/axes/src/eventInput/TouchEventInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,24 @@ export class TouchEventInput extends EventInput {

private _baseTouches: TouchList;

public onEventStart(event: InputEventType): ExtendedEvent {
public onEventStart(
event: InputEventType,
inputKey?: string[]
): ExtendedEvent {
this._baseTouches = (event as TouchEvent).touches;
if (!this._isValidEvent(event, inputKey)) {
return null;
}
return this.extendEvent(event);
}

public onEventMove(event: InputEventType): ExtendedEvent {
public onEventMove(
event: InputEventType,
inputKey?: string[]
): ExtendedEvent {
if (!this._isValidEvent(event, inputKey)) {
return null;
}
return this.extendEvent(event);
}

Expand Down
9 changes: 4 additions & 5 deletions packages/axes/src/eventInput/TouchMouseEventInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ export class TouchMouseEventInput extends EventInput {

public onEventStart(
event: InputEventType,
inputKey?: string[],
inputButton?: string[]
): ExtendedEvent {
const button = this._getButton(event);
if (this._isTouchEvent(event)) {
this._baseTouches = event.touches;
}
if (inputButton && !this._isValidButton(button, inputButton)) {
if (!this._isValidEvent(event, inputKey, inputButton)) {
return null;
}
this._preventMouseButton(event, button);
Expand All @@ -30,12 +31,10 @@ export class TouchMouseEventInput extends EventInput {

public onEventMove(
event: InputEventType,
inputKey?: string[],
inputButton?: string[]
): ExtendedEvent {
if (
inputButton &&
!this._isValidButton(this._getButton(event), inputButton)
) {
if (!this._isValidEvent(event, inputKey, inputButton)) {
return null;
}
return this.extendEvent(event);
Expand Down
29 changes: 25 additions & 4 deletions packages/axes/src/inputType/PanInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
DIRECTION_VERTICAL,
DIRECTION_HORIZONTAL,
MOUSE_LEFT,
ANY,
} from "../const";
import { ActiveEvent, ElementType, InputEventType } from "../types";

Expand All @@ -31,6 +32,7 @@ import {

export interface PanInputOption {
inputType?: string[];
inputKey?: string[];
inputButton?: string[];
scale?: number[];
thresholdAngle?: number;
Expand Down Expand Up @@ -66,6 +68,19 @@ export const getDirectionByAngle = (
* - touch: 터치 입력 장치
* - mouse: 마우스
* - pointer: 마우스 및 터치</ko>
* @param {String[]} [inputKey=["any"]] List of key combinations to allow input
* - any: any key
* - shift: shift key
* - ctrl: ctrl key and pinch gesture on the trackpad
* - alt: alt key
* - meta: meta key
* - none: none of these keys are pressed <ko>입력을 허용할 키 조합 목록
* - any: 아무 키
* - shift: shift 키
* - ctrl: ctrl 키 및 트랙패드의 pinch 제스쳐
* - alt: alt 키
* - meta: meta 키
* - none: 아무 키도 눌리지 않은 상태 </ko>
* @param {String[]} [inputButton=["left"]] List of buttons to allow input
* - left: Left mouse button and normal touch
* - middle: Mouse wheel press
Expand Down Expand Up @@ -127,6 +142,7 @@ export class PanInput implements InputType {
this.element = $(el);
this.options = {
inputType: ["touch", "mouse", "pointer"],
inputKey: [ANY],
inputButton: [MOUSE_LEFT],
scale: [1, 1],
thresholdAngle: 45,
Expand Down Expand Up @@ -224,10 +240,14 @@ export class PanInput implements InputType {
}

protected _onPanstart(event: InputEventType) {
const inputButton = this.options.inputButton;
const { inputKey, inputButton } = this.options;
const activeEvent = this._activeEvent;
const panEvent = activeEvent.onEventStart(event, inputButton);
if (!panEvent || !this._enabled || activeEvent.getTouches(event, inputButton) > 1) {
const panEvent = activeEvent.onEventStart(event, inputKey, inputButton);
if (
!panEvent ||
!this._enabled ||
activeEvent.getTouches(event, inputButton) > 1
) {
return;
}
if (panEvent.srcEvent.cancelable !== false) {
Expand All @@ -247,12 +267,13 @@ export class PanInput implements InputType {
const {
iOSEdgeSwipeThreshold,
releaseOnScroll,
inputKey,
inputButton,
threshold,
thresholdAngle,
} = this.options;
const activeEvent = this._activeEvent;
const panEvent = activeEvent.onEventMove(event, inputButton);
const panEvent = activeEvent.onEventMove(event, inputKey, inputButton);
const touches = activeEvent.getTouches(event, inputButton);

if (
Expand Down
6 changes: 4 additions & 2 deletions packages/axes/src/inputType/RotatePanInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ export class RotatePanInput extends PanInput {
}

protected _onPanstart(event: MouseEvent) {
const { inputKey, inputButton } = this.options;
const activeEvent = this._activeEvent;
const panEvent = activeEvent.onEventStart(event, this.options.inputButton);
const panEvent = activeEvent.onEventStart(event, inputKey, inputButton);
if (!panEvent || !this.isEnabled()) {
return;
}
Expand All @@ -78,8 +79,9 @@ export class RotatePanInput extends PanInput {
}

protected _onPanmove(event: MouseEvent) {
const { inputKey, inputButton } = this.options;
const activeEvent = this._activeEvent;
const panEvent = activeEvent.onEventMove(event, this.options.inputButton);
const panEvent = activeEvent.onEventMove(event, inputKey, inputButton);
if (!panEvent || !this.isEnabled()) {
return;
}
Expand Down
30 changes: 22 additions & 8 deletions packages/axes/src/inputType/WheelInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
* egjs projects are licensed under the MIT license
*/
import { $, getDirection, useDirection } from "../utils";
import { DIRECTION_HORIZONTAL, DIRECTION_VERTICAL } from "../const";
import { ANY, DIRECTION_HORIZONTAL, DIRECTION_VERTICAL } from "../const";
import { ElementType } from "../types";

import { toAxis, InputType, InputTypeObserver } from "./InputType";
import { isValidKey } from "../eventInput/EventInput";

export interface WheelInputOption {
inputKey?: string[];
scale?: number;
releaseDelay?: number;
useNormalized?: boolean;
Expand All @@ -18,6 +20,19 @@ export interface WheelInputOption {
/**
* @typedef {Object} WheelInputOption The option object of the eg.Axes.WheelInput module
* @ko eg.Axes.WheelInput 모듈의 옵션 객체
* @param {String[]} [inputKey=["any"]] List of key combinations to allow input
* - any: any key
* - shift: shift key
* - ctrl: ctrl key and pinch gesture on the trackpad
* - alt: alt key
* - meta: meta key
* - none: none of these keys are pressed <ko>입력을 허용할 키 조합 목록
* - any: 아무 키
* - shift: shift 키
* - ctrl: ctrl 키 및 트랙패드의 pinch 제스쳐
* - alt: alt 키
* - meta: meta 키
* - none: 아무 키도 눌리지 않은 상태 </ko>
* @param {Number} [scale=1] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko>
* @param {Number} [releaseDelay=300] Millisecond that trigger release event after last input<ko>마지막 입력 이후 release 이벤트가 트리거되기까지의 밀리초</ko>
* @param {Boolean} [useNormalized=true] Whether to calculate scroll speed the same in all browsers<ko>모든 브라우저에서 스크롤 속도를 동일하게 처리할지 여부</ko>
Expand Down Expand Up @@ -63,12 +78,11 @@ export class WheelInput implements InputType {
public constructor(el: ElementType, options?: WheelInputOption) {
this.element = $(el);
this.options = {
...{
scale: 1,
releaseDelay: 300,
useNormalized: true,
useAnimation: false,
},
inputKey: [ANY],
scale: 1,
releaseDelay: 300,
useNormalized: true,
useAnimation: false,
...options,
};
this._onWheel = this._onWheel.bind(this);
Expand Down Expand Up @@ -130,7 +144,7 @@ export class WheelInput implements InputType {
}

private _onWheel(event: WheelEvent) {
if (!this._enabled) {
if (!this._enabled || !isValidKey(event, this.options.inputKey)) {
return;
}

Expand Down
Loading

0 comments on commit 1169aca

Please sign in to comment.