@egjs/axes
Advanced tools
Comparing version 2.8.0 to 3.0.0
import { Axis, AxisManager } from "./AxisManager"; | ||
import { InterruptManager } from "./InterruptManager"; | ||
import { EventManager, ChangeEventOption } from "./EventManager"; | ||
import { AnimationParam } from "./types"; | ||
import { AxesOption } from "./Axes"; | ||
import { AnimationParam, UpdateAnimationOption } from "./types"; | ||
export declare class AnimationManager { | ||
interruptManager: InterruptManager; | ||
eventManager: EventManager; | ||
axisManager: AxisManager; | ||
private _raf; | ||
private _animateParam; | ||
private options; | ||
itm: InterruptManager; | ||
em: EventManager; | ||
axm: AxisManager; | ||
constructor({ options, itm, em, axm }: { | ||
options: any; | ||
itm: any; | ||
em: any; | ||
axm: any; | ||
private _initialEasingPer; | ||
private _prevEasingPer; | ||
private _durationOffset; | ||
private _options; | ||
constructor({ options, interruptManager, eventManager, axisManager, }: { | ||
options: AxesOption; | ||
interruptManager: InterruptManager; | ||
eventManager: EventManager; | ||
axisManager: AxisManager; | ||
}); | ||
getDuration(depaPos: Axis, destPos: Axis, wishDuration?: number): number; | ||
private createAnimationParam; | ||
grab(axes: string[], option?: ChangeEventOption): void; | ||
getDisplacement(velocity: number[]): number[]; | ||
interpolate(displacement: number, threshold: number): number; | ||
stopAnimation(axes: string[], option?: ChangeEventOption): void; | ||
getEventInfo(): ChangeEventOption; | ||
restore(option: ChangeEventOption): void; | ||
animationEnd(): void; | ||
finish(isTrusted: any): void; | ||
private animateLoop; | ||
private getFinalPos; | ||
private getRoundUnit; | ||
getUserControll(param: AnimationParam): { | ||
finish(isTrusted: boolean): void; | ||
getUserControl(param: AnimationParam): { | ||
destPos: Axis; | ||
@@ -33,5 +35,10 @@ duration: number; | ||
animateTo(destPos: Axis, duration: number, option?: ChangeEventOption): void; | ||
easing(p: any): number; | ||
easing(p: number): number; | ||
setTo(pos: Axis, duration?: number): this; | ||
setBy(pos: Axis, duration?: number): this; | ||
updateAnimation(options: UpdateAnimationOption): void; | ||
private _createAnimationParam; | ||
private _animateLoop; | ||
private _getFinalPos; | ||
private _getRoundUnit; | ||
} |
@@ -7,4 +7,4 @@ import Component from "@egjs/component"; | ||
import { InputObserver } from "./InputObserver"; | ||
import { IInputType } from "./inputType/InputType"; | ||
import { AxesEvents, ObjectInterface } from "./types"; | ||
import { InputType } from "./inputType/InputType"; | ||
import { AxesEvents, ObjectInterface, UpdateAnimationOption } from "./types"; | ||
export interface AxesOption { | ||
@@ -18,3 +18,3 @@ easing?: (x: number) => number; | ||
} | ||
export default class Axes extends Component<AxesEvents> { | ||
declare class Axes extends Component<AxesEvents> { | ||
axis: ObjectInterface<AxisOption>; | ||
@@ -37,16 +37,19 @@ static VERSION: string; | ||
options: AxesOption; | ||
em: EventManager; | ||
axm: AxisManager; | ||
itm: InterruptManager; | ||
am: AnimationManager; | ||
io: InputObserver; | ||
eventManager: EventManager; | ||
axisManager: AxisManager; | ||
interruptManager: InterruptManager; | ||
animationManager: AnimationManager; | ||
inputObserver: InputObserver; | ||
private _inputs; | ||
constructor(axis?: ObjectInterface<AxisOption>, options?: AxesOption, startPos?: Axis); | ||
connect(axes: string[] | string, inputType: IInputType): this; | ||
disconnect(inputType?: IInputType): this; | ||
connect(axes: string[] | string, inputType: InputType): this; | ||
disconnect(inputType?: InputType): this; | ||
get(axes?: string[]): Axis; | ||
setTo(pos: Axis, duration?: number): this; | ||
setBy(pos: Axis, duration?: number): this; | ||
stopAnimation(): this; | ||
updateAnimation(options: UpdateAnimationOption): this; | ||
isBounceArea(axes?: string[]): boolean; | ||
destroy(): void; | ||
} | ||
export default Axes; |
@@ -11,7 +11,5 @@ import { ObjectInterface } from "./types"; | ||
export declare class AxisManager { | ||
private axis; | ||
private options; | ||
private _axis; | ||
private _pos; | ||
constructor(axis: ObjectInterface<AxisOption>, options: any); | ||
private _complementOptions; | ||
constructor(_axis: ObjectInterface<AxisOption>); | ||
getDelta(depaPos: Axis, destPos: Axis): Axis; | ||
@@ -28,2 +26,3 @@ get(axes?: string[] | Axis): Axis; | ||
getAxisOptions(key: string): AxisOption; | ||
private _complementOptions; | ||
} |
@@ -1,4 +0,16 @@ | ||
export { DIRECTION_NONE, DIRECTION_LEFT, DIRECTION_RIGHT, DIRECTION_UP, DIRECTION_DOWN, DIRECTION_HORIZONTAL, DIRECTION_VERTICAL, DIRECTION_ALL, } from "@egjs/hammerjs"; | ||
export declare const DIRECTION_NONE = 1; | ||
export declare const DIRECTION_LEFT = 2; | ||
export declare const DIRECTION_RIGHT = 4; | ||
export declare const DIRECTION_HORIZONTAL: number; | ||
export declare const DIRECTION_UP = 8; | ||
export declare const DIRECTION_DOWN = 16; | ||
export declare const DIRECTION_VERTICAL: number; | ||
export declare const DIRECTION_ALL: number; | ||
export declare const IOS_EDGE_THRESHOLD = 30; | ||
export declare const IS_IOS_SAFARI: boolean; | ||
export declare const TRANSFORM: string; | ||
export declare const PREVENT_SCROLL_CSSPROPS: { | ||
"touch-action": string; | ||
"user-select": string; | ||
"-webkit-user-drag": string; | ||
}; |
@@ -1,5 +0,5 @@ | ||
export declare function getInsidePosition(destPos: number, range: number[], circular: boolean[], bounce?: number[]): number; | ||
export declare function isOutside(pos: number, range: number[]): boolean; | ||
export declare function getDuration(distance: number, deceleration: any): number; | ||
export declare function isCircularable(destPos: number, range: number[], circular: boolean[]): boolean; | ||
export declare function getCirculatedPos(pos: number, range: number[], circular: boolean[]): number; | ||
export declare const getInsidePosition: (destPos: number, range: number[], circular: boolean[], bounce?: number[]) => number; | ||
export declare const isOutside: (pos: number, range: number[]) => boolean; | ||
export declare const getDuration: (distance: number, deceleration: any) => number; | ||
export declare const isCircularable: (destPos: number, range: number[], circular: boolean[]) => boolean; | ||
export declare const getCirculatedPos: (pos: number, range: number[], circular: boolean[]) => number; |
@@ -1,2 +0,2 @@ | ||
import { IInputType } from "./inputType/InputType"; | ||
import { InputType } from "./inputType/InputType"; | ||
import { Axis } from "./AxisManager"; | ||
@@ -7,19 +7,20 @@ import { AnimationManager } from "./AnimationManager"; | ||
export interface ChangeEventOption { | ||
input: IInputType; | ||
input: InputType; | ||
event: any; | ||
} | ||
export declare class EventManager { | ||
private axes; | ||
am: AnimationManager; | ||
constructor(axes: Axes); | ||
triggerHold(pos: Axis, option: ChangeEventOption): void; | ||
private _axes; | ||
animationManager: AnimationManager; | ||
constructor(_axes: Axes); | ||
hold(pos: Axis, option: ChangeEventOption): void; | ||
triggerRelease(param: AnimationParam): void; | ||
triggerChange(pos: Axis, isAccurate?: boolean, depaPos?: Axis, option?: ChangeEventOption, holding?: boolean): boolean; | ||
triggerAnimationStart(param: AnimationParam): boolean; | ||
triggerChange(pos: Axis, isAccurate?: boolean, depaPos?: Axis, option?: ChangeEventOption, holding?: boolean): Axes; | ||
triggerAnimationStart(param: AnimationParam): Axes; | ||
triggerAnimationEnd(isTrusted?: boolean): void; | ||
triggerFinish(isTrusted?: boolean): void; | ||
private createUserControll; | ||
setAnimationManager(am: AnimationManager): void; | ||
setAnimationManager(animationManager: AnimationManager): void; | ||
destroy(): void; | ||
private getRoundPos; | ||
private _createUserControll; | ||
private _getRoundPos; | ||
private _getBounceRatio; | ||
} |
@@ -1,25 +0,28 @@ | ||
import { IInputType, IInputTypeObserver } from "./inputType/InputType"; | ||
import { Axis } from "./AxisManager"; | ||
import { InterruptManager } from "./InterruptManager"; | ||
import { InputType, InputTypeObserver } from "./inputType/InputType"; | ||
import { EventManager } from "./EventManager"; | ||
import { AxisManager, Axis } from "./AxisManager"; | ||
import { AnimationManager } from "./AnimationManager"; | ||
import { AxesOption } from "./Axes"; | ||
export declare class InputObserver implements IInputTypeObserver { | ||
export declare class InputObserver implements InputTypeObserver { | ||
options: AxesOption; | ||
private itm; | ||
private em; | ||
private axm; | ||
private am; | ||
private isOutside; | ||
private moveDistance; | ||
private isStopped; | ||
constructor({ options, itm, em, axm, am }: { | ||
options: any; | ||
itm: any; | ||
em: any; | ||
axm: any; | ||
am: any; | ||
private _interruptManager; | ||
private _eventManager; | ||
private _axisManager; | ||
private _animationManager; | ||
private _isOutside; | ||
private _moveDistance; | ||
private _isStopped; | ||
constructor({ options, interruptManager, eventManager, axisManager, animationManager, }: { | ||
options: AxesOption; | ||
interruptManager: InterruptManager; | ||
eventManager: EventManager; | ||
axisManager: AxisManager; | ||
animationManager: AnimationManager; | ||
}); | ||
private atOutside; | ||
get(input: IInputType): Axis; | ||
hold(input: IInputType, event: any): void; | ||
change(input: IInputType, event: any, offset: Axis): void; | ||
release(input: IInputType, event: any, offset: Axis, inputDuration?: number): void; | ||
get(input: InputType): Axis; | ||
hold(input: InputType, event: any): void; | ||
change(input: InputType, event: any, offset: Axis, useDuration?: boolean): void; | ||
release(input: InputType, event: any, velocity: number[], inputDuration?: number): void; | ||
private _atOutside; | ||
} |
@@ -1,10 +0,9 @@ | ||
/// <reference types="hammerjs" /> | ||
import { Axis } from "../AxisManager"; | ||
import { AxesOption } from "../Axes"; | ||
export interface IInputType { | ||
import { ActiveInput } from "../types"; | ||
export interface InputType { | ||
axes: string[]; | ||
element: HTMLElement; | ||
hammer?: any; | ||
mapAxes(axes: string[]): any; | ||
connect(observer: IInputTypeObserver): IInputType; | ||
connect(observer: InputTypeObserver): InputType; | ||
disconnect(): any; | ||
@@ -16,14 +15,10 @@ destroy(): any; | ||
} | ||
export interface IInputTypeObserver { | ||
export interface InputTypeObserver { | ||
options: AxesOption; | ||
get(inputType: IInputType): Axis; | ||
change(inputType: IInputType, event: any, offset: Axis): any; | ||
hold(inputType: IInputType, event: any): any; | ||
release(inputType: IInputType, event: any, offset: Axis, duration?: number): any; | ||
get(inputType: InputType): Axis; | ||
change(inputType: InputType, event: any, offset: Axis, useDuration?: boolean): any; | ||
hold(inputType: InputType, event: any): any; | ||
release(inputType: InputType, event: any, velocity: number[], inputDuration?: number): any; | ||
} | ||
export declare const SUPPORT_POINTER_EVENTS: boolean; | ||
export declare const SUPPORT_TOUCH: boolean; | ||
export declare const UNIQUEKEY = "_EGJS_AXES_INPUTTYPE_"; | ||
export declare function toAxis(source: string[], offset: number[]): Axis; | ||
export declare function createHammer(element: HTMLElement, options: any): HammerManager; | ||
export declare function convertInputType(inputType?: string[]): any; | ||
export declare const toAxis: (source: string[], offset: number[]) => Axis; | ||
export declare const convertInputType: (inputType?: string[]) => ActiveInput; |
@@ -1,2 +0,2 @@ | ||
import { IInputType, IInputTypeObserver } from "./InputType"; | ||
import { InputType, InputTypeObserver } from "./InputType"; | ||
export declare const KEY_LEFT_ARROW = 37; | ||
@@ -13,22 +13,22 @@ export declare const KEY_A = 65; | ||
} | ||
export declare class MoveKeyInput implements IInputType { | ||
export declare class MoveKeyInput implements InputType { | ||
options: MoveKeyInputOption; | ||
axes: string[]; | ||
element: HTMLElement; | ||
private _isEnabled; | ||
private _isHolded; | ||
private _observer; | ||
private _enabled; | ||
private _holding; | ||
private _timer; | ||
private observer; | ||
constructor(el: any, options?: MoveKeyInputOption); | ||
mapAxes(axes: string[]): void; | ||
connect(observer: IInputTypeObserver): IInputType; | ||
connect(observer: InputTypeObserver): InputType; | ||
disconnect(): this; | ||
destroy(): void; | ||
private onKeydown; | ||
private onKeyup; | ||
private attachEvent; | ||
private dettachEvent; | ||
enable(): this; | ||
disable(): this; | ||
isEnable(): boolean; | ||
isEnabled(): boolean; | ||
private _onKeydown; | ||
private _onKeyup; | ||
private _attachEvent; | ||
private _detachEvent; | ||
} |
@@ -1,3 +0,3 @@ | ||
import { IInputType, IInputTypeObserver } from "./InputType"; | ||
import { ObjectInterface } from "../types"; | ||
import { ActiveInput, InputEventType } from "../types"; | ||
import { InputType, InputTypeObserver } from "./InputType"; | ||
export interface PanInputOption { | ||
@@ -8,23 +8,22 @@ inputType?: string[]; | ||
threshold?: number; | ||
hammerManagerOptions?: ObjectInterface; | ||
iOSEdgeSwipeThreshold?: number; | ||
releaseOnScroll?: boolean; | ||
} | ||
export declare function getDirectionByAngle(angle: number, thresholdAngle: number): number; | ||
export declare function getNextOffset(speeds: number[], deceleration: number): number[]; | ||
export declare function useDirection(checkType: any, direction: any, userDirection?: any): boolean; | ||
export declare class PanInput implements IInputType { | ||
export declare const getDirectionByAngle: (angle: number, thresholdAngle: number) => number; | ||
export declare const useDirection: (checkType: any, direction: any, userDirection?: any) => boolean; | ||
export declare class PanInput implements InputType { | ||
options: PanInputOption; | ||
axes: string[]; | ||
hammer: any; | ||
element: HTMLElement; | ||
protected observer: IInputTypeObserver; | ||
protected _observer: InputTypeObserver; | ||
protected _direction: any; | ||
private panRecognizer; | ||
private isRightEdge; | ||
private rightEdgeTimer; | ||
private panFlag; | ||
protected _panFlag: boolean; | ||
protected _enabled: boolean; | ||
protected _activeInput: ActiveInput; | ||
private _originalCssProps; | ||
private _atRightEdge; | ||
private _rightEdgeTimer; | ||
constructor(el: string | HTMLElement, options?: PanInputOption); | ||
mapAxes(axes: string[]): void; | ||
connect(observer: IInputTypeObserver): IInputType; | ||
connect(observer: InputTypeObserver): InputType; | ||
disconnect(): this; | ||
@@ -34,10 +33,9 @@ destroy(): void; | ||
disable(): this; | ||
isEnable(): boolean; | ||
private removeRecognizer; | ||
protected onHammerInput(event: any): void; | ||
protected onPanmove(event: any): void; | ||
protected onPanend(event: any): void; | ||
private attachEvent; | ||
private dettachEvent; | ||
private getOffset; | ||
isEnabled(): boolean; | ||
protected _onPanstart(event: InputEventType): void; | ||
protected _onPanmove(event: InputEventType): void; | ||
protected _onPanend(event: InputEventType): void; | ||
private _attachEvent; | ||
private _detachEvent; | ||
private _getOffset; | ||
} |
@@ -1,3 +0,2 @@ | ||
import { IInputType, IInputTypeObserver } from "./InputType"; | ||
import { ObjectInterface } from "../types"; | ||
import { InputType, InputTypeObserver } from "./InputType"; | ||
export interface PinchInputOption { | ||
@@ -7,28 +6,27 @@ scale?: number; | ||
inputType?: string[]; | ||
hammerManagerOptions?: ObjectInterface; | ||
} | ||
export declare class PinchInput implements IInputType { | ||
export declare class PinchInput implements InputType { | ||
options: PinchInputOption; | ||
axes: string[]; | ||
hammer: any; | ||
element: HTMLElement; | ||
private observer; | ||
private _base; | ||
private _prev; | ||
private pinchRecognizer; | ||
constructor(el: any, options?: PinchInputOption); | ||
private _observer; | ||
private _pinchFlag; | ||
private _enabled; | ||
private _originalCssProps; | ||
private _activeInput; | ||
private _baseValue; | ||
constructor(el: string | HTMLElement, options?: PinchInputOption); | ||
mapAxes(axes: string[]): void; | ||
connect(observer: IInputTypeObserver): IInputType; | ||
connect(observer: InputTypeObserver): InputType; | ||
disconnect(): this; | ||
destroy(): void; | ||
private removeRecognizer; | ||
private onPinchStart; | ||
private onPinchMove; | ||
private onPinchEnd; | ||
private getOffset; | ||
private attachEvent; | ||
private dettachEvent; | ||
enable(): this; | ||
disable(): this; | ||
isEnable(): boolean; | ||
isEnabled(): boolean; | ||
private _onPinchStart; | ||
private _onPinchMove; | ||
private _onPinchEnd; | ||
private _attachEvent; | ||
private _detachEvent; | ||
private _getOffset; | ||
} |
import { PanInput, PanInputOption } from "./PanInput"; | ||
export declare class RotatePanInput extends PanInput { | ||
private rotateOrigin; | ||
private prevAngle; | ||
private prevQuadrant; | ||
private lastDiff; | ||
private coefficientForDistanceToAngle; | ||
private _rotateOrigin; | ||
private _prevAngle; | ||
private _prevQuadrant; | ||
private _lastDiff; | ||
private _coefficientForDistanceToAngle; | ||
constructor(el: string | HTMLElement, options?: PanInputOption); | ||
mapAxes(axes: string[]): void; | ||
onHammerInput(event: any): void; | ||
onPanstart(event: any): void; | ||
onPanmove(event: any): void; | ||
onPanend(event: any): void; | ||
private triggerChange; | ||
private triggerAnimation; | ||
private getDifference; | ||
private getPosFromOrigin; | ||
private getAngle; | ||
private getQuadrant; | ||
protected _onPanstart(event: MouseEvent): void; | ||
protected _onPanmove(event: MouseEvent): void; | ||
protected _onPanend(event: MouseEvent): void; | ||
private _triggerChange; | ||
private _getDifference; | ||
private _getPosFromOrigin; | ||
private _getQuadrant; | ||
} |
@@ -1,25 +0,26 @@ | ||
import { IInputType, IInputTypeObserver } from "./InputType"; | ||
import { InputType, InputTypeObserver } from "./InputType"; | ||
export interface WheelInputOption { | ||
scale?: number; | ||
releaseDelay?: number; | ||
useNormalized?: boolean; | ||
} | ||
export declare class WheelInput implements IInputType { | ||
export declare class WheelInput implements InputType { | ||
options: WheelInputOption; | ||
axes: string[]; | ||
element: HTMLElement; | ||
private _isEnabled; | ||
private _isHolded; | ||
private _observer; | ||
private _enabled; | ||
private _holding; | ||
private _timer; | ||
private observer; | ||
constructor(el: any, options?: WheelInputOption); | ||
mapAxes(axes: string[]): void; | ||
connect(observer: IInputTypeObserver): IInputType; | ||
connect(observer: InputTypeObserver): InputType; | ||
disconnect(): this; | ||
destroy(): void; | ||
private onWheel; | ||
private attachEvent; | ||
private dettachEvent; | ||
enable(): this; | ||
disable(): this; | ||
isEnable(): boolean; | ||
isEnabled(): boolean; | ||
private _onWheel; | ||
private _attachEvent; | ||
private _detachEvent; | ||
} |
import { AxesOption } from "./Axes"; | ||
export declare class InterruptManager { | ||
private options; | ||
private _options; | ||
private _prevented; | ||
constructor(options: AxesOption); | ||
constructor(_options: AxesOption); | ||
isInterrupting(): boolean; | ||
@@ -7,0 +7,0 @@ isInterrupted(): boolean; |
import { Axis } from "./AxisManager"; | ||
import { IInputType } from "./inputType/InputType"; | ||
import { MouseEventInput } from "./eventInput/MouseEventInput"; | ||
import { TouchEventInput } from "./eventInput/TouchEventInput"; | ||
import { PointerEventInput } from "./eventInput/PointerEventInput"; | ||
import { TouchMouseEventInput } from "./eventInput/TouchMouseEventInput"; | ||
import { InputType } from "./inputType/InputType"; | ||
export declare type ObjectInterface<T = any> = Record<string | number, T>; | ||
export declare type AxesEvents = { | ||
export declare type InputEventType = PointerEvent | MouseEvent | TouchEvent; | ||
export declare type ActiveInput = MouseEventInput | TouchEventInput | TouchMouseEventInput | PointerEventInput; | ||
export interface AxesEvents { | ||
hold: OnHold; | ||
@@ -11,4 +17,4 @@ change: OnChange; | ||
finish: OnFinish; | ||
}; | ||
export declare type AnimationParam = { | ||
} | ||
export interface AnimationParam { | ||
depaPos: Axis; | ||
@@ -27,11 +33,16 @@ destPos: Axis; | ||
inputEvent?: any; | ||
input?: IInputType; | ||
}; | ||
export declare type OnHold = { | ||
input?: InputType; | ||
} | ||
export interface UpdateAnimationOption { | ||
destPos?: Axis; | ||
duration?: number; | ||
restart?: boolean; | ||
} | ||
export interface OnHold { | ||
pos: Record<string, any>; | ||
input: IInputType | null; | ||
input: InputType | null; | ||
inputEvent: any; | ||
isTrusted: boolean; | ||
}; | ||
export declare type OnAnimationStart = { | ||
} | ||
export interface OnAnimationStart { | ||
depaPos: Axis; | ||
@@ -44,18 +55,19 @@ destPos: Axis; | ||
inputEvent?: any; | ||
input?: IInputType | null; | ||
input?: InputType | null; | ||
setTo(destPos?: Axis, duration?: number): void; | ||
done(): void; | ||
stop(): void; | ||
}; | ||
export declare type OnChange = { | ||
} | ||
export interface OnChange { | ||
pos: Axis; | ||
delta: Axis; | ||
bounceRatio: Axis; | ||
holding: boolean; | ||
inputEvent: any; | ||
isTrusted: boolean; | ||
input: IInputType | null; | ||
input: InputType | null; | ||
set(toPos?: Axis, userDuration?: number): void; | ||
stop(): void; | ||
}; | ||
export declare type OnRelease = { | ||
} | ||
export interface OnRelease { | ||
depaPos: Axis; | ||
@@ -65,14 +77,31 @@ destPos: Axis; | ||
delta: Axis; | ||
bounceRatio: Axis; | ||
isTrusted?: boolean; | ||
startTime?: number; | ||
inputEvent?: any; | ||
input?: IInputType | null; | ||
input?: InputType | null; | ||
setTo(destPos?: Axis, duration?: number): void; | ||
done(): void; | ||
}; | ||
export declare type OnAnimationEnd = { | ||
} | ||
export interface OnAnimationEnd { | ||
isTrusted: boolean; | ||
}; | ||
export declare type OnFinish = { | ||
} | ||
export interface OnFinish { | ||
isTrusted: boolean; | ||
}; | ||
} | ||
export interface ExtendedEvent { | ||
srcEvent: InputEventType; | ||
angle: number; | ||
scale: number; | ||
center: { | ||
x: number; | ||
y: number; | ||
}; | ||
deltaX: number; | ||
deltaY: number; | ||
offsetX: number; | ||
offsetY: number; | ||
velocityX: number; | ||
velocityY: number; | ||
preventSystemEvent: boolean; | ||
} |
import { ObjectInterface } from "./types"; | ||
export declare function toArray(nodes: NodeList): HTMLElement[]; | ||
export declare function $(param: any, multi?: boolean): any; | ||
export declare function requestAnimationFrame(fp: any): any; | ||
export declare function cancelAnimationFrame(key: any): void; | ||
export declare function map<T, U>(obj: ObjectInterface<T>, callback: (value: T, key: string) => U): ObjectInterface<U>; | ||
export declare function filter<T>(obj: ObjectInterface<T>, callback: (value: T, key: string) => boolean): ObjectInterface<T>; | ||
export declare function every<T>(obj: ObjectInterface<T>, callback: (value: T, key: string) => boolean): boolean; | ||
export declare function equal(target: ObjectInterface, base: ObjectInterface): boolean; | ||
export declare function roundNumber(num: number, roundUnit: number): any; | ||
export declare function roundNumbers(num: ObjectInterface<number>, roundUnit: ObjectInterface<number> | number): Record<string | number, any>; | ||
export declare function getDecimalPlace(val: number): number; | ||
export declare function inversePow(n: number): number; | ||
export declare function getRoundFunc(v: number): (n: number) => number; | ||
export declare const toArray: (nodes: NodeList) => HTMLElement[]; | ||
export declare const $: (param: any, multi?: boolean) => any; | ||
export declare const requestAnimationFrame: (fp: any) => any; | ||
export declare const cancelAnimationFrame: (key: any) => void; | ||
export declare const map: <T, U>(obj: Record<string | number, T>, callback: (value: T, key: string) => U) => Record<string | number, U>; | ||
export declare const filter: <T>(obj: Record<string | number, T>, callback: (value: T, key: string) => boolean) => Record<string | number, T>; | ||
export declare const every: <T>(obj: Record<string | number, T>, callback: (value: T, key: string) => boolean) => boolean; | ||
export declare const equal: (target: ObjectInterface, base: ObjectInterface) => boolean; | ||
export declare const roundNumber: (num: number, roundUnit: number) => any; | ||
export declare const roundNumbers: (num: ObjectInterface<number>, roundUnit: ObjectInterface<number> | number) => ObjectInterface<number>; | ||
export declare const getDecimalPlace: (val: number) => number; | ||
export declare const inversePow: (n: number) => number; | ||
export declare const getRoundFunc: (v: number) => (n: number) => number; | ||
export declare const getAngle: (posX: number, posY: number) => number; | ||
export declare const setCssProps: (element: HTMLElement, originalCssProps?: { | ||
[key: string]: string; | ||
}) => { | ||
[key: string]: string; | ||
}; |
@@ -7,5 +7,5 @@ /* | ||
repository: https://github.com/naver/egjs-axes | ||
version: 2.8.0 | ||
version: 3.0.0 | ||
*/ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@egjs/hammerjs"),require("@egjs/agent"),require("@egjs/component")):"function"==typeof define&&define.amd?define(["@egjs/hammerjs","@egjs/agent","@egjs/component"],e):(t.eg=t.eg||{},t.eg.Axes=e(t.Hammer,t.eg.agent,t.eg.Component))}(this,function(c,t,e){"use strict";var i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)};function n(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}var s,g=function(){return(g=Object.assign||function(t){for(var e,n=1,i=arguments.length;n<i;n++)for(var s in e=arguments[n])Object.prototype.hasOwnProperty.call(e,s)&&(t[s]=e[s]);return t}).apply(this,arguments)};function l(t,e,n,i){var s=t,r=[!n[0]&&i?e[0]-i[0]:e[0],!n[1]&&i?e[1]+i[1]:e[1]],s=Math.max(r[0],s);return Math.min(r[1],s)}function r(t,e){return t<e[0]||t>e[1]}function u(t,e,n){return n[1]&&t>e[1]||n[0]&&t<e[0]}function v(t,e,n){var i=t,s=e[0],r=e[1],o=r-s;return n[1]&&r<t&&(i=(i-r)%o+s),n[0]&&t<s&&(i=(i-s)%o+r),i}function o(t){for(var e=[],n=0,i=t.length;n<i;n++)e.push(t[n]);return e}function a(t,e){var n,i;return void 0===e&&(e=!1),"string"==typeof t?(i=t.match(/^<([a-z]+)\s*([^>]*)>/)?((n=document.createElement("div")).innerHTML=t,o(n.childNodes)):o(document.querySelectorAll(t)),e||(i=1<=i.length?i[0]:void 0)):t!==s&&(!t.nodeName||1!==t.nodeType&&9!==t.nodeType)?"jQuery"in s&&t instanceof jQuery||t.constructor.prototype.jquery?i=e?t.toArray():t.get(0):Array.isArray(t)&&(i=t.map(function(t){return a(t)}),e||(i=1<=i.length?i[0]:void 0)):i=t,i}var h,m,E=(s="undefined"==typeof window?{navigator:{userAgent:""}}:window).requestAnimationFrame||s.webkitRequestAnimationFrame,d=s.cancelAnimationFrame||s.webkitCancelAnimationFrame;function _(t,e){var n={};for(var i in t)i&&(n[i]=e(t[i],i));return n}function f(t,e){var n={};for(var i in t)i&&e(t[i],i)&&(n[i]=t[i]);return n}function p(t,e){for(var n in t)if(n&&!e(t[n],n))return!1;return!0}function b(t,n){return p(t,function(t,e){return t===n[e]})}E&&!d?(h={},m=E,E=function(e){var n=m(function(t){h[n]&&e(t)});return h[n]=!0,n},d=function(t){delete h[t]}):E&&d||(E=function(t){return s.setTimeout(function(){t(s.performance&&s.performance.now&&s.performance.now()||(new Date).getTime())},16)},d=s.clearTimeout);var x={};function P(t,e){var n,i;return x[e]||(x[e]=(i=(n=e)<1?Math.pow(10,y(n)):1,function(t){return 0===n?0:Math.round(Math.round(t/n)*n*i)/i})),x[e](t)}function T(t,n){if(!t||!n)return t;var i="number"==typeof n;return _(t,function(t,e){return P(t,i?n:n[e])})}function y(t){if(!isFinite(t))return 0;var e=t+"";if(0<=e.indexOf("e")){for(var n=0,i=1;Math.round(t*i)/i!==t;)i*=10,n++;return n}return 0<=e.indexOf(".")?e.length-e.indexOf(".")-1:0}function I(t,e,n){return Math.max(Math.min(t,n),e)}var O=function(){function t(t){var e=t.options,n=t.itm,i=t.em,s=t.axm;this.options=e,this.itm=n,this.em=i,this.axm=s,this.animationEnd=this.animationEnd.bind(this)}var e=t.prototype;return e.getDuration=function(r,t,e){var n,o=this;return I(void 0!==e?e:(n=_(t,function(t,e){return n=Math.abs(t-r[e]),i=o.options.deceleration,(s=Math.sqrt(n/i*2))<100?0:s;var n,i,s}),Object.keys(n).reduce(function(t,e){return Math.max(t,n[e])},-1/0)),this.options.minimumDuration,this.options.maximumDuration)},e.createAnimationParam=function(t,e,n){var i=this.axm.get(),s=t,r=n&&n.event||null;return{depaPos:i,destPos:s,duration:I(e,this.options.minimumDuration,this.options.maximumDuration),delta:this.axm.getDelta(i,s),inputEvent:r,input:n&&n.input||null,isTrusted:!!r,done:this.animationEnd}},e.grab=function(t,e){var n,i,s;this._animateParam&&t.length&&(n=this.axm.get(t),p(i=this.axm.map(n,function(t,e){return v(t,e.range,e.circular)}),function(t,e){return n[e]===t})||this.em.triggerChange(i,!1,n,e,!!e),this._animateParam=null,this._raf&&(s=this._raf,d(s)),this._raf=null,this.em.triggerAnimationEnd(!(!e||!e.event)))},e.getEventInfo=function(){return this._animateParam&&this._animateParam.input&&this._animateParam.inputEvent?{input:this._animateParam.input,event:this._animateParam.inputEvent}:null},e.restore=function(t){var e=this.axm.get(),n=this.axm.map(e,function(t,e){return Math.min(e.range[1],Math.max(e.range[0],t))});this.animateTo(n,this.getDuration(e,n),t)},e.animationEnd=function(){var t=this.getEventInfo();this._animateParam=null;var e=this.axm.filter(this.axm.get(),function(t,e){return u(t,e.range,e.circular)});0<Object.keys(e).length&&this.setTo(this.axm.map(e,function(t,e){return v(t,e.range,e.circular)})),this.itm.setInterrupt(!1),this.em.triggerAnimationEnd(!!t),this.axm.isOutside()?this.restore(t):this.finish(!!t)},e.finish=function(t){this._animateParam=null,this.itm.setInterrupt(!1),this.em.triggerFinish(t)},e.animateLoop=function(s,r){var h,u,c,m,l,d,f,p;s.duration?(this._animateParam=g({},s),h=this._animateParam,u=this,c=h.destPos,m=h.depaPos,l=0,d=_(m,function(t,e){return t<=c[e]?1:-1}),f=_(c,function(t){return t}),p=(new Date).getTime(),h.startTime=p,function t(){u._raf=null;var e=(new Date).getTime(),o=(e-h.startTime)/s.duration,a=u.easing(o),n=u.axm.map(m,function(t,e,n){var i,s=1<=o?c[n]:t+h.delta[n]*(a-l),r=v(s,e.range,e.circular);return s!==r&&(i=d[n]*(e.range[1]-e.range[0]),c[n]-=i,m[n]-=i),r}),i=!u.em.triggerChange(n,!1,m);if(m=n,p=e,1<=(l=a))return b(c=u.getFinalPos(c,f),u.axm.get(Object.keys(c)))||u.em.triggerChange(c,!0,m),void r();i?u.finish(!1):u._raf=E(t)}()):(this.em.triggerChange(s.destPos,!0),r())},e.getFinalPos=function(t,n){var i=this;return _(t,function(t,e){return t>=n[e]-1e-6&&t<=n[e]+1e-6?n[e]:P(t,i.getRoundUnit(t,e))})},e.getRoundUnit=function(t,e){var n,i,s=this.options.round,r=null;return s||(n=this.axm.getAxisOptions(e),i=Math.max(y(n.range[0]),y(n.range[1]),y(t)),r=1/Math.pow(10,i)),r||s},e.getUserControll=function(t){var e=t.setTo();return e.destPos=this.axm.get(e.destPos),e.duration=I(e.duration,this.options.minimumDuration,this.options.maximumDuration),e},e.animateTo=function(t,e,n){var i,s=this,r=this.createAnimationParam(t,e,n),o=g({},r.depaPos),a=this.em.triggerAnimationStart(r),h=this.getUserControll(r);!a&&this.axm.every(h.destPos,function(t,e){return u(t,e.range,e.circular)})&&console.warn("You can't stop the 'animation' event when 'circular' is true."),a&&!b(h.destPos,o)&&(i=n&&n.event||null,this.animateLoop({depaPos:o,destPos:h.destPos,duration:h.duration,delta:this.axm.getDelta(o,h.destPos),isTrusted:!!i,inputEvent:i,input:n&&n.input||null},function(){return s.animationEnd()}))},e.easing=function(t){return 1<t?1:this.options.easing(t)},e.setTo=function(t,e){void 0===e&&(e=0);var n=Object.keys(t);this.grab(n);var i=this.axm.get(n);if(b(t,i))return this;this.itm.setInterrupt(!0);var s=f(t,function(t,e){return i[e]!==t});return Object.keys(s).length&&(b(s=this.axm.map(s,function(t,e){var n=e.range,i=e.circular;return i&&(i[0]||i[1])?t:l(t,n,i)}),i)||(0<e?this.animateTo(s,e):(this.em.triggerChange(s),this.finish(!1)))),this},e.setBy=function(n,t){return void 0===t&&(t=0),this.setTo(_(this.axm.get(Object.keys(n)),function(t,e){return t+n[e]}),t)},t}(),R=function(){function t(t){this.axes=t}var e=t.prototype;return e.triggerHold=function(t,e){var n=this.getRoundPos(t).roundPos;this.axes.trigger("hold",{pos:n,input:e.input||null,inputEvent:e.event||null,isTrusted:!0})},e.triggerRelease=function(t){var e=this.getRoundPos(t.destPos,t.depaPos),n=e.roundPos,i=e.roundDepa;t.destPos=n,t.depaPos=i,t.setTo=this.createUserControll(t.destPos,t.duration),this.axes.trigger("release",t)},e.triggerChange=function(t,e,n,i,s){void 0===s&&(s=!1);var r=this.am,o=r.axm,a=r.getEventInfo(),h=this.getRoundPos(t,n),u=h.roundPos,c=h.roundDepa,m=o.moveTo(u,c),l=i&&i.event||a&&a.event||null,d={pos:m.pos,delta:m.delta,holding:s,inputEvent:l,isTrusted:!!l,input:i&&i.input||a&&a.input||null,set:l?this.createUserControll(m.pos):function(){}},f=this.axes.trigger("change",d);return l&&o.set(d.set().destPos),f},e.triggerAnimationStart=function(t){var e=this.getRoundPos(t.destPos,t.depaPos),n=e.roundPos,i=e.roundDepa;return t.destPos=n,t.depaPos=i,t.setTo=this.createUserControll(t.destPos,t.duration),this.axes.trigger("animationStart",t)},e.triggerAnimationEnd=function(t){void 0===t&&(t=!1),this.axes.trigger("animationEnd",{isTrusted:t})},e.triggerFinish=function(t){void 0===t&&(t=!1),this.axes.trigger("finish",{isTrusted:t})},e.createUserControll=function(t,e){void 0===e&&(e=0);var n={destPos:g({},t),duration:e};return function(t,e){return t&&(n.destPos=g({},t)),void 0!==e&&(n.duration=e),n}},e.setAnimationManager=function(t){this.am=t},e.destroy=function(){this.axes.off()},e.getRoundPos=function(t,e){var n=this.axes.options.round;return{roundPos:T(t,n),roundDepa:T(e,n)}},t}(),D=function(){function t(t){this.options=t,this._prevented=!1}var e=t.prototype;return e.isInterrupting=function(){return this.options.interruptable||this._prevented},e.isInterrupted=function(){return!this.options.interruptable&&this._prevented},e.setInterrupt=function(t){this.options.interruptable||(this._prevented=t)},t}(),A=function(){function t(t,e){var n=this;this.axis=t,this.options=e,this._complementOptions(),this._pos=Object.keys(this.axis).reduce(function(t,e){return t[e]=n.axis[e].range[0],t},{})}var e=t.prototype;return e._complementOptions=function(){var s=this;Object.keys(this.axis).forEach(function(i){s.axis[i]=g({range:[0,100],bounce:[0,0],circular:[!1,!1]},s.axis[i]),["bounce","circular"].forEach(function(t){var e=s.axis,n=e[i][t];/string|number|boolean/.test(typeof n)&&(e[i][t]=[n,n])})})},e.getDelta=function(t,e){var n=this.get(t);return _(this.get(e),function(t,e){return t-n[e]})},e.get=function(t){var n=this;return t&&Array.isArray(t)?t.reduce(function(t,e){return e&&e in n._pos&&(t[e]=n._pos[e]),t},{}):g(g({},this._pos),t||{})},e.moveTo=function(n,i){void 0===i&&(i=this._pos);var t=_(this._pos,function(t,e){return e in n&&e in i?n[e]-i[e]:0});return this.set(this.map(n,function(t,e){return e?v(t,e.range,e.circular):0})),{pos:g({},this._pos),delta:t}},e.set=function(t){for(var e in t)e&&e in this._pos&&(this._pos[e]=t[e])},e.every=function(t,n){var i=this.axis;return p(t,function(t,e){return n(t,i[e],e)})},e.filter=function(t,n){var i=this.axis;return f(t,function(t,e){return n(t,i[e],e)})},e.map=function(t,n){var i=this.axis;return _(t,function(t,e){return n(t,i[e],e)})},e.isOutside=function(t){return!this.every(t?this.get(t):this._pos,function(t,e){return!r(t,e.range)})},e.getAxisOptions=function(t){return this.axis[t]},t}(),C=function(){function t(t){var e=t.options,n=t.itm,i=t.em,s=t.axm,r=t.am;this.isOutside=!1,this.moveDistance=null,this.isStopped=!1,this.options=e,this.itm=n,this.em=i,this.axm=s,this.am=r}var e=t.prototype;return e.atOutside=function(t){var o=this;if(this.isOutside)return this.axm.map(t,function(t,e){var n=e.range[0]-e.bounce[0],i=e.range[1]+e.bounce[1];return i<t?i:t<n?n:t});var a=this.am.easing(1e-5)/1e-5;return this.axm.map(t,function(t,e){var n=e.range[0],i=e.range[1],s=e.bounce,r=e.circular;return r&&(r[0]||r[1])?t:t<n?n-o.am.easing((n-t)/(s[0]*a))*s[0]:i<t?i+o.am.easing((t-i)/(s[1]*a))*s[1]:t})},e.get=function(t){return this.axm.get(t.axes)},e.hold=function(t,e){var n;!this.itm.isInterrupted()&&t.axes.length&&(n={input:t,event:e},this.isStopped=!1,this.itm.setInterrupt(!0),this.am.grab(t.axes,n),this.moveDistance||this.em.triggerHold(this.axm.get(),n),this.isOutside=this.axm.isOutside(t.axes),this.moveDistance=this.axm.get(t.axes))},e.change=function(t,e,n){var i,s;this.isStopped||!this.itm.isInterrupting()||this.axm.every(n,function(t){return 0===t})||(s=_(i=this.moveDistance||this.axm.get(t.axes),function(t,e){return t+(n[e]||0)}),this.moveDistance&&(this.moveDistance=s),this.isOutside&&this.axm.every(i,function(t,e){return!r(t,e.range)})&&(this.isOutside=!1),i=this.atOutside(i),s=this.atOutside(s),this.em.triggerChange(s,!1,i,{input:t,event:e},!0)||(this.isStopped=!0,this.moveDistance=null,this.am.finish(!1)))},e.release=function(t,e,n,i){var s,r,o,a,h,u,c,m;!this.isStopped&&this.itm.isInterrupting()&&this.moveDistance&&(s=this.axm.get(t.axes),r=this.axm.get(),o=this.axm.get(this.axm.map(n,function(t,e,n){return e.circular&&(e.circular[0]||e.circular[1])?s[n]+t:l(s[n]+t,e.range,e.circular,e.bounce)})),0===(a=this.am.getDuration(o,s,i))&&(o=g({},r)),h={depaPos:r,destPos:o,duration:a,delta:this.axm.getDelta(r,o),inputEvent:e,input:t,isTrusted:!0},this.em.triggerRelease(h),this.moveDistance=null,m={input:t,event:e},(c=b((u=this.am.getUserControll(h)).destPos,r))||0===u.duration?(c||this.em.triggerChange(u.destPos,!1,r,m,!0),this.itm.setInterrupt(!1),this.axm.isOutside()?this.am.restore(m):this.em.triggerFinish(!0)):this.am.animateTo(u.destPos,u.duration,m))},t}(),w="ontouchstart"in s&&"safari"===t().browser.name,N=function(){if("undefined"==typeof document)return"";for(var t=(document.head||document.getElementsByTagName("head")[0]).style,e=["transform","webkitTransform","msTransform","mozTransform"],n=0,i=e.length;n<i;n++)if(e[n]in t)return e[n];return""}(),M=function(s){function t(t,e,n){void 0===t&&(t={}),void 0===e&&(e={});var i=s.call(this)||this;return i.axis=t,i._inputs=[],i.options=g({easing:function(t){return 1-Math.pow(1-t,3)},interruptable:!0,maximumDuration:1/0,minimumDuration:0,deceleration:6e-4,round:null},e),i.itm=new D(i.options),i.axm=new A(i.axis,i.options),i.em=new R(i),i.am=new O(i),i.io=new C(i),i.em.setAnimationManager(i.am),n&&i.em.triggerChange(n),i}n(t,s);var e=t.prototype;return e.connect=function(t,e){var n,i="string"==typeof t?t.split(" "):t.concat();return~this._inputs.indexOf(e)&&this.disconnect(e),"hammer"in e&&((n=this._inputs.filter(function(t){return t.hammer&&t.element===e.element})).length&&(e.hammer=n[0].hammer)),e.mapAxes(i),e.connect(this.io),this._inputs.push(e),this},e.disconnect=function(t){var e;return t?0<=(e=this._inputs.indexOf(t))&&(this._inputs[e].disconnect(),this._inputs.splice(e,1)):(this._inputs.forEach(function(t){return t.disconnect()}),this._inputs=[]),this},e.get=function(t){return this.axm.get(t)},e.setTo=function(t,e){return void 0===e&&(e=0),this.am.setTo(t,e),this},e.setBy=function(t,e){return void 0===e&&(e=0),this.am.setBy(t,e),this},e.isBounceArea=function(t){return this.axm.isOutside(t)},e.destroy=function(){this.disconnect(),this.em.destroy()},t.VERSION="2.8.0",t.TRANSFORM=N,t.DIRECTION_NONE=c.DIRECTION_NONE,t.DIRECTION_LEFT=c.DIRECTION_LEFT,t.DIRECTION_RIGHT=c.DIRECTION_RIGHT,t.DIRECTION_UP=c.DIRECTION_UP,t.DIRECTION_DOWN=c.DIRECTION_DOWN,t.DIRECTION_HORIZONTAL=c.DIRECTION_HORIZONTAL,t.DIRECTION_VERTICAL=c.DIRECTION_VERTICAL,t.DIRECTION_ALL=c.DIRECTION_ALL,t}(e),L="PointerEvent"in s||"MSPointerEvent"in s,S="ontouchstart"in s,H="_EGJS_AXES_INPUTTYPE_";function j(i,t){return t.reduce(function(t,e,n){return i[n]&&(t[i[n]]=e),t},{})}function F(t,e){try{return new c.Manager(t,g({},e))}catch(t){return null}}function z(t){void 0===t&&(t=[]);var e=!1,n=!1,i=!1;return t.forEach(function(t){switch(t){case"mouse":n=!0;break;case"touch":e=S;break;case"pointer":i=L}}),i?c.PointerEventInput:e&&n?c.TouchMouseInput:e?c.TouchInput:n?c.MouseInput:null}function k(t,e,n){return n?!!(e===c.DIRECTION_ALL||e&t&&n&t):!!(e&t)}var Y=function(){function t(t,e){if(this.axes=[],this.hammer=null,this.element=null,this.panRecognizer=null,this.isRightEdge=!1,this.rightEdgeTimer=0,this.panFlag=!1,void 0===c.Manager)throw new Error("The Hammerjs must be loaded before eg.Axes.PanInput.\nhttp://hammerjs.github.io/");this.element=a(t),this.options=g({inputType:["touch","mouse","pointer"],scale:[1,1],thresholdAngle:45,threshold:0,iOSEdgeSwipeThreshold:30,releaseOnScroll:!1,hammerManagerOptions:{cssProps:{userSelect:"none",touchSelect:"none",touchCallout:"none",userDrag:"none"}}},e),this.onHammerInput=this.onHammerInput.bind(this),this.onPanmove=this.onPanmove.bind(this),this.onPanend=this.onPanend.bind(this)}var e=t.prototype;return e.mapAxes=function(t){var e=!!t[0],n=!!t[1];this._direction=e&&n?c.DIRECTION_ALL:e?c.DIRECTION_HORIZONTAL:n?c.DIRECTION_VERTICAL:c.DIRECTION_NONE,this.axes=t},e.connect=function(t){var e={direction:this._direction,threshold:this.options.threshold};if(this.hammer)this.removeRecognizer(),this.dettachEvent();else{var n=(n=this.element[H])||String(Math.round(Math.random()*(new Date).getTime())),i=z(this.options.inputType);if(!i)throw new Error("Wrong inputType parameter!");this.hammer=F(this.element,g({inputClass:i},this.options.hammerManagerOptions)),this.element[H]=n}return this.panRecognizer=new c.Pan(e),this.hammer.add(this.panRecognizer),this.attachEvent(t),this},e.disconnect=function(){return this.removeRecognizer(),this.hammer&&this.dettachEvent(),this._direction=c.DIRECTION_NONE,this},e.destroy=function(){this.disconnect(),this.hammer&&0===this.hammer.recognizers.length&&this.hammer.destroy(),delete this.element[H],this.element=null,this.hammer=null},e.enable=function(){return this.hammer&&(this.hammer.get("pan").options.enable=!0),this},e.disable=function(){return this.hammer&&(this.hammer.get("pan").options.enable=!1),this},e.isEnable=function(){return!(!this.hammer||!this.hammer.get("pan").options.enable)},e.removeRecognizer=function(){this.hammer&&this.panRecognizer&&(this.hammer.remove(this.panRecognizer),this.panRecognizer=null)},e.onHammerInput=function(t){var e;this.isEnable()&&(t.isFirst?(this.panFlag=!1)!==t.srcEvent.cancelable&&(e=this.options.iOSEdgeSwipeThreshold,this.observer.hold(this,t),this.isRightEdge=w&&t.center.x>window.innerWidth-e,this.panFlag=!0):t.isFinal&&this.onPanend(t))},e.onPanmove=function(t){var e=this;if(this.panFlag){var n=this.options,i=n.iOSEdgeSwipeThreshold,s=n.releaseOnScroll,r=function(t,e){if(e<0||90<e)return c.DIRECTION_NONE;var n=Math.abs(t);return e<n&&n<180-e?c.DIRECTION_VERTICAL:c.DIRECTION_HORIZONTAL}(t.angle,this.options.thresholdAngle),o=this.hammer.session.prevInput;if(!s||t.srcEvent.cancelable){if(o&&w){if(t.center.x<0)return void this.onPanend(g(g({},o),{velocityX:0,velocityY:0,offsetX:0,offsetY:0}));this.isRightEdge&&(clearTimeout(this.rightEdgeTimer),t.deltaX<-i?this.isRightEdge=!1:this.rightEdgeTimer=window.setTimeout(function(){e.onPanend(g(g({},o),{velocityX:0,velocityY:0,offsetX:0,offsetY:0}))},100))}o?(t.offsetX=t.deltaX-o.deltaX,t.offsetY=t.deltaY-o.deltaY):(t.offsetX=0,t.offsetY=0);var a,h=this.getOffset([t.offsetX,t.offsetY],[k(c.DIRECTION_HORIZONTAL,this._direction,r),k(c.DIRECTION_VERTICAL,this._direction,r)]),u=h.some(function(t){return 0!==t});u&&(!1!==(a=t.srcEvent).cancelable&&a.preventDefault(),a.stopPropagation()),(t.preventSystemEvent=u)&&this.observer.change(this,t,j(this.axes,h))}else this.onPanend(g(g({},t),{velocityX:0,velocityY:0,offsetX:0,offsetY:0}))}},e.onPanend=function(t){var e,n,i,s,r;this.panFlag&&(clearTimeout(this.rightEdgeTimer),this.panFlag=!1,e=this.getOffset([Math.abs(t.velocityX)*(t.deltaX<0?-1:1),Math.abs(t.velocityY)*(t.deltaY<0?-1:1)],[k(c.DIRECTION_HORIZONTAL,this._direction),k(c.DIRECTION_VERTICAL,this._direction)]),n=e,i=this.observer.options.deceleration,s=Math.sqrt(n[0]*n[0]+n[1]*n[1]),r=Math.abs(s/-i),e=[n[0]/2*r,n[1]/2*r],this.observer.release(this,t,j(this.axes,e)))},e.attachEvent=function(t){this.observer=t,this.hammer.on("hammer.input",this.onHammerInput).on("panstart panmove",this.onPanmove)},e.dettachEvent=function(){this.hammer.off("hammer.input",this.onHammerInput).off("panstart panmove",this.onPanmove),this.observer=null},e.getOffset=function(t,e){var n=[0,0],i=this.options.scale;return e[0]&&(n[0]=t[0]*i[0]),e[1]&&(n[1]=t[1]*i[1]),n},t}(),X=function(i){function t(t,e){var n=i.call(this,t,e)||this;return n.prevQuadrant=null,n.lastDiff=0,n}n(t,i);var e=t.prototype;return e.mapAxes=function(t){this._direction=M.DIRECTION_ALL,this.axes=t},e.onHammerInput=function(t){this.isEnable()&&(t.isFirst?(this.observer.hold(this,t),this.onPanstart(t)):t.isFinal&&this.onPanend(t))},e.onPanstart=function(t){var e=this.element.getBoundingClientRect();this.coefficientForDistanceToAngle=360/(e.width*Math.PI),this.rotateOrigin=[e.left+(e.width-1)/2,e.top+(e.height-1)/2],this.prevAngle=null,this.triggerChange(t)},e.onPanmove=function(t){this.triggerChange(t)},e.onPanend=function(t){this.triggerChange(t),this.triggerAnimation(t)},e.triggerChange=function(t){var e=this.getAngle(t.center.x,t.center.y),n=this.getQuadrant(t.center.x,t.center.y),i=this.getDifference(this.prevAngle,e,this.prevQuadrant,n);this.prevAngle=e,this.prevQuadrant=n,0!==i&&(this.lastDiff=i,this.observer.change(this,t,j(this.axes,[-i])))},e.triggerAnimation=function(t){var e=t.velocityX,n=t.velocityY,i=Math.sqrt(e*e+n*n)*(0<this.lastDiff?-1:1),s=i/2*Math.abs(i/-this.observer.options.deceleration);this.observer.release(this,t,j(this.axes,[s*this.coefficientForDistanceToAngle]))},e.getDifference=function(t,e,n,i){var s=null===t?0:1===n&&4===i?-t-(360-e):4===n&&1===i?360-t+e:e-t;return s},e.getPosFromOrigin=function(t,e){return{x:t-this.rotateOrigin[0],y:this.rotateOrigin[1]-e}},e.getAngle=function(t,e){var n=this.getPosFromOrigin(t,e),i=n.x,s=n.y,r=180*Math.atan2(s,i)/Math.PI;return r<0?360+r:r},e.getQuadrant=function(t,e){var n=this.getPosFromOrigin(t,e),i=n.x,s=n.y,r=0;return 0<=i&&0<=s?r=1:i<0&&0<=s?r=2:i<0&&s<0?r=3:0<=i&&s<0&&(r=4),r},t}(Y),K=function(){function t(t,e){if(this.axes=[],this.hammer=null,this.element=null,this._base=null,this._prev=null,this.pinchRecognizer=null,void 0===c.Manager)throw new Error("The Hammerjs must be loaded before eg.Axes.PinchInput.\nhttp://hammerjs.github.io/");this.element=a(t),this.options=g({scale:1,threshold:0,inputType:["touch","pointer"],hammerManagerOptions:{cssProps:{userSelect:"none",touchSelect:"none",touchCallout:"none",userDrag:"none"}}},e),this.onPinchStart=this.onPinchStart.bind(this),this.onPinchMove=this.onPinchMove.bind(this),this.onPinchEnd=this.onPinchEnd.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){var e={threshold:this.options.threshold};if(this.hammer)this.removeRecognizer(),this.dettachEvent();else{var n=(n=this.element[H])||String(Math.round(Math.random()*(new Date).getTime())),i=z(this.options.inputType);if(!i)throw new Error("Wrong inputType parameter!");this.hammer=F(this.element,g({inputClass:i},this.options.hammerManagerOptions)),this.element[H]=n}return this.pinchRecognizer=new c.Pinch(e),this.hammer.add(this.pinchRecognizer),this.attachEvent(t),this},e.disconnect=function(){return this.removeRecognizer(),this.hammer&&(this.hammer.remove(this.pinchRecognizer),this.pinchRecognizer=null,this.dettachEvent()),this},e.destroy=function(){this.disconnect(),this.hammer&&0===this.hammer.recognizers.length&&this.hammer.destroy(),delete this.element[H],this.element=null,this.hammer=null},e.removeRecognizer=function(){this.hammer&&this.pinchRecognizer&&(this.hammer.remove(this.pinchRecognizer),this.pinchRecognizer=null)},e.onPinchStart=function(t){this._base=this.observer.get(this)[this.axes[0]];var e=this.getOffset(t.scale);this.observer.hold(this,t),this.observer.change(this,t,j(this.axes,[e])),this._prev=t.scale},e.onPinchMove=function(t){var e=this.getOffset(t.scale,this._prev);this.observer.change(this,t,j(this.axes,[e])),this._prev=t.scale},e.onPinchEnd=function(t){var e=this.getOffset(t.scale,this._prev);this.observer.change(this,t,j(this.axes,[e])),this.observer.release(this,t,j(this.axes,[0]),0),this._base=null,this._prev=null},e.getOffset=function(t,e){return void 0===e&&(e=1),this._base*(t-e)*this.options.scale},e.attachEvent=function(t){this.observer=t,this.hammer.on("pinchstart",this.onPinchStart).on("pinchmove",this.onPinchMove).on("pinchend",this.onPinchEnd)},e.dettachEvent=function(){this.hammer.off("pinchstart",this.onPinchStart).off("pinchmove",this.onPinchMove).off("pinchend",this.onPinchEnd),this.observer=null,this._prev=null},e.enable=function(){return this.hammer&&(this.hammer.get("pinch").options.enable=!0),this},e.disable=function(){return this.hammer&&(this.hammer.get("pinch").options.enable=!1),this},e.isEnable=function(){return!(!this.hammer||!this.hammer.get("pinch").options.enable)},t}(),U=function(){function t(t,e){this.axes=[],this.element=null,this._isEnabled=!1,this._isHolded=!1,this._timer=null,this.element=a(t),this.options=g({scale:1,useNormalized:!0},e),this.onWheel=this.onWheel.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this.dettachEvent(),this.attachEvent(t),this},e.disconnect=function(){return this.dettachEvent(),this},e.destroy=function(){this.disconnect(),this.element=null},e.onWheel=function(t){var e,n=this;this._isEnabled&&(t.preventDefault(),0!==t.deltaY&&(this._isHolded||(this.observer.hold(this,t),this._isHolded=!0),e=(0<t.deltaY?-1:1)*this.options.scale*(this.options.useNormalized?1:Math.abs(t.deltaY)),this.observer.change(this,t,j(this.axes,[e])),clearTimeout(this._timer),this._timer=setTimeout(function(){n._isHolded&&(n._isHolded=!1,n.observer.release(n,t,j(n.axes,[0])))},50)))},e.attachEvent=function(t){this.observer=t,this.element.addEventListener("wheel",this.onWheel),this._isEnabled=!0},e.dettachEvent=function(){this.element.removeEventListener("wheel",this.onWheel),this._isEnabled=!1,this.observer=null,this._timer&&(clearTimeout(this._timer),this._timer=null)},e.enable=function(){return this._isEnabled=!0,this},e.disable=function(){return this._isEnabled=!1,this},e.isEnable=function(){return this._isEnabled},t}(),W=function(){function t(t,e){this.axes=[],this.element=null,this._isEnabled=!1,this._isHolded=!1,this._timer=null,this.element=a(t),this.options=g({scale:[1,1]},e),this.onKeydown=this.onKeydown.bind(this),this.onKeyup=this.onKeyup.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this.dettachEvent(),"0"!==this.element.getAttribute("tabindex")&&this.element.setAttribute("tabindex","0"),this.attachEvent(t),this},e.disconnect=function(){return this.dettachEvent(),this},e.destroy=function(){this.disconnect(),this.element=null},e.onKeydown=function(t){if(this._isEnabled){var e,n=!0,i=1,s=-1;switch(t.keyCode){case 37:case 65:i=-1;break;case 39:case 68:break;case 40:case 83:i=-1,s=1;break;case 38:case 87:s=1;break;default:n=!1}(-1===s&&!this.axes[0]||1===s&&!this.axes[1])&&(n=!1),n&&(e=-1===s?[this.options.scale[0]*i,0]:[0,this.options.scale[1]*i],this._isHolded||(this.observer.hold(this,event),this._isHolded=!0),clearTimeout(this._timer),this.observer.change(this,event,j(this.axes,e)))}},e.onKeyup=function(t){var e=this;this._isHolded&&(clearTimeout(this._timer),this._timer=setTimeout(function(){e.observer.release(e,t,j(e.axes,[0,0])),e._isHolded=!1},80))},e.attachEvent=function(t){this.observer=t,this.element.addEventListener("keydown",this.onKeydown,!1),this.element.addEventListener("keypress",this.onKeydown,!1),this.element.addEventListener("keyup",this.onKeyup,!1),this._isEnabled=!0},e.dettachEvent=function(){this.element.removeEventListener("keydown",this.onKeydown,!1),this.element.removeEventListener("keypress",this.onKeydown,!1),this.element.removeEventListener("keyup",this.onKeyup,!1),this._isEnabled=!1,this.observer=null},e.enable=function(){return this._isEnabled=!0,this},e.disable=function(){return this._isEnabled=!1,this},e.isEnable=function(){return this._isEnabled},t}();return M.PanInput=Y,M.RotatePanInput=X,M.PinchInput=K,M.WheelInput=U,M.MoveKeyInput=W,M}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("@egjs/agent"),require("@egjs/component")):"function"==typeof define&&define.amd?define(["@egjs/agent","@egjs/component"],e):(t.eg=t.eg||{},t.eg.Axes=e(t.eg.agent,t.eg.Component))}(this,function(t,p){"use strict";var i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)};function s(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}function _(t,e,n,i){var r=t,s=[!n[0]&&i?e[0]-i[0]:e[0],!n[1]&&i?e[1]+i[1]:e[1]],r=Math.max(s[0],r);return Math.min(s[1],r)}function u(t,e){return t<e[0]||t>e[1]}function h(t,e,n){return n[1]&&t>e[1]||n[0]&&t<e[0]}function v(t,e,n){var i=t,r=e[0],s=e[1],a=s-r;return n[1]&&s<t&&(i=(i-s)%a+r),n[0]&&t<r&&(i=(i-r)%a+s),i}function r(t){for(var e=[],n=0,i=t.length;n<i;n++)e.push(t[n]);return e}var a,o,d=function(){return(d=Object.assign||function(t){for(var e,n=1,i=arguments.length;n<i;n++)for(var r in e=arguments[n])Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t}).apply(this,arguments)},c="undefined"==typeof window?{navigator:{userAgent:""}}:window,l="ontouchstart"in c&&"safari"===t().browser.name,n=function(){if("undefined"==typeof document)return"";for(var t=(document.head||document.getElementsByTagName("head")[0]).style,e=["transform","webkitTransform","msTransform","mozTransform"],n=0,i=e.length;n<i;n++)if(e[n]in t)return e[n];return""}(),g={"touch-action":"none","user-select":"none","-webkit-user-drag":"none"},f=function(t,e){var n,i;return void 0===e&&(e=!1),"string"==typeof t?(i=t.match(/^<([a-z]+)\s*([^>]*)>/)?((n=document.createElement("div")).innerHTML=t,r(n.childNodes)):r(document.querySelectorAll(t)),e||(i=1<=i.length?i[0]:void 0)):t!==c&&(!t.nodeName||1!==t.nodeType&&9!==t.nodeType)?"jQuery"in c&&t instanceof jQuery||t.constructor.prototype.jquery?i=e?t.toArray():t.get(0):Array.isArray(t)&&(i=t.map(function(t){return f(t)}),e||(i=1<=i.length?i[0]:void 0)):i=t,i},m=c.requestAnimationFrame||c.webkitRequestAnimationFrame,E=c.cancelAnimationFrame||c.webkitCancelAnimationFrame;m&&!E?(a={},o=m,m=function(e){var n=o(function(t){a[n]&&e(t)});return a[n]=!0,n},E=function(t){delete a[t]}):m&&E||(m=function(t){return c.setTimeout(function(){t(c.performance&&c.performance.now&&c.performance.now()||(new Date).getTime())},16)},E=c.clearTimeout);function x(t,e){var n={};for(var i in t)i&&(n[i]=e(t[i],i));return n}function M(t,e){var n={};for(var i in t)i&&e(t[i],i)&&(n[i]=t[i]);return n}function b(t,e){for(var n in t)if(n&&!e(t[n],n))return!1;return!0}function P(t,n){return b(t,function(t,e){return t===n[e]})}function y(t,e){return R[e]||(R[e]=F(e)),R[e](t)}function I(t,n){return t&&n?x(t,function(t,e){return y(t,"number"==typeof n?n:n[e])}):t}function T(t){if(!isFinite(t))return 0;var e=""+t;if(0<=e.indexOf("e")){for(var n=0,i=1;Math.round(t*i)/i!==t;)i*=10,n++;return n}return 0<=e.indexOf(".")?e.length-e.indexOf(".")-1:0}function O(t,e){return 180*Math.atan2(e,t)/Math.PI}function w(e,t){var n,i={};return e.style&&(n=t||g,Object.keys(n).forEach(function(t){i[t]=e.style[t],e.style[t]=n[t]})),i}function D(t,e,n){return Math.max(Math.min(t,n),e)}function A(i,t){return t.reduce(function(t,e,n){return i[n]&&(t[i[n]]=e),t},{})}function C(t){void 0===t&&(t=[]);var e=!1,n=!1,i=!1;return t.forEach(function(t){switch(t){case"mouse":n=!0;break;case"touch":e=j;break;case"pointer":i=K}}),i?new W:e&&n?new Q:e?new B:n?new q:null}function S(t,e,n){return n?!!(30===e||e&t&&n&t):!!(e&t)}var R={},F=function(e){var n=e<1?Math.pow(10,T(e)):1;return function(t){return 0===e?0:Math.round(Math.round(t/e)*e*n)/n}},L=function(){function t(t){var e=t.options,n=t.interruptManager,i=t.eventManager,r=t.axisManager;this._options=e,this.interruptManager=n,this.eventManager=i,this.axisManager=r,this.animationEnd=this.animationEnd.bind(this)}var e=t.prototype;return e.getDuration=function(s,t,e){var n,i,a=this;return i=void 0!==e?e:(n=x(t,function(t,e){return n=Math.abs(t-s[e]),i=a._options.deceleration,(r=Math.sqrt(n/i*2))<100?0:r;var n,i,r}),Object.keys(n).reduce(function(t,e){return Math.max(t,n[e])},-1/0)),D(i,this._options.minimumDuration,this._options.maximumDuration)},e.getDisplacement=function(t){var e=Math.pow(t.reduce(function(t,e){return t+e*e},0),1/t.length),n=Math.abs(e/-this._options.deceleration);return t.map(function(t){return t/2*n})},e.interpolate=function(t,e){var n=this.easing(1e-5)/1e-5;return this.easing(t/(e*n))*e},e.stopAnimation=function(t,e){var n,i,r;this._animateParam&&t.length&&(n=this.axisManager.get(t),i=this.axisManager.map(n,function(t,e){return v(t,e.range,e.circular)}),b(i,function(t,e){return n[e]===t})||this.eventManager.triggerChange(i,!1,n,e,!!e),this._animateParam=null,this._raf&&(r=this._raf,E(r)),this._raf=null,this.eventManager.triggerAnimationEnd(!(null==e||!e.event)))},e.getEventInfo=function(){return this._animateParam&&this._animateParam.input&&this._animateParam.inputEvent?{input:this._animateParam.input,event:this._animateParam.inputEvent}:null},e.restore=function(t){var e=this.axisManager.get(),n=this.axisManager.map(e,function(t,e){return Math.min(e.range[1],Math.max(e.range[0],t))});this.stopAnimation(Object.keys(this.axisManager.get())),this.animateTo(n,this.getDuration(e,n),t)},e.animationEnd=function(){var t=this.getEventInfo();this._animateParam=null;var e=this.axisManager.filter(this.axisManager.get(),function(t,e){return h(t,e.range,e.circular)});0<Object.keys(e).length&&this.setTo(this.axisManager.map(e,function(t,e){return v(t,e.range,e.circular)})),this.interruptManager.setInterrupt(!1),this.eventManager.triggerAnimationEnd(!!t),this.axisManager.isOutside()?this.restore(t):this.finish(!!t)},e.finish=function(t){this._animateParam=null,this.interruptManager.setInterrupt(!1),this.eventManager.triggerFinish(t)},e.getUserControl=function(t){var e=t.setTo();return e.destPos=this.axisManager.get(e.destPos),e.duration=D(e.duration,this._options.minimumDuration,this._options.maximumDuration),e},e.animateTo=function(t,e,n){var i,r=this,s=this._createAnimationParam(t,e,n),a=d({},s.depaPos),o=this.eventManager.triggerAnimationStart(s),u=this.getUserControl(s);!o&&this.axisManager.every(u.destPos,function(t,e){return h(t,e.range,e.circular)})&&console.warn("You can't stop the 'animation' event when 'circular' is true."),o&&!P(u.destPos,a)&&(i=(null==n?void 0:n.event)||null,this._animateLoop({depaPos:a,destPos:u.destPos,duration:u.duration,delta:this.axisManager.getDelta(a,u.destPos),isTrusted:!!i,inputEvent:i,input:(null==n?void 0:n.input)||null},function(){return r.animationEnd()}))},e.easing=function(t){return 1<t?1:this._options.easing(t)},e.setTo=function(t,e){void 0===e&&(e=0);var n=Object.keys(t);this.stopAnimation(n);var i=this.axisManager.get(n);if(P(t,i))return this;this.interruptManager.setInterrupt(!0);var r=M(t,function(t,e){return i[e]!==t});return Object.keys(r).length?(r=this.axisManager.map(r,function(t,e){var n=e.range,i=e.circular;return i&&(i[0]||i[1])?t:_(t,n,i)}),P(r,i)||(0<e?this.animateTo(r,e):(this.eventManager.triggerChange(r),this.finish(!1))),this):this},e.setBy=function(n,t){return void 0===t&&(t=0),this.setTo(x(this.axisManager.get(Object.keys(n)),function(t,e){return t+n[e]}),t)},e.updateAnimation=function(t){var e,n,i,r,s,a=this._animateParam;a&&(e=(new Date).getTime()-a.startTime,n=(null==t?void 0:t.destPos)||a.destPos,i=(null==t?void 0:t.duration)||a.duration,null!=t&&t.restart||i<=e?this.setTo(n,i-e):(null!=t&&t.destPos&&(r=this.axisManager.get(),this._initialEasingPer=this._prevEasingPer,a.delta=this.axisManager.getDelta(r,n),a.destPos=n),null!=t&&t.duration&&(s=(e+this._durationOffset)/a.duration,this._durationOffset=s*i-e,a.duration=i)))},e._createAnimationParam=function(t,e,n){var i=this.axisManager.get(),r=t,s=(null==n?void 0:n.event)||null;return{depaPos:i,destPos:r,duration:D(e,this._options.minimumDuration,this._options.maximumDuration),delta:this.axisManager.getDelta(i,r),inputEvent:s,input:(null==n?void 0:n.input)||null,isTrusted:!!s,done:this.animationEnd}},e._animateLoop=function(n,i){var h,c,r,s,l=this;n.duration?(h=n.depaPos,this._initialEasingPer=0,this._prevEasingPer=0,this._durationOffset=0,this._animateParam=d(d({},n),{startTime:(new Date).getTime()}),c=x(h,function(t,e){return t<=n.destPos[e]?1:-1}),r=x(n.destPos,function(t){return t}),(s=function(){var a=l._animateParam,o=((new Date).getTime()-a.startTime+l._durationOffset)/a.duration,u=l.easing(o);l._raf=null;var t=l.axisManager.map(h,function(t,e,n){var i,r=1<=o?a.destPos[n]:t+a.delta[n]*(u-l._prevEasingPer)/(1-l._initialEasingPer),s=v(r,e.range,e.circular);return r!==s&&(i=c[n]*(e.range[1]-e.range[0]),a.destPos[n]-=i,h[n]-=i),s}),e=!l.eventManager.triggerChange(t,!1,h);if(h=t,1<=(l._prevEasingPer=u))return a.destPos=l._getFinalPos(a.destPos,r),P(a.destPos,l.axisManager.get(Object.keys(a.destPos)))||l.eventManager.triggerChange(a.destPos,!0,h),void i();e?l.finish(!1):l._raf=m(s)})()):(this.eventManager.triggerChange(n.destPos,!0),i())},e._getFinalPos=function(t,i){var r=this;return x(t,function(t,e){if(t>=i[e]-1e-6&&t<=i[e]+1e-6)return i[e];var n=r._getRoundUnit(t,e);return y(t,n)})},e._getRoundUnit=function(t,e){var n,i,r=this._options.round,s=null;return r||(n=this.axisManager.getAxisOptions(e),i=Math.max(T(n.range[0]),T(n.range[1]),T(t)),s=1/Math.pow(10,i)),s||r},t}(),k=function(){function t(t){this._axes=t}var e=t.prototype;return e.hold=function(t,e){var n=this._getRoundPos(t).roundPos;this._axes.trigger(new p.ComponentEvent("hold",{pos:n,input:e.input||null,inputEvent:e.event||null,isTrusted:!0}))},e.triggerRelease=function(t){var e=this._getRoundPos(t.destPos,t.depaPos),n=e.roundPos,i=e.roundDepa;t.destPos=n,t.depaPos=i,t.setTo=this._createUserControll(t.destPos,t.duration),this._axes.trigger(new p.ComponentEvent("release",d(d({},t),{bounceRatio:this._getBounceRatio(n)})))},e.triggerChange=function(t,e,n,i,r){void 0===r&&(r=!1);var s=this.animationManager,a=s.axisManager,o=s.getEventInfo(),u=this._getRoundPos(t,n),h=u.roundPos,c=u.roundDepa,l=a.moveTo(h,c),v=(null==i?void 0:i.event)||(null==o?void 0:o.event)||null,_={pos:l.pos,delta:l.delta,bounceRatio:this._getBounceRatio(l.pos),holding:r,inputEvent:v,isTrusted:!!v,input:(null==i?void 0:i.input)||(null==o?void 0:o.input)||null,set:v?this._createUserControll(l.pos):function(){}},d=this._axes.trigger(new p.ComponentEvent("change",_));return v&&a.set(_.set().destPos),d},e.triggerAnimationStart=function(t){var e=this._getRoundPos(t.destPos,t.depaPos),n=e.roundPos,i=e.roundDepa;return t.destPos=n,t.depaPos=i,t.setTo=this._createUserControll(t.destPos,t.duration),this._axes.trigger(new p.ComponentEvent("animationStart",t))},e.triggerAnimationEnd=function(t){void 0===t&&(t=!1),this._axes.trigger(new p.ComponentEvent("animationEnd",{isTrusted:t}))},e.triggerFinish=function(t){void 0===t&&(t=!1),this._axes.trigger(new p.ComponentEvent("finish",{isTrusted:t}))},e.setAnimationManager=function(t){this.animationManager=t},e.destroy=function(){this._axes.off()},e._createUserControll=function(t,e){void 0===e&&(e=0);var n={destPos:d({},t),duration:e};return function(t,e){return t&&(n.destPos=d({},t)),void 0!==e&&(n.duration=e),n}},e._getRoundPos=function(t,e){var n=this._axes.options.round;return{roundPos:I(t,n),roundDepa:I(e,n)}},e._getBounceRatio=function(t){return this._axes.axisManager.map(t,function(t,e){return t<e.range[0]&&0!==e.bounce[0]?(e.range[0]-t)/e.bounce[0]:t>e.range[1]&&0!==e.bounce[1]?(t-e.range[1])/e.bounce[1]:0})},t}(),Y=function(){function t(t){this._options=t,this._prevented=!1}var e=t.prototype;return e.isInterrupting=function(){return this._options.interruptable||this._prevented},e.isInterrupted=function(){return!this._options.interruptable&&this._prevented},e.setInterrupt=function(t){this._options.interruptable||(this._prevented=t)},t}(),X=function(){function t(t){var n=this;this._axis=t,this._complementOptions(),this._pos=Object.keys(this._axis).reduce(function(t,e){return t[e]=n._axis[e].range[0],t},{})}var e=t.prototype;return e.getDelta=function(t,e){var n=this.get(t);return x(this.get(e),function(t,e){return t-n[e]})},e.get=function(t){var n=this;return t&&Array.isArray(t)?t.reduce(function(t,e){return e&&e in n._pos&&(t[e]=n._pos[e]),t},{}):d(d({},this._pos),t||{})},e.moveTo=function(n,i){void 0===i&&(i=this._pos);var t=x(this._pos,function(t,e){return e in n&&e in i?n[e]-i[e]:0});return this.set(this.map(n,function(t,e){return e?v(t,e.range,e.circular):0})),{pos:d({},this._pos),delta:t}},e.set=function(t){for(var e in t)e&&e in this._pos&&(this._pos[e]=t[e])},e.every=function(t,n){var i=this._axis;return b(t,function(t,e){return n(t,i[e],e)})},e.filter=function(t,n){var i=this._axis;return M(t,function(t,e){return n(t,i[e],e)})},e.map=function(t,n){var i=this._axis;return x(t,function(t,e){return n(t,i[e],e)})},e.isOutside=function(t){return!this.every(t?this.get(t):this._pos,function(t,e){return!u(t,e.range)})},e.getAxisOptions=function(t){return this._axis[t]},e._complementOptions=function(){var r=this;Object.keys(this._axis).forEach(function(i){r._axis[i]=d({range:[0,100],bounce:[0,0],circular:[!1,!1]},r._axis[i]),["bounce","circular"].forEach(function(t){var e=r._axis,n=e[i][t];/string|number|boolean/.test(typeof n)&&(e[i][t]=[n,n])})})},t}(),j="ontouchstart"in c,N="PointerEvent"in c,e="MSPointerEvent"in c,K=N||e,U=function(){function t(){}var e=t.prototype;return e.extendEvent=function(t){var e=this.prevEvent,n=this._getCenter(t),i=e?this._getMovement(t):{x:0,y:0},r=e?this._getScale(t):1,s=e?O(n.x-e.center.x,n.y-e.center.y):0,a=e?e.deltaX+i.x:i.x,o=e?e.deltaY+i.y:i.y,u=e?a-e.deltaX:0,h=e?o-e.deltaY:0,c=e?t.timeStamp-e.srcEvent.timeStamp:0;return{srcEvent:t,scale:r,angle:s,center:n,deltaX:a,deltaY:o,offsetX:u,offsetY:h,velocityX:e&&0!=c?u/c:0,velocityY:e&&0!=c?h/c:0,preventSystemEvent:!0}},e._getDistance=function(t,e){var n=e.clientX-t.clientX,i=e.clientY-t.clientY;return Math.sqrt(n*n+i*i)},t}(),q=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.start=["mousedown"],t.move=["mousemove"],t.end=["mouseup"],t}s(t,e);var n=t.prototype;return n.onEventStart=function(t){return this.extendEvent(t)},n.onEventMove=function(t){return this.extendEvent(t)},n.onEventEnd=function(){},n.getTouches=function(){return 0},n._getScale=function(){return 1},n._getCenter=function(t){return{x:t.clientX,y:t.clientY}},n._getMovement=function(t){var e=this.prevEvent.srcEvent;return{x:t.pageX-e.pageX,y:t.pageY-e.pageY}},t}(U),B=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.start=["touchstart"],t.move=["touchmove"],t.end=["touchend","touchcancel"],t}s(t,e);var n=t.prototype;return n.onEventStart=function(t){return this._firstTouch=t,this.extendEvent(t)},n.onEventMove=function(t){return this.extendEvent(t)},n.onEventEnd=function(){},n.getTouches=function(t){return t.touches.length},n._getScale=function(t){return 2!==t.touches.length?null:this._getDistance(t.touches[0],t.touches[1])/this._getDistance(this._firstTouch.touches[0],this._firstTouch.touches[1])},n._getCenter=function(t){return{x:t.touches[0].clientX,y:t.touches[0].clientY}},n._getMovement=function(t){var e=this.prevEvent.srcEvent;return t.touches[0].identifier!==e.touches[0].identifier?{x:0,y:0}:{x:t.touches[0].pageX-e.touches[0].pageX,y:t.touches[0].pageY-e.touches[0].pageY}},t}(U),W=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.start=N?["pointerdown"]:["MSPointerDown"],t.move=N?["pointermove"]:["MSPointerMove"],t.end=N?["pointerup","pointercancel"]:["MSPointerUp","MSPointerCancel"],t._firstInputs=[],t._recentInputs=[],t}s(t,e);var n=t.prototype;return n.onEventStart=function(t){return this._updatePointerEvent(t),this.extendEvent(t)},n.onEventMove=function(t){return this._updatePointerEvent(t),this.extendEvent(t)},n.onEventEnd=function(t){this._removePointerEvent(t)},n.getTouches=function(){return this._recentInputs.length},n._getScale=function(){return 2!==this._recentInputs.length?null:this._getDistance(this._recentInputs[0],this._recentInputs[1])/this._getDistance(this._firstInputs[0],this._firstInputs[1])},n._getCenter=function(t){return{x:t.clientX,y:t.clientY}},n._getMovement=function(t){var e=this.prevEvent.srcEvent;return t.pointerId!==e.pointerId?{x:0,y:0}:{x:t.pageX-e.pageX,y:t.pageY-e.pageY}},n._updatePointerEvent=function(n){var i=this,r=!1;this._recentInputs.forEach(function(t,e){t.pointerId===n.pointerId&&(r=!0,i._recentInputs[e]=n)}),r||(this._firstInputs.push(n),this._recentInputs.push(n))},n._removePointerEvent=function(e){this._firstInputs=this._firstInputs.filter(function(t){return t.pointerId!==e.pointerId}),this._recentInputs=this._recentInputs.filter(function(t){return t.pointerId!==e.pointerId})},t}(U),Q=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.start=["mousedown","touchstart"],t.move=["mousemove","touchmove"],t.end=["mouseup","touchend","touchcancel"],t}s(t,e);var n=t.prototype;return n.onEventStart=function(t){return this._firstTouch=t.hasOwnProperty("touches")?t:null,this.extendEvent(t)},n.onEventMove=function(t){return this.extendEvent(t)},n.onEventEnd=function(){},n.getTouches=function(t){return this._isTouchEvent(t)?t.touches.length:0},n._getScale=function(t){return!this._firstTouch||this._isTouchEvent(t)&&2!==t.touches.length?1:this._isTouchEvent(t)?this._getDistance(t.touches[0],t.touches[1])/this._getDistance(this._firstTouch.touches[0],this._firstTouch.touches[1]):this.prevEvent.scale},n._getCenter=function(t){return this._isTouchEvent(t)?{x:t.touches[0].clientX,y:t.touches[0].clientY}:{x:t.clientX,y:t.clientY}},n._getMovement=function(e){var n=this,t=this.prevEvent.srcEvent,i=[e,t].map(function(t){return n._isTouchEvent(e)?{id:t.touches[0].identifier,x:t.touches[0].pageX,y:t.touches[0].pageY}:{id:null,x:t.pageX,y:t.pageY}}),r=i[0],s=i[1];return r.id===s.id?{x:r.x-s.x,y:r.y-s.y}:{x:0,y:0}},n._isTouchEvent=function(t){return t.hasOwnProperty("touches")},t}(U),V=function(){function t(t){var e=t.options,n=t.interruptManager,i=t.eventManager,r=t.axisManager,s=t.animationManager;this._isOutside=!1,this._moveDistance=null,this._isStopped=!1,this.options=e,this._interruptManager=n,this._eventManager=i,this._axisManager=r,this._animationManager=s}var e=t.prototype;return e.get=function(t){return this._axisManager.get(t.axes)},e.hold=function(t,e){var n;!this._interruptManager.isInterrupted()&&t.axes.length&&(n={input:t,event:e},this._isStopped=!1,this._interruptManager.setInterrupt(!0),this._animationManager.stopAnimation(t.axes,n),this._moveDistance||this._eventManager.hold(this._axisManager.get(),n),this._isOutside=this._axisManager.isOutside(t.axes),this._moveDistance=this._axisManager.get(t.axes))},e.change=function(t,e,n,i){var r,s,a,o;this._isStopped||!this._interruptManager.isInterrupting()||this._axisManager.every(n,function(t){return 0===t})||(r=this._moveDistance||this._axisManager.get(t.axes),s=x(r,function(t,e){return t+(n[e]||0)}),this._moveDistance&&(this._moveDistance=this._axisManager.map(s,function(t,e){var n=e.circular,i=e.range;return n&&(n[0]||n[1])?v(t,i,n):t})),this._isOutside&&this._axisManager.every(r,function(t,e){return!u(t,e.range)})&&(this._isOutside=!1),r=this._atOutside(r),s=this._atOutside(s),a={input:t,event:e},i?(o=this._animationManager.getDuration(s,r),this._animationManager.stopAnimation(t.axes,a),this._animationManager.animateTo(s,o,a)):this._eventManager.triggerChange(s,!1,r,a,!0)||(this._isStopped=!0,this._moveDistance=null,this._animationManager.finish(!1)))},e.release=function(t,e,n,i){var r,s,a,o,u,h,c,l,v;!this._isStopped&&this._interruptManager.isInterrupting()&&this._moveDistance&&(r=this._axisManager.get(t.axes),s=this._axisManager.get(),a=this._animationManager.getDisplacement(n),o=A(t.axes,a),h={depaPos:s,destPos:u=this._axisManager.get(this._axisManager.map(o,function(t,e,n){return e.circular&&(e.circular[0]||e.circular[1])?r[n]+t:_(r[n]+t,e.range,e.circular,e.bounce)})),duration:this._animationManager.getDuration(u,r,i),delta:this._axisManager.getDelta(s,u),inputEvent:e,input:t,isTrusted:!0},this._eventManager.triggerRelease(h),this._moveDistance=null,c=this._animationManager.getUserControl(h),v={input:t,event:e},(l=P(c.destPos,s))||0===c.duration?(l||this._eventManager.triggerChange(c.destPos,!1,s,v,!0),this._interruptManager.setInterrupt(!1),this._axisManager.isOutside()?this._animationManager.restore(v):this._eventManager.triggerFinish(!0)):this._animationManager.animateTo(c.destPos,c.duration,v))},e._atOutside=function(t){var a=this;return this._isOutside?this._axisManager.map(t,function(t,e){var n=e.range[0]-e.bounce[0],i=e.range[1]+e.bounce[1];return i<t?i:t<n?n:t}):this._axisManager.map(t,function(t,e){var n=e.range[0],i=e.range[1],r=e.bounce,s=e.circular;return s&&(s[0]||s[1])?t:t<n?n-a._animationManager.interpolate(n-t,r[0]):i<t?i+a._animationManager.interpolate(t-i,r[1]):t})},t}(),z=function(r){function t(t,e,n){void 0===t&&(t={}),void 0===e&&(e={}),void 0===n&&(n=null);var i=r.call(this)||this;return i.axis=t,i._inputs=[],i.options=d({easing:function(t){return 1-Math.pow(1-t,3)},interruptable:!0,maximumDuration:1/0,minimumDuration:0,deceleration:6e-4,round:null},e),i.interruptManager=new Y(i.options),i.axisManager=new X(i.axis),i.eventManager=new k(i),i.animationManager=new L(i),i.inputObserver=new V(i),i.eventManager.setAnimationManager(i.animationManager),n&&i.eventManager.triggerChange(n),i}s(t,r);var e=t.prototype;return e.connect=function(t,e){var n="string"==typeof t?t.split(" "):t.concat();return~this._inputs.indexOf(e)&&this.disconnect(e),e.mapAxes(n),e.connect(this.inputObserver),this._inputs.push(e),this},e.disconnect=function(t){var e;return t?0<=(e=this._inputs.indexOf(t))&&(this._inputs[e].disconnect(),this._inputs.splice(e,1)):(this._inputs.forEach(function(t){return t.disconnect()}),this._inputs=[]),this},e.get=function(t){return this.axisManager.get(t)},e.setTo=function(t,e){return void 0===e&&(e=0),this.animationManager.setTo(t,e),this},e.setBy=function(t,e){return void 0===e&&(e=0),this.animationManager.setBy(t,e),this},e.stopAnimation=function(){return this.animationManager.stopAnimation(Object.keys(this.axisManager.get())),this},e.updateAnimation=function(t){return this.animationManager.updateAnimation(t),this},e.isBounceArea=function(t){return this.axisManager.isOutside(t)},e.destroy=function(){this.disconnect(),this.eventManager.destroy()},t.VERSION="3.0.0",t.TRANSFORM=n,t.DIRECTION_NONE=1,t.DIRECTION_LEFT=2,t.DIRECTION_RIGHT=4,t.DIRECTION_UP=8,t.DIRECTION_DOWN=16,t.DIRECTION_HORIZONTAL=6,t.DIRECTION_VERTICAL=24,t.DIRECTION_ALL=30,t}(p),H=function(){function t(t,e){this.axes=[],this.element=null,this._panFlag=!1,this._enabled=!1,this._activeInput=null,this._atRightEdge=!1,this._rightEdgeTimer=0,this.element=f(t),this.options=d({inputType:["touch","mouse","pointer"],scale:[1,1],thresholdAngle:45,threshold:0,iOSEdgeSwipeThreshold:30,releaseOnScroll:!1},e),this._onPanstart=this._onPanstart.bind(this),this._onPanmove=this._onPanmove.bind(this),this._onPanend=this._onPanend.bind(this)}var e=t.prototype;return e.mapAxes=function(t){var e=!!t[0],n=!!t[1];this._direction=e&&n?30:e?6:n?24:1,this.axes=t},e.connect=function(t){return this._activeInput&&this._detachEvent(),this._attachEvent(t),this._originalCssProps=w(this.element),this},e.disconnect=function(){return this._detachEvent(),this._originalCssProps!==g&&w(this.element,this._originalCssProps),this._direction=1,this},e.destroy=function(){this.disconnect(),this.element=null},e.enable=function(){return this._enabled=!0,this},e.disable=function(){return this._enabled=!1,this},e.isEnabled=function(){return this._enabled},e._onPanstart=function(t){var e,n;this._activeInput.onEventStart(t),!this._enabled||1<this._activeInput.getTouches(t)||(e=this._activeInput.extendEvent(t),(this._panFlag=!1)!==e.srcEvent.cancelable&&(n=this.options.iOSEdgeSwipeThreshold,this._observer.hold(this,e),this._atRightEdge=l&&e.center.x>window.innerWidth-n,this._panFlag=!0,this._activeInput.prevEvent=e))},e._onPanmove=function(t){var e=this;if(this._activeInput.onEventMove(t),this._panFlag&&this._enabled&&!(1<this._activeInput.getTouches(t))){var n=this._activeInput.extendEvent(t),i=this.options,r=i.iOSEdgeSwipeThreshold,s=i.releaseOnScroll,a=function(t,e){if(e<0||90<e)return 1;var n=Math.abs(t);return e<n&&n<180-e?24:6}(n.angle,this.options.thresholdAngle);if(!s||n.srcEvent.cancelable){if(this._activeInput.prevEvent&&l){if(n.center.x<0)return void this._observer.release(this,this._activeInput.prevEvent,[0,0]);this._atRightEdge&&(clearTimeout(this._rightEdgeTimer),n.deltaX<-r?this._atRightEdge=!1:this._rightEdgeTimer=window.setTimeout(function(){e._observer.release(e,e._activeInput.prevEvent,[0,0])},100))}var o=this._getOffset([n.offsetX,n.offsetY],[S(6,this._direction,a),S(24,this._direction,a)]),u=o.some(function(t){return 0!==t});u&&(!1!==n.srcEvent.cancelable&&n.srcEvent.preventDefault(),n.srcEvent.stopPropagation()),(n.preventSystemEvent=u)&&this._observer.change(this,n,A(this.axes,o)),this._activeInput.prevEvent=n}else this._onPanend(t)}},e._onPanend=function(t){var e,n;this._activeInput.onEventEnd(t),this._panFlag&&this._enabled&&0===this._activeInput.getTouches(t)&&(this._panFlag=!1,clearTimeout(this._rightEdgeTimer),e=this._activeInput.prevEvent,n=this._getOffset([Math.abs(e.velocityX)*(e.offsetX<0?-1:1),Math.abs(e.velocityY)*(e.offsetY<0?-1:1)],[S(6,this._direction),S(24,this._direction)]),this._observer.release(this,e,n))},e._attachEvent=function(t){var e=this,n=C(this.options.inputType);this._observer=t,this._enabled=!0,null!=(this._activeInput=n)&&n.start.forEach(function(t){e.element.addEventListener(t,e._onPanstart,!1)}),null!=n&&n.move.forEach(function(t){window.addEventListener(t,e._onPanmove,!1)}),null!=n&&n.end.forEach(function(t){window.addEventListener(t,e._onPanend,!1)})},e._detachEvent=function(){var e=this,t=this._activeInput;null!=t&&t.start.forEach(function(t){e.element.removeEventListener(t,e._onPanstart,!1)}),null!=t&&t.move.forEach(function(t){window.removeEventListener(t,e._onPanmove,!1)}),null!=t&&t.end.forEach(function(t){window.removeEventListener(t,e._onPanend,!1)}),this._enabled=!1,this._observer=null},e._getOffset=function(t,e){var n=[0,0],i=this.options.scale;return e[0]&&(n[0]=t[0]*i[0]),e[1]&&(n[1]=t[1]*i[1]),n},t}(),G=function(i){function t(t,e){var n=i.call(this,t,e)||this;return n._prevQuadrant=null,n._lastDiff=0,n}s(t,i);var e=t.prototype;return e.mapAxes=function(t){this._direction=z.DIRECTION_ALL,this.axes=t},e._onPanstart=function(t){var e,n;this._activeInput.onEventStart(t),this.isEnabled&&(e=this.element.getBoundingClientRect(),n=this._activeInput.extendEvent(t),this._observer.hold(this,n),this._panFlag=!0,this._coefficientForDistanceToAngle=360/(e.width*Math.PI),this._rotateOrigin=[e.left+(e.width-1)/2,e.top+(e.height-1)/2],this._prevAngle=null,this._triggerChange(n),this._activeInput.prevEvent=n)},e._onPanmove=function(t){var e;this._activeInput.onEventMove(t),this._panFlag&&this.isEnabled&&(!1!==(e=this._activeInput.extendEvent(t)).srcEvent.cancelable&&e.srcEvent.preventDefault(),e.srcEvent.stopPropagation(),this._triggerChange(e),this._activeInput.prevEvent=e)},e._onPanend=function(t){var e,n,i,r;this._activeInput.onEventEnd(t),this._panFlag&&this.isEnabled&&(e=this._activeInput.prevEvent,this._triggerChange(e),n=e.velocityX,i=e.velocityY,r=Math.sqrt(n*n+i*i)*(0<this._lastDiff?-1:1),this._observer.release(this,e,[r*this._coefficientForDistanceToAngle]),this._panFlag=!1)},e._triggerChange=function(t){var e=this._getPosFromOrigin(t.center.x,t.center.y),n=e.x,i=e.y,r=O(n,i),s=r<0?360+r:r,a=this._getQuadrant(t.center.x,t.center.y),o=this._getDifference(this._prevAngle,s,this._prevQuadrant,a);this._prevAngle=s,this._prevQuadrant=a,0!==o&&(this._lastDiff=o,this._observer.change(this,t,A(this.axes,[-o])))},e._getDifference=function(t,e,n,i){var r=null===t?0:1===n&&4===i?-t-(360-e):4===n&&1===i?360-t+e:e-t;return r},e._getPosFromOrigin=function(t,e){return{x:t-this._rotateOrigin[0],y:this._rotateOrigin[1]-e}},e._getQuadrant=function(t,e){var n=this._getPosFromOrigin(t,e),i=n.x,r=n.y,s=0;return 0<=i&&0<=r?s=1:i<0&&0<=r?s=2:i<0&&r<0?s=3:0<=i&&r<0&&(s=4),s},t}(H),Z=function(){function t(t,e){this.axes=[],this.element=null,this._pinchFlag=!1,this._enabled=!1,this._activeInput=null,this.element=f(t),this.options=d({scale:1,threshold:0,inputType:["touch","pointer"]},e),this._onPinchStart=this._onPinchStart.bind(this),this._onPinchMove=this._onPinchMove.bind(this),this._onPinchEnd=this._onPinchEnd.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this._activeInput&&this._detachEvent(),this._attachEvent(t),this._originalCssProps=w(this.element),this},e.disconnect=function(){return this._detachEvent(),this._originalCssProps!==g&&w(this.element,this._originalCssProps),this},e.destroy=function(){this.disconnect(),this.element=null},e.enable=function(){return this._enabled=!0,this},e.disable=function(){return this._enabled=!1,this},e.isEnabled=function(){return this._enabled},e._onPinchStart=function(t){var e;this._activeInput.onEventStart(t),this._enabled&&2===this._activeInput.getTouches(t)&&(this._baseValue=this._observer.get(this)[this.axes[0]],this._observer.hold(this,t),this._pinchFlag=!0,e=this._activeInput.extendEvent(t),this._activeInput.prevEvent=e)},e._onPinchMove=function(t){var e,n;this._activeInput.onEventMove(t),this._pinchFlag&&this._enabled&&2===this._activeInput.getTouches(t)&&(e=this._activeInput.extendEvent(t),n=this._getOffset(e.scale,this._activeInput.prevEvent.scale),this._observer.change(this,t,A(this.axes,[n])),this._activeInput.prevEvent=e)},e._onPinchEnd=function(t){this._activeInput.onEventEnd(t),!this._pinchFlag||!this._enabled||2<this._activeInput.getTouches(t)||(this._observer.release(this,t,[0],0),this._baseValue=null,this._pinchFlag=!1,this._activeInput.prevEvent=null)},e._attachEvent=function(t){var e=this,n=C(this.options.inputType);this._observer=t,this._enabled=!0,null!=(this._activeInput=n)&&n.start.forEach(function(t){e.element.addEventListener(t,e._onPinchStart,!1)}),null!=n&&n.move.forEach(function(t){e.element.addEventListener(t,e._onPinchMove,!1)}),null!=n&&n.end.forEach(function(t){e.element.addEventListener(t,e._onPinchEnd,!1)})},e._detachEvent=function(){var e=this,t=this._activeInput;null!=t&&t.start.forEach(function(t){e.element.removeEventListener(t,e._onPinchStart,!1)}),null!=t&&t.move.forEach(function(t){e.element.removeEventListener(t,e._onPinchMove,!1)}),null!=t&&t.end.forEach(function(t){e.element.removeEventListener(t,e._onPinchEnd,!1)}),this._enabled=!1,this._observer=null},e._getOffset=function(t,e){return void 0===e&&(e=1),this._baseValue*(t-e)*this.options.scale},t}(),J=function(){function t(t,e){this.axes=[],this.element=null,this._enabled=!1,this._holding=!1,this._timer=null,this.element=f(t),this.options=d({scale:1,releaseDelay:300,useNormalized:!0},e),this._onWheel=this._onWheel.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this._detachEvent(),this._attachEvent(t),this},e.disconnect=function(){return this._detachEvent(),this},e.destroy=function(){this.disconnect(),this.element=null},e.enable=function(){return this._enabled=!0,this},e.disable=function(){return this._enabled=!1,this},e.isEnabled=function(){return this._enabled},e._onWheel=function(t){var e,n=this;this._enabled&&(t.preventDefault(),0!==t.deltaY&&(this._holding||(this._observer.hold(this,t),this._holding=!0),e=(0<t.deltaY?-1:1)*this.options.scale*(this.options.useNormalized?1:Math.abs(t.deltaY)),this._observer.change(this,t,A(this.axes,[e]),!0),clearTimeout(this._timer),this._timer=setTimeout(function(){n._holding&&(n._holding=!1,n._observer.release(n,t,[0]))},this.options.releaseDelay)))},e._attachEvent=function(t){this._observer=t,this.element.addEventListener("wheel",this._onWheel),this._enabled=!0},e._detachEvent=function(){this.element.removeEventListener("wheel",this._onWheel),this._enabled=!1,this._observer=null,this._timer&&(clearTimeout(this._timer),this._timer=null)},t}(),$=function(){function t(t,e){this.axes=[],this.element=null,this._enabled=!1,this._holding=!1,this._timer=null,this.element=f(t),this.options=d({scale:[1,1]},e),this._onKeydown=this._onKeydown.bind(this),this._onKeyup=this._onKeyup.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this._detachEvent(),"0"!==this.element.getAttribute("tabindex")&&this.element.setAttribute("tabindex","0"),this._attachEvent(t),this},e.disconnect=function(){return this._detachEvent(),this},e.destroy=function(){this.disconnect(),this.element=null},e.enable=function(){return this._enabled=!0,this},e.disable=function(){return this._enabled=!1,this},e.isEnabled=function(){return this._enabled},e._onKeydown=function(t){if(this._enabled){var e,n=!0,i=1,r=-1;switch(t.keyCode){case 37:case 65:i=-1;break;case 39:case 68:break;case 40:case 83:i=-1,r=1;break;case 38:case 87:r=1;break;default:n=!1}(-1===r&&!this.axes[0]||1===r&&!this.axes[1])&&(n=!1),n&&(t.preventDefault(),e=-1===r?[this.options.scale[0]*i,0]:[0,this.options.scale[1]*i],this._holding||(this._observer.hold(this,t),this._holding=!0),clearTimeout(this._timer),this._observer.change(this,t,A(this.axes,e)))}},e._onKeyup=function(t){var e=this;this._holding&&(clearTimeout(this._timer),this._timer=setTimeout(function(){e._observer.release(e,t,[0,0]),e._holding=!1},80))},e._attachEvent=function(t){this._observer=t,this.element.addEventListener("keydown",this._onKeydown,!1),this.element.addEventListener("keypress",this._onKeydown,!1),this.element.addEventListener("keyup",this._onKeyup,!1),this._enabled=!0},e._detachEvent=function(){this.element.removeEventListener("keydown",this._onKeydown,!1),this.element.removeEventListener("keypress",this._onKeydown,!1),this.element.removeEventListener("keyup",this._onKeyup,!1),this._enabled=!1,this._observer=null},t}();return z.PanInput=H,z.RotatePanInput=G,z.PinchInput=Z,z.WheelInput=J,z.MoveKeyInput=$,z}); | ||
//# sourceMappingURL=axes.min.js.map |
@@ -7,5 +7,5 @@ /* | ||
repository: https://github.com/naver/egjs-axes | ||
version: 2.8.0 | ||
version: 3.0.0 | ||
*/ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t.eg=t.eg||{},t.eg.Axes=e())}(this,function(){"use strict";var i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)};function n(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}var v=function(){return(v=Object.assign||function(t){for(var e,n=1,i=arguments.length;n<i;n++)for(var r in e=arguments[n])Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t}).apply(this,arguments)};function c(t){return void 0===t}var r,t=function(){function t(){this.options={},this._eventHandler={}}var e=t.prototype;return e.trigger=function(t){for(var e=this,n=[],i=1;i<arguments.length;i++)n[i-1]=arguments[i];if(!(0<(o=this._eventHandler[t]||[]).length))return!0;var r=n[0]||{},s=n.slice(1),o=o.concat(),a=!1;r.eventType=t,r.stop=function(){a=!0},r.currentTarget=this;var h=[r];return 1<=s.length&&(h=h.concat(s)),o.forEach(function(t){t.apply(e,h)}),!a},e.once=function(n,i){var r,s=this;if("object"==typeof n&&c(i)){var t=n;for(var e in t)this.once(e,t[e]);return this}return"string"==typeof n&&"function"==typeof i&&(r=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];i.apply(s,t),s.off(n,r)},this.on(n,r)),this},e.hasOn=function(t){return!!this._eventHandler[t]},e.on=function(t,e){if("object"==typeof t&&c(e)){var n=t;for(var i in n)this.on(i,n[i]);return this}var r;return"string"==typeof t&&"function"==typeof e&&(c(r=this._eventHandler[t])&&(this._eventHandler[t]=[],r=this._eventHandler[t]),r.push(e)),this},e.off=function(t,e){var n,i;if(c(t))return this._eventHandler={},this;if(c(e)){if("string"==typeof t)return delete this._eventHandler[t],this;var r=t;for(var s in r)this.off(s,r[s]);return this}var o=this._eventHandler[t];if(o){var a=0;try{for(var h=function(t){var e="function"==typeof Symbol&&Symbol.iterator,n=e&&t[e],i=0;if(n)return n.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&i>=t.length&&(t=void 0),{value:t&&t[i++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}(o),u=h.next();!u.done;u=h.next()){if(u.value===e){o.splice(a,1);break}a++}}catch(t){n={error:t}}finally{try{u&&!u.done&&(i=h.return)&&i.call(h)}finally{if(n)throw n.error}}}return this},t.VERSION="2.2.2",t}();function f(t,e,n,i){var r=t,s=[!n[0]&&i?e[0]-i[0]:e[0],!n[1]&&i?e[1]+i[1]:e[1]],r=Math.max(s[0],r);return Math.min(s[1],r)}function s(t,e){return t<e[0]||t>e[1]}function u(t,e,n){return n[1]&&t>e[1]||n[0]&&t<e[0]}function g(t,e,n){var i=t,r=e[0],s=e[1],o=s-r;return n[1]&&s<t&&(i=(i-s)%o+r),n[0]&&t<r&&(i=(i-r)%o+s),i}function o(t){for(var e=[],n=0,i=t.length;n<i;n++)e.push(t[n]);return e}function a(t,e){var n,i;return void 0===e&&(e=!1),"string"==typeof t?(i=t.match(/^<([a-z]+)\s*([^>]*)>/)?((n=document.createElement("div")).innerHTML=t,o(n.childNodes)):o(document.querySelectorAll(t)),e||(i=1<=i.length?i[0]:void 0)):t!==r&&(!t.nodeName||1!==t.nodeType&&9!==t.nodeType)?"jQuery"in r&&t instanceof jQuery||t.constructor.prototype.jquery?i=e?t.toArray():t.get(0):Array.isArray(t)&&(i=t.map(function(t){return a(t)}),e||(i=1<=i.length?i[0]:void 0)):i=t,i}var h,l,y=(r="undefined"==typeof window?{navigator:{userAgent:""}}:window).requestAnimationFrame||r.webkitRequestAnimationFrame,p=r.cancelAnimationFrame||r.webkitCancelAnimationFrame;function b(t,e){var n={};for(var i in t)i&&(n[i]=e(t[i],i));return n}function d(t,e){var n={};for(var i in t)i&&e(t[i],i)&&(n[i]=t[i]);return n}function m(t,e){for(var n in t)if(n&&!e(t[n],n))return!1;return!0}function x(t,n){return m(t,function(t,e){return t===n[e]})}y&&!p?(h={},l=y,y=function(e){var n=l(function(t){h[n]&&e(t)});return h[n]=!0,n},p=function(t){delete h[t]}):y&&p||(y=function(t){return r.setTimeout(function(){t(r.performance&&r.performance.now&&r.performance.now()||(new Date).getTime())},16)},p=r.clearTimeout);var w={};function E(t,e){var n,i;return w[e]||(w[e]=(i=(n=e)<1?Math.pow(10,P(n)):1,function(t){return 0===n?0:Math.round(Math.round(t/n)*n*i)/i})),w[e](t)}function T(t,n){if(!t||!n)return t;var i="number"==typeof n;return b(t,function(t,e){return E(t,i?n:n[e])})}function P(t){if(!isFinite(t))return 0;var e=t+"";if(0<=e.indexOf("e")){for(var n=0,i=1;Math.round(t*i)/i!==t;)i*=10,n++;return n}return 0<=e.indexOf(".")?e.length-e.indexOf(".")-1:0}function _(t,e,n){return Math.max(Math.min(t,n),e)}var O=function(){function t(t){var e=t.options,n=t.itm,i=t.em,r=t.axm;this.options=e,this.itm=n,this.em=i,this.axm=r,this.animationEnd=this.animationEnd.bind(this)}var e=t.prototype;return e.getDuration=function(s,t,e){var n,o=this;return _(void 0!==e?e:(n=b(t,function(t,e){return n=Math.abs(t-s[e]),i=o.options.deceleration,(r=Math.sqrt(n/i*2))<100?0:r;var n,i,r}),Object.keys(n).reduce(function(t,e){return Math.max(t,n[e])},-1/0)),this.options.minimumDuration,this.options.maximumDuration)},e.createAnimationParam=function(t,e,n){var i=this.axm.get(),r=t,s=n&&n.event||null;return{depaPos:i,destPos:r,duration:_(e,this.options.minimumDuration,this.options.maximumDuration),delta:this.axm.getDelta(i,r),inputEvent:s,input:n&&n.input||null,isTrusted:!!s,done:this.animationEnd}},e.grab=function(t,e){var n,i,r;this._animateParam&&t.length&&(n=this.axm.get(t),m(i=this.axm.map(n,function(t,e){return g(t,e.range,e.circular)}),function(t,e){return n[e]===t})||this.em.triggerChange(i,!1,n,e,!!e),this._animateParam=null,this._raf&&(r=this._raf,p(r)),this._raf=null,this.em.triggerAnimationEnd(!(!e||!e.event)))},e.getEventInfo=function(){return this._animateParam&&this._animateParam.input&&this._animateParam.inputEvent?{input:this._animateParam.input,event:this._animateParam.inputEvent}:null},e.restore=function(t){var e=this.axm.get(),n=this.axm.map(e,function(t,e){return Math.min(e.range[1],Math.max(e.range[0],t))});this.animateTo(n,this.getDuration(e,n),t)},e.animationEnd=function(){var t=this.getEventInfo();this._animateParam=null;var e=this.axm.filter(this.axm.get(),function(t,e){return u(t,e.range,e.circular)});0<Object.keys(e).length&&this.setTo(this.axm.map(e,function(t,e){return g(t,e.range,e.circular)})),this.itm.setInterrupt(!1),this.em.triggerAnimationEnd(!!t),this.axm.isOutside()?this.restore(t):this.finish(!!t)},e.finish=function(t){this._animateParam=null,this.itm.setInterrupt(!1),this.em.triggerFinish(t)},e.animateLoop=function(r,s){var h,u,c,l,f,p,d,m;r.duration?(this._animateParam=v({},r),h=this._animateParam,u=this,c=h.destPos,l=h.depaPos,f=0,p=b(l,function(t,e){return t<=c[e]?1:-1}),d=b(c,function(t){return t}),m=(new Date).getTime(),h.startTime=m,function t(){u._raf=null;var e=(new Date).getTime(),o=(e-h.startTime)/r.duration,a=u.easing(o),n=u.axm.map(l,function(t,e,n){var i,r=1<=o?c[n]:t+h.delta[n]*(a-f),s=g(r,e.range,e.circular);return r!==s&&(i=p[n]*(e.range[1]-e.range[0]),c[n]-=i,l[n]-=i),s}),i=!u.em.triggerChange(n,!1,l);if(l=n,m=e,1<=(f=a))return x(c=u.getFinalPos(c,d),u.axm.get(Object.keys(c)))||u.em.triggerChange(c,!0,l),void s();i?u.finish(!1):u._raf=y(t)}()):(this.em.triggerChange(r.destPos,!0),s())},e.getFinalPos=function(t,n){var i=this;return b(t,function(t,e){return t>=n[e]-1e-6&&t<=n[e]+1e-6?n[e]:E(t,i.getRoundUnit(t,e))})},e.getRoundUnit=function(t,e){var n,i,r=this.options.round,s=null;return r||(n=this.axm.getAxisOptions(e),i=Math.max(P(n.range[0]),P(n.range[1]),P(t)),s=1/Math.pow(10,i)),s||r},e.getUserControll=function(t){var e=t.setTo();return e.destPos=this.axm.get(e.destPos),e.duration=_(e.duration,this.options.minimumDuration,this.options.maximumDuration),e},e.animateTo=function(t,e,n){var i,r=this,s=this.createAnimationParam(t,e,n),o=v({},s.depaPos),a=this.em.triggerAnimationStart(s),h=this.getUserControll(s);!a&&this.axm.every(h.destPos,function(t,e){return u(t,e.range,e.circular)})&&console.warn("You can't stop the 'animation' event when 'circular' is true."),a&&!x(h.destPos,o)&&(i=n&&n.event||null,this.animateLoop({depaPos:o,destPos:h.destPos,duration:h.duration,delta:this.axm.getDelta(o,h.destPos),isTrusted:!!i,inputEvent:i,input:n&&n.input||null},function(){return r.animationEnd()}))},e.easing=function(t){return 1<t?1:this.options.easing(t)},e.setTo=function(t,e){void 0===e&&(e=0);var n=Object.keys(t);this.grab(n);var i=this.axm.get(n);if(x(t,i))return this;this.itm.setInterrupt(!0);var r=d(t,function(t,e){return i[e]!==t});return Object.keys(r).length&&(x(r=this.axm.map(r,function(t,e){var n=e.range,i=e.circular;return i&&(i[0]||i[1])?t:f(t,n,i)}),i)||(0<e?this.animateTo(r,e):(this.em.triggerChange(r),this.finish(!1)))),this},e.setBy=function(n,t){return void 0===t&&(t=0),this.setTo(b(this.axm.get(Object.keys(n)),function(t,e){return t+n[e]}),t)},t}(),A=function(){function t(t){this.axes=t}var e=t.prototype;return e.triggerHold=function(t,e){var n=this.getRoundPos(t).roundPos;this.axes.trigger("hold",{pos:n,input:e.input||null,inputEvent:e.event||null,isTrusted:!0})},e.triggerRelease=function(t){var e=this.getRoundPos(t.destPos,t.depaPos),n=e.roundPos,i=e.roundDepa;t.destPos=n,t.depaPos=i,t.setTo=this.createUserControll(t.destPos,t.duration),this.axes.trigger("release",t)},e.triggerChange=function(t,e,n,i,r){void 0===r&&(r=!1);var s=this.am,o=s.axm,a=s.getEventInfo(),h=this.getRoundPos(t,n),u=h.roundPos,c=h.roundDepa,l=o.moveTo(u,c),f=i&&i.event||a&&a.event||null,p={pos:l.pos,delta:l.delta,holding:r,inputEvent:f,isTrusted:!!f,input:i&&i.input||a&&a.input||null,set:f?this.createUserControll(l.pos):function(){}},d=this.axes.trigger("change",p);return f&&o.set(p.set().destPos),d},e.triggerAnimationStart=function(t){var e=this.getRoundPos(t.destPos,t.depaPos),n=e.roundPos,i=e.roundDepa;return t.destPos=n,t.depaPos=i,t.setTo=this.createUserControll(t.destPos,t.duration),this.axes.trigger("animationStart",t)},e.triggerAnimationEnd=function(t){void 0===t&&(t=!1),this.axes.trigger("animationEnd",{isTrusted:t})},e.triggerFinish=function(t){void 0===t&&(t=!1),this.axes.trigger("finish",{isTrusted:t})},e.createUserControll=function(t,e){void 0===e&&(e=0);var n={destPos:v({},t),duration:e};return function(t,e){return t&&(n.destPos=v({},t)),void 0!==e&&(n.duration=e),n}},e.setAnimationManager=function(t){this.am=t},e.destroy=function(){this.axes.off()},e.getRoundPos=function(t,e){var n=this.axes.options.round;return{roundPos:T(t,n),roundDepa:T(e,n)}},t}(),D=function(){function t(t){this.options=t,this._prevented=!1}var e=t.prototype;return e.isInterrupting=function(){return this.options.interruptable||this._prevented},e.isInterrupted=function(){return!this.options.interruptable&&this._prevented},e.setInterrupt=function(t){this.options.interruptable||(this._prevented=t)},t}(),I=function(){function t(t,e){var n=this;this.axis=t,this.options=e,this._complementOptions(),this._pos=Object.keys(this.axis).reduce(function(t,e){return t[e]=n.axis[e].range[0],t},{})}var e=t.prototype;return e._complementOptions=function(){var r=this;Object.keys(this.axis).forEach(function(i){r.axis[i]=v({range:[0,100],bounce:[0,0],circular:[!1,!1]},r.axis[i]),["bounce","circular"].forEach(function(t){var e=r.axis,n=e[i][t];/string|number|boolean/.test(typeof n)&&(e[i][t]=[n,n])})})},e.getDelta=function(t,e){var n=this.get(t);return b(this.get(e),function(t,e){return t-n[e]})},e.get=function(t){var n=this;return t&&Array.isArray(t)?t.reduce(function(t,e){return e&&e in n._pos&&(t[e]=n._pos[e]),t},{}):v(v({},this._pos),t||{})},e.moveTo=function(n,i){void 0===i&&(i=this._pos);var t=b(this._pos,function(t,e){return e in n&&e in i?n[e]-i[e]:0});return this.set(this.map(n,function(t,e){return e?g(t,e.range,e.circular):0})),{pos:v({},this._pos),delta:t}},e.set=function(t){for(var e in t)e&&e in this._pos&&(this._pos[e]=t[e])},e.every=function(t,n){var i=this.axis;return m(t,function(t,e){return n(t,i[e],e)})},e.filter=function(t,n){var i=this.axis;return d(t,function(t,e){return n(t,i[e],e)})},e.map=function(t,n){var i=this.axis;return b(t,function(t,e){return n(t,i[e],e)})},e.isOutside=function(t){return!this.every(t?this.get(t):this._pos,function(t,e){return!s(t,e.range)})},e.getAxisOptions=function(t){return this.axis[t]},t}(),M=function(){function t(t){var e=t.options,n=t.itm,i=t.em,r=t.axm,s=t.am;this.isOutside=!1,this.moveDistance=null,this.isStopped=!1,this.options=e,this.itm=n,this.em=i,this.axm=r,this.am=s}var e=t.prototype;return e.atOutside=function(t){var o=this;if(this.isOutside)return this.axm.map(t,function(t,e){var n=e.range[0]-e.bounce[0],i=e.range[1]+e.bounce[1];return i<t?i:t<n?n:t});var a=this.am.easing(1e-5)/1e-5;return this.axm.map(t,function(t,e){var n=e.range[0],i=e.range[1],r=e.bounce,s=e.circular;return s&&(s[0]||s[1])?t:t<n?n-o.am.easing((n-t)/(r[0]*a))*r[0]:i<t?i+o.am.easing((t-i)/(r[1]*a))*r[1]:t})},e.get=function(t){return this.axm.get(t.axes)},e.hold=function(t,e){var n;!this.itm.isInterrupted()&&t.axes.length&&(n={input:t,event:e},this.isStopped=!1,this.itm.setInterrupt(!0),this.am.grab(t.axes,n),this.moveDistance||this.em.triggerHold(this.axm.get(),n),this.isOutside=this.axm.isOutside(t.axes),this.moveDistance=this.axm.get(t.axes))},e.change=function(t,e,n){var i,r;this.isStopped||!this.itm.isInterrupting()||this.axm.every(n,function(t){return 0===t})||(r=b(i=this.moveDistance||this.axm.get(t.axes),function(t,e){return t+(n[e]||0)}),this.moveDistance&&(this.moveDistance=r),this.isOutside&&this.axm.every(i,function(t,e){return!s(t,e.range)})&&(this.isOutside=!1),i=this.atOutside(i),r=this.atOutside(r),this.em.triggerChange(r,!1,i,{input:t,event:e},!0)||(this.isStopped=!0,this.moveDistance=null,this.am.finish(!1)))},e.release=function(t,e,n,i){var r,s,o,a,h,u,c,l;!this.isStopped&&this.itm.isInterrupting()&&this.moveDistance&&(r=this.axm.get(t.axes),s=this.axm.get(),o=this.axm.get(this.axm.map(n,function(t,e,n){return e.circular&&(e.circular[0]||e.circular[1])?r[n]+t:f(r[n]+t,e.range,e.circular,e.bounce)})),0===(a=this.am.getDuration(o,r,i))&&(o=v({},s)),h={depaPos:s,destPos:o,duration:a,delta:this.axm.getDelta(s,o),inputEvent:e,input:t,isTrusted:!0},this.em.triggerRelease(h),this.moveDistance=null,l={input:t,event:e},(c=x((u=this.am.getUserControll(h)).destPos,s))||0===u.duration?(c||this.em.triggerChange(u.destPos,!1,s,l,!0),this.itm.setInterrupt(!1),this.axm.isOutside()?this.am.restore(l):this.em.triggerFinish(!0)):this.am.animateTo(u.destPos,u.duration,l))},t}();function R(){return(R=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var i in n)Object.prototype.hasOwnProperty.call(n,i)&&(t[i]=n[i])}return t}).apply(this,arguments)}function S(t,e){t.prototype=Object.create(e.prototype),(t.prototype.constructor=t).__proto__=e}function C(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}var z,k="function"!=typeof Object.assign?function(t){if(null==t)throw new TypeError("Cannot convert undefined or null to object");for(var e=Object(t),n=1;n<arguments.length;n++){var i=arguments[n];if(null!=i)for(var r in i)i.hasOwnProperty(r)&&(e[r]=i[r])}return e}:Object.assign,F=["","webkit","Moz","MS","ms","o"],e="undefined"==typeof document?{style:{}}:document.createElement("div"),j="function",H=Math.round,Y=Math.abs,X=Date.now;function L(t,e){for(var n,i,r=e[0].toUpperCase()+e.slice(1),s=0;s<F.length;){if((i=(n=F[s])?n+r:e)in t)return i;s++}}z="undefined"==typeof window?{}:window;var W=L(e.style,"touchAction"),N=void 0!==W;var q="compute",V="manipulation",U="none",K="pan-x",Q="pan-y",B=function(){if(!N)return!1;var e={},n=z.CSS&&z.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach(function(t){return e[t]=!n||z.CSS.supports("touch-action",t)}),e}(),G="ontouchstart"in z,Z=void 0!==L(z,"PointerEvent"),J=G&&/mobile|tablet|ip(ad|hone|od)|android/i.test(navigator.userAgent),$="touch",tt="mouse",et=25,nt=1,it=4,rt=8,st=1,ot=2,at=4,ht=8,ut=16,ct=ot|at,lt=ht|ut,ft=ct|lt,pt=["x","y"],dt=["clientX","clientY"];function mt(t,e,n){var i;if(t)if(t.forEach)t.forEach(e,n);else if(void 0!==t.length)for(i=0;i<t.length;)e.call(n,t[i],i,t),i++;else for(i in t)t.hasOwnProperty(i)&&e.call(n,t[i],i,t)}function vt(t,e){return typeof t===j?t.apply(e&&e[0]||void 0,e):t}function gt(t,e){return-1<t.indexOf(e)}var yt=function(){function t(t,e){this.manager=t,this.set(e)}var e=t.prototype;return e.set=function(t){t===q&&(t=this.compute()),N&&this.manager.element.style&&B[t]&&(this.manager.element.style[W]=t),this.actions=t.toLowerCase().trim()},e.update=function(){this.set(this.manager.options.touchAction)},e.compute=function(){var e=[];return mt(this.manager.recognizers,function(t){vt(t.options.enable,[t])&&(e=e.concat(t.getTouchAction()))}),function(t){if(gt(t,U))return U;var e=gt(t,K),n=gt(t,Q);return e&&n?U:e||n?e?K:Q:gt(t,V)?V:"auto"}(e.join(" "))},e.preventDefaults=function(t){var e=t.srcEvent,n=t.offsetDirection;if(this.manager.session.prevented)e.preventDefault();else{var i=this.actions,r=gt(i,U)&&!B[U],s=gt(i,Q)&&!B[Q],o=gt(i,K)&&!B[K];if(r){var a=1===t.pointers.length,h=t.distance<2,u=t.deltaTime<250;if(a&&h&&u)return}if(!o||!s)return r||s&&n&ct||o&&n<?this.preventSrc(e):void 0}},e.preventSrc=function(t){this.manager.session.prevented=!0,t.preventDefault()},t}();function bt(t,e){for(;t;){if(t===e)return!0;t=t.parentNode}return!1}function xt(t){var e=t.length;if(1===e)return{x:H(t[0].clientX),y:H(t[0].clientY)};for(var n=0,i=0,r=0;r<e;)n+=t[r].clientX,i+=t[r].clientY,r++;return{x:H(n/e),y:H(i/e)}}function wt(t){for(var e=[],n=0;n<t.pointers.length;)e[n]={clientX:H(t.pointers[n].clientX),clientY:H(t.pointers[n].clientY)},n++;return{timeStamp:X(),pointers:e,center:xt(e),deltaX:t.deltaX,deltaY:t.deltaY}}function Et(t,e,n){var i=e[(n=n||pt)[0]]-t[n[0]],r=e[n[1]]-t[n[1]];return Math.sqrt(i*i+r*r)}function Tt(t,e,n){var i=e[(n=n||pt)[0]]-t[n[0]],r=e[n[1]]-t[n[1]];return 180*Math.atan2(r,i)/Math.PI}function Pt(t,e){return t===e?st:Y(t)>=Y(e)?t<0?ot:at:e<0?ht:ut}function _t(t,e,n){return{x:e/t||0,y:n/t||0}}function Ot(t,e){var n=t.session,i=e.pointers,r=i.length;n.firstInput||(n.firstInput=wt(e)),1<r&&!n.firstMultiple?n.firstMultiple=wt(e):1===r&&(n.firstMultiple=!1);var s,o,a,h,u,c,l=n.firstInput,f=n.firstMultiple,p=f?f.center:l.center,d=e.center=xt(i);e.timeStamp=X(),e.deltaTime=e.timeStamp-l.timeStamp,e.angle=Tt(p,d),e.distance=Et(p,d),s=n,a=(o=e).center,h=s.offsetDelta||{},u=s.prevDelta||{},c=s.prevInput||{},o.eventType!==nt&&c.eventType!==it||(u=s.prevDelta={x:c.deltaX||0,y:c.deltaY||0},h=s.offsetDelta={x:a.x,y:a.y}),o.deltaX=u.x+(a.x-h.x),o.deltaY=u.y+(a.y-h.y),e.offsetDirection=Pt(e.deltaX,e.deltaY);var m,v,g,y,b,x,w,E,T,P,_,O,A,D,I,M=_t(e.deltaTime,e.deltaX,e.deltaY);e.overallVelocityX=M.x,e.overallVelocityY=M.y,e.overallVelocity=Y(M.x)>Y(M.y)?M.x:M.y,e.scale=f?(m=f.pointers,Et((v=i)[0],v[1],dt)/Et(m[0],m[1],dt)):1,e.rotation=f?(g=f.pointers,Tt((y=i)[1],y[0],dt)+Tt(g[1],g[0],dt)):0,e.maxPointers=!n.prevInput||e.pointers.length>n.prevInput.maxPointers?e.pointers.length:n.prevInput.maxPointers,x=e,D=(b=n).lastInterval||x,I=x.timeStamp-D.timeStamp,x.eventType!==rt&&(et<I||void 0===D.velocity)?(P=(T=_t(I,w=x.deltaX-D.deltaX,E=x.deltaY-D.deltaY)).x,_=T.y,O=Y(T.x)>Y(T.y)?T.x:T.y,A=Pt(w,E),b.lastInterval=x):(O=D.velocity,P=D.velocityX,_=D.velocityY,A=D.direction),x.velocity=O,x.velocityX=P,x.velocityY=_,x.direction=A;var R=t.element,S=e.srcEvent,C=S.composedPath?S.composedPath()[0]:S.path?S.path[0]:S.target;bt(C,R)&&(R=C),e.target=R}function At(t,e,n){var i=n.pointers.length,r=n.changedPointers.length,s=e&nt&&i-r==0,o=e&(it|rt)&&i-r==0;n.isFirst=!!s,n.isFinal=!!o,s&&(t.session={}),n.eventType=e,Ot(t,n),t.emit("hammer.input",n),t.recognize(n),t.session.prevInput=n}function Dt(t){return t.trim().split(/\s+/g)}function It(e,t,n){mt(Dt(t),function(t){e.addEventListener(t,n,!1)})}function Mt(e,t,n){mt(Dt(t),function(t){e.removeEventListener(t,n,!1)})}function Rt(t){var e=t.ownerDocument||t;return e.defaultView||e.parentWindow||window}var St=function(){function t(e,t){var n=this;this.manager=e,this.callback=t,this.element=e.element,this.target=e.options.inputTarget,this.domHandler=function(t){vt(e.options.enable,[e])&&n.handler(t)},this.init()}var e=t.prototype;return e.handler=function(){},e.init=function(){this.evEl&&It(this.element,this.evEl,this.domHandler),this.evTarget&&It(this.target,this.evTarget,this.domHandler),this.evWin&&It(Rt(this.element),this.evWin,this.domHandler)},e.destroy=function(){this.evEl&&Mt(this.element,this.evEl,this.domHandler),this.evTarget&&Mt(this.target,this.evTarget,this.domHandler),this.evWin&&Mt(Rt(this.element),this.evWin,this.domHandler)},t}();function Ct(t,e,n){if(t.indexOf&&!n)return t.indexOf(e);for(var i=0;i<t.length;){if(n&&t[i][n]==e||!n&&t[i]===e)return i;i++}return-1}var zt={pointerdown:nt,pointermove:2,pointerup:it,pointercancel:rt,pointerout:rt},kt={2:$,3:"pen",4:tt,5:"kinect"},Ft="pointerdown",jt="pointermove pointerup pointercancel";z.MSPointerEvent&&!z.PointerEvent&&(Ft="MSPointerDown",jt="MSPointerMove MSPointerUp MSPointerCancel");var Ht=function(n){function i(){var t,e=i.prototype;return e.evEl=Ft,e.evWin=jt,(t=n.apply(this,arguments)||this).store=t.manager.session.pointerEvents=[],t}return S(i,n),i.prototype.handler=function(t){var e=this.store,n=!1,i=t.type.toLowerCase().replace("ms",""),r=zt[i],s=kt[t.pointerType]||t.pointerType,o=s===$,a=Ct(e,t.pointerId,"pointerId");r&nt&&(0===t.button||o)?a<0&&(e.push(t),a=e.length-1):r&(it|rt)&&(n=!0),a<0||(e[a]=t,this.callback(this.manager,r,{pointers:e,changedPointers:[t],pointerType:s,srcEvent:t}),n&&e.splice(a,1))},i}(St);function Yt(t){return Array.prototype.slice.call(t,0)}function Xt(t,n,e){for(var i=[],r=[],s=0;s<t.length;){var o=n?t[s][n]:t[s];Ct(r,o)<0&&i.push(t[s]),r[s]=o,s++}return e&&(i=n?i.sort(function(t,e){return t[n]>e[n]}):i.sort()),i}var Lt={touchstart:nt,touchmove:2,touchend:it,touchcancel:rt},Wt="touchstart touchmove touchend touchcancel",Nt=function(e){function n(){var t;return n.prototype.evTarget=Wt,(t=e.apply(this,arguments)||this).targetIds={},t}return S(n,e),n.prototype.handler=function(t){var e=Lt[t.type],n=function(t,e){var n,i,r=Yt(t.touches),s=this.targetIds;if(e&(2|nt)&&1===r.length)return s[r[0].identifier]=!0,[r,r];var o=Yt(t.changedTouches),a=[],h=this.target;if(i=r.filter(function(t){return bt(t.target,h)}),e===nt)for(n=0;n<i.length;)s[i[n].identifier]=!0,n++;n=0;for(;n<o.length;)s[o[n].identifier]&&a.push(o[n]),e&(it|rt)&&delete s[o[n].identifier],n++;return a.length?[Xt(i.concat(a),"identifier",!0),a]:void 0}.call(this,t,e);n&&this.callback(this.manager,e,{pointers:n[0],changedPointers:n[1],pointerType:$,srcEvent:t})},n}(St);var qt={mousedown:nt,mousemove:2,mouseup:it},Vt="mousedown",Ut="mousemove mouseup",Kt=function(n){function i(){var t,e=i.prototype;return e.evEl=Vt,e.evWin=Ut,(t=n.apply(this,arguments)||this).pressed=!1,t}return S(i,n),i.prototype.handler=function(t){var e=qt[t.type];e&nt&&0===t.button&&(this.pressed=!0),2&e&&1!==t.which&&(e=it),this.pressed&&(e&it&&(this.pressed=!1),this.callback(this.manager,e,{pointers:[t],changedPointers:[t],pointerType:tt,srcEvent:t}))},i}(St),Qt=2500,Bt=25;function Gt(t){var e,n,i=t.changedPointers[0];i.identifier===this.primaryTouch&&(e={x:i.clientX,y:i.clientY},n=this.lastTouches,this.lastTouches.push(e),setTimeout(function(){var t=n.indexOf(e);-1<t&&n.splice(t,1)},Qt))}var Zt=function(){return function(n){function t(t,e){var s=n.call(this,t,e)||this;return s.handler=function(t,e,n){var i=n.pointerType===$,r=n.pointerType===tt;if(!(r&&n.sourceCapabilities&&n.sourceCapabilities.firesTouchEvents)){if(i)(function(t,e){t&nt?(this.primaryTouch=e.changedPointers[0].identifier,Gt.call(this,e)):t&(it|rt)&&Gt.call(this,e)}).call(C(C(s)),e,n);else if(r&&function(t){for(var e=t.srcEvent.clientX,n=t.srcEvent.clientY,i=0;i<this.lastTouches.length;i++){var r=this.lastTouches[i],s=Math.abs(e-r.x),o=Math.abs(n-r.y);if(s<=Bt&&o<=Bt)return!0}return!1}.call(C(C(s)),n))return;s.callback(t,e,n)}},s.touch=new Nt(s.manager,s.handler),s.mouse=new Kt(s.manager,s.handler),s.primaryTouch=null,s.lastTouches=[],s}return S(t,n),t.prototype.destroy=function(){this.touch.destroy(),this.mouse.destroy()},t}(St)}();function Jt(t,e,n){return Array.isArray(t)&&(mt(t,n[e],n),1)}var $t=1;function te(t,e){var n=e.manager;return n?n.get(t):t}function ee(t){return 16&t?"cancel":8&t?"end":4&t?"move":2&t?"start":""}var ne=function(){function t(t){void 0===t&&(t={}),this.options=R({enable:!0},t),this.id=$t++,this.manager=null,this.state=1,this.simultaneous={},this.requireFail=[]}var e=t.prototype;return e.set=function(t){return k(this.options,t),this.manager&&this.manager.touchAction.update(),this},e.recognizeWith=function(t){if(Jt(t,"recognizeWith",this))return this;var e=this.simultaneous;return e[(t=te(t,this)).id]||(e[t.id]=t).recognizeWith(this),this},e.dropRecognizeWith=function(t){return Jt(t,"dropRecognizeWith",this)||(t=te(t,this),delete this.simultaneous[t.id]),this},e.requireFailure=function(t){if(Jt(t,"requireFailure",this))return this;var e=this.requireFail;return-1===Ct(e,t=te(t,this))&&(e.push(t),t.requireFailure(this)),this},e.dropRequireFailure=function(t){if(Jt(t,"dropRequireFailure",this))return this;t=te(t,this);var e=Ct(this.requireFail,t);return-1<e&&this.requireFail.splice(e,1),this},e.hasRequireFailures=function(){return 0<this.requireFail.length},e.canRecognizeWith=function(t){return!!this.simultaneous[t.id]},e.emit=function(e){var n=this,t=this.state;function i(t){n.manager.emit(t,e)}t<8&&i(n.options.event+ee(t)),i(n.options.event),e.additionalEvent&&i(e.additionalEvent),8<=t&&i(n.options.event+ee(t))},e.tryEmit=function(t){if(this.canEmit())return this.emit(t);this.state=32},e.canEmit=function(){for(var t=0;t<this.requireFail.length;){if(!(33&this.requireFail[t].state))return!1;t++}return!0},e.recognize=function(t){var e=k({},t);if(!vt(this.options.enable,[this,e]))return this.reset(),void(this.state=32);56&this.state&&(this.state=1),this.state=this.process(e),30&this.state&&this.tryEmit(e)},e.process=function(){},e.getTouchAction=function(){},e.reset=function(){},t}(),ie=function(e){function t(t){return void 0===t&&(t={}),e.call(this,R({pointers:1},t))||this}S(t,e);var n=t.prototype;return n.attrTest=function(t){var e=this.options.pointers;return 0===e||t.pointers.length===e},n.process=function(t){var e=this.state,n=t.eventType,i=6&e,r=this.attrTest(t);return i&&(n&rt||!r)?16|e:i||r?n&it?8|e:2&e?4|e:2:32},t}(ne);function re(t){return t===ut?"down":t===ht?"up":t===ot?"left":t===at?"right":""}var se=function(n){function t(t){var e;return void 0===t&&(t={}),(e=n.call(this,R({event:"pan",threshold:10,pointers:1,direction:ft},t))||this).pX=null,e.pY=null,e}S(t,n);var e=t.prototype;return e.getTouchAction=function(){var t=this.options.direction,e=[];return t&ct&&e.push(Q),t<&&e.push(K),e},e.directionTest=function(t){var e=this.options,n=!0,i=t.distance,r=t.direction,s=t.deltaX,o=t.deltaY;return r&e.direction||(i=e.direction&ct?(r=0===s?st:s<0?ot:at,n=s!==this.pX,Math.abs(t.deltaX)):(r=0===o?st:o<0?ht:ut,n=o!==this.pY,Math.abs(t.deltaY))),t.direction=r,n&&i>e.threshold&&r&e.direction},e.attrTest=function(t){return ie.prototype.attrTest.call(this,t)&&(2&this.state||!(2&this.state)&&this.directionTest(t))},e.emit=function(t){this.pX=t.deltaX,this.pY=t.deltaY;var e=re(t.direction);e&&(t.additionalEvent=this.options.event+e),n.prototype.emit.call(this,t)},t}(ie),oe=function(n){function t(t){return void 0===t&&(t={}),n.call(this,R({event:"pinch",threshold:0,pointers:2},t))||this}S(t,n);var e=t.prototype;return e.getTouchAction=function(){return[U]},e.attrTest=function(t){return n.prototype.attrTest.call(this,t)&&(Math.abs(t.scale-1)>this.options.threshold||2&this.state)},e.emit=function(t){var e;1!==t.scale&&(e=t.scale<1?"in":"out",t.additionalEvent=this.options.event+e),n.prototype.emit.call(this,t)},t}(ie),ae={domEvents:!1,touchAction:q,enable:!0,inputTarget:null,inputClass:null,cssProps:{userSelect:"none",touchSelect:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}};function he(n,i){var r,s=n.element;s.style&&(mt(n.options.cssProps,function(t,e){r=L(s.style,e),i?(n.oldCssProps[r]=s.style[r],s.style[r]=t):s.style[r]=n.oldCssProps[r]||""}),i||(n.oldCssProps={}))}var ue=function(){function t(t,e){var n,i,r=this;this.options=k({},ae,e||{}),this.options.inputTarget=this.options.inputTarget||t,this.handlers={},this.session={},this.recognizers=[],this.oldCssProps={},this.element=t,this.input=(i=(n=this).options.inputClass,new(i||(Z?Ht:J?Nt:G?Zt:Kt))(n,At)),this.touchAction=new yt(this,this.options.touchAction),he(this,!0),mt(this.options.recognizers,function(t){var e=r.add(new t[0](t[1]));t[2]&&e.recognizeWith(t[2]),t[3]&&e.requireFailure(t[3])},this)}var e=t.prototype;return e.set=function(t){return k(this.options,t),t.touchAction&&this.touchAction.update(),t.inputTarget&&(this.input.destroy(),this.input.target=t.inputTarget,this.input.init()),this},e.stop=function(t){this.session.stopped=t?2:1},e.recognize=function(t){var e,n=this.session;if(!n.stopped){this.touchAction.preventDefaults(t);var i=this.recognizers,r=n.curRecognizer;(!r||r&&8&r.state)&&(r=n.curRecognizer=null);for(var s=0;s<i.length;)e=i[s],2===n.stopped||r&&e!==r&&!e.canRecognizeWith(r)?e.reset():e.recognize(t),!r&&14&e.state&&(r=n.curRecognizer=e),s++}},e.get=function(t){if(t instanceof ne)return t;for(var e=this.recognizers,n=0;n<e.length;n++)if(e[n].options.event===t)return e[n];return null},e.add=function(t){if(Jt(t,"add",this))return this;var e=this.get(t.options.event);return e&&this.remove(e),this.recognizers.push(t),(t.manager=this).touchAction.update(),t},e.remove=function(t){if(Jt(t,"remove",this))return this;var e,n,i=this.get(t);return!t||-1!==(n=Ct(e=this.recognizers,i))&&(e.splice(n,1),this.touchAction.update()),this},e.on=function(t,e){if(void 0===t||void 0===e)return this;var n=this.handlers;return mt(Dt(t),function(t){n[t]=n[t]||[],n[t].push(e)}),this},e.off=function(t,e){if(void 0===t)return this;var n=this.handlers;return mt(Dt(t),function(t){e?n[t]&&n[t].splice(Ct(n[t],e),1):delete n[t]}),this},e.emit=function(t,e){var n,i,r;this.options.domEvents&&(n=t,i=e,(r=document.createEvent("Event")).initEvent(n,!0,!0),(r.gesture=i).target.dispatchEvent(r));var s=this.handlers[t]&&this.handlers[t].slice();if(s&&s.length){e.type=t,e.preventDefault=function(){e.srcEvent.preventDefault()};for(var o=0;o<s.length;)s[o](e),o++}},e.destroy=function(){this.element&&he(this,!1),this.handlers={},this.session={},this.input.destroy(),this.element=null},t}();function ce(i,t,e){var r="DEPRECATED METHOD: "+t+"\n"+e+" AT \n";return function(){var t=new Error("get-stack-trace"),e=t&&t.stack?t.stack.replace(/^[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^Object.<anonymous>\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",n=window.console&&(window.console.warn||window.console.log);return n&&n.call(window.console,r,e),i.apply(this,arguments)}}var le=ce(function(t,e,n){for(var i=Object.keys(e),r=0;r<i.length;)(!n||n&&void 0===t[i[r]])&&(t[i[r]]=e[i[r]]),r++;return t},"extend","Use `assign`.");ce(function(t,e){return le(t,e,!0)},"merge","Use `assign`.");function fe(t,e){for(var n=t.length,i=0;i<n;++i)if(e(t[i],i))return!0;return!1}function pe(t,e){for(var n=t.length,i=0;i<n;++i)if(e(t[i],i))return t[i];return null}function de(t,e){try{return new RegExp(t,"g").exec(e)}catch(t){return null}}function me(t){return t.replace(/_/g,".")}function ve(t,r){var s=null,o="-1";return fe(t,function(t){var e,n,i=de("("+t.test+")((?:\\/|\\s|:)([0-9|\\.|_]+))?",r);return i&&!t.brand&&(s=t,o=i[3]||"-1",t.versionAlias?o=t.versionAlias:t.versionTest&&(e=t.versionTest.toLowerCase(),n=de("("+e+")((?:\\/|\\s|:)([0-9|\\.|_]+))?",r),o=(n?n[3]:"")||o),o=me(o),1)}),{preset:s,version:o}}function ge(t,n){return pe(t,function(t){var e=t.brand;return de(""+n.test,e.toLowerCase())})}var ye=[{test:"phantomjs",id:"phantomjs"},{test:"whale",id:"whale"},{test:"edgios|edge|edg",id:"edge"},{test:"msie|trident|windows phone",id:"ie",versionTest:"iemobile|msie|rv"},{test:"miuibrowser",id:"miui browser"},{test:"samsungbrowser",id:"samsung internet"},{test:"samsung",id:"samsung internet",versionTest:"version"},{test:"chrome|crios",id:"chrome"},{test:"firefox|fxios",id:"firefox"},{test:"android",id:"android browser",versionTest:"version"},{test:"safari|iphone|ipad|ipod",id:"safari",versionTest:"version"}],be=[{test:"(?=.*applewebkit/(53[0-7]|5[0-2]|[0-4]))(?=.*\\schrome)",id:"chrome"},{test:"chromium",id:"chrome"},{test:"whale",id:"chrome",brand:!0}],xe=[{test:"applewebkit",id:"webkit"}],we=[{test:"(?=(iphone|ipad))(?!(.*version))",id:"webview"},{test:"(?=(android|iphone|ipad))(?=.*(naver|daum|; wv))",id:"webview"},{test:"webview",id:"webview"}],Ee=[{test:"windows phone",id:"windows phone"},{test:"windows 2000",id:"window",versionAlias:"5.0"},{test:"windows nt",id:"window"},{test:"iphone|ipad|ipod",id:"ios",versionTest:"iphone os|cpu os"},{test:"mac os x",id:"mac"},{test:"android",id:"android"},{test:"tizen",id:"tizen"},{test:"webos|web0s",id:"webos"}];function Te(t){var e=function(t){var e=t;if(void 0===e){if("undefined"==typeof navigator||!navigator)return"";e=navigator.userAgent||""}return e.toLowerCase()}(t),n=!!/mobi/g.exec(e),i={name:"unknown",version:"-1",majorVersion:-1,webview:!!ve(we,e).preset,chromium:!!ve(be,e).preset,webkit:!1},r={name:"unknown",version:"-1",majorVersion:-1},s=ve(ye,e),o=s.preset,a=s.version,h=ve(Ee,e),u=h.preset,c=h.version;return i.webkit=!i.chromium&&!!ve(xe,e).preset,u&&(r.name=u.id,r.version=c,r.majorVersion=parseInt(c,10)),o&&(i.name=o.id,i.version=a,i.webview&&"ios"===r.name&&"safari"!==i.name&&(i.webview=!1)),i.majorVersion=parseInt(i.version,10),{browser:i,os:r,isMobile:n,isHints:!1}}var Pe,_e,Oe,Ae,De,Ie,Me,Re,Se,Ce,ze="ontouchstart"in r&&"safari"===(void 0===Pe&&function(){if("undefined"!=typeof navigator&&navigator&&navigator.userAgentData){var t=navigator.userAgentData,e=t.brands||t.uaList;return e&&e.length}}()?(De=navigator.userAgentData,Ie=(De.uaList||De.brands).slice(),Me=De.mobile||!1,Re=Ie[0],Se={name:Re.brand,version:Re.version,majorVersion:-1,webkit:!1,webview:fe(we,function(t){return ge(Ie,t)}),chromium:fe(be,function(t){return ge(Ie,t)})},Ce={name:"unknown",version:"-1",majorVersion:-1},Se.webkit=!Se.chromium&&fe(xe,function(t){return ge(Ie,t)}),_e&&(Oe=_e.platform.toLowerCase(),Ae=pe(Ee,function(t){return new RegExp(""+t.test,"g").exec(Oe)}),Ce.name=Ae?Ae.id:Oe,Ce.version=_e.platformVersion),fe(ye,function(t){var e=ge(Ie,t);return e&&(Se.name=t.id,Se.version=_e?_e.uaFullVersion:e.version,1)}),"Linux armv8l"===navigator.platform?Ce.name="android":Se.webkit&&(Ce.name=Me?"ios":"mac"),"ios"===Ce.name&&Se.webview&&(Se.version="-1"),Ce.version=me(Ce.version),Se.version=me(Se.version),Ce.majorVersion=parseInt(Ce.version,10),Se.majorVersion=parseInt(Se.version,10),{browser:Se,os:Ce,isMobile:Me,isHints:!0}):Te(Pe)).browser.name,ke=function(){if("undefined"==typeof document)return"";for(var t=(document.head||document.getElementsByTagName("head")[0]).style,e=["transform","webkitTransform","msTransform","mozTransform"],n=0,i=e.length;n<i;n++)if(e[n]in t)return e[n];return""}(),Fe=function(r){function t(t,e,n){void 0===t&&(t={}),void 0===e&&(e={});var i=r.call(this)||this;return i.axis=t,i._inputs=[],i.options=v({easing:function(t){return 1-Math.pow(1-t,3)},interruptable:!0,maximumDuration:1/0,minimumDuration:0,deceleration:6e-4,round:null},e),i.itm=new D(i.options),i.axm=new I(i.axis,i.options),i.em=new A(i),i.am=new O(i),i.io=new M(i),i.em.setAnimationManager(i.am),n&&i.em.triggerChange(n),i}n(t,r);var e=t.prototype;return e.connect=function(t,e){var n,i="string"==typeof t?t.split(" "):t.concat();return~this._inputs.indexOf(e)&&this.disconnect(e),"hammer"in e&&((n=this._inputs.filter(function(t){return t.hammer&&t.element===e.element})).length&&(e.hammer=n[0].hammer)),e.mapAxes(i),e.connect(this.io),this._inputs.push(e),this},e.disconnect=function(t){var e;return t?0<=(e=this._inputs.indexOf(t))&&(this._inputs[e].disconnect(),this._inputs.splice(e,1)):(this._inputs.forEach(function(t){return t.disconnect()}),this._inputs=[]),this},e.get=function(t){return this.axm.get(t)},e.setTo=function(t,e){return void 0===e&&(e=0),this.am.setTo(t,e),this},e.setBy=function(t,e){return void 0===e&&(e=0),this.am.setBy(t,e),this},e.isBounceArea=function(t){return this.axm.isOutside(t)},e.destroy=function(){this.disconnect(),this.em.destroy()},t.VERSION="2.8.0",t.TRANSFORM=ke,t.DIRECTION_NONE=st,t.DIRECTION_LEFT=ot,t.DIRECTION_RIGHT=at,t.DIRECTION_UP=ht,t.DIRECTION_DOWN=ut,t.DIRECTION_HORIZONTAL=ct,t.DIRECTION_VERTICAL=lt,t.DIRECTION_ALL=ft,t}(t),je="PointerEvent"in r||"MSPointerEvent"in r,He="ontouchstart"in r,Ye="_EGJS_AXES_INPUTTYPE_";function Xe(i,t){return t.reduce(function(t,e,n){return i[n]&&(t[i[n]]=e),t},{})}function Le(t,e){try{return new ue(t,v({},e))}catch(t){return null}}function We(t){void 0===t&&(t=[]);var e=!1,n=!1,i=!1;return t.forEach(function(t){switch(t){case"mouse":n=!0;break;case"touch":e=He;break;case"pointer":i=je}}),i?Ht:e&&n?Zt:e?Nt:n?Kt:null}function Ne(t,e,n){return n?!!(e===ft||e&t&&n&t):!!(e&t)}var qe=function(){function t(t,e){if(this.axes=[],this.hammer=null,this.element=null,this.panRecognizer=null,this.isRightEdge=!1,this.rightEdgeTimer=0,this.panFlag=!1,void 0===ue)throw new Error("The Hammerjs must be loaded before eg.Axes.PanInput.\nhttp://hammerjs.github.io/");this.element=a(t),this.options=v({inputType:["touch","mouse","pointer"],scale:[1,1],thresholdAngle:45,threshold:0,iOSEdgeSwipeThreshold:30,releaseOnScroll:!1,hammerManagerOptions:{cssProps:{userSelect:"none",touchSelect:"none",touchCallout:"none",userDrag:"none"}}},e),this.onHammerInput=this.onHammerInput.bind(this),this.onPanmove=this.onPanmove.bind(this),this.onPanend=this.onPanend.bind(this)}var e=t.prototype;return e.mapAxes=function(t){var e=!!t[0],n=!!t[1];this._direction=e&&n?ft:e?ct:n?lt:st,this.axes=t},e.connect=function(t){var e={direction:this._direction,threshold:this.options.threshold};if(this.hammer)this.removeRecognizer(),this.dettachEvent();else{var n=(n=this.element[Ye])||String(Math.round(Math.random()*(new Date).getTime())),i=We(this.options.inputType);if(!i)throw new Error("Wrong inputType parameter!");this.hammer=Le(this.element,v({inputClass:i},this.options.hammerManagerOptions)),this.element[Ye]=n}return this.panRecognizer=new se(e),this.hammer.add(this.panRecognizer),this.attachEvent(t),this},e.disconnect=function(){return this.removeRecognizer(),this.hammer&&this.dettachEvent(),this._direction=st,this},e.destroy=function(){this.disconnect(),this.hammer&&0===this.hammer.recognizers.length&&this.hammer.destroy(),delete this.element[Ye],this.element=null,this.hammer=null},e.enable=function(){return this.hammer&&(this.hammer.get("pan").options.enable=!0),this},e.disable=function(){return this.hammer&&(this.hammer.get("pan").options.enable=!1),this},e.isEnable=function(){return!(!this.hammer||!this.hammer.get("pan").options.enable)},e.removeRecognizer=function(){this.hammer&&this.panRecognizer&&(this.hammer.remove(this.panRecognizer),this.panRecognizer=null)},e.onHammerInput=function(t){var e;this.isEnable()&&(t.isFirst?(this.panFlag=!1)!==t.srcEvent.cancelable&&(e=this.options.iOSEdgeSwipeThreshold,this.observer.hold(this,t),this.isRightEdge=ze&&t.center.x>window.innerWidth-e,this.panFlag=!0):t.isFinal&&this.onPanend(t))},e.onPanmove=function(t){var e=this;if(this.panFlag){var n=this.options,i=n.iOSEdgeSwipeThreshold,r=n.releaseOnScroll,s=function(t,e){if(e<0||90<e)return st;var n=Math.abs(t);return e<n&&n<180-e?lt:ct}(t.angle,this.options.thresholdAngle),o=this.hammer.session.prevInput;if(!r||t.srcEvent.cancelable){if(o&&ze){if(t.center.x<0)return void this.onPanend(v(v({},o),{velocityX:0,velocityY:0,offsetX:0,offsetY:0}));this.isRightEdge&&(clearTimeout(this.rightEdgeTimer),t.deltaX<-i?this.isRightEdge=!1:this.rightEdgeTimer=window.setTimeout(function(){e.onPanend(v(v({},o),{velocityX:0,velocityY:0,offsetX:0,offsetY:0}))},100))}o?(t.offsetX=t.deltaX-o.deltaX,t.offsetY=t.deltaY-o.deltaY):(t.offsetX=0,t.offsetY=0);var a,h=this.getOffset([t.offsetX,t.offsetY],[Ne(ct,this._direction,s),Ne(lt,this._direction,s)]),u=h.some(function(t){return 0!==t});u&&(!1!==(a=t.srcEvent).cancelable&&a.preventDefault(),a.stopPropagation()),(t.preventSystemEvent=u)&&this.observer.change(this,t,Xe(this.axes,h))}else this.onPanend(v(v({},t),{velocityX:0,velocityY:0,offsetX:0,offsetY:0}))}},e.onPanend=function(t){var e,n,i,r,s;this.panFlag&&(clearTimeout(this.rightEdgeTimer),this.panFlag=!1,e=this.getOffset([Math.abs(t.velocityX)*(t.deltaX<0?-1:1),Math.abs(t.velocityY)*(t.deltaY<0?-1:1)],[Ne(ct,this._direction),Ne(lt,this._direction)]),n=e,i=this.observer.options.deceleration,r=Math.sqrt(n[0]*n[0]+n[1]*n[1]),s=Math.abs(r/-i),e=[n[0]/2*s,n[1]/2*s],this.observer.release(this,t,Xe(this.axes,e)))},e.attachEvent=function(t){this.observer=t,this.hammer.on("hammer.input",this.onHammerInput).on("panstart panmove",this.onPanmove)},e.dettachEvent=function(){this.hammer.off("hammer.input",this.onHammerInput).off("panstart panmove",this.onPanmove),this.observer=null},e.getOffset=function(t,e){var n=[0,0],i=this.options.scale;return e[0]&&(n[0]=t[0]*i[0]),e[1]&&(n[1]=t[1]*i[1]),n},t}(),Ve=function(i){function t(t,e){var n=i.call(this,t,e)||this;return n.prevQuadrant=null,n.lastDiff=0,n}n(t,i);var e=t.prototype;return e.mapAxes=function(t){this._direction=Fe.DIRECTION_ALL,this.axes=t},e.onHammerInput=function(t){this.isEnable()&&(t.isFirst?(this.observer.hold(this,t),this.onPanstart(t)):t.isFinal&&this.onPanend(t))},e.onPanstart=function(t){var e=this.element.getBoundingClientRect();this.coefficientForDistanceToAngle=360/(e.width*Math.PI),this.rotateOrigin=[e.left+(e.width-1)/2,e.top+(e.height-1)/2],this.prevAngle=null,this.triggerChange(t)},e.onPanmove=function(t){this.triggerChange(t)},e.onPanend=function(t){this.triggerChange(t),this.triggerAnimation(t)},e.triggerChange=function(t){var e=this.getAngle(t.center.x,t.center.y),n=this.getQuadrant(t.center.x,t.center.y),i=this.getDifference(this.prevAngle,e,this.prevQuadrant,n);this.prevAngle=e,this.prevQuadrant=n,0!==i&&(this.lastDiff=i,this.observer.change(this,t,Xe(this.axes,[-i])))},e.triggerAnimation=function(t){var e=t.velocityX,n=t.velocityY,i=Math.sqrt(e*e+n*n)*(0<this.lastDiff?-1:1),r=i/2*Math.abs(i/-this.observer.options.deceleration);this.observer.release(this,t,Xe(this.axes,[r*this.coefficientForDistanceToAngle]))},e.getDifference=function(t,e,n,i){var r=null===t?0:1===n&&4===i?-t-(360-e):4===n&&1===i?360-t+e:e-t;return r},e.getPosFromOrigin=function(t,e){return{x:t-this.rotateOrigin[0],y:this.rotateOrigin[1]-e}},e.getAngle=function(t,e){var n=this.getPosFromOrigin(t,e),i=n.x,r=n.y,s=180*Math.atan2(r,i)/Math.PI;return s<0?360+s:s},e.getQuadrant=function(t,e){var n=this.getPosFromOrigin(t,e),i=n.x,r=n.y,s=0;return 0<=i&&0<=r?s=1:i<0&&0<=r?s=2:i<0&&r<0?s=3:0<=i&&r<0&&(s=4),s},t}(qe),Ue=function(){function t(t,e){if(this.axes=[],this.hammer=null,this.element=null,this._base=null,this._prev=null,this.pinchRecognizer=null,void 0===ue)throw new Error("The Hammerjs must be loaded before eg.Axes.PinchInput.\nhttp://hammerjs.github.io/");this.element=a(t),this.options=v({scale:1,threshold:0,inputType:["touch","pointer"],hammerManagerOptions:{cssProps:{userSelect:"none",touchSelect:"none",touchCallout:"none",userDrag:"none"}}},e),this.onPinchStart=this.onPinchStart.bind(this),this.onPinchMove=this.onPinchMove.bind(this),this.onPinchEnd=this.onPinchEnd.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){var e={threshold:this.options.threshold};if(this.hammer)this.removeRecognizer(),this.dettachEvent();else{var n=(n=this.element[Ye])||String(Math.round(Math.random()*(new Date).getTime())),i=We(this.options.inputType);if(!i)throw new Error("Wrong inputType parameter!");this.hammer=Le(this.element,v({inputClass:i},this.options.hammerManagerOptions)),this.element[Ye]=n}return this.pinchRecognizer=new oe(e),this.hammer.add(this.pinchRecognizer),this.attachEvent(t),this},e.disconnect=function(){return this.removeRecognizer(),this.hammer&&(this.hammer.remove(this.pinchRecognizer),this.pinchRecognizer=null,this.dettachEvent()),this},e.destroy=function(){this.disconnect(),this.hammer&&0===this.hammer.recognizers.length&&this.hammer.destroy(),delete this.element[Ye],this.element=null,this.hammer=null},e.removeRecognizer=function(){this.hammer&&this.pinchRecognizer&&(this.hammer.remove(this.pinchRecognizer),this.pinchRecognizer=null)},e.onPinchStart=function(t){this._base=this.observer.get(this)[this.axes[0]];var e=this.getOffset(t.scale);this.observer.hold(this,t),this.observer.change(this,t,Xe(this.axes,[e])),this._prev=t.scale},e.onPinchMove=function(t){var e=this.getOffset(t.scale,this._prev);this.observer.change(this,t,Xe(this.axes,[e])),this._prev=t.scale},e.onPinchEnd=function(t){var e=this.getOffset(t.scale,this._prev);this.observer.change(this,t,Xe(this.axes,[e])),this.observer.release(this,t,Xe(this.axes,[0]),0),this._base=null,this._prev=null},e.getOffset=function(t,e){return void 0===e&&(e=1),this._base*(t-e)*this.options.scale},e.attachEvent=function(t){this.observer=t,this.hammer.on("pinchstart",this.onPinchStart).on("pinchmove",this.onPinchMove).on("pinchend",this.onPinchEnd)},e.dettachEvent=function(){this.hammer.off("pinchstart",this.onPinchStart).off("pinchmove",this.onPinchMove).off("pinchend",this.onPinchEnd),this.observer=null,this._prev=null},e.enable=function(){return this.hammer&&(this.hammer.get("pinch").options.enable=!0),this},e.disable=function(){return this.hammer&&(this.hammer.get("pinch").options.enable=!1),this},e.isEnable=function(){return!(!this.hammer||!this.hammer.get("pinch").options.enable)},t}(),Ke=function(){function t(t,e){this.axes=[],this.element=null,this._isEnabled=!1,this._isHolded=!1,this._timer=null,this.element=a(t),this.options=v({scale:1,useNormalized:!0},e),this.onWheel=this.onWheel.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this.dettachEvent(),this.attachEvent(t),this},e.disconnect=function(){return this.dettachEvent(),this},e.destroy=function(){this.disconnect(),this.element=null},e.onWheel=function(t){var e,n=this;this._isEnabled&&(t.preventDefault(),0!==t.deltaY&&(this._isHolded||(this.observer.hold(this,t),this._isHolded=!0),e=(0<t.deltaY?-1:1)*this.options.scale*(this.options.useNormalized?1:Math.abs(t.deltaY)),this.observer.change(this,t,Xe(this.axes,[e])),clearTimeout(this._timer),this._timer=setTimeout(function(){n._isHolded&&(n._isHolded=!1,n.observer.release(n,t,Xe(n.axes,[0])))},50)))},e.attachEvent=function(t){this.observer=t,this.element.addEventListener("wheel",this.onWheel),this._isEnabled=!0},e.dettachEvent=function(){this.element.removeEventListener("wheel",this.onWheel),this._isEnabled=!1,this.observer=null,this._timer&&(clearTimeout(this._timer),this._timer=null)},e.enable=function(){return this._isEnabled=!0,this},e.disable=function(){return this._isEnabled=!1,this},e.isEnable=function(){return this._isEnabled},t}(),Qe=function(){function t(t,e){this.axes=[],this.element=null,this._isEnabled=!1,this._isHolded=!1,this._timer=null,this.element=a(t),this.options=v({scale:[1,1]},e),this.onKeydown=this.onKeydown.bind(this),this.onKeyup=this.onKeyup.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this.dettachEvent(),"0"!==this.element.getAttribute("tabindex")&&this.element.setAttribute("tabindex","0"),this.attachEvent(t),this},e.disconnect=function(){return this.dettachEvent(),this},e.destroy=function(){this.disconnect(),this.element=null},e.onKeydown=function(t){if(this._isEnabled){var e,n=!0,i=1,r=-1;switch(t.keyCode){case 37:case 65:i=-1;break;case 39:case 68:break;case 40:case 83:i=-1,r=1;break;case 38:case 87:r=1;break;default:n=!1}(-1===r&&!this.axes[0]||1===r&&!this.axes[1])&&(n=!1),n&&(e=-1===r?[this.options.scale[0]*i,0]:[0,this.options.scale[1]*i],this._isHolded||(this.observer.hold(this,event),this._isHolded=!0),clearTimeout(this._timer),this.observer.change(this,event,Xe(this.axes,e)))}},e.onKeyup=function(t){var e=this;this._isHolded&&(clearTimeout(this._timer),this._timer=setTimeout(function(){e.observer.release(e,t,Xe(e.axes,[0,0])),e._isHolded=!1},80))},e.attachEvent=function(t){this.observer=t,this.element.addEventListener("keydown",this.onKeydown,!1),this.element.addEventListener("keypress",this.onKeydown,!1),this.element.addEventListener("keyup",this.onKeyup,!1),this._isEnabled=!0},e.dettachEvent=function(){this.element.removeEventListener("keydown",this.onKeydown,!1),this.element.removeEventListener("keypress",this.onKeydown,!1),this.element.removeEventListener("keyup",this.onKeyup,!1),this._isEnabled=!1,this.observer=null},e.enable=function(){return this._isEnabled=!0,this},e.disable=function(){return this._isEnabled=!1,this},e.isEnable=function(){return this._isEnabled},t}();return Fe.PanInput=qe,Fe.RotatePanInput=Ve,Fe.PinchInput=Ue,Fe.WheelInput=Ke,Fe.MoveKeyInput=Qe,Fe}); | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t.eg=t.eg||{},t.eg.Axes=e())}(this,function(){"use strict";var i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)};function s(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}var l=function(){return(l=Object.assign||function(t){for(var e,n=1,i=arguments.length;n<i;n++)for(var r in e=arguments[n])Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t}).apply(this,arguments)};function c(t){var e="function"==typeof Symbol&&Symbol.iterator,n=e&&t[e],i=0;if(n)return n.call(t);if(t&&"number"==typeof t.length)return{next:function(){return t&&i>=t.length&&(t=void 0),{value:t&&t[i++],done:!t}}};throw new TypeError(e?"Object is not iterable.":"Symbol.iterator is not defined.")}function a(){for(var t=[],e=0;e<arguments.length;e++)t=t.concat(function(t,e){var n="function"==typeof Symbol&&t[Symbol.iterator];if(!n)return t;var i,r,s=n.call(t),a=[];try{for(;(void 0===e||0<e--)&&!(i=s.next()).done;)a.push(i.value)}catch(t){r={error:t}}finally{try{i&&!i.done&&(n=s.return)&&n.call(s)}finally{if(r)throw r.error}}return a}(arguments[e]));return t}function v(t){return void 0===t}function d(t,e,n,i){var r=t,s=[!n[0]&&i?e[0]-i[0]:e[0],!n[1]&&i?e[1]+i[1]:e[1]],r=Math.max(s[0],r);return Math.min(s[1],r)}function u(t,e){return t<e[0]||t>e[1]}function h(t,e,n){return n[1]&&t>e[1]||n[0]&&t<e[0]}function f(t,e,n){var i=t,r=e[0],s=e[1],a=s-r;return n[1]&&s<t&&(i=(i-s)%a+r),n[0]&&t<r&&(i=(i-r)%a+s),i}var r,o=function(){function t(t,e){var n,i;if(this._canceled=!1,e)try{for(var r=c(Object.keys(e)),s=r.next();!s.done;s=r.next()){var a=s.value;this[a]=e[a]}}catch(t){n={error:t}}finally{try{s&&!s.done&&(i=r.return)&&i.call(r)}finally{if(n)throw n.error}}this.eventType=t}var e=t.prototype;return e.stop=function(){this._canceled=!0},e.isCanceled=function(){return this._canceled},t}(),t=function(){function t(){this._eventHandler={}}var e=t.prototype;return e.trigger=function(e){for(var n=[],t=1;t<arguments.length;t++)n[t-1]=arguments[t];var i=e instanceof o?e.eventType:e,r=a(this._eventHandler[i]||[]);return r.length<=0||(e instanceof o?(e.currentTarget=this,r.forEach(function(t){t(e)})):r.forEach(function(t){t.apply(void 0,a(n))})),this},e.once=function(n,i){var r,s=this;if("object"==typeof n&&v(i)){var t=n;for(var e in t)this.once(e,t[e]);return this}return"string"==typeof n&&"function"==typeof i&&(r=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];i.apply(void 0,a(t)),s.off(n,r)},this.on(n,r)),this},e.hasOn=function(t){return!!this._eventHandler[t]},e.on=function(t,e){if("object"==typeof t&&v(e)){var n=t;for(var i in n)this.on(i,n[i]);return this}var r;return"string"==typeof t&&"function"==typeof e&&(r=this._eventHandler[t],v(r)&&(this._eventHandler[t]=[],r=this._eventHandler[t]),r.push(e)),this},e.off=function(t,e){var n,i;if(v(t))return this._eventHandler={},this;if(v(e)){if("string"==typeof t)return delete this._eventHandler[t],this;var r=t;for(var s in r)this.off(s,r[s]);return this}var a=this._eventHandler[t];if(a){var o=0;try{for(var u=c(a),h=u.next();!h.done;h=u.next()){if(h.value===e){a.splice(o,1),a.length<=0&&delete this._eventHandler[t];break}o++}}catch(t){n={error:t}}finally{try{h&&!h.done&&(i=u.return)&&i.call(u)}finally{if(n)throw n.error}}}return this},t.VERSION="3.0.2",t}(),_=o;function e(t,e){for(var n=t.length,i=0;i<n;++i)if(e(t[i],i))return!0;return!1}function p(t,e){for(var n=t.length,i=0;i<n;++i)if(e(t[i],i))return t[i];return null}function g(t,e){try{return new RegExp(t,"g").exec(e)}catch(t){return null}}function m(t){return t.replace(/_/g,".")}function E(t,r){var s=null,a="-1";return e(t,function(t){var e,n,i=g("("+t.test+")((?:\\/|\\s|:)([0-9|\\.|_]+))?",r);return i&&!t.brand&&(s=t,a=i[3]||"-1",t.versionAlias?a=t.versionAlias:t.versionTest&&(e=t.versionTest.toLowerCase(),n=g("("+e+")((?:\\/|\\s|:)([0-9|\\.|_]+))?",r),a=(n?n[3]:"")||a),a=m(a),1)}),{preset:s,version:a}}function n(t,n){return p(t,function(t){var e=t.brand;return g(""+n.test,e.toLowerCase())})}r="undefined"==typeof window?{navigator:{userAgent:""}}:window;var b=[{test:"phantomjs",id:"phantomjs"},{test:"whale",id:"whale"},{test:"edgios|edge|edg",id:"edge"},{test:"msie|trident|windows phone",id:"ie",versionTest:"iemobile|msie|rv"},{test:"miuibrowser",id:"miui browser"},{test:"samsungbrowser",id:"samsung internet"},{test:"samsung",id:"samsung internet",versionTest:"version"},{test:"chrome|crios",id:"chrome"},{test:"firefox|fxios",id:"firefox"},{test:"android",id:"android browser",versionTest:"version"},{test:"safari|iphone|ipad|ipod",id:"safari",versionTest:"version"}],x=[{test:"(?=.*applewebkit/(53[0-7]|5[0-2]|[0-4]))(?=.*\\schrome)",id:"chrome"},{test:"chromium",id:"chrome"},{test:"whale",id:"chrome",brand:!0}],y=[{test:"applewebkit",id:"webkit"}],M=[{test:"(?=(iphone|ipad))(?!(.*version))",id:"webview"},{test:"(?=(android|iphone|ipad))(?=.*(naver|daum|; wv))",id:"webview"},{test:"webview",id:"webview"}],P=[{test:"windows phone",id:"windows phone"},{test:"windows 2000",id:"window",versionAlias:"5.0"},{test:"windows nt",id:"window"},{test:"iphone|ipad|ipod",id:"ios",versionTest:"iphone os|cpu os"},{test:"mac os x",id:"mac"},{test:"android",id:"android"},{test:"tizen",id:"tizen"},{test:"webos|web0s",id:"webos"}];function w(t){var e=function(t){var e=t;if(void 0===e){if("undefined"==typeof navigator||!navigator)return"";e=navigator.userAgent||""}return e.toLowerCase()}(t),n=!!/mobi/g.exec(e),i={name:"unknown",version:"-1",majorVersion:-1,webview:!!E(M,e).preset,chromium:!!E(x,e).preset,webkit:!1},r={name:"unknown",version:"-1",majorVersion:-1},s=E(b,e),a=s.preset,o=s.version,u=E(P,e),h=u.preset,c=u.version;return i.webkit=!i.chromium&&!!E(y,e).preset,h&&(r.name=h.id,r.version=c,r.majorVersion=parseInt(c,10)),a&&(i.name=a.id,i.version=o,i.webview&&"ios"===r.name&&"safari"!==i.name&&(i.webview=!1)),i.majorVersion=parseInt(i.version,10),{browser:i,os:r,isMobile:n,isHints:!1}}function I(t){for(var e=[],n=0,i=t.length;n<i;n++)e.push(t[n]);return e}var T,O,D,A,S,C,k,R,L,j,F,Y,X="ontouchstart"in r&&"safari"===(void 0===T&&function(){if("undefined"!=typeof navigator&&navigator&&navigator.userAgentData){var t=navigator.userAgentData,e=t.brands||t.uaList;return e&&e.length}}()?(S=navigator.userAgentData,C=(S.uaList||S.brands).slice(),k=S.mobile||!1,R=C[0],L={name:R.brand,version:R.version,majorVersion:-1,webkit:!1,webview:e(M,function(t){return n(C,t)}),chromium:e(x,function(t){return n(C,t)})},j={name:"unknown",version:"-1",majorVersion:-1},L.webkit=!L.chromium&&e(y,function(t){return n(C,t)}),O&&(D=O.platform.toLowerCase(),A=p(P,function(t){return new RegExp(""+t.test,"g").exec(D)}),j.name=A?A.id:D,j.version=O.platformVersion),e(b,function(t){var e=n(C,t);return e&&(L.name=t.id,L.version=O?O.uaFullVersion:e.version,1)}),"Linux armv8l"===navigator.platform?j.name="android":L.webkit&&(j.name=k?"ios":"mac"),"ios"===j.name&&L.webview&&(L.version="-1"),j.version=m(j.version),L.version=m(L.version),j.majorVersion=parseInt(j.version,10),L.majorVersion=parseInt(L.version,10),{browser:L,os:j,isMobile:k,isHints:!0}):w(T)).browser.name,N=function(){if("undefined"==typeof document)return"";for(var t=(document.head||document.getElementsByTagName("head")[0]).style,e=["transform","webkitTransform","msTransform","mozTransform"],n=0,i=e.length;n<i;n++)if(e[n]in t)return e[n];return""}(),V={"touch-action":"none","user-select":"none","-webkit-user-drag":"none"},H=function(t,e){var n,i;return void 0===e&&(e=!1),"string"==typeof t?(i=t.match(/^<([a-z]+)\s*([^>]*)>/)?((n=document.createElement("div")).innerHTML=t,I(n.childNodes)):I(document.querySelectorAll(t)),e||(i=1<=i.length?i[0]:void 0)):t!==r&&(!t.nodeName||1!==t.nodeType&&9!==t.nodeType)?"jQuery"in r&&t instanceof jQuery||t.constructor.prototype.jquery?i=e?t.toArray():t.get(0):Array.isArray(t)&&(i=t.map(function(t){return H(t)}),e||(i=1<=i.length?i[0]:void 0)):i=t,i},K=r.requestAnimationFrame||r.webkitRequestAnimationFrame,U=r.cancelAnimationFrame||r.webkitCancelAnimationFrame;K&&!U?(F={},Y=K,K=function(e){var n=Y(function(t){F[n]&&e(t)});return F[n]=!0,n},U=function(t){delete F[t]}):K&&U||(K=function(t){return r.setTimeout(function(){t(r.performance&&r.performance.now&&r.performance.now()||(new Date).getTime())},16)},U=r.clearTimeout);function B(t,e){var n={};for(var i in t)i&&(n[i]=e(t[i],i));return n}function W(t,e){var n={};for(var i in t)i&&e(t[i],i)&&(n[i]=t[i]);return n}function q(t,e){for(var n in t)if(n&&!e(t[n],n))return!1;return!0}function Q(t,n){return q(t,function(t,e){return t===n[e]})}function z(t,e){return rt[e]||(rt[e]=st(e)),rt[e](t)}function G(t,n){return t&&n?B(t,function(t,e){return z(t,"number"==typeof n?n:n[e])}):t}function Z(t){if(!isFinite(t))return 0;var e=""+t;if(0<=e.indexOf("e")){for(var n=0,i=1;Math.round(t*i)/i!==t;)i*=10,n++;return n}return 0<=e.indexOf(".")?e.length-e.indexOf(".")-1:0}function J(t,e){return 180*Math.atan2(e,t)/Math.PI}function $(e,t){var n,i={};return e.style&&(n=t||V,Object.keys(n).forEach(function(t){i[t]=e.style[t],e.style[t]=n[t]})),i}function tt(t,e,n){return Math.max(Math.min(t,n),e)}function et(i,t){return t.reduce(function(t,e,n){return i[n]&&(t[i[n]]=e),t},{})}function nt(t){void 0===t&&(t=[]);var e=!1,n=!1,i=!1;return t.forEach(function(t){switch(t){case"mouse":n=!0;break;case"touch":e=ct;break;case"pointer":i=dt}}),i?new gt:e&&n?new mt:e?new pt:n?new _t:null}function it(t,e,n){return n?!!(30===e||e&t&&n&t):!!(e&t)}var rt={},st=function(e){var n=e<1?Math.pow(10,Z(e)):1;return function(t){return 0===e?0:Math.round(Math.round(t/e)*e*n)/n}},at=function(){function t(t){var e=t.options,n=t.interruptManager,i=t.eventManager,r=t.axisManager;this._options=e,this.interruptManager=n,this.eventManager=i,this.axisManager=r,this.animationEnd=this.animationEnd.bind(this)}var e=t.prototype;return e.getDuration=function(s,t,e){var n,i,a=this;return i=void 0!==e?e:(n=B(t,function(t,e){return n=Math.abs(t-s[e]),i=a._options.deceleration,(r=Math.sqrt(n/i*2))<100?0:r;var n,i,r}),Object.keys(n).reduce(function(t,e){return Math.max(t,n[e])},-1/0)),tt(i,this._options.minimumDuration,this._options.maximumDuration)},e.getDisplacement=function(t){var e=Math.pow(t.reduce(function(t,e){return t+e*e},0),1/t.length),n=Math.abs(e/-this._options.deceleration);return t.map(function(t){return t/2*n})},e.interpolate=function(t,e){var n=this.easing(1e-5)/1e-5;return this.easing(t/(e*n))*e},e.stopAnimation=function(t,e){var n,i,r;this._animateParam&&t.length&&(n=this.axisManager.get(t),i=this.axisManager.map(n,function(t,e){return f(t,e.range,e.circular)}),q(i,function(t,e){return n[e]===t})||this.eventManager.triggerChange(i,!1,n,e,!!e),this._animateParam=null,this._raf&&(r=this._raf,U(r)),this._raf=null,this.eventManager.triggerAnimationEnd(!(null==e||!e.event)))},e.getEventInfo=function(){return this._animateParam&&this._animateParam.input&&this._animateParam.inputEvent?{input:this._animateParam.input,event:this._animateParam.inputEvent}:null},e.restore=function(t){var e=this.axisManager.get(),n=this.axisManager.map(e,function(t,e){return Math.min(e.range[1],Math.max(e.range[0],t))});this.stopAnimation(Object.keys(this.axisManager.get())),this.animateTo(n,this.getDuration(e,n),t)},e.animationEnd=function(){var t=this.getEventInfo();this._animateParam=null;var e=this.axisManager.filter(this.axisManager.get(),function(t,e){return h(t,e.range,e.circular)});0<Object.keys(e).length&&this.setTo(this.axisManager.map(e,function(t,e){return f(t,e.range,e.circular)})),this.interruptManager.setInterrupt(!1),this.eventManager.triggerAnimationEnd(!!t),this.axisManager.isOutside()?this.restore(t):this.finish(!!t)},e.finish=function(t){this._animateParam=null,this.interruptManager.setInterrupt(!1),this.eventManager.triggerFinish(t)},e.getUserControl=function(t){var e=t.setTo();return e.destPos=this.axisManager.get(e.destPos),e.duration=tt(e.duration,this._options.minimumDuration,this._options.maximumDuration),e},e.animateTo=function(t,e,n){var i,r=this,s=this._createAnimationParam(t,e,n),a=l({},s.depaPos),o=this.eventManager.triggerAnimationStart(s),u=this.getUserControl(s);!o&&this.axisManager.every(u.destPos,function(t,e){return h(t,e.range,e.circular)})&&console.warn("You can't stop the 'animation' event when 'circular' is true."),o&&!Q(u.destPos,a)&&(i=(null==n?void 0:n.event)||null,this._animateLoop({depaPos:a,destPos:u.destPos,duration:u.duration,delta:this.axisManager.getDelta(a,u.destPos),isTrusted:!!i,inputEvent:i,input:(null==n?void 0:n.input)||null},function(){return r.animationEnd()}))},e.easing=function(t){return 1<t?1:this._options.easing(t)},e.setTo=function(t,e){void 0===e&&(e=0);var n=Object.keys(t);this.stopAnimation(n);var i=this.axisManager.get(n);if(Q(t,i))return this;this.interruptManager.setInterrupt(!0);var r=W(t,function(t,e){return i[e]!==t});return Object.keys(r).length?(r=this.axisManager.map(r,function(t,e){var n=e.range,i=e.circular;return i&&(i[0]||i[1])?t:d(t,n,i)}),Q(r,i)||(0<e?this.animateTo(r,e):(this.eventManager.triggerChange(r),this.finish(!1))),this):this},e.setBy=function(n,t){return void 0===t&&(t=0),this.setTo(B(this.axisManager.get(Object.keys(n)),function(t,e){return t+n[e]}),t)},e.updateAnimation=function(t){var e,n,i,r,s,a=this._animateParam;a&&(e=(new Date).getTime()-a.startTime,n=(null==t?void 0:t.destPos)||a.destPos,i=(null==t?void 0:t.duration)||a.duration,null!=t&&t.restart||i<=e?this.setTo(n,i-e):(null!=t&&t.destPos&&(r=this.axisManager.get(),this._initialEasingPer=this._prevEasingPer,a.delta=this.axisManager.getDelta(r,n),a.destPos=n),null!=t&&t.duration&&(s=(e+this._durationOffset)/a.duration,this._durationOffset=s*i-e,a.duration=i)))},e._createAnimationParam=function(t,e,n){var i=this.axisManager.get(),r=t,s=(null==n?void 0:n.event)||null;return{depaPos:i,destPos:r,duration:tt(e,this._options.minimumDuration,this._options.maximumDuration),delta:this.axisManager.getDelta(i,r),inputEvent:s,input:(null==n?void 0:n.input)||null,isTrusted:!!s,done:this.animationEnd}},e._animateLoop=function(n,i){var h,c,r,s,v=this;n.duration?(h=n.depaPos,this._initialEasingPer=0,this._prevEasingPer=0,this._durationOffset=0,this._animateParam=l(l({},n),{startTime:(new Date).getTime()}),c=B(h,function(t,e){return t<=n.destPos[e]?1:-1}),r=B(n.destPos,function(t){return t}),(s=function(){var a=v._animateParam,o=((new Date).getTime()-a.startTime+v._durationOffset)/a.duration,u=v.easing(o);v._raf=null;var t=v.axisManager.map(h,function(t,e,n){var i,r=1<=o?a.destPos[n]:t+a.delta[n]*(u-v._prevEasingPer)/(1-v._initialEasingPer),s=f(r,e.range,e.circular);return r!==s&&(i=c[n]*(e.range[1]-e.range[0]),a.destPos[n]-=i,h[n]-=i),s}),e=!v.eventManager.triggerChange(t,!1,h);if(h=t,1<=(v._prevEasingPer=u))return a.destPos=v._getFinalPos(a.destPos,r),Q(a.destPos,v.axisManager.get(Object.keys(a.destPos)))||v.eventManager.triggerChange(a.destPos,!0,h),void i();e?v.finish(!1):v._raf=K(s)})()):(this.eventManager.triggerChange(n.destPos,!0),i())},e._getFinalPos=function(t,i){var r=this;return B(t,function(t,e){if(t>=i[e]-1e-6&&t<=i[e]+1e-6)return i[e];var n=r._getRoundUnit(t,e);return z(t,n)})},e._getRoundUnit=function(t,e){var n,i,r=this._options.round,s=null;return r||(n=this.axisManager.getAxisOptions(e),i=Math.max(Z(n.range[0]),Z(n.range[1]),Z(t)),s=1/Math.pow(10,i)),s||r},t}(),ot=function(){function t(t){this._axes=t}var e=t.prototype;return e.hold=function(t,e){var n=this._getRoundPos(t).roundPos;this._axes.trigger(new _("hold",{pos:n,input:e.input||null,inputEvent:e.event||null,isTrusted:!0}))},e.triggerRelease=function(t){var e=this._getRoundPos(t.destPos,t.depaPos),n=e.roundPos,i=e.roundDepa;t.destPos=n,t.depaPos=i,t.setTo=this._createUserControll(t.destPos,t.duration),this._axes.trigger(new _("release",l(l({},t),{bounceRatio:this._getBounceRatio(n)})))},e.triggerChange=function(t,e,n,i,r){void 0===r&&(r=!1);var s=this.animationManager,a=s.axisManager,o=s.getEventInfo(),u=this._getRoundPos(t,n),h=u.roundPos,c=u.roundDepa,v=a.moveTo(h,c),l=(null==i?void 0:i.event)||(null==o?void 0:o.event)||null,d={pos:v.pos,delta:v.delta,bounceRatio:this._getBounceRatio(v.pos),holding:r,inputEvent:l,isTrusted:!!l,input:(null==i?void 0:i.input)||(null==o?void 0:o.input)||null,set:l?this._createUserControll(v.pos):function(){}},f=this._axes.trigger(new _("change",d));return l&&a.set(d.set().destPos),f},e.triggerAnimationStart=function(t){var e=this._getRoundPos(t.destPos,t.depaPos),n=e.roundPos,i=e.roundDepa;return t.destPos=n,t.depaPos=i,t.setTo=this._createUserControll(t.destPos,t.duration),this._axes.trigger(new _("animationStart",t))},e.triggerAnimationEnd=function(t){void 0===t&&(t=!1),this._axes.trigger(new _("animationEnd",{isTrusted:t}))},e.triggerFinish=function(t){void 0===t&&(t=!1),this._axes.trigger(new _("finish",{isTrusted:t}))},e.setAnimationManager=function(t){this.animationManager=t},e.destroy=function(){this._axes.off()},e._createUserControll=function(t,e){void 0===e&&(e=0);var n={destPos:l({},t),duration:e};return function(t,e){return t&&(n.destPos=l({},t)),void 0!==e&&(n.duration=e),n}},e._getRoundPos=function(t,e){var n=this._axes.options.round;return{roundPos:G(t,n),roundDepa:G(e,n)}},e._getBounceRatio=function(t){return this._axes.axisManager.map(t,function(t,e){return t<e.range[0]&&0!==e.bounce[0]?(e.range[0]-t)/e.bounce[0]:t>e.range[1]&&0!==e.bounce[1]?(t-e.range[1])/e.bounce[1]:0})},t}(),ut=function(){function t(t){this._options=t,this._prevented=!1}var e=t.prototype;return e.isInterrupting=function(){return this._options.interruptable||this._prevented},e.isInterrupted=function(){return!this._options.interruptable&&this._prevented},e.setInterrupt=function(t){this._options.interruptable||(this._prevented=t)},t}(),ht=function(){function t(t){var n=this;this._axis=t,this._complementOptions(),this._pos=Object.keys(this._axis).reduce(function(t,e){return t[e]=n._axis[e].range[0],t},{})}var e=t.prototype;return e.getDelta=function(t,e){var n=this.get(t);return B(this.get(e),function(t,e){return t-n[e]})},e.get=function(t){var n=this;return t&&Array.isArray(t)?t.reduce(function(t,e){return e&&e in n._pos&&(t[e]=n._pos[e]),t},{}):l(l({},this._pos),t||{})},e.moveTo=function(n,i){void 0===i&&(i=this._pos);var t=B(this._pos,function(t,e){return e in n&&e in i?n[e]-i[e]:0});return this.set(this.map(n,function(t,e){return e?f(t,e.range,e.circular):0})),{pos:l({},this._pos),delta:t}},e.set=function(t){for(var e in t)e&&e in this._pos&&(this._pos[e]=t[e])},e.every=function(t,n){var i=this._axis;return q(t,function(t,e){return n(t,i[e],e)})},e.filter=function(t,n){var i=this._axis;return W(t,function(t,e){return n(t,i[e],e)})},e.map=function(t,n){var i=this._axis;return B(t,function(t,e){return n(t,i[e],e)})},e.isOutside=function(t){return!this.every(t?this.get(t):this._pos,function(t,e){return!u(t,e.range)})},e.getAxisOptions=function(t){return this._axis[t]},e._complementOptions=function(){var r=this;Object.keys(this._axis).forEach(function(i){r._axis[i]=l({range:[0,100],bounce:[0,0],circular:[!1,!1]},r._axis[i]),["bounce","circular"].forEach(function(t){var e=r._axis,n=e[i][t];/string|number|boolean/.test(typeof n)&&(e[i][t]=[n,n])})})},t}(),ct="ontouchstart"in r,vt="PointerEvent"in r,lt="MSPointerEvent"in r,dt=vt||lt,ft=function(){function t(){}var e=t.prototype;return e.extendEvent=function(t){var e=this.prevEvent,n=this._getCenter(t),i=e?this._getMovement(t):{x:0,y:0},r=e?this._getScale(t):1,s=e?J(n.x-e.center.x,n.y-e.center.y):0,a=e?e.deltaX+i.x:i.x,o=e?e.deltaY+i.y:i.y,u=e?a-e.deltaX:0,h=e?o-e.deltaY:0,c=e?t.timeStamp-e.srcEvent.timeStamp:0;return{srcEvent:t,scale:r,angle:s,center:n,deltaX:a,deltaY:o,offsetX:u,offsetY:h,velocityX:e&&0!=c?u/c:0,velocityY:e&&0!=c?h/c:0,preventSystemEvent:!0}},e._getDistance=function(t,e){var n=e.clientX-t.clientX,i=e.clientY-t.clientY;return Math.sqrt(n*n+i*i)},t}(),_t=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.start=["mousedown"],t.move=["mousemove"],t.end=["mouseup"],t}s(t,e);var n=t.prototype;return n.onEventStart=function(t){return this.extendEvent(t)},n.onEventMove=function(t){return this.extendEvent(t)},n.onEventEnd=function(){},n.getTouches=function(){return 0},n._getScale=function(){return 1},n._getCenter=function(t){return{x:t.clientX,y:t.clientY}},n._getMovement=function(t){var e=this.prevEvent.srcEvent;return{x:t.pageX-e.pageX,y:t.pageY-e.pageY}},t}(ft),pt=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.start=["touchstart"],t.move=["touchmove"],t.end=["touchend","touchcancel"],t}s(t,e);var n=t.prototype;return n.onEventStart=function(t){return this._firstTouch=t,this.extendEvent(t)},n.onEventMove=function(t){return this.extendEvent(t)},n.onEventEnd=function(){},n.getTouches=function(t){return t.touches.length},n._getScale=function(t){return 2!==t.touches.length?null:this._getDistance(t.touches[0],t.touches[1])/this._getDistance(this._firstTouch.touches[0],this._firstTouch.touches[1])},n._getCenter=function(t){return{x:t.touches[0].clientX,y:t.touches[0].clientY}},n._getMovement=function(t){var e=this.prevEvent.srcEvent;return t.touches[0].identifier!==e.touches[0].identifier?{x:0,y:0}:{x:t.touches[0].pageX-e.touches[0].pageX,y:t.touches[0].pageY-e.touches[0].pageY}},t}(ft),gt=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.start=vt?["pointerdown"]:["MSPointerDown"],t.move=vt?["pointermove"]:["MSPointerMove"],t.end=vt?["pointerup","pointercancel"]:["MSPointerUp","MSPointerCancel"],t._firstInputs=[],t._recentInputs=[],t}s(t,e);var n=t.prototype;return n.onEventStart=function(t){return this._updatePointerEvent(t),this.extendEvent(t)},n.onEventMove=function(t){return this._updatePointerEvent(t),this.extendEvent(t)},n.onEventEnd=function(t){this._removePointerEvent(t)},n.getTouches=function(){return this._recentInputs.length},n._getScale=function(){return 2!==this._recentInputs.length?null:this._getDistance(this._recentInputs[0],this._recentInputs[1])/this._getDistance(this._firstInputs[0],this._firstInputs[1])},n._getCenter=function(t){return{x:t.clientX,y:t.clientY}},n._getMovement=function(t){var e=this.prevEvent.srcEvent;return t.pointerId!==e.pointerId?{x:0,y:0}:{x:t.pageX-e.pageX,y:t.pageY-e.pageY}},n._updatePointerEvent=function(n){var i=this,r=!1;this._recentInputs.forEach(function(t,e){t.pointerId===n.pointerId&&(r=!0,i._recentInputs[e]=n)}),r||(this._firstInputs.push(n),this._recentInputs.push(n))},n._removePointerEvent=function(e){this._firstInputs=this._firstInputs.filter(function(t){return t.pointerId!==e.pointerId}),this._recentInputs=this._recentInputs.filter(function(t){return t.pointerId!==e.pointerId})},t}(ft),mt=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.start=["mousedown","touchstart"],t.move=["mousemove","touchmove"],t.end=["mouseup","touchend","touchcancel"],t}s(t,e);var n=t.prototype;return n.onEventStart=function(t){return this._firstTouch=t.hasOwnProperty("touches")?t:null,this.extendEvent(t)},n.onEventMove=function(t){return this.extendEvent(t)},n.onEventEnd=function(){},n.getTouches=function(t){return this._isTouchEvent(t)?t.touches.length:0},n._getScale=function(t){return!this._firstTouch||this._isTouchEvent(t)&&2!==t.touches.length?1:this._isTouchEvent(t)?this._getDistance(t.touches[0],t.touches[1])/this._getDistance(this._firstTouch.touches[0],this._firstTouch.touches[1]):this.prevEvent.scale},n._getCenter=function(t){return this._isTouchEvent(t)?{x:t.touches[0].clientX,y:t.touches[0].clientY}:{x:t.clientX,y:t.clientY}},n._getMovement=function(e){var n=this,t=this.prevEvent.srcEvent,i=[e,t].map(function(t){return n._isTouchEvent(e)?{id:t.touches[0].identifier,x:t.touches[0].pageX,y:t.touches[0].pageY}:{id:null,x:t.pageX,y:t.pageY}}),r=i[0],s=i[1];return r.id===s.id?{x:r.x-s.x,y:r.y-s.y}:{x:0,y:0}},n._isTouchEvent=function(t){return t.hasOwnProperty("touches")},t}(ft),Et=function(){function t(t){var e=t.options,n=t.interruptManager,i=t.eventManager,r=t.axisManager,s=t.animationManager;this._isOutside=!1,this._moveDistance=null,this._isStopped=!1,this.options=e,this._interruptManager=n,this._eventManager=i,this._axisManager=r,this._animationManager=s}var e=t.prototype;return e.get=function(t){return this._axisManager.get(t.axes)},e.hold=function(t,e){var n;!this._interruptManager.isInterrupted()&&t.axes.length&&(n={input:t,event:e},this._isStopped=!1,this._interruptManager.setInterrupt(!0),this._animationManager.stopAnimation(t.axes,n),this._moveDistance||this._eventManager.hold(this._axisManager.get(),n),this._isOutside=this._axisManager.isOutside(t.axes),this._moveDistance=this._axisManager.get(t.axes))},e.change=function(t,e,n,i){var r,s,a,o;this._isStopped||!this._interruptManager.isInterrupting()||this._axisManager.every(n,function(t){return 0===t})||(r=this._moveDistance||this._axisManager.get(t.axes),s=B(r,function(t,e){return t+(n[e]||0)}),this._moveDistance&&(this._moveDistance=this._axisManager.map(s,function(t,e){var n=e.circular,i=e.range;return n&&(n[0]||n[1])?f(t,i,n):t})),this._isOutside&&this._axisManager.every(r,function(t,e){return!u(t,e.range)})&&(this._isOutside=!1),r=this._atOutside(r),s=this._atOutside(s),a={input:t,event:e},i?(o=this._animationManager.getDuration(s,r),this._animationManager.stopAnimation(t.axes,a),this._animationManager.animateTo(s,o,a)):this._eventManager.triggerChange(s,!1,r,a,!0)||(this._isStopped=!0,this._moveDistance=null,this._animationManager.finish(!1)))},e.release=function(t,e,n,i){var r,s,a,o,u,h,c,v,l;!this._isStopped&&this._interruptManager.isInterrupting()&&this._moveDistance&&(r=this._axisManager.get(t.axes),s=this._axisManager.get(),a=this._animationManager.getDisplacement(n),o=et(t.axes,a),h={depaPos:s,destPos:u=this._axisManager.get(this._axisManager.map(o,function(t,e,n){return e.circular&&(e.circular[0]||e.circular[1])?r[n]+t:d(r[n]+t,e.range,e.circular,e.bounce)})),duration:this._animationManager.getDuration(u,r,i),delta:this._axisManager.getDelta(s,u),inputEvent:e,input:t,isTrusted:!0},this._eventManager.triggerRelease(h),this._moveDistance=null,c=this._animationManager.getUserControl(h),l={input:t,event:e},(v=Q(c.destPos,s))||0===c.duration?(v||this._eventManager.triggerChange(c.destPos,!1,s,l,!0),this._interruptManager.setInterrupt(!1),this._axisManager.isOutside()?this._animationManager.restore(l):this._eventManager.triggerFinish(!0)):this._animationManager.animateTo(c.destPos,c.duration,l))},e._atOutside=function(t){var a=this;return this._isOutside?this._axisManager.map(t,function(t,e){var n=e.range[0]-e.bounce[0],i=e.range[1]+e.bounce[1];return i<t?i:t<n?n:t}):this._axisManager.map(t,function(t,e){var n=e.range[0],i=e.range[1],r=e.bounce,s=e.circular;return s&&(s[0]||s[1])?t:t<n?n-a._animationManager.interpolate(n-t,r[0]):i<t?i+a._animationManager.interpolate(t-i,r[1]):t})},t}(),bt=function(r){function t(t,e,n){void 0===t&&(t={}),void 0===e&&(e={}),void 0===n&&(n=null);var i=r.call(this)||this;return i.axis=t,i._inputs=[],i.options=l({easing:function(t){return 1-Math.pow(1-t,3)},interruptable:!0,maximumDuration:1/0,minimumDuration:0,deceleration:6e-4,round:null},e),i.interruptManager=new ut(i.options),i.axisManager=new ht(i.axis),i.eventManager=new ot(i),i.animationManager=new at(i),i.inputObserver=new Et(i),i.eventManager.setAnimationManager(i.animationManager),n&&i.eventManager.triggerChange(n),i}s(t,r);var e=t.prototype;return e.connect=function(t,e){var n="string"==typeof t?t.split(" "):t.concat();return~this._inputs.indexOf(e)&&this.disconnect(e),e.mapAxes(n),e.connect(this.inputObserver),this._inputs.push(e),this},e.disconnect=function(t){var e;return t?0<=(e=this._inputs.indexOf(t))&&(this._inputs[e].disconnect(),this._inputs.splice(e,1)):(this._inputs.forEach(function(t){return t.disconnect()}),this._inputs=[]),this},e.get=function(t){return this.axisManager.get(t)},e.setTo=function(t,e){return void 0===e&&(e=0),this.animationManager.setTo(t,e),this},e.setBy=function(t,e){return void 0===e&&(e=0),this.animationManager.setBy(t,e),this},e.stopAnimation=function(){return this.animationManager.stopAnimation(Object.keys(this.axisManager.get())),this},e.updateAnimation=function(t){return this.animationManager.updateAnimation(t),this},e.isBounceArea=function(t){return this.axisManager.isOutside(t)},e.destroy=function(){this.disconnect(),this.eventManager.destroy()},t.VERSION="3.0.0",t.TRANSFORM=N,t.DIRECTION_NONE=1,t.DIRECTION_LEFT=2,t.DIRECTION_RIGHT=4,t.DIRECTION_UP=8,t.DIRECTION_DOWN=16,t.DIRECTION_HORIZONTAL=6,t.DIRECTION_VERTICAL=24,t.DIRECTION_ALL=30,t}(t),xt=function(){function t(t,e){this.axes=[],this.element=null,this._panFlag=!1,this._enabled=!1,this._activeInput=null,this._atRightEdge=!1,this._rightEdgeTimer=0,this.element=H(t),this.options=l({inputType:["touch","mouse","pointer"],scale:[1,1],thresholdAngle:45,threshold:0,iOSEdgeSwipeThreshold:30,releaseOnScroll:!1},e),this._onPanstart=this._onPanstart.bind(this),this._onPanmove=this._onPanmove.bind(this),this._onPanend=this._onPanend.bind(this)}var e=t.prototype;return e.mapAxes=function(t){var e=!!t[0],n=!!t[1];this._direction=e&&n?30:e?6:n?24:1,this.axes=t},e.connect=function(t){return this._activeInput&&this._detachEvent(),this._attachEvent(t),this._originalCssProps=$(this.element),this},e.disconnect=function(){return this._detachEvent(),this._originalCssProps!==V&&$(this.element,this._originalCssProps),this._direction=1,this},e.destroy=function(){this.disconnect(),this.element=null},e.enable=function(){return this._enabled=!0,this},e.disable=function(){return this._enabled=!1,this},e.isEnabled=function(){return this._enabled},e._onPanstart=function(t){var e,n;this._activeInput.onEventStart(t),!this._enabled||1<this._activeInput.getTouches(t)||(e=this._activeInput.extendEvent(t),(this._panFlag=!1)!==e.srcEvent.cancelable&&(n=this.options.iOSEdgeSwipeThreshold,this._observer.hold(this,e),this._atRightEdge=X&&e.center.x>window.innerWidth-n,this._panFlag=!0,this._activeInput.prevEvent=e))},e._onPanmove=function(t){var e=this;if(this._activeInput.onEventMove(t),this._panFlag&&this._enabled&&!(1<this._activeInput.getTouches(t))){var n=this._activeInput.extendEvent(t),i=this.options,r=i.iOSEdgeSwipeThreshold,s=i.releaseOnScroll,a=function(t,e){if(e<0||90<e)return 1;var n=Math.abs(t);return e<n&&n<180-e?24:6}(n.angle,this.options.thresholdAngle);if(!s||n.srcEvent.cancelable){if(this._activeInput.prevEvent&&X){if(n.center.x<0)return void this._observer.release(this,this._activeInput.prevEvent,[0,0]);this._atRightEdge&&(clearTimeout(this._rightEdgeTimer),n.deltaX<-r?this._atRightEdge=!1:this._rightEdgeTimer=window.setTimeout(function(){e._observer.release(e,e._activeInput.prevEvent,[0,0])},100))}var o=this._getOffset([n.offsetX,n.offsetY],[it(6,this._direction,a),it(24,this._direction,a)]),u=o.some(function(t){return 0!==t});u&&(!1!==n.srcEvent.cancelable&&n.srcEvent.preventDefault(),n.srcEvent.stopPropagation()),(n.preventSystemEvent=u)&&this._observer.change(this,n,et(this.axes,o)),this._activeInput.prevEvent=n}else this._onPanend(t)}},e._onPanend=function(t){var e,n;this._activeInput.onEventEnd(t),this._panFlag&&this._enabled&&0===this._activeInput.getTouches(t)&&(this._panFlag=!1,clearTimeout(this._rightEdgeTimer),e=this._activeInput.prevEvent,n=this._getOffset([Math.abs(e.velocityX)*(e.offsetX<0?-1:1),Math.abs(e.velocityY)*(e.offsetY<0?-1:1)],[it(6,this._direction),it(24,this._direction)]),this._observer.release(this,e,n))},e._attachEvent=function(t){var e=this,n=nt(this.options.inputType);this._observer=t,this._enabled=!0,null!=(this._activeInput=n)&&n.start.forEach(function(t){e.element.addEventListener(t,e._onPanstart,!1)}),null!=n&&n.move.forEach(function(t){window.addEventListener(t,e._onPanmove,!1)}),null!=n&&n.end.forEach(function(t){window.addEventListener(t,e._onPanend,!1)})},e._detachEvent=function(){var e=this,t=this._activeInput;null!=t&&t.start.forEach(function(t){e.element.removeEventListener(t,e._onPanstart,!1)}),null!=t&&t.move.forEach(function(t){window.removeEventListener(t,e._onPanmove,!1)}),null!=t&&t.end.forEach(function(t){window.removeEventListener(t,e._onPanend,!1)}),this._enabled=!1,this._observer=null},e._getOffset=function(t,e){var n=[0,0],i=this.options.scale;return e[0]&&(n[0]=t[0]*i[0]),e[1]&&(n[1]=t[1]*i[1]),n},t}(),yt=function(i){function t(t,e){var n=i.call(this,t,e)||this;return n._prevQuadrant=null,n._lastDiff=0,n}s(t,i);var e=t.prototype;return e.mapAxes=function(t){this._direction=bt.DIRECTION_ALL,this.axes=t},e._onPanstart=function(t){var e,n;this._activeInput.onEventStart(t),this.isEnabled&&(e=this.element.getBoundingClientRect(),n=this._activeInput.extendEvent(t),this._observer.hold(this,n),this._panFlag=!0,this._coefficientForDistanceToAngle=360/(e.width*Math.PI),this._rotateOrigin=[e.left+(e.width-1)/2,e.top+(e.height-1)/2],this._prevAngle=null,this._triggerChange(n),this._activeInput.prevEvent=n)},e._onPanmove=function(t){var e;this._activeInput.onEventMove(t),this._panFlag&&this.isEnabled&&(!1!==(e=this._activeInput.extendEvent(t)).srcEvent.cancelable&&e.srcEvent.preventDefault(),e.srcEvent.stopPropagation(),this._triggerChange(e),this._activeInput.prevEvent=e)},e._onPanend=function(t){var e,n,i,r;this._activeInput.onEventEnd(t),this._panFlag&&this.isEnabled&&(e=this._activeInput.prevEvent,this._triggerChange(e),n=e.velocityX,i=e.velocityY,r=Math.sqrt(n*n+i*i)*(0<this._lastDiff?-1:1),this._observer.release(this,e,[r*this._coefficientForDistanceToAngle]),this._panFlag=!1)},e._triggerChange=function(t){var e=this._getPosFromOrigin(t.center.x,t.center.y),n=e.x,i=e.y,r=J(n,i),s=r<0?360+r:r,a=this._getQuadrant(t.center.x,t.center.y),o=this._getDifference(this._prevAngle,s,this._prevQuadrant,a);this._prevAngle=s,this._prevQuadrant=a,0!==o&&(this._lastDiff=o,this._observer.change(this,t,et(this.axes,[-o])))},e._getDifference=function(t,e,n,i){var r=null===t?0:1===n&&4===i?-t-(360-e):4===n&&1===i?360-t+e:e-t;return r},e._getPosFromOrigin=function(t,e){return{x:t-this._rotateOrigin[0],y:this._rotateOrigin[1]-e}},e._getQuadrant=function(t,e){var n=this._getPosFromOrigin(t,e),i=n.x,r=n.y,s=0;return 0<=i&&0<=r?s=1:i<0&&0<=r?s=2:i<0&&r<0?s=3:0<=i&&r<0&&(s=4),s},t}(xt),Mt=function(){function t(t,e){this.axes=[],this.element=null,this._pinchFlag=!1,this._enabled=!1,this._activeInput=null,this.element=H(t),this.options=l({scale:1,threshold:0,inputType:["touch","pointer"]},e),this._onPinchStart=this._onPinchStart.bind(this),this._onPinchMove=this._onPinchMove.bind(this),this._onPinchEnd=this._onPinchEnd.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this._activeInput&&this._detachEvent(),this._attachEvent(t),this._originalCssProps=$(this.element),this},e.disconnect=function(){return this._detachEvent(),this._originalCssProps!==V&&$(this.element,this._originalCssProps),this},e.destroy=function(){this.disconnect(),this.element=null},e.enable=function(){return this._enabled=!0,this},e.disable=function(){return this._enabled=!1,this},e.isEnabled=function(){return this._enabled},e._onPinchStart=function(t){var e;this._activeInput.onEventStart(t),this._enabled&&2===this._activeInput.getTouches(t)&&(this._baseValue=this._observer.get(this)[this.axes[0]],this._observer.hold(this,t),this._pinchFlag=!0,e=this._activeInput.extendEvent(t),this._activeInput.prevEvent=e)},e._onPinchMove=function(t){var e,n;this._activeInput.onEventMove(t),this._pinchFlag&&this._enabled&&2===this._activeInput.getTouches(t)&&(e=this._activeInput.extendEvent(t),n=this._getOffset(e.scale,this._activeInput.prevEvent.scale),this._observer.change(this,t,et(this.axes,[n])),this._activeInput.prevEvent=e)},e._onPinchEnd=function(t){this._activeInput.onEventEnd(t),!this._pinchFlag||!this._enabled||2<this._activeInput.getTouches(t)||(this._observer.release(this,t,[0],0),this._baseValue=null,this._pinchFlag=!1,this._activeInput.prevEvent=null)},e._attachEvent=function(t){var e=this,n=nt(this.options.inputType);this._observer=t,this._enabled=!0,null!=(this._activeInput=n)&&n.start.forEach(function(t){e.element.addEventListener(t,e._onPinchStart,!1)}),null!=n&&n.move.forEach(function(t){e.element.addEventListener(t,e._onPinchMove,!1)}),null!=n&&n.end.forEach(function(t){e.element.addEventListener(t,e._onPinchEnd,!1)})},e._detachEvent=function(){var e=this,t=this._activeInput;null!=t&&t.start.forEach(function(t){e.element.removeEventListener(t,e._onPinchStart,!1)}),null!=t&&t.move.forEach(function(t){e.element.removeEventListener(t,e._onPinchMove,!1)}),null!=t&&t.end.forEach(function(t){e.element.removeEventListener(t,e._onPinchEnd,!1)}),this._enabled=!1,this._observer=null},e._getOffset=function(t,e){return void 0===e&&(e=1),this._baseValue*(t-e)*this.options.scale},t}(),Pt=function(){function t(t,e){this.axes=[],this.element=null,this._enabled=!1,this._holding=!1,this._timer=null,this.element=H(t),this.options=l({scale:1,releaseDelay:300,useNormalized:!0},e),this._onWheel=this._onWheel.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this._detachEvent(),this._attachEvent(t),this},e.disconnect=function(){return this._detachEvent(),this},e.destroy=function(){this.disconnect(),this.element=null},e.enable=function(){return this._enabled=!0,this},e.disable=function(){return this._enabled=!1,this},e.isEnabled=function(){return this._enabled},e._onWheel=function(t){var e,n=this;this._enabled&&(t.preventDefault(),0!==t.deltaY&&(this._holding||(this._observer.hold(this,t),this._holding=!0),e=(0<t.deltaY?-1:1)*this.options.scale*(this.options.useNormalized?1:Math.abs(t.deltaY)),this._observer.change(this,t,et(this.axes,[e]),!0),clearTimeout(this._timer),this._timer=setTimeout(function(){n._holding&&(n._holding=!1,n._observer.release(n,t,[0]))},this.options.releaseDelay)))},e._attachEvent=function(t){this._observer=t,this.element.addEventListener("wheel",this._onWheel),this._enabled=!0},e._detachEvent=function(){this.element.removeEventListener("wheel",this._onWheel),this._enabled=!1,this._observer=null,this._timer&&(clearTimeout(this._timer),this._timer=null)},t}(),wt=function(){function t(t,e){this.axes=[],this.element=null,this._enabled=!1,this._holding=!1,this._timer=null,this.element=H(t),this.options=l({scale:[1,1]},e),this._onKeydown=this._onKeydown.bind(this),this._onKeyup=this._onKeyup.bind(this)}var e=t.prototype;return e.mapAxes=function(t){this.axes=t},e.connect=function(t){return this._detachEvent(),"0"!==this.element.getAttribute("tabindex")&&this.element.setAttribute("tabindex","0"),this._attachEvent(t),this},e.disconnect=function(){return this._detachEvent(),this},e.destroy=function(){this.disconnect(),this.element=null},e.enable=function(){return this._enabled=!0,this},e.disable=function(){return this._enabled=!1,this},e.isEnabled=function(){return this._enabled},e._onKeydown=function(t){if(this._enabled){var e,n=!0,i=1,r=-1;switch(t.keyCode){case 37:case 65:i=-1;break;case 39:case 68:break;case 40:case 83:i=-1,r=1;break;case 38:case 87:r=1;break;default:n=!1}(-1===r&&!this.axes[0]||1===r&&!this.axes[1])&&(n=!1),n&&(t.preventDefault(),e=-1===r?[this.options.scale[0]*i,0]:[0,this.options.scale[1]*i],this._holding||(this._observer.hold(this,t),this._holding=!0),clearTimeout(this._timer),this._observer.change(this,t,et(this.axes,e)))}},e._onKeyup=function(t){var e=this;this._holding&&(clearTimeout(this._timer),this._timer=setTimeout(function(){e._observer.release(e,t,[0,0]),e._holding=!1},80))},e._attachEvent=function(t){this._observer=t,this.element.addEventListener("keydown",this._onKeydown,!1),this.element.addEventListener("keypress",this._onKeydown,!1),this.element.addEventListener("keyup",this._onKeyup,!1),this._enabled=!0},e._detachEvent=function(){this.element.removeEventListener("keydown",this._onKeydown,!1),this.element.removeEventListener("keypress",this._onKeydown,!1),this.element.removeEventListener("keyup",this._onKeyup,!1),this._enabled=!1,this._observer=null},t}();return bt.PanInput=xt,bt.RotatePanInput=yt,bt.PinchInput=Mt,bt.WheelInput=Pt,bt.MoveKeyInput=wt,bt}); | ||
//# sourceMappingURL=axes.pkgd.min.js.map |
@@ -12,14 +12,14 @@ var __assign = (this && this.__assign) || function () { | ||
}; | ||
import { getInsidePosition, isCircularable, getCirculatedPos, getDuration } from "./Coordinate"; | ||
import { requestAnimationFrame, cancelAnimationFrame, map, every, filter, equal, roundNumber, getDecimalPlace, inversePow } from "./utils"; | ||
function minMax(value, min, max) { | ||
import { getInsidePosition, isCircularable, getCirculatedPos, getDuration, } from "./Coordinate"; | ||
import { requestAnimationFrame, cancelAnimationFrame, map, every, filter, equal, roundNumber, getDecimalPlace, inversePow, } from "./utils"; | ||
var clamp = function (value, min, max) { | ||
return Math.max(Math.min(value, max), min); | ||
} | ||
var AnimationManager = /** @class */ (function () { | ||
}; | ||
var AnimationManager = (function () { | ||
function AnimationManager(_a) { | ||
var options = _a.options, itm = _a.itm, em = _a.em, axm = _a.axm; | ||
this.options = options; | ||
this.itm = itm; | ||
this.em = em; | ||
this.axm = axm; | ||
var options = _a.options, interruptManager = _a.interruptManager, eventManager = _a.eventManager, axisManager = _a.axisManager; | ||
this._options = options; | ||
this.interruptManager = interruptManager; | ||
this.eventManager = eventManager; | ||
this.axisManager = axisManager; | ||
this.animationEnd = this.animationEnd.bind(this); | ||
@@ -34,37 +34,39 @@ } | ||
else { | ||
var durations_1 = map(destPos, function (v, k) { return getDuration(Math.abs(v - depaPos[k]), _this.options.deceleration); }); | ||
var durations_1 = map(destPos, function (v, k) { | ||
return getDuration(Math.abs(v - depaPos[k]), _this._options.deceleration); | ||
}); | ||
duration = Object.keys(durations_1).reduce(function (max, v) { return Math.max(max, durations_1[v]); }, -Infinity); | ||
} | ||
return minMax(duration, this.options.minimumDuration, this.options.maximumDuration); | ||
return clamp(duration, this._options.minimumDuration, this._options.maximumDuration); | ||
}; | ||
AnimationManager.prototype.createAnimationParam = function (pos, duration, option) { | ||
var depaPos = this.axm.get(); | ||
var destPos = pos; | ||
var inputEvent = option && option.event || null; | ||
return { | ||
depaPos: depaPos, | ||
destPos: destPos, | ||
duration: minMax(duration, this.options.minimumDuration, this.options.maximumDuration), | ||
delta: this.axm.getDelta(depaPos, destPos), | ||
inputEvent: inputEvent, | ||
input: option && option.input || null, | ||
isTrusted: !!inputEvent, | ||
done: this.animationEnd, | ||
}; | ||
AnimationManager.prototype.getDisplacement = function (velocity) { | ||
var totalVelocity = Math.pow(velocity.reduce(function (total, v) { return total + v * v; }, 0), 1 / velocity.length); | ||
var duration = Math.abs(totalVelocity / -this._options.deceleration); | ||
return velocity.map(function (v) { return (v / 2) * duration; }); | ||
}; | ||
AnimationManager.prototype.grab = function (axes, option) { | ||
AnimationManager.prototype.interpolate = function (displacement, threshold) { | ||
var initSlope = this.easing(0.00001) / 0.00001; | ||
return this.easing(displacement / (threshold * initSlope)) * threshold; | ||
}; | ||
AnimationManager.prototype.stopAnimation = function (axes, option) { | ||
if (this._animateParam && axes.length) { | ||
var orgPos_1 = this.axm.get(axes); | ||
var pos = this.axm.map(orgPos_1, function (v, opt) { return getCirculatedPos(v, opt.range, opt.circular); }); | ||
var orgPos_1 = this.axisManager.get(axes); | ||
var pos = this.axisManager.map(orgPos_1, function (v, opt) { | ||
return getCirculatedPos(v, opt.range, opt.circular); | ||
}); | ||
if (!every(pos, function (v, k) { return orgPos_1[k] === v; })) { | ||
this.em.triggerChange(pos, false, orgPos_1, option, !!option); | ||
this.eventManager.triggerChange(pos, false, orgPos_1, option, !!option); | ||
} | ||
this._animateParam = null; | ||
this._raf && cancelAnimationFrame(this._raf); | ||
if (this._raf) { | ||
cancelAnimationFrame(this._raf); | ||
} | ||
this._raf = null; | ||
this.em.triggerAnimationEnd(!!(option && option.event)); | ||
this.eventManager.triggerAnimationEnd(!!(option === null || option === void 0 ? void 0 : option.event)); | ||
} | ||
}; | ||
AnimationManager.prototype.getEventInfo = function () { | ||
if (this._animateParam && this._animateParam.input && this._animateParam.inputEvent) { | ||
if (this._animateParam && | ||
this._animateParam.input && | ||
this._animateParam.inputEvent) { | ||
return { | ||
@@ -80,4 +82,7 @@ input: this._animateParam.input, | ||
AnimationManager.prototype.restore = function (option) { | ||
var pos = this.axm.get(); | ||
var destPos = this.axm.map(pos, function (v, opt) { return Math.min(opt.range[1], Math.max(opt.range[0], v)); }); | ||
var pos = this.axisManager.get(); | ||
var destPos = this.axisManager.map(pos, function (v, opt) { | ||
return Math.min(opt.range[1], Math.max(opt.range[0], v)); | ||
}); | ||
this.stopAnimation(Object.keys(this.axisManager.get())); | ||
this.animateTo(destPos, this.getDuration(pos, destPos), option); | ||
@@ -88,8 +93,11 @@ }; | ||
this._animateParam = null; | ||
// for Circular | ||
var circularTargets = this.axm.filter(this.axm.get(), function (v, opt) { return isCircularable(v, opt.range, opt.circular); }); | ||
Object.keys(circularTargets).length > 0 && this.setTo(this.axm.map(circularTargets, function (v, opt) { return getCirculatedPos(v, opt.range, opt.circular); })); | ||
this.itm.setInterrupt(false); | ||
this.em.triggerAnimationEnd(!!beforeParam); | ||
if (this.axm.isOutside()) { | ||
var circularTargets = this.axisManager.filter(this.axisManager.get(), function (v, opt) { return isCircularable(v, opt.range, opt.circular); }); | ||
if (Object.keys(circularTargets).length > 0) { | ||
this.setTo(this.axisManager.map(circularTargets, function (v, opt) { | ||
return getCirculatedPos(v, opt.range, opt.circular); | ||
})); | ||
} | ||
this.interruptManager.setInterrupt(false); | ||
this.eventManager.triggerAnimationEnd(!!beforeParam); | ||
if (this.axisManager.isOutside()) { | ||
this.restore(beforeParam); | ||
@@ -103,110 +111,9 @@ } | ||
this._animateParam = null; | ||
this.itm.setInterrupt(false); | ||
this.em.triggerFinish(isTrusted); | ||
this.interruptManager.setInterrupt(false); | ||
this.eventManager.triggerFinish(isTrusted); | ||
}; | ||
AnimationManager.prototype.animateLoop = function (param, complete) { | ||
if (param.duration) { | ||
this._animateParam = __assign({}, param); | ||
var info_1 = this._animateParam; | ||
var self_1 = this; | ||
var destPos_1 = info_1.destPos; | ||
var prevPos_1 = info_1.depaPos; | ||
var prevEasingPer_1 = 0; | ||
var directions_1 = map(prevPos_1, function (value, key) { | ||
return value <= destPos_1[key] ? 1 : -1; | ||
}); | ||
var originalIntendedPos_1 = map(destPos_1, function (v) { return v; }); | ||
var prevTime_1 = new Date().getTime(); | ||
info_1.startTime = prevTime_1; | ||
(function loop() { | ||
self_1._raf = null; | ||
var currentTime = new Date().getTime(); | ||
var ratio = (currentTime - info_1.startTime) / param.duration; | ||
var easingPer = self_1.easing(ratio); | ||
var toPos = self_1.axm.map(prevPos_1, function (pos, options, key) { | ||
var nextPos = ratio >= 1 | ||
? destPos_1[key] | ||
: pos + info_1.delta[key] * (easingPer - prevEasingPer_1); | ||
// Subtract distance from distance already moved. | ||
// Recalculate the remaining distance. | ||
// Fix the bouncing phenomenon by changing the range. | ||
var circulatedPos = getCirculatedPos(nextPos, options.range, options.circular); | ||
if (nextPos !== circulatedPos) { | ||
// circular | ||
var rangeOffset = directions_1[key] * (options.range[1] - options.range[0]); | ||
destPos_1[key] -= rangeOffset; | ||
prevPos_1[key] -= rangeOffset; | ||
} | ||
return circulatedPos; | ||
}); | ||
var isCanceled = !self_1.em.triggerChange(toPos, false, prevPos_1); | ||
prevPos_1 = toPos; | ||
prevTime_1 = currentTime; | ||
prevEasingPer_1 = easingPer; | ||
if (easingPer >= 1) { | ||
destPos_1 = self_1.getFinalPos(destPos_1, originalIntendedPos_1); | ||
if (!equal(destPos_1, self_1.axm.get(Object.keys(destPos_1)))) { | ||
self_1.em.triggerChange(destPos_1, true, prevPos_1); | ||
} | ||
complete(); | ||
return; | ||
} | ||
else if (isCanceled) { | ||
self_1.finish(false); | ||
} | ||
else { | ||
// animationEnd | ||
self_1._raf = requestAnimationFrame(loop); | ||
} | ||
})(); | ||
} | ||
else { | ||
this.em.triggerChange(param.destPos, true); | ||
complete(); | ||
} | ||
}; | ||
/** | ||
* Get estimated final value. | ||
* | ||
* If destPos is within the 'error range' of the original intended position, the initial intended position is returned. | ||
* - eg. original intended pos: 100, destPos: 100.0000000004 ==> return 100; | ||
* If dest Pos is outside the 'range of error' compared to the originally intended pos, it is returned rounded based on the originally intended pos. | ||
* - eg. original intended pos: 100.123 destPos: 50.12345 => return 50.123 | ||
* | ||
* @param originalIntendedPos | ||
* @param destPos | ||
*/ | ||
AnimationManager.prototype.getFinalPos = function (destPos, originalIntendedPos) { | ||
var _this = this; | ||
// compare destPos and originalIntendedPos | ||
var ERROR_LIMIT = 0.000001; | ||
var finalPos = map(destPos, function (value, key) { | ||
if (value >= originalIntendedPos[key] - ERROR_LIMIT && value <= originalIntendedPos[key] + ERROR_LIMIT) { | ||
// In error range, return original intended | ||
return originalIntendedPos[key]; | ||
} | ||
else { | ||
// Out of error range, return rounded pos. | ||
var roundUnit = _this.getRoundUnit(value, key); | ||
var result = roundNumber(value, roundUnit); | ||
return result; | ||
} | ||
}); | ||
return finalPos; | ||
}; | ||
AnimationManager.prototype.getRoundUnit = function (val, key) { | ||
var roundUnit = this.options.round; // manual mode | ||
var minRoundUnit = null; // auto mode | ||
// auto mode | ||
if (!roundUnit) { | ||
// Get minimum round unit | ||
var options = this.axm.getAxisOptions(key); | ||
minRoundUnit = inversePow(Math.max(getDecimalPlace(options.range[0]), getDecimalPlace(options.range[1]), getDecimalPlace(val))); | ||
} | ||
return minRoundUnit || roundUnit; | ||
}; | ||
AnimationManager.prototype.getUserControll = function (param) { | ||
AnimationManager.prototype.getUserControl = function (param) { | ||
var userWish = param.setTo(); | ||
userWish.destPos = this.axm.get(userWish.destPos); | ||
userWish.duration = minMax(userWish.duration, this.options.minimumDuration, this.options.maximumDuration); | ||
userWish.destPos = this.axisManager.get(userWish.destPos); | ||
userWish.duration = clamp(userWish.duration, this._options.minimumDuration, this._options.maximumDuration); | ||
return userWish; | ||
@@ -216,21 +123,22 @@ }; | ||
var _this = this; | ||
var param = this.createAnimationParam(destPos, duration, option); | ||
var param = this._createAnimationParam(destPos, duration, option); | ||
var depaPos = __assign({}, param.depaPos); | ||
var retTrigger = this.em.triggerAnimationStart(param); | ||
// to control | ||
var userWish = this.getUserControll(param); | ||
// You can't stop the 'animationStart' event when 'circular' is true. | ||
if (!retTrigger && this.axm.every(userWish.destPos, function (v, opt) { return isCircularable(v, opt.range, opt.circular); })) { | ||
var retTrigger = this.eventManager.triggerAnimationStart(param); | ||
var userWish = this.getUserControl(param); | ||
if (!retTrigger && | ||
this.axisManager.every(userWish.destPos, function (v, opt) { | ||
return isCircularable(v, opt.range, opt.circular); | ||
})) { | ||
console.warn("You can't stop the 'animation' event when 'circular' is true."); | ||
} | ||
if (retTrigger && !equal(userWish.destPos, depaPos)) { | ||
var inputEvent = option && option.event || null; | ||
this.animateLoop({ | ||
var inputEvent = (option === null || option === void 0 ? void 0 : option.event) || null; | ||
this._animateLoop({ | ||
depaPos: depaPos, | ||
destPos: userWish.destPos, | ||
duration: userWish.duration, | ||
delta: this.axm.getDelta(depaPos, userWish.destPos), | ||
delta: this.axisManager.getDelta(depaPos, userWish.destPos), | ||
isTrusted: !!inputEvent, | ||
inputEvent: inputEvent, | ||
input: option && option.input || null, | ||
input: (option === null || option === void 0 ? void 0 : option.input) || null, | ||
}, function () { return _this.animationEnd(); }); | ||
@@ -240,3 +148,3 @@ } | ||
AnimationManager.prototype.easing = function (p) { | ||
return p > 1 ? 1 : this.options.easing(p); | ||
return p > 1 ? 1 : this._options.easing(p); | ||
}; | ||
@@ -246,8 +154,8 @@ AnimationManager.prototype.setTo = function (pos, duration) { | ||
var axes = Object.keys(pos); | ||
this.grab(axes); | ||
var orgPos = this.axm.get(axes); | ||
this.stopAnimation(axes); | ||
var orgPos = this.axisManager.get(axes); | ||
if (equal(pos, orgPos)) { | ||
return this; | ||
} | ||
this.itm.setInterrupt(true); | ||
this.interruptManager.setInterrupt(true); | ||
var movedPos = filter(pos, function (v, k) { return orgPos[k] !== v; }); | ||
@@ -257,3 +165,3 @@ if (!Object.keys(movedPos).length) { | ||
} | ||
movedPos = this.axm.map(movedPos, function (v, opt) { | ||
movedPos = this.axisManager.map(movedPos, function (v, opt) { | ||
var range = opt.range, circular = opt.circular; | ||
@@ -274,3 +182,3 @@ if (circular && (circular[0] || circular[1])) { | ||
else { | ||
this.em.triggerChange(movedPos); | ||
this.eventManager.triggerChange(movedPos); | ||
this.finish(false); | ||
@@ -282,4 +190,126 @@ } | ||
if (duration === void 0) { duration = 0; } | ||
return this.setTo(map(this.axm.get(Object.keys(pos)), function (v, k) { return v + pos[k]; }), duration); | ||
return this.setTo(map(this.axisManager.get(Object.keys(pos)), function (v, k) { return v + pos[k]; }), duration); | ||
}; | ||
AnimationManager.prototype.updateAnimation = function (options) { | ||
var animateParam = this._animateParam; | ||
if (!animateParam) { | ||
return; | ||
} | ||
var diffTime = new Date().getTime() - animateParam.startTime; | ||
var pos = (options === null || options === void 0 ? void 0 : options.destPos) || animateParam.destPos; | ||
var duration = (options === null || options === void 0 ? void 0 : options.duration) || animateParam.duration; | ||
if ((options === null || options === void 0 ? void 0 : options.restart) || duration <= diffTime) { | ||
this.setTo(pos, duration - diffTime); | ||
return; | ||
} | ||
if (options === null || options === void 0 ? void 0 : options.destPos) { | ||
var currentPos = this.axisManager.get(); | ||
this._initialEasingPer = this._prevEasingPer; | ||
animateParam.delta = this.axisManager.getDelta(currentPos, pos); | ||
animateParam.destPos = pos; | ||
} | ||
if (options === null || options === void 0 ? void 0 : options.duration) { | ||
var ratio = (diffTime + this._durationOffset) / animateParam.duration; | ||
this._durationOffset = ratio * duration - diffTime; | ||
animateParam.duration = duration; | ||
} | ||
}; | ||
AnimationManager.prototype._createAnimationParam = function (pos, duration, option) { | ||
var depaPos = this.axisManager.get(); | ||
var destPos = pos; | ||
var inputEvent = (option === null || option === void 0 ? void 0 : option.event) || null; | ||
return { | ||
depaPos: depaPos, | ||
destPos: destPos, | ||
duration: clamp(duration, this._options.minimumDuration, this._options.maximumDuration), | ||
delta: this.axisManager.getDelta(depaPos, destPos), | ||
inputEvent: inputEvent, | ||
input: (option === null || option === void 0 ? void 0 : option.input) || null, | ||
isTrusted: !!inputEvent, | ||
done: this.animationEnd, | ||
}; | ||
}; | ||
AnimationManager.prototype._animateLoop = function (param, complete) { | ||
var _this = this; | ||
if (param.duration) { | ||
var prevPos_1 = param.depaPos; | ||
this._initialEasingPer = 0; | ||
this._prevEasingPer = 0; | ||
this._durationOffset = 0; | ||
this._animateParam = __assign(__assign({}, param), { startTime: new Date().getTime() }); | ||
var directions_1 = map(prevPos_1, function (value, key) { | ||
return value <= param.destPos[key] ? 1 : -1; | ||
}); | ||
var originalIntendedPos_1 = map(param.destPos, function (v) { return v; }); | ||
var loop_1 = function () { | ||
var animateParam = _this._animateParam; | ||
var diffTime = new Date().getTime() - animateParam.startTime; | ||
var ratio = (diffTime + _this._durationOffset) / animateParam.duration; | ||
var easingPer = _this.easing(ratio); | ||
_this._raf = null; | ||
var toPos = _this.axisManager.map(prevPos_1, function (pos, options, key) { | ||
var nextPos = ratio >= 1 | ||
? animateParam.destPos[key] | ||
: pos + | ||
(animateParam.delta[key] * | ||
(easingPer - _this._prevEasingPer)) / | ||
(1 - _this._initialEasingPer); | ||
var circulatedPos = getCirculatedPos(nextPos, options.range, options.circular); | ||
if (nextPos !== circulatedPos) { | ||
var rangeOffset = directions_1[key] * (options.range[1] - options.range[0]); | ||
animateParam.destPos[key] -= rangeOffset; | ||
prevPos_1[key] -= rangeOffset; | ||
} | ||
return circulatedPos; | ||
}); | ||
var isCanceled = !_this.eventManager.triggerChange(toPos, false, prevPos_1); | ||
prevPos_1 = toPos; | ||
_this._prevEasingPer = easingPer; | ||
if (easingPer >= 1) { | ||
animateParam.destPos = _this._getFinalPos(animateParam.destPos, originalIntendedPos_1); | ||
if (!equal(animateParam.destPos, _this.axisManager.get(Object.keys(animateParam.destPos)))) { | ||
_this.eventManager.triggerChange(animateParam.destPos, true, prevPos_1); | ||
} | ||
complete(); | ||
return; | ||
} | ||
else if (isCanceled) { | ||
_this.finish(false); | ||
} | ||
else { | ||
_this._raf = requestAnimationFrame(loop_1); | ||
} | ||
}; | ||
loop_1(); | ||
} | ||
else { | ||
this.eventManager.triggerChange(param.destPos, true); | ||
complete(); | ||
} | ||
}; | ||
AnimationManager.prototype._getFinalPos = function (destPos, originalIntendedPos) { | ||
var _this = this; | ||
var ERROR_LIMIT = 0.000001; | ||
var finalPos = map(destPos, function (value, key) { | ||
if (value >= originalIntendedPos[key] - ERROR_LIMIT && | ||
value <= originalIntendedPos[key] + ERROR_LIMIT) { | ||
return originalIntendedPos[key]; | ||
} | ||
else { | ||
var roundUnit = _this._getRoundUnit(value, key); | ||
var result = roundNumber(value, roundUnit); | ||
return result; | ||
} | ||
}); | ||
return finalPos; | ||
}; | ||
AnimationManager.prototype._getRoundUnit = function (val, key) { | ||
var roundUnit = this._options.round; | ||
var minRoundUnit = null; | ||
if (!roundUnit) { | ||
var options = this.axisManager.getAxisOptions(key); | ||
minRoundUnit = inversePow(Math.max(getDecimalPlace(options.range[0]), getDecimalPlace(options.range[1]), getDecimalPlace(val))); | ||
} | ||
return minRoundUnit || roundUnit; | ||
}; | ||
return AnimationManager; | ||
@@ -286,0 +316,0 @@ }()); |
@@ -31,96 +31,4 @@ var __extends = (this && this.__extends) || (function () { | ||
import { InputObserver } from "./InputObserver"; | ||
import { TRANSFORM, DIRECTION_NONE, DIRECTION_LEFT, DIRECTION_RIGHT, DIRECTION_UP, DIRECTION_DOWN, DIRECTION_HORIZONTAL, DIRECTION_VERTICAL, DIRECTION_ALL } from "./const"; | ||
/** | ||
* @typedef {Object} AxisOption The Axis information. The key of the axis specifies the name to use as the logical virtual coordinate system. | ||
* @ko 축 정보. 축의 키는 논리적인 가상 좌표계로 사용할 이름을 지정한다. | ||
* @property {Number[]} [range] The coordinate of range <ko>좌표 범위</ko> | ||
* @property {Number} [range.0=0] The coordinate of the minimum <ko>최소 좌표</ko> | ||
* @property {Number} [range.1=0] The coordinate of the maximum <ko>최대 좌표</ko> | ||
* @property {Number[]} [bounce] The size of bouncing area. The coordinates can exceed the coordinate area as much as the bouncing area based on user action. If the coordinates does not exceed the bouncing area when an element is dragged, the coordinates where bouncing effects are applied are retuned back into the coordinate area<ko>바운스 영역의 크기. 사용자의 동작에 따라 좌표가 좌표 영역을 넘어 바운스 영역의 크기만큼 더 이동할 수 있다. 사용자가 끌어다 놓는 동작을 했을 때 좌표가 바운스 영역에 있으면, 바운스 효과가 적용된 좌표가 다시 좌표 영역 안으로 들어온다</ko> | ||
* @property {Number} [bounce.0=0] The size of coordinate of the minimum area <ko>최소 좌표 바운스 영역의 크기</ko> | ||
* @property {Number} [bounce.1=0] The size of coordinate of the maximum area <ko>최대 좌표 바운스 영역의 크기</ko> | ||
* @property {Boolean[]} [circular] Indicates whether a circular element is available. If it is set to "true" and an element is dragged outside the coordinate area, the element will appear on the other side.<ko>순환 여부. 'true'로 설정한 방향의 좌표 영역 밖으로 엘리먼트가 이동하면 반대 방향에서 엘리먼트가 나타난다</ko> | ||
* @property {Boolean} [circular.0=false] Indicates whether to circulate to the coordinate of the minimum <ko>최소 좌표 방향의 순환 여부</ko> | ||
* @property {Boolean} [circular.1=false] Indicates whether to circulate to the coordinate of the maximum <ko>최대 좌표 방향의 순환 여부</ko> | ||
**/ | ||
/** | ||
* @typedef {Object} AxesOption The option object of the eg.Axes module | ||
* @ko eg.Axes 모듈의 옵션 객체 | ||
* @property {Function} [easing=easing.easeOutCubic] The easing function to apply to an animation <ko>애니메이션에 적용할 easing 함수</ko> | ||
* @property {Number} [maximumDuration=Infinity] Maximum duration of the animation <ko>가속도에 의해 애니메이션이 동작할 때의 최대 좌표 이동 시간</ko> | ||
* @property {Number} [minimumDuration=0] Minimum duration of the animation <ko>가속도에 의해 애니메이션이 동작할 때의 최소 좌표 이동 시간</ko> | ||
* @property {Number} [deceleration=0.0006] Deceleration of the animation where acceleration is manually enabled by user. A higher value indicates shorter running time. <ko>사용자의 동작으로 가속도가 적용된 애니메이션의 감속도. 값이 높을수록 애니메이션 실행 시간이 짧아진다</ko> | ||
* @property {Boolean} [interruptable=true] Indicates whether an animation is interruptible.<br>- true: It can be paused or stopped by user action or the API.<br>- false: It cannot be paused or stopped by user action or the API while it is running.<ko>진행 중인 애니메이션 중지 가능 여부.<br>- true: 사용자의 동작이나 API로 애니메이션을 중지할 수 있다.<br>- false: 애니메이션이 진행 중일 때는 사용자의 동작이나 API가 적용되지 않는다</ko> | ||
* @property {Number} [round = null] Rounding unit. For example, 0.1 rounds to 0.1 decimal point(6.1234 => 6.1), 5 rounds to 5 (93 => 95) <br>[Details](https://github.com/naver/egjs-axes/wiki/round-option)<ko>반올림 단위. 예를 들어 0.1 은 소숫점 0.1 까지 반올림(6.1234 => 6.1), 5 는 5 단위로 반올림(93 => 95).<br>[상세내용](https://github.com/naver/egjs-axes/wiki/round-option)</ko> | ||
**/ | ||
/** | ||
* @class eg.Axes | ||
* @classdesc A module used to change the information of user action entered by various input devices such as touch screen or mouse into the logical virtual coordinates. You can easily create a UI that responds to user actions. | ||
* @ko 터치 입력 장치나 마우스와 같은 다양한 입력 장치를 통해 전달 받은 사용자의 동작을 논리적인 가상 좌표로 변경하는 모듈이다. 사용자 동작에 반응하는 UI를 손쉽게 만들수 있다. | ||
* @extends eg.Component | ||
* | ||
* @param {Object.<string, AxisOption>} axis Axis information managed by eg.Axes. The key of the axis specifies the name to use as the logical virtual coordinate system. <ko>eg.Axes가 관리하는 축 정보. 축의 키는 논리적인 가상 좌표계로 사용할 이름을 지정한다.</ko> | ||
* @param {AxesOption} [options] The option object of the eg.Axes module<ko>eg.Axes 모듈의 옵션 객체</ko> | ||
* @param {Object.<string, number>} [startPos] The coordinates to be moved when creating an instance. not triggering change event.<ko>인스턴스 생성시 이동할 좌표, change 이벤트는 발생하지 않음.</ko> | ||
* | ||
* @support {"ie": "10+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"} | ||
* @example | ||
* | ||
* // 1. Initialize eg.Axes | ||
* const axes = new eg.Axes({ | ||
* something1: { | ||
* range: [0, 150], | ||
* bounce: 50 | ||
* }, | ||
* something2: { | ||
* range: [0, 200], | ||
* bounce: 100 | ||
* }, | ||
* somethingN: { | ||
* range: [1, 10], | ||
* } | ||
* }, { | ||
* deceleration : 0.0024 | ||
* }); | ||
* | ||
* // 2. attach event handler | ||
* axes.on({ | ||
* "hold" : function(evt) { | ||
* }, | ||
* "release" : function(evt) { | ||
* }, | ||
* "animationStart" : function(evt) { | ||
* }, | ||
* "animationEnd" : function(evt) { | ||
* }, | ||
* "change" : function(evt) { | ||
* } | ||
* }); | ||
* | ||
* // 3. Initialize inputTypes | ||
* const panInputArea = new eg.Axes.PanInput("#area", { | ||
* scale: [0.5, 1] | ||
* }); | ||
* const panInputHmove = new eg.Axes.PanInput("#hmove"); | ||
* const panInputVmove = new eg.Axes.PanInput("#vmove"); | ||
* const pinchInputArea = new eg.Axes.PinchInput("#area", { | ||
* scale: 1.5 | ||
* }); | ||
* | ||
* // 4. Connect eg.Axes and InputTypes | ||
* // [PanInput] When the mouse or touchscreen is down and moved. | ||
* // Connect the 'something2' axis to the mouse or touchscreen x position and | ||
* // connect the 'somethingN' axis to the mouse or touchscreen y position. | ||
* axes.connect(["something2", "somethingN"], panInputArea); // or axes.connect("something2 somethingN", panInputArea); | ||
* | ||
* // Connect only one 'something1' axis to the mouse or touchscreen x position. | ||
* axes.connect(["something1"], panInputHmove); // or axes.connect("something1", panInputHmove); | ||
* | ||
* // Connect only one 'something2' axis to the mouse or touchscreen y position. | ||
* axes.connect(["", "something2"], panInputVmove); // or axes.connect(" something2", panInputVmove); | ||
* | ||
* // [PinchInput] Connect 'something2' axis when two pointers are moving toward (zoom-in) or away from each other (zoom-out). | ||
* axes.connect("something2", pinchInputArea); | ||
*/ | ||
var Axes = /** @class */ (function (_super) { | ||
import { TRANSFORM, DIRECTION_NONE, DIRECTION_LEFT, DIRECTION_RIGHT, DIRECTION_UP, DIRECTION_DOWN, DIRECTION_HORIZONTAL, DIRECTION_VERTICAL, DIRECTION_ALL, } from "./const"; | ||
var Axes = (function (_super) { | ||
__extends(Axes, _super); | ||
@@ -130,2 +38,3 @@ function Axes(axis, options, startPos) { | ||
if (options === void 0) { options = {}; } | ||
if (startPos === void 0) { startPos = null; } | ||
var _this = _super.call(this) || this; | ||
@@ -135,3 +44,3 @@ _this.axis = axis; | ||
_this.options = __assign({ | ||
easing: function easeOutCubic(x) { | ||
easing: function (x) { | ||
return 1 - Math.pow(1 - x, 3); | ||
@@ -145,35 +54,13 @@ }, | ||
}, options); | ||
_this.itm = new InterruptManager(_this.options); | ||
_this.axm = new AxisManager(_this.axis, _this.options); | ||
_this.em = new EventManager(_this); | ||
_this.am = new AnimationManager(_this); | ||
_this.io = new InputObserver(_this); | ||
_this.em.setAnimationManager(_this.am); | ||
startPos && _this.em.triggerChange(startPos); | ||
_this.interruptManager = new InterruptManager(_this.options); | ||
_this.axisManager = new AxisManager(_this.axis); | ||
_this.eventManager = new EventManager(_this); | ||
_this.animationManager = new AnimationManager(_this); | ||
_this.inputObserver = new InputObserver(_this); | ||
_this.eventManager.setAnimationManager(_this.animationManager); | ||
if (startPos) { | ||
_this.eventManager.triggerChange(startPos); | ||
} | ||
return _this; | ||
} | ||
/** | ||
* Connect the axis of eg.Axes to the inputType. | ||
* @ko eg.Axes의 축과 inputType을 연결한다 | ||
* @method eg.Axes#connect | ||
* @param {(String[]|String)} axes The name of the axis to associate with inputType <ko>inputType과 연결할 축의 이름</ko> | ||
* @param {Object} inputType The inputType instance to associate with the axis of eg.Axes <ko>eg.Axes의 축과 연결할 inputType 인스턴스<ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* } | ||
* }); | ||
* | ||
* axes.connect("x", new eg.Axes.PanInput("#area1")) | ||
* .connect("x xOther", new eg.Axes.PanInput("#area2")) | ||
* .connect(" xOther", new eg.Axes.PanInput("#area3")) | ||
* .connect(["x"], new eg.Axes.PanInput("#area4")) | ||
* .connect(["xOther", "x"], new eg.Axes.PanInput("#area5")) | ||
* .connect(["", "xOther"], new eg.Axes.PanInput("#area6")); | ||
*/ | ||
Axes.prototype.connect = function (axes, inputType) { | ||
@@ -187,45 +74,10 @@ var mapped; | ||
} | ||
// check same instance | ||
if (~this._inputs.indexOf(inputType)) { | ||
this.disconnect(inputType); | ||
} | ||
// check same element in hammer type for share | ||
if ("hammer" in inputType) { | ||
var targets = this._inputs.filter(function (v) { return v.hammer && v.element === inputType.element; }); | ||
if (targets.length) { | ||
inputType.hammer = targets[0].hammer; | ||
} | ||
} | ||
inputType.mapAxes(mapped); | ||
inputType.connect(this.io); | ||
inputType.connect(this.inputObserver); | ||
this._inputs.push(inputType); | ||
return this; | ||
}; | ||
/** | ||
* Disconnect the axis of eg.Axes from the inputType. | ||
* @ko eg.Axes의 축과 inputType의 연결을 끊는다. | ||
* @method eg.Axes#disconnect | ||
* @param {Object} [inputType] An inputType instance associated with the axis of eg.Axes <ko>eg.Axes의 축과 연결한 inputType 인스턴스<ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* } | ||
* }); | ||
* | ||
* const input1 = new eg.Axes.PanInput("#area1"); | ||
* const input2 = new eg.Axes.PanInput("#area2"); | ||
* const input3 = new eg.Axes.PanInput("#area3"); | ||
* | ||
* axes.connect("x", input1); | ||
* .connect("x xOther", input2) | ||
* .connect(["xOther", "x"], input3); | ||
* | ||
* axes.disconnect(input1); // disconnects input1 | ||
* axes.disconnect(); // disconnects all of them | ||
*/ | ||
Axes.prototype.disconnect = function (inputType) { | ||
@@ -245,197 +97,39 @@ if (inputType) { | ||
}; | ||
/** | ||
* Returns the current position of the coordinates. | ||
* @ko 좌표의 현재 위치를 반환한다 | ||
* @method eg.Axes#get | ||
* @param {Object} [axes] The names of the axis <ko>축 이름들</ko> | ||
* @return {Object.<string, number>} Axis coordinate information <ko>축 좌표 정보</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.get(); // {"x": 0, "xOther": -100, "zoom": 50} | ||
* axes.get(["x", "zoom"]); // {"x": 0, "zoom": 50} | ||
*/ | ||
Axes.prototype.get = function (axes) { | ||
return this.axm.get(axes); | ||
return this.axisManager.get(axes); | ||
}; | ||
/** | ||
* Moves an axis to specific coordinates. | ||
* @ko 좌표를 이동한다. | ||
* @method eg.Axes#setTo | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @param {Number} [duration=0] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.setTo({"x": 30, "zoom": 60}); | ||
* axes.get(); // {"x": 30, "xOther": -100, "zoom": 60} | ||
* | ||
* axes.setTo({"x": 100, "xOther": 60}, 1000); // animatation | ||
* | ||
* // after 1000 ms | ||
* axes.get(); // {"x": 100, "xOther": 60, "zoom": 60} | ||
*/ | ||
Axes.prototype.setTo = function (pos, duration) { | ||
if (duration === void 0) { duration = 0; } | ||
this.am.setTo(pos, duration); | ||
this.animationManager.setTo(pos, duration); | ||
return this; | ||
}; | ||
/** | ||
* Moves an axis from the current coordinates to specific coordinates. | ||
* @ko 현재 좌표를 기준으로 좌표를 이동한다. | ||
* @method eg.Axes#setBy | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @param {Number} [duration=0] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.setBy({"x": 30, "zoom": 10}); | ||
* axes.get(); // {"x": 30, "xOther": -100, "zoom": 60} | ||
* | ||
* axes.setBy({"x": 70, "xOther": 60}, 1000); // animatation | ||
* | ||
* // after 1000 ms | ||
* axes.get(); // {"x": 100, "xOther": -40, "zoom": 60} | ||
*/ | ||
Axes.prototype.setBy = function (pos, duration) { | ||
if (duration === void 0) { duration = 0; } | ||
this.am.setBy(pos, duration); | ||
this.animationManager.setBy(pos, duration); | ||
return this; | ||
}; | ||
/** | ||
* Returns whether there is a coordinate in the bounce area of the target axis. | ||
* @ko 대상 축 중 bounce영역에 좌표가 존재하는지를 반환한다 | ||
* @method eg.Axes#isBounceArea | ||
* @param {Object} [axes] The names of the axis <ko>축 이름들</ko> | ||
* @return {Boolen} Whether the bounce area exists. <ko>bounce 영역 존재 여부</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.isBounceArea(["x"]); | ||
* axes.isBounceArea(["x", "zoom"]); | ||
* axes.isBounceArea(); | ||
*/ | ||
Axes.prototype.stopAnimation = function () { | ||
this.animationManager.stopAnimation(Object.keys(this.axisManager.get())); | ||
return this; | ||
}; | ||
Axes.prototype.updateAnimation = function (options) { | ||
this.animationManager.updateAnimation(options); | ||
return this; | ||
}; | ||
Axes.prototype.isBounceArea = function (axes) { | ||
return this.axm.isOutside(axes); | ||
return this.axisManager.isOutside(axes); | ||
}; | ||
/** | ||
* Destroys properties, and events used in a module and disconnect all connections to inputTypes. | ||
* @ko 모듈에 사용한 속성, 이벤트를 해제한다. 모든 inputType과의 연결을 끊는다. | ||
* @method eg.Axes#destroy | ||
*/ | ||
Axes.prototype.destroy = function () { | ||
this.disconnect(); | ||
this.em.destroy(); | ||
this.eventManager.destroy(); | ||
}; | ||
/** | ||
* Version info string | ||
* @ko 버전정보 문자열 | ||
* @name VERSION | ||
* @static | ||
* @type {String} | ||
* @example | ||
* eg.Axes.VERSION; // ex) 3.3.3 | ||
* @memberof eg.Axes | ||
*/ | ||
Axes.VERSION = "#__VERSION__#"; | ||
/** | ||
* @name eg.Axes.TRANSFORM | ||
* @desc Returns the transform attribute with CSS vendor prefixes. | ||
* @ko CSS vendor prefixes를 붙인 transform 속성을 반환한다. | ||
* | ||
* @constant | ||
* @type {String} | ||
* @example | ||
* eg.Axes.TRANSFORM; // "transform" or "webkitTransform" | ||
*/ | ||
Axes.TRANSFORM = TRANSFORM; | ||
/** | ||
* @name eg.Axes.DIRECTION_NONE | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
Axes.DIRECTION_NONE = DIRECTION_NONE; | ||
/** | ||
* @name eg.Axes.DIRECTION_LEFT | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
Axes.DIRECTION_LEFT = DIRECTION_LEFT; | ||
/** | ||
* @name eg.Axes.DIRECTION_RIGHT | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
Axes.DIRECTION_RIGHT = DIRECTION_RIGHT; | ||
/** | ||
* @name eg.Axes.DIRECTION_UP | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
Axes.DIRECTION_UP = DIRECTION_UP; | ||
/** | ||
* @name eg.Axes.DIRECTION_DOWN | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
Axes.DIRECTION_DOWN = DIRECTION_DOWN; | ||
/** | ||
* @name eg.Axes.DIRECTION_HORIZONTAL | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
Axes.DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL; | ||
/** | ||
* @name eg.Axes.DIRECTION_VERTICAL | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
Axes.DIRECTION_VERTICAL = DIRECTION_VERTICAL; | ||
/** | ||
* @name eg.Axes.DIRECTION_ALL | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
Axes.DIRECTION_ALL = DIRECTION_ALL; | ||
@@ -442,0 +136,0 @@ return Axes; |
@@ -14,34 +14,12 @@ var __assign = (this && this.__assign) || function () { | ||
import { map, filter, every } from "./utils"; | ||
var AxisManager = /** @class */ (function () { | ||
function AxisManager(axis, options) { | ||
var AxisManager = (function () { | ||
function AxisManager(_axis) { | ||
var _this = this; | ||
this.axis = axis; | ||
this.options = options; | ||
this._axis = _axis; | ||
this._complementOptions(); | ||
this._pos = Object.keys(this.axis).reduce(function (acc, v) { | ||
acc[v] = _this.axis[v].range[0]; | ||
this._pos = Object.keys(this._axis).reduce(function (acc, v) { | ||
acc[v] = _this._axis[v].range[0]; | ||
return acc; | ||
}, {}); | ||
} | ||
/** | ||
* set up 'css' expression | ||
* @private | ||
*/ | ||
AxisManager.prototype._complementOptions = function () { | ||
var _this = this; | ||
Object.keys(this.axis).forEach(function (axis) { | ||
_this.axis[axis] = __assign({ | ||
range: [0, 100], | ||
bounce: [0, 0], | ||
circular: [false, false], | ||
}, _this.axis[axis]); | ||
["bounce", "circular"].forEach(function (v) { | ||
var axisOption = _this.axis; | ||
var key = axisOption[axis][v]; | ||
if (/string|number|boolean/.test(typeof key)) { | ||
axisOption[axis][v] = [key, key]; | ||
} | ||
}); | ||
}); | ||
}; | ||
AxisManager.prototype.getDelta = function (depaPos, destPos) { | ||
@@ -55,3 +33,3 @@ var fullDepaPos = this.get(depaPos); | ||
return axes.reduce(function (acc, v) { | ||
if (v && (v in _this._pos)) { | ||
if (v && v in _this._pos) { | ||
acc[v] = _this._pos[v]; | ||
@@ -71,3 +49,5 @@ } | ||
}); | ||
this.set(this.map(pos, function (v, opt) { return opt ? getCirculatedPos(v, opt.range, opt.circular) : 0; })); | ||
this.set(this.map(pos, function (v, opt) { | ||
return opt ? getCirculatedPos(v, opt.range, opt.circular) : 0; | ||
})); | ||
return { | ||
@@ -80,3 +60,3 @@ pos: __assign({}, this._pos), | ||
for (var k in pos) { | ||
if (k && (k in this._pos)) { | ||
if (k && k in this._pos) { | ||
this._pos[k] = pos[k]; | ||
@@ -87,12 +67,14 @@ } | ||
AxisManager.prototype.every = function (pos, callback) { | ||
var axisOptions = this.axis; | ||
var axisOptions = this._axis; | ||
return every(pos, function (value, key) { return callback(value, axisOptions[key], key); }); | ||
}; | ||
AxisManager.prototype.filter = function (pos, callback) { | ||
var axisOptions = this.axis; | ||
var axisOptions = this._axis; | ||
return filter(pos, function (value, key) { return callback(value, axisOptions[key], key); }); | ||
}; | ||
AxisManager.prototype.map = function (pos, callback) { | ||
var axisOptions = this.axis; | ||
return map(pos, function (value, key) { return callback(value, axisOptions[key], key); }); | ||
var axisOptions = this._axis; | ||
return map(pos, function (value, key) { | ||
return callback(value, axisOptions[key], key); | ||
}); | ||
}; | ||
@@ -103,4 +85,21 @@ AxisManager.prototype.isOutside = function (axes) { | ||
AxisManager.prototype.getAxisOptions = function (key) { | ||
return this.axis[key]; | ||
return this._axis[key]; | ||
}; | ||
AxisManager.prototype._complementOptions = function () { | ||
var _this = this; | ||
Object.keys(this._axis).forEach(function (axis) { | ||
_this._axis[axis] = __assign({ | ||
range: [0, 100], | ||
bounce: [0, 0], | ||
circular: [false, false], | ||
}, _this._axis[axis]); | ||
["bounce", "circular"].forEach(function (v) { | ||
var axisOption = _this._axis; | ||
var key = axisOption[axis][v]; | ||
if (/string|number|boolean/.test(typeof key)) { | ||
axisOption[axis][v] = [key, key]; | ||
} | ||
}); | ||
}); | ||
}; | ||
return AxisManager; | ||
@@ -107,0 +106,0 @@ }()); |
@@ -1,5 +0,3 @@ | ||
/* eslint-disable no-new-func, no-nested-ternary */ | ||
var win; | ||
if (typeof window === "undefined") { | ||
// window is undefined in node.js | ||
win = { | ||
@@ -14,4 +12,3 @@ navigator: { | ||
} | ||
/* eslint-enable no-new-func, no-nested-ternary */ | ||
export { win as window }; | ||
//# sourceMappingURL=browser.js.map |
@@ -1,10 +0,9 @@ | ||
// export const DIRECTION_NONE = 1; | ||
// export const DIRECTION_LEFT = 2; | ||
// export const DIRECTION_RIGHT = 4; | ||
// export const DIRECTION_HORIZONTAL = 2 | 4; | ||
// export const DIRECTION_UP = 8; | ||
// export const DIRECTION_DOWN = 16; | ||
// export const DIRECTION_VERTICAL = 8 | 16; | ||
// export const DIRECTION_ALL = 2 | 4 | 8 | 16; | ||
export { DIRECTION_NONE, DIRECTION_LEFT, DIRECTION_RIGHT, DIRECTION_UP, DIRECTION_DOWN, DIRECTION_HORIZONTAL, DIRECTION_VERTICAL, DIRECTION_ALL, } from "@egjs/hammerjs"; | ||
export var DIRECTION_NONE = 1; | ||
export var DIRECTION_LEFT = 2; | ||
export var DIRECTION_RIGHT = 4; | ||
export var DIRECTION_HORIZONTAL = 2 | 4; | ||
export var DIRECTION_UP = 8; | ||
export var DIRECTION_DOWN = 16; | ||
export var DIRECTION_VERTICAL = 8 | 16; | ||
export var DIRECTION_ALL = 2 | 4 | 8 | 16; | ||
import getAgent from "@egjs/agent"; | ||
@@ -18,4 +17,10 @@ import { window } from "./browser"; | ||
} | ||
var bodyStyle = (document.head || document.getElementsByTagName("head")[0]).style; | ||
var target = ["transform", "webkitTransform", "msTransform", "mozTransform"]; | ||
var bodyStyle = (document.head || document.getElementsByTagName("head")[0]) | ||
.style; | ||
var target = [ | ||
"transform", | ||
"webkitTransform", | ||
"msTransform", | ||
"mozTransform", | ||
]; | ||
for (var i = 0, len = target.length; i < len; i++) { | ||
@@ -28,2 +33,7 @@ if (target[i] in bodyStyle) { | ||
})(); | ||
export var PREVENT_SCROLL_CSSPROPS = { | ||
"touch-action": "none", | ||
"user-select": "none", | ||
"-webkit-user-drag": "none", | ||
}; | ||
//# sourceMappingURL=const.js.map |
@@ -1,6 +0,6 @@ | ||
export function getInsidePosition(destPos, range, circular, bounce) { | ||
export var getInsidePosition = function (destPos, range, circular, bounce) { | ||
var toDestPos = destPos; | ||
var targetRange = [ | ||
circular[0] ? range[0] : (bounce ? range[0] - bounce[0] : range[0]), | ||
circular[1] ? range[1] : (bounce ? range[1] + bounce[1] : range[1]), | ||
circular[0] ? range[0] : bounce ? range[0] - bounce[0] : range[0], | ||
circular[1] ? range[1] : bounce ? range[1] + bounce[1] : range[1], | ||
]; | ||
@@ -10,17 +10,14 @@ toDestPos = Math.max(targetRange[0], toDestPos); | ||
return toDestPos; | ||
} | ||
// determine outside | ||
export function isOutside(pos, range) { | ||
}; | ||
export var isOutside = function (pos, range) { | ||
return pos < range[0] || pos > range[1]; | ||
} | ||
export function getDuration(distance, deceleration) { | ||
var duration = Math.sqrt(distance / deceleration * 2); | ||
// when duration is under 100, then value is zero | ||
}; | ||
export var getDuration = function (distance, deceleration) { | ||
var duration = Math.sqrt((distance / deceleration) * 2); | ||
return duration < 100 ? 0 : duration; | ||
} | ||
export function isCircularable(destPos, range, circular) { | ||
return (circular[1] && destPos > range[1]) || | ||
(circular[0] && destPos < range[0]); | ||
} | ||
export function getCirculatedPos(pos, range, circular) { | ||
}; | ||
export var isCircularable = function (destPos, range, circular) { | ||
return ((circular[1] && destPos > range[1]) || (circular[0] && destPos < range[0])); | ||
}; | ||
export var getCirculatedPos = function (pos, range, circular) { | ||
var toPos = pos; | ||
@@ -30,10 +27,10 @@ var min = range[0]; | ||
var length = max - min; | ||
if (circular[1] && pos > max) { // right | ||
toPos = (toPos - max) % length + min; | ||
if (circular[1] && pos > max) { | ||
toPos = ((toPos - max) % length) + min; | ||
} | ||
if (circular[0] && pos < min) { // left | ||
toPos = (toPos - min) % length + max; | ||
if (circular[0] && pos < min) { | ||
toPos = ((toPos - min) % length) + max; | ||
} | ||
return toPos; | ||
} | ||
}; | ||
//# sourceMappingURL=Coordinate.js.map |
@@ -12,36 +12,11 @@ var __assign = (this && this.__assign) || function () { | ||
}; | ||
import { ComponentEvent } from "@egjs/component"; | ||
import { roundNumbers } from "./utils"; | ||
var EventManager = /** @class */ (function () { | ||
function EventManager(axes) { | ||
this.axes = axes; | ||
var EventManager = (function () { | ||
function EventManager(_axes) { | ||
this._axes = _axes; | ||
} | ||
/** | ||
* This event is fired when a user holds an element on the screen of the device. | ||
* @ko 사용자가 기기의 화면에 손을 대고 있을 때 발생하는 이벤트 | ||
* @name eg.Axes#hold | ||
* @event | ||
* @type {object} | ||
* @property {Object.<string, number>} pos coordinate <ko>좌표 정보</ko> | ||
* @property {Object} input The instance of inputType where the event occurred<ko>이벤트가 발생한 inputType 인스턴스</ko> | ||
* @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("hold", function(event) { | ||
* // event.pos | ||
* // event.input | ||
* // event.inputEvent | ||
* // isTrusted | ||
* }); | ||
*/ | ||
EventManager.prototype.triggerHold = function (pos, option) { | ||
var roundPos = this.getRoundPos(pos).roundPos; | ||
this.axes.trigger("hold", { | ||
EventManager.prototype.hold = function (pos, option) { | ||
var roundPos = this._getRoundPos(pos).roundPos; | ||
this._axes.trigger(new ComponentEvent("hold", { | ||
pos: roundPos, | ||
@@ -51,237 +26,62 @@ input: option.input || null, | ||
isTrusted: true, | ||
}); | ||
})); | ||
}; | ||
/** | ||
* Specifies the coordinates to move after the 'change' event. It works when the holding value of the change event is true. | ||
* @ko 'change' 이벤트 이후 이동할 좌표를 지정한다. change이벤트의 holding 값이 true일 경우에 동작한다 | ||
* @name set | ||
* @function | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("change", function(event) { | ||
* event.holding && event.set({x: 10}); | ||
* }); | ||
*/ | ||
/** Specifies the animation coordinates to move after the 'release' or 'animationStart' events. | ||
* @ko 'release' 또는 'animationStart' 이벤트 이후 이동할 좌표를 지정한다. | ||
* @name setTo | ||
* @function | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @param {Number} [duration] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("animationStart", function(event) { | ||
* event.setTo({x: 10}, 2000); | ||
* }); | ||
*/ | ||
/** | ||
* This event is fired when a user release an element on the screen of the device. | ||
* @ko 사용자가 기기의 화면에서 손을 뗐을 때 발생하는 이벤트 | ||
* @name eg.Axes#release | ||
* @event | ||
* @type {object} | ||
* @property {Object.<string, number>} depaPos The coordinates when releasing an element<ko>손을 뗐을 때의 좌표 </ko> | ||
* @property {Object.<string, number>} destPos The coordinates to move to after releasing an element<ko>손을 뗀 뒤에 이동할 좌표</ko> | ||
* @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko> | ||
* @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko> | ||
* @property {Object} input The instance of inputType where the event occurred<ko>이벤트가 발생한 inputType 인스턴스</ko> | ||
* @property {setTo} setTo Specifies the animation coordinates to move after the event <ko>이벤트 이후 이동할 애니메이션 좌표를 지정한다</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("release", function(event) { | ||
* // event.depaPos | ||
* // event.destPos | ||
* // event.delta | ||
* // event.input | ||
* // event.inputEvent | ||
* // event.setTo | ||
* // event.isTrusted | ||
* | ||
* // if you want to change the animation coordinates to move after the 'release' event. | ||
* event.setTo({x: 10}, 2000); | ||
* }); | ||
*/ | ||
EventManager.prototype.triggerRelease = function (param) { | ||
var _a = this.getRoundPos(param.destPos, param.depaPos), roundPos = _a.roundPos, roundDepa = _a.roundDepa; | ||
var _a = this._getRoundPos(param.destPos, param.depaPos), roundPos = _a.roundPos, roundDepa = _a.roundDepa; | ||
param.destPos = roundPos; | ||
param.depaPos = roundDepa; | ||
param.setTo = this.createUserControll(param.destPos, param.duration); | ||
this.axes.trigger("release", param); | ||
param.setTo = this._createUserControll(param.destPos, param.duration); | ||
this._axes.trigger(new ComponentEvent("release", __assign(__assign({}, param), { bounceRatio: this._getBounceRatio(roundPos) }))); | ||
}; | ||
/** | ||
* This event is fired when coordinate changes. | ||
* @ko 좌표가 변경됐을 때 발생하는 이벤트 | ||
* @name eg.Axes#change | ||
* @event | ||
* @type {object} | ||
* @property {Object.<string, number>} pos The coordinate <ko>좌표</ko> | ||
* @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko> | ||
* @property {Boolean} holding Indicates whether a user holds an element on the screen of the device.<ko>사용자가 기기의 화면을 누르고 있는지 여부</ko> | ||
* @property {Object} input The instance of inputType where the event occurred. If the value is changed by animation, it returns 'null'.<ko>이벤트가 발생한 inputType 인스턴스. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko> | ||
* @property {Object} inputEvent The event object received from inputType. If the value is changed by animation, it returns 'null'.<ko>inputType으로 부터 받은 이벤트 객체. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko> | ||
* @property {set} set Specifies the coordinates to move after the event. It works when the holding value is true <ko>이벤트 이후 이동할 좌표를 지정한다. holding 값이 true일 경우에 동작한다.</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("change", function(event) { | ||
* // event.pos | ||
* // event.delta | ||
* // event.input | ||
* // event.inputEvent | ||
* // event.holding | ||
* // event.set | ||
* // event.isTrusted | ||
* | ||
* // if you want to change the coordinates to move after the 'change' event. | ||
* // it works when the holding value of the change event is true. | ||
* event.holding && event.set({x: 10}); | ||
* }); | ||
*/ | ||
EventManager.prototype.triggerChange = function (pos, isAccurate, depaPos, option, holding) { | ||
if (holding === void 0) { holding = false; } | ||
var am = this.am; | ||
var axm = am.axm; | ||
var eventInfo = am.getEventInfo(); | ||
var _a = this.getRoundPos(pos, depaPos), roundPos = _a.roundPos, roundDepa = _a.roundDepa; | ||
var moveTo = axm.moveTo(roundPos, roundDepa); | ||
var inputEvent = option && option.event || eventInfo && eventInfo.event || null; | ||
var animationManager = this.animationManager; | ||
var axisManager = animationManager.axisManager; | ||
var eventInfo = animationManager.getEventInfo(); | ||
var _a = this._getRoundPos(pos, depaPos), roundPos = _a.roundPos, roundDepa = _a.roundDepa; | ||
var moveTo = axisManager.moveTo(roundPos, roundDepa); | ||
var inputEvent = (option === null || option === void 0 ? void 0 : option.event) || (eventInfo === null || eventInfo === void 0 ? void 0 : eventInfo.event) || null; | ||
var param = { | ||
pos: moveTo.pos, | ||
delta: moveTo.delta, | ||
bounceRatio: this._getBounceRatio(moveTo.pos), | ||
holding: holding, | ||
inputEvent: inputEvent, | ||
isTrusted: !!inputEvent, | ||
input: option && option.input || eventInfo && eventInfo.input || null, | ||
set: inputEvent ? this.createUserControll(moveTo.pos) : function () { }, | ||
input: (option === null || option === void 0 ? void 0 : option.input) || (eventInfo === null || eventInfo === void 0 ? void 0 : eventInfo.input) || null, | ||
set: inputEvent ? this._createUserControll(moveTo.pos) : function () { }, | ||
}; | ||
var result = this.axes.trigger("change", param); | ||
inputEvent && axm.set(param.set()["destPos"]); | ||
var result = this._axes.trigger(new ComponentEvent("change", param)); | ||
if (inputEvent) { | ||
axisManager.set(param.set().destPos); | ||
} | ||
return result; | ||
}; | ||
/** | ||
* This event is fired when animation starts. | ||
* @ko 에니메이션이 시작할 때 발생한다. | ||
* @name eg.Axes#animationStart | ||
* @event | ||
* @type {object} | ||
* @property {Object.<string, number>} depaPos The coordinates when animation starts<ko>애니메이션이 시작 되었을 때의 좌표 </ko> | ||
* @property {Object.<string, number>} destPos The coordinates to move to. If you change this value, you can run the animation<ko>이동할 좌표. 이값을 변경하여 애니메이션을 동작시킬수 있다</ko> | ||
* @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko> | ||
* @property {Number} duration Duration of the animation (unit: ms). If you change this value, you can control the animation duration time.<ko>애니메이션 진행 시간(단위: ms). 이값을 변경하여 애니메이션의 이동시간을 조절할 수 있다.</ko> | ||
* @property {Object} input The instance of inputType where the event occurred. If the value is changed by animation, it returns 'null'.<ko>이벤트가 발생한 inputType 인스턴스. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko> | ||
* @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko> | ||
* @property {setTo} setTo Specifies the animation coordinates to move after the event <ko>이벤트 이후 이동할 애니메이션 좌표를 지정한다</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("release", function(event) { | ||
* // event.depaPos | ||
* // event.destPos | ||
* // event.delta | ||
* // event.input | ||
* // event.inputEvent | ||
* // event.setTo | ||
* // event.isTrusted | ||
* | ||
* // if you want to change the animation coordinates to move after the 'animationStart' event. | ||
* event.setTo({x: 10}, 2000); | ||
* }); | ||
*/ | ||
EventManager.prototype.triggerAnimationStart = function (param) { | ||
var _a = this.getRoundPos(param.destPos, param.depaPos), roundPos = _a.roundPos, roundDepa = _a.roundDepa; | ||
var _a = this._getRoundPos(param.destPos, param.depaPos), roundPos = _a.roundPos, roundDepa = _a.roundDepa; | ||
param.destPos = roundPos; | ||
param.depaPos = roundDepa; | ||
param.setTo = this.createUserControll(param.destPos, param.duration); | ||
return this.axes.trigger("animationStart", param); | ||
param.setTo = this._createUserControll(param.destPos, param.duration); | ||
return this._axes.trigger(new ComponentEvent("animationStart", param)); | ||
}; | ||
/** | ||
* This event is fired when animation ends. | ||
* @ko 에니메이션이 끝났을 때 발생한다. | ||
* @name eg.Axes#animationEnd | ||
* @event | ||
* @type {object} | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("animationEnd", function(event) { | ||
* // event.isTrusted | ||
* }); | ||
*/ | ||
EventManager.prototype.triggerAnimationEnd = function (isTrusted) { | ||
if (isTrusted === void 0) { isTrusted = false; } | ||
this.axes.trigger("animationEnd", { | ||
this._axes.trigger(new ComponentEvent("animationEnd", { | ||
isTrusted: isTrusted, | ||
}); | ||
})); | ||
}; | ||
/** | ||
* This event is fired when all actions have been completed. | ||
* @ko 에니메이션이 끝났을 때 발생한다. | ||
* @name eg.Axes#finish | ||
* @event | ||
* @type {object} | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("finish", function(event) { | ||
* // event.isTrusted | ||
* }); | ||
*/ | ||
EventManager.prototype.triggerFinish = function (isTrusted) { | ||
if (isTrusted === void 0) { isTrusted = false; } | ||
this.axes.trigger("finish", { | ||
this._axes.trigger(new ComponentEvent("finish", { | ||
isTrusted: isTrusted, | ||
}); | ||
})); | ||
}; | ||
EventManager.prototype.createUserControll = function (pos, duration) { | ||
EventManager.prototype.setAnimationManager = function (animationManager) { | ||
this.animationManager = animationManager; | ||
}; | ||
EventManager.prototype.destroy = function () { | ||
this._axes.off(); | ||
}; | ||
EventManager.prototype._createUserControll = function (pos, duration) { | ||
if (duration === void 0) { duration = 0; } | ||
// to controll | ||
var userControl = { | ||
@@ -292,19 +92,13 @@ destPos: __assign({}, pos), | ||
return function (toPos, userDuration) { | ||
toPos && (userControl.destPos = __assign({}, toPos)); | ||
(userDuration !== undefined) && (userControl.duration = userDuration); | ||
if (toPos) { | ||
userControl.destPos = __assign({}, toPos); | ||
} | ||
if (userDuration !== undefined) { | ||
userControl.duration = userDuration; | ||
} | ||
return userControl; | ||
}; | ||
}; | ||
EventManager.prototype.setAnimationManager = function (am) { | ||
this.am = am; | ||
}; | ||
EventManager.prototype.destroy = function () { | ||
this.axes.off(); | ||
}; | ||
EventManager.prototype.getRoundPos = function (pos, depaPos) { | ||
// round value if round exist | ||
var roundUnit = this.axes.options.round; | ||
// if (round == null) { | ||
// return {pos, depaPos}; // undefined, undefined | ||
// } | ||
EventManager.prototype._getRoundPos = function (pos, depaPos) { | ||
var roundUnit = this._axes.options.round; | ||
return { | ||
@@ -315,2 +109,15 @@ roundPos: roundNumbers(pos, roundUnit), | ||
}; | ||
EventManager.prototype._getBounceRatio = function (pos) { | ||
return this._axes.axisManager.map(pos, function (v, opt) { | ||
if (v < opt.range[0] && opt.bounce[0] !== 0) { | ||
return (opt.range[0] - v) / opt.bounce[0]; | ||
} | ||
else if (v > opt.range[1] && opt.bounce[1] !== 0) { | ||
return (v - opt.range[1]) / opt.bounce[1]; | ||
} | ||
else { | ||
return 0; | ||
} | ||
}); | ||
}; | ||
return EventManager; | ||
@@ -317,0 +124,0 @@ }()); |
@@ -1,63 +0,21 @@ | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
import { isOutside, getInsidePosition } from "./Coordinate"; | ||
import { toAxis } from "./inputType/InputType"; | ||
import { isOutside, getInsidePosition, getCirculatedPos } from "./Coordinate"; | ||
import { map, equal } from "./utils"; | ||
var InputObserver = /** @class */ (function () { | ||
var InputObserver = (function () { | ||
function InputObserver(_a) { | ||
var options = _a.options, itm = _a.itm, em = _a.em, axm = _a.axm, am = _a.am; | ||
this.isOutside = false; | ||
this.moveDistance = null; | ||
this.isStopped = false; | ||
var options = _a.options, interruptManager = _a.interruptManager, eventManager = _a.eventManager, axisManager = _a.axisManager, animationManager = _a.animationManager; | ||
this._isOutside = false; | ||
this._moveDistance = null; | ||
this._isStopped = false; | ||
this.options = options; | ||
this.itm = itm; | ||
this.em = em; | ||
this.axm = axm; | ||
this.am = am; | ||
this._interruptManager = interruptManager; | ||
this._eventManager = eventManager; | ||
this._axisManager = axisManager; | ||
this._animationManager = animationManager; | ||
} | ||
// when move pointer is held in outside | ||
InputObserver.prototype.atOutside = function (pos) { | ||
var _this = this; | ||
if (this.isOutside) { | ||
return this.axm.map(pos, function (v, opt) { | ||
var tn = opt.range[0] - opt.bounce[0]; | ||
var tx = opt.range[1] + opt.bounce[1]; | ||
return v > tx ? tx : (v < tn ? tn : v); | ||
}); | ||
} | ||
else { | ||
// when start pointer is held in inside | ||
// get a initialization slope value to prevent smooth animation. | ||
var initSlope_1 = this.am.easing(0.00001) / 0.00001; | ||
return this.axm.map(pos, function (v, opt) { | ||
var min = opt.range[0]; | ||
var max = opt.range[1]; | ||
var out = opt.bounce; | ||
var circular = opt.circular; | ||
if (circular && (circular[0] || circular[1])) { | ||
return v; | ||
} | ||
else if (v < min) { // left | ||
return min - _this.am.easing((min - v) / (out[0] * initSlope_1)) * out[0]; | ||
} | ||
else if (v > max) { // right | ||
return max + _this.am.easing((v - max) / (out[1] * initSlope_1)) * out[1]; | ||
} | ||
return v; | ||
}); | ||
} | ||
}; | ||
InputObserver.prototype.get = function (input) { | ||
return this.axm.get(input.axes); | ||
return this._axisManager.get(input.axes); | ||
}; | ||
InputObserver.prototype.hold = function (input, event) { | ||
if (this.itm.isInterrupted() || !input.axes.length) { | ||
if (this._interruptManager.isInterrupted() || !input.axes.length) { | ||
return; | ||
@@ -69,42 +27,63 @@ } | ||
}; | ||
this.isStopped = false; | ||
this.itm.setInterrupt(true); | ||
this.am.grab(input.axes, changeOption); | ||
!this.moveDistance && this.em.triggerHold(this.axm.get(), changeOption); | ||
this.isOutside = this.axm.isOutside(input.axes); | ||
this.moveDistance = this.axm.get(input.axes); | ||
this._isStopped = false; | ||
this._interruptManager.setInterrupt(true); | ||
this._animationManager.stopAnimation(input.axes, changeOption); | ||
if (!this._moveDistance) { | ||
this._eventManager.hold(this._axisManager.get(), changeOption); | ||
} | ||
this._isOutside = this._axisManager.isOutside(input.axes); | ||
this._moveDistance = this._axisManager.get(input.axes); | ||
}; | ||
InputObserver.prototype.change = function (input, event, offset) { | ||
if (this.isStopped || !this.itm.isInterrupting() || this.axm.every(offset, function (v) { return v === 0; })) { | ||
InputObserver.prototype.change = function (input, event, offset, useDuration) { | ||
if (this._isStopped || | ||
!this._interruptManager.isInterrupting() || | ||
this._axisManager.every(offset, function (v) { return v === 0; })) { | ||
return; | ||
} | ||
var depaPos = this.moveDistance || this.axm.get(input.axes); | ||
var depaPos = this._moveDistance || this._axisManager.get(input.axes); | ||
var destPos; | ||
// for outside logic | ||
destPos = map(depaPos, function (v, k) { return v + (offset[k] || 0); }); | ||
this.moveDistance && (this.moveDistance = destPos); | ||
// from outside to inside | ||
if (this.isOutside && | ||
this.axm.every(depaPos, function (v, opt) { return !isOutside(v, opt.range); })) { | ||
this.isOutside = false; | ||
if (this._moveDistance) { | ||
this._moveDistance = this._axisManager.map(destPos, function (v, _a) { | ||
var circular = _a.circular, range = _a.range; | ||
return circular && (circular[0] || circular[1]) | ||
? getCirculatedPos(v, range, circular) | ||
: v; | ||
}); | ||
} | ||
depaPos = this.atOutside(depaPos); | ||
destPos = this.atOutside(destPos); | ||
var isCanceled = !this.em.triggerChange(destPos, false, depaPos, { | ||
if (this._isOutside && | ||
this._axisManager.every(depaPos, function (v, opt) { return !isOutside(v, opt.range); })) { | ||
this._isOutside = false; | ||
} | ||
depaPos = this._atOutside(depaPos); | ||
destPos = this._atOutside(destPos); | ||
var changeOption = { | ||
input: input, | ||
event: event, | ||
}, true); | ||
if (isCanceled) { | ||
this.isStopped = true; | ||
this.moveDistance = null; | ||
this.am.finish(false); | ||
}; | ||
if (useDuration) { | ||
var duration = this._animationManager.getDuration(destPos, depaPos); | ||
this._animationManager.stopAnimation(input.axes, changeOption); | ||
this._animationManager.animateTo(destPos, duration, changeOption); | ||
} | ||
else { | ||
var isCanceled = !this._eventManager.triggerChange(destPos, false, depaPos, changeOption, true); | ||
if (isCanceled) { | ||
this._isStopped = true; | ||
this._moveDistance = null; | ||
this._animationManager.finish(false); | ||
} | ||
} | ||
}; | ||
InputObserver.prototype.release = function (input, event, offset, inputDuration) { | ||
if (this.isStopped || !this.itm.isInterrupting() || !this.moveDistance) { | ||
InputObserver.prototype.release = function (input, event, velocity, inputDuration) { | ||
if (this._isStopped || | ||
!this._interruptManager.isInterrupting() || | ||
!this._moveDistance) { | ||
return; | ||
} | ||
var pos = this.axm.get(input.axes); | ||
var depaPos = this.axm.get(); | ||
var destPos = this.axm.get(this.axm.map(offset, function (v, opt, k) { | ||
var pos = this._axisManager.get(input.axes); | ||
var depaPos = this._axisManager.get(); | ||
var displacement = this._animationManager.getDisplacement(velocity); | ||
var offset = toAxis(input.axes, displacement); | ||
var destPos = this._axisManager.get(this._axisManager.map(offset, function (v, opt, k) { | ||
if (opt.circular && (opt.circular[0] || opt.circular[1])) { | ||
@@ -117,7 +96,3 @@ return pos[k] + v; | ||
})); | ||
var duration = this.am.getDuration(destPos, pos, inputDuration); | ||
if (duration === 0) { | ||
destPos = __assign({}, depaPos); | ||
} | ||
// prepare params | ||
var duration = this._animationManager.getDuration(destPos, pos, inputDuration); | ||
var param = { | ||
@@ -127,3 +102,3 @@ depaPos: depaPos, | ||
duration: duration, | ||
delta: this.axm.getDelta(depaPos, destPos), | ||
delta: this._axisManager.getDelta(depaPos, destPos), | ||
inputEvent: event, | ||
@@ -133,6 +108,5 @@ input: input, | ||
}; | ||
this.em.triggerRelease(param); | ||
this.moveDistance = null; | ||
// to contol | ||
var userWish = this.am.getUserControll(param); | ||
this._eventManager.triggerRelease(param); | ||
this._moveDistance = null; | ||
var userWish = this._animationManager.getUserControl(param); | ||
var isEqual = equal(userWish.destPos, depaPos); | ||
@@ -144,15 +118,45 @@ var changeOption = { | ||
if (isEqual || userWish.duration === 0) { | ||
!isEqual && this.em.triggerChange(userWish.destPos, false, depaPos, changeOption, true); | ||
this.itm.setInterrupt(false); | ||
if (this.axm.isOutside()) { | ||
this.am.restore(changeOption); | ||
if (!isEqual) { | ||
this._eventManager.triggerChange(userWish.destPos, false, depaPos, changeOption, true); | ||
} | ||
this._interruptManager.setInterrupt(false); | ||
if (this._axisManager.isOutside()) { | ||
this._animationManager.restore(changeOption); | ||
} | ||
else { | ||
this.em.triggerFinish(true); | ||
this._eventManager.triggerFinish(true); | ||
} | ||
} | ||
else { | ||
this.am.animateTo(userWish.destPos, userWish.duration, changeOption); | ||
this._animationManager.animateTo(userWish.destPos, userWish.duration, changeOption); | ||
} | ||
}; | ||
InputObserver.prototype._atOutside = function (pos) { | ||
var _this = this; | ||
if (this._isOutside) { | ||
return this._axisManager.map(pos, function (v, opt) { | ||
var tn = opt.range[0] - opt.bounce[0]; | ||
var tx = opt.range[1] + opt.bounce[1]; | ||
return v > tx ? tx : v < tn ? tn : v; | ||
}); | ||
} | ||
else { | ||
return this._axisManager.map(pos, function (v, opt) { | ||
var min = opt.range[0]; | ||
var max = opt.range[1]; | ||
var out = opt.bounce; | ||
var circular = opt.circular; | ||
if (circular && (circular[0] || circular[1])) { | ||
return v; | ||
} | ||
else if (v < min) { | ||
return (min - _this._animationManager.interpolate(min - v, out[0])); | ||
} | ||
else if (v > max) { | ||
return (max + _this._animationManager.interpolate(v - max, out[1])); | ||
} | ||
return v; | ||
}); | ||
} | ||
}; | ||
return InputObserver; | ||
@@ -159,0 +163,0 @@ }()); |
@@ -1,18 +0,7 @@ | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
import { Manager, PointerEventInput, TouchMouseInput, TouchInput, MouseInput } from "@egjs/hammerjs"; | ||
import { window } from "../browser"; | ||
export var SUPPORT_POINTER_EVENTS = "PointerEvent" in window || "MSPointerEvent" in window; | ||
export var SUPPORT_TOUCH = "ontouchstart" in window; | ||
export var UNIQUEKEY = "_EGJS_AXES_INPUTTYPE_"; | ||
export function toAxis(source, offset) { | ||
import { MouseEventInput } from "../eventInput/MouseEventInput"; | ||
import { TouchEventInput } from "../eventInput/TouchEventInput"; | ||
import { PointerEventInput } from "../eventInput/PointerEventInput"; | ||
import { TouchMouseEventInput } from "../eventInput/TouchMouseEventInput"; | ||
import { SUPPORT_POINTER_EVENTS, SUPPORT_TOUCH, } from "../eventInput/EventInput"; | ||
export var toAxis = function (source, offset) { | ||
return offset.reduce(function (acc, v, i) { | ||
@@ -24,13 +13,4 @@ if (source[i]) { | ||
}, {}); | ||
} | ||
export function createHammer(element, options) { | ||
try { | ||
// create Hammer | ||
return new Manager(element, __assign({}, options)); | ||
} | ||
catch (e) { | ||
return null; | ||
} | ||
} | ||
export function convertInputType(inputType) { | ||
}; | ||
export var convertInputType = function (inputType) { | ||
if (inputType === void 0) { inputType = []; } | ||
@@ -48,20 +28,20 @@ var hasTouch = false; | ||
break; | ||
case "pointer": hasPointer = SUPPORT_POINTER_EVENTS; | ||
// no default | ||
case "pointer": | ||
hasPointer = SUPPORT_POINTER_EVENTS; | ||
} | ||
}); | ||
if (hasPointer) { | ||
return PointerEventInput; | ||
return new PointerEventInput(); | ||
} | ||
else if (hasTouch && hasMouse) { | ||
return TouchMouseInput; | ||
return new TouchMouseEventInput(); | ||
} | ||
else if (hasTouch) { | ||
return TouchInput; | ||
return new TouchEventInput(); | ||
} | ||
else if (hasMouse) { | ||
return MouseInput; | ||
return new MouseEventInput(); | ||
} | ||
return null; | ||
} | ||
}; | ||
//# sourceMappingURL=InputType.js.map |
@@ -27,31 +27,8 @@ var __assign = (this && this.__assign) || function () { | ||
var DELAY = 80; | ||
/** | ||
* @typedef {Object} MoveKeyInputOption The option object of the eg.Axes.MoveKeyInput module | ||
* @ko eg.Axes.MoveKeyInput 모듈의 옵션 객체 | ||
* @property {Array<Number>} [scale] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
* @property {Number} [scale[0]=1] Coordinate scale for the first axis<ko>첫번째 축의 배율</ko> | ||
* @property {Number} [scale[1]=1] Coordinate scale for the decond axis<ko>두번째 축의 배율</ko> | ||
**/ | ||
/** | ||
* @class eg.Axes.MoveKeyInput | ||
* @classdesc A module that passes the amount of change to eg.Axes when the move key stroke is occured. use two axis. | ||
* @ko 이동키 입력이 발생했을 때의 변화량을 eg.Axes에 전달하는 모듈. 두 개 의 축을 사용한다. | ||
* | ||
* @example | ||
* const moveKey = new eg.Axes.MoveKeyInput("#area", { | ||
* scale: [1, 1] | ||
* }); | ||
* | ||
* // Connect 'x', 'y' axes when the moveKey is pressed. | ||
* axes.connect(["x", "y"], moveKey); | ||
* | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.MoveKeyInput module <ko>eg.Axes.MoveKeyInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {MoveKeyInputOption} [options] The option object of the eg.Axes.MoveKeyInput module<ko>eg.Axes.MoveKeyInput 모듈의 옵션 객체</ko> | ||
*/ | ||
var MoveKeyInput = /** @class */ (function () { | ||
var MoveKeyInput = (function () { | ||
function MoveKeyInput(el, options) { | ||
this.axes = []; | ||
this.element = null; | ||
this._isEnabled = false; | ||
this._isHolded = false; | ||
this._enabled = false; | ||
this._holding = false; | ||
this._timer = null; | ||
@@ -62,4 +39,4 @@ this.element = $(el); | ||
}, options); | ||
this.onKeydown = this.onKeydown.bind(this); | ||
this.onKeyup = this.onKeyup.bind(this); | ||
this._onKeydown = this._onKeydown.bind(this); | ||
this._onKeyup = this._onKeyup.bind(this); | ||
} | ||
@@ -70,19 +47,13 @@ MoveKeyInput.prototype.mapAxes = function (axes) { | ||
MoveKeyInput.prototype.connect = function (observer) { | ||
this.dettachEvent(); | ||
// add tabindex="0" to the container for making it focusable | ||
this._detachEvent(); | ||
if (this.element.getAttribute("tabindex") !== "0") { | ||
this.element.setAttribute("tabindex", "0"); | ||
} | ||
this.attachEvent(observer); | ||
this._attachEvent(observer); | ||
return this; | ||
}; | ||
MoveKeyInput.prototype.disconnect = function () { | ||
this.dettachEvent(); | ||
this._detachEvent(); | ||
return this; | ||
}; | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
* @method eg.Axes.MoveKeyInput#destroy | ||
*/ | ||
MoveKeyInput.prototype.destroy = function () { | ||
@@ -92,4 +63,15 @@ this.disconnect(); | ||
}; | ||
MoveKeyInput.prototype.onKeydown = function (e) { | ||
if (!this._isEnabled) { | ||
MoveKeyInput.prototype.enable = function () { | ||
this._enabled = true; | ||
return this; | ||
}; | ||
MoveKeyInput.prototype.disable = function () { | ||
this._enabled = false; | ||
return this; | ||
}; | ||
MoveKeyInput.prototype.isEnabled = function () { | ||
return this._enabled; | ||
}; | ||
MoveKeyInput.prototype._onKeydown = function (event) { | ||
if (!this._enabled) { | ||
return; | ||
@@ -100,3 +82,3 @@ } | ||
var move = DIRECTION_HORIZONTAL; | ||
switch (e.keyCode) { | ||
switch (event.keyCode) { | ||
case KEY_LEFT_ARROW: | ||
@@ -128,13 +110,16 @@ case KEY_A: | ||
} | ||
var offsets = move === DIRECTION_HORIZONTAL ? [+this.options.scale[0] * direction, 0] : [0, +this.options.scale[1] * direction]; | ||
if (!this._isHolded) { | ||
this.observer.hold(this, event); | ||
this._isHolded = true; | ||
event.preventDefault(); | ||
var offsets = move === DIRECTION_HORIZONTAL | ||
? [+this.options.scale[0] * direction, 0] | ||
: [0, +this.options.scale[1] * direction]; | ||
if (!this._holding) { | ||
this._observer.hold(this, event); | ||
this._holding = true; | ||
} | ||
clearTimeout(this._timer); | ||
this.observer.change(this, event, toAxis(this.axes, offsets)); | ||
this._observer.change(this, event, toAxis(this.axes, offsets)); | ||
}; | ||
MoveKeyInput.prototype.onKeyup = function (e) { | ||
MoveKeyInput.prototype._onKeyup = function (event) { | ||
var _this = this; | ||
if (!this._isHolded) { | ||
if (!this._holding) { | ||
return; | ||
@@ -144,49 +129,20 @@ } | ||
this._timer = setTimeout(function () { | ||
_this.observer.release(_this, e, toAxis(_this.axes, [0, 0])); | ||
_this._isHolded = false; | ||
_this._observer.release(_this, event, [0, 0]); | ||
_this._holding = false; | ||
}, DELAY); | ||
}; | ||
MoveKeyInput.prototype.attachEvent = function (observer) { | ||
this.observer = observer; | ||
this.element.addEventListener("keydown", this.onKeydown, false); | ||
this.element.addEventListener("keypress", this.onKeydown, false); | ||
this.element.addEventListener("keyup", this.onKeyup, false); | ||
this._isEnabled = true; | ||
MoveKeyInput.prototype._attachEvent = function (observer) { | ||
this._observer = observer; | ||
this.element.addEventListener("keydown", this._onKeydown, false); | ||
this.element.addEventListener("keypress", this._onKeydown, false); | ||
this.element.addEventListener("keyup", this._onKeyup, false); | ||
this._enabled = true; | ||
}; | ||
MoveKeyInput.prototype.dettachEvent = function () { | ||
this.element.removeEventListener("keydown", this.onKeydown, false); | ||
this.element.removeEventListener("keypress", this.onKeydown, false); | ||
this.element.removeEventListener("keyup", this.onKeyup, false); | ||
this._isEnabled = false; | ||
this.observer = null; | ||
MoveKeyInput.prototype._detachEvent = function () { | ||
this.element.removeEventListener("keydown", this._onKeydown, false); | ||
this.element.removeEventListener("keypress", this._onKeydown, false); | ||
this.element.removeEventListener("keyup", this._onKeyup, false); | ||
this._enabled = false; | ||
this._observer = null; | ||
}; | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @method eg.Axes.MoveKeyInput#enable | ||
* @return {eg.Axes.MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
MoveKeyInput.prototype.enable = function () { | ||
this._isEnabled = true; | ||
return this; | ||
}; | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @method eg.Axes.MoveKeyInput#disable | ||
* @return {eg.Axes.MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
MoveKeyInput.prototype.disable = function () { | ||
this._isEnabled = false; | ||
return this; | ||
}; | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @method eg.Axes.MoveKeyInput#isEnable | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
MoveKeyInput.prototype.isEnable = function () { | ||
return this._isEnabled; | ||
}; | ||
return MoveKeyInput; | ||
@@ -193,0 +149,0 @@ }()); |
@@ -12,8 +12,6 @@ var __assign = (this && this.__assign) || function () { | ||
}; | ||
import { DIRECTION_ALL, DIRECTION_HORIZONTAL, DIRECTION_NONE, DIRECTION_VERTICAL, Manager, Pan } from "@egjs/hammerjs"; | ||
import { $ } from "../utils"; | ||
import { convertInputType, createHammer, toAxis, UNIQUEKEY } from "./InputType"; | ||
import { IS_IOS_SAFARI, IOS_EDGE_THRESHOLD } from "../const"; | ||
// get user's direction | ||
export function getDirectionByAngle(angle, thresholdAngle) { | ||
import { $, setCssProps } from "../utils"; | ||
import { IS_IOS_SAFARI, IOS_EDGE_THRESHOLD, DIRECTION_NONE, DIRECTION_VERTICAL, DIRECTION_HORIZONTAL, DIRECTION_ALL, PREVENT_SCROLL_CSSPROPS, } from "../const"; | ||
import { convertInputType, toAxis, } from "./InputType"; | ||
export var getDirectionByAngle = function (angle, thresholdAngle) { | ||
if (thresholdAngle < 0 || thresholdAngle > 90) { | ||
@@ -23,17 +21,10 @@ return DIRECTION_NONE; | ||
var toAngle = Math.abs(angle); | ||
return toAngle > thresholdAngle && toAngle < 180 - thresholdAngle ? | ||
DIRECTION_VERTICAL : DIRECTION_HORIZONTAL; | ||
} | ||
export function getNextOffset(speeds, deceleration) { | ||
var normalSpeed = Math.sqrt(speeds[0] * speeds[0] + speeds[1] * speeds[1]); | ||
var duration = Math.abs(normalSpeed / -deceleration); | ||
return [ | ||
speeds[0] / 2 * duration, | ||
speeds[1] / 2 * duration, | ||
]; | ||
} | ||
export function useDirection(checkType, direction, userDirection) { | ||
return toAngle > thresholdAngle && toAngle < 180 - thresholdAngle | ||
? DIRECTION_VERTICAL | ||
: DIRECTION_HORIZONTAL; | ||
}; | ||
export var useDirection = function (checkType, direction, userDirection) { | ||
if (userDirection) { | ||
return !!((direction === DIRECTION_ALL) || | ||
((direction & checkType) && (userDirection & checkType))); | ||
return !!(direction === DIRECTION_ALL || | ||
(direction & checkType && userDirection & checkType)); | ||
} | ||
@@ -43,73 +34,17 @@ else { | ||
} | ||
} | ||
/** | ||
* @typedef {Object} PanInputOption The option object of the eg.Axes.PanInput module. | ||
* @ko eg.Axes.PanInput 모듈의 옵션 객체 | ||
* @property {String[]} [inputType=["touch","mouse", "pointer"]] Types of input devices.<br>- touch: Touch screen<br>- mouse: Mouse <ko>입력 장치 종류.<br>- touch: 터치 입력 장치<br>- mouse: 마우스</ko> | ||
* @property {Number[]} [scale] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
* @property {Number} [scale.0=1] horizontal axis scale <ko>수평축 배율</ko> | ||
* @property {Number} [scale.1=1] vertical axis scale <ko>수직축 배율</ko> | ||
* @property {Number} [thresholdAngle=45] The threshold value that determines whether user action is horizontal or vertical (0~90) <ko>사용자의 동작이 가로 방향인지 세로 방향인지 판단하는 기준 각도(0~90)</ko> | ||
* @property {Number} [threshold=0] Minimal pan distance required before recognizing <ko>사용자의 Pan 동작을 인식하기 위해산 최소한의 거리</ko> | ||
* @property {Number} [iOSEdgeSwipeThreshold=30] Area (px) that can go to the next page when swiping the right edge in iOS safari <ko>iOS Safari에서 오른쪽 엣지를 스와이프 하는 경우 다음 페이지로 넘어갈 수 있는 영역(px)</ko> | ||
* @property {Object} [hammerManagerOptions={cssProps: {userSelect: "none",touchSelect: "none",touchCallout: "none",userDrag: "none"}] Options of Hammer.Manager <ko>Hammer.Manager의 옵션</ko> | ||
**/ | ||
/** | ||
* @class eg.Axes.PanInput | ||
* @classdesc A module that passes the amount of change to eg.Axes when the mouse or touchscreen is down and moved. use less than two axes. | ||
* @ko 마우스나 터치 스크린을 누르고 움직일때의 변화량을 eg.Axes에 전달하는 모듈. 두개 이하의 축을 사용한다. | ||
* | ||
* @example | ||
* const pan = new eg.Axes.PanInput("#area", { | ||
* inputType: ["touch"], | ||
* scale: [1, 1.3], | ||
* }); | ||
* | ||
* // Connect the 'something2' axis to the mouse or touchscreen x position when the mouse or touchscreen is down and moved. | ||
* // Connect the 'somethingN' axis to the mouse or touchscreen y position when the mouse or touchscreen is down and moved. | ||
* axes.connect(["something2", "somethingN"], pan); // or axes.connect("something2 somethingN", pan); | ||
* | ||
* // Connect only one 'something1' axis to the mouse or touchscreen x position when the mouse or touchscreen is down and moved. | ||
* axes.connect(["something1"], pan); // or axes.connect("something1", pan); | ||
* | ||
* // Connect only one 'something2' axis to the mouse or touchscreen y position when the mouse or touchscreen is down and moved. | ||
* axes.connect(["", "something2"], pan); // or axes.connect(" something2", pan); | ||
* | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.PanInput module <ko>eg.Axes.PanInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {PanInputOption} [options] The option object of the eg.Axes.PanInput module<ko>eg.Axes.PanInput 모듈의 옵션 객체</ko> | ||
*/ | ||
var PanInput = /** @class */ (function () { | ||
}; | ||
var PanInput = (function () { | ||
function PanInput(el, options) { | ||
this.axes = []; | ||
this.hammer = null; | ||
this.element = null; | ||
this.panRecognizer = null; | ||
this.isRightEdge = false; | ||
this.rightEdgeTimer = 0; | ||
this.panFlag = false; | ||
/** | ||
* Hammer helps you add support for touch gestures to your page | ||
* | ||
* @external Hammer | ||
* @see {@link http://hammerjs.github.io|Hammer.JS} | ||
* @see {@link http://hammerjs.github.io/jsdoc/Hammer.html|Hammer.JS API documents} | ||
* @see Hammer.JS applies specific CSS properties by {@link http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html|default} when creating an instance. The eg.Axes module removes all default CSS properties provided by Hammer.JS | ||
*/ | ||
if (typeof Manager === "undefined") { | ||
throw new Error("The Hammerjs must be loaded before eg.Axes.PanInput.\nhttp://hammerjs.github.io/"); | ||
} | ||
this._panFlag = false; | ||
this._enabled = false; | ||
this._activeInput = null; | ||
this._atRightEdge = false; | ||
this._rightEdgeTimer = 0; | ||
this.element = $(el); | ||
this.options = __assign({ inputType: ["touch", "mouse", "pointer"], scale: [1, 1], thresholdAngle: 45, threshold: 0, iOSEdgeSwipeThreshold: IOS_EDGE_THRESHOLD, releaseOnScroll: false, hammerManagerOptions: { | ||
// css properties were removed due to usablility issue | ||
// http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html | ||
cssProps: { | ||
userSelect: "none", | ||
touchSelect: "none", | ||
touchCallout: "none", | ||
userDrag: "none", | ||
}, | ||
} }, options); | ||
this.onHammerInput = this.onHammerInput.bind(this); | ||
this.onPanmove = this.onPanmove.bind(this); | ||
this.onPanend = this.onPanend.bind(this); | ||
this.options = __assign({ inputType: ["touch", "mouse", "pointer"], scale: [1, 1], thresholdAngle: 45, threshold: 0, iOSEdgeSwipeThreshold: IOS_EDGE_THRESHOLD, releaseOnScroll: false }, options); | ||
this._onPanstart = this._onPanstart.bind(this); | ||
this._onPanmove = this._onPanmove.bind(this); | ||
this._onPanend = this._onPanend.bind(this); | ||
} | ||
@@ -134,34 +69,13 @@ PanInput.prototype.mapAxes = function (axes) { | ||
PanInput.prototype.connect = function (observer) { | ||
var hammerOption = { | ||
direction: this._direction, | ||
threshold: this.options.threshold, | ||
}; | ||
if (this.hammer) { // for sharing hammer instance. | ||
// hammer remove previous PanRecognizer. | ||
this.removeRecognizer(); | ||
this.dettachEvent(); | ||
if (this._activeInput) { | ||
this._detachEvent(); | ||
} | ||
else { | ||
var keyValue = this.element[UNIQUEKEY]; | ||
if (!keyValue) { | ||
keyValue = String(Math.round(Math.random() * new Date().getTime())); | ||
} | ||
var inputClass = convertInputType(this.options.inputType); | ||
if (!inputClass) { | ||
throw new Error("Wrong inputType parameter!"); | ||
} | ||
this.hammer = createHammer(this.element, __assign({ | ||
inputClass: inputClass, | ||
}, this.options.hammerManagerOptions)); | ||
this.element[UNIQUEKEY] = keyValue; | ||
} | ||
this.panRecognizer = new Pan(hammerOption); | ||
this.hammer.add(this.panRecognizer); | ||
this.attachEvent(observer); | ||
this._attachEvent(observer); | ||
this._originalCssProps = setCssProps(this.element); | ||
return this; | ||
}; | ||
PanInput.prototype.disconnect = function () { | ||
this.removeRecognizer(); | ||
if (this.hammer) { | ||
this.dettachEvent(); | ||
this._detachEvent(); | ||
if (this._originalCssProps !== PREVENT_SCROLL_CSSPROPS) { | ||
setCssProps(this.element, this._originalCssProps); | ||
} | ||
@@ -171,98 +85,63 @@ this._direction = DIRECTION_NONE; | ||
}; | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
* @method eg.Axes.PanInput#destroy | ||
*/ | ||
PanInput.prototype.destroy = function () { | ||
this.disconnect(); | ||
if (this.hammer && this.hammer.recognizers.length === 0) { | ||
this.hammer.destroy(); | ||
} | ||
delete this.element[UNIQUEKEY]; | ||
this.element = null; | ||
this.hammer = null; | ||
}; | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @method eg.Axes.PanInput#enable | ||
* @return {eg.Axes.PanInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
PanInput.prototype.enable = function () { | ||
this.hammer && (this.hammer.get("pan").options.enable = true); | ||
this._enabled = true; | ||
return this; | ||
}; | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @method eg.Axes.PanInput#disable | ||
* @return {eg.Axes.PanInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
PanInput.prototype.disable = function () { | ||
this.hammer && (this.hammer.get("pan").options.enable = false); | ||
this._enabled = false; | ||
return this; | ||
}; | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @method eg.Axes.PanInput#isEnable | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
PanInput.prototype.isEnable = function () { | ||
return !!(this.hammer && this.hammer.get("pan").options.enable); | ||
PanInput.prototype.isEnabled = function () { | ||
return this._enabled; | ||
}; | ||
PanInput.prototype.removeRecognizer = function () { | ||
if (this.hammer && this.panRecognizer) { | ||
this.hammer.remove(this.panRecognizer); | ||
this.panRecognizer = null; | ||
PanInput.prototype._onPanstart = function (event) { | ||
this._activeInput.onEventStart(event); | ||
if (!this._enabled || this._activeInput.getTouches(event) > 1) { | ||
return; | ||
} | ||
}; | ||
PanInput.prototype.onHammerInput = function (event) { | ||
if (this.isEnable()) { | ||
if (event.isFirst) { | ||
this.panFlag = false; | ||
if (event.srcEvent.cancelable !== false) { | ||
var edgeThreshold = this.options.iOSEdgeSwipeThreshold; | ||
this.observer.hold(this, event); | ||
this.isRightEdge = IS_IOS_SAFARI && event.center.x > window.innerWidth - edgeThreshold; | ||
this.panFlag = true; | ||
} | ||
} | ||
else if (event.isFinal) { | ||
this.onPanend(event); | ||
} | ||
var panEvent = this._activeInput.extendEvent(event); | ||
this._panFlag = false; | ||
if (panEvent.srcEvent.cancelable !== false) { | ||
var edgeThreshold = this.options.iOSEdgeSwipeThreshold; | ||
this._observer.hold(this, panEvent); | ||
this._atRightEdge = | ||
IS_IOS_SAFARI && panEvent.center.x > window.innerWidth - edgeThreshold; | ||
this._panFlag = true; | ||
this._activeInput.prevEvent = panEvent; | ||
} | ||
}; | ||
PanInput.prototype.onPanmove = function (event) { | ||
PanInput.prototype._onPanmove = function (event) { | ||
var _this = this; | ||
if (!this.panFlag) { | ||
this._activeInput.onEventMove(event); | ||
if (!this._panFlag || | ||
!this._enabled || | ||
this._activeInput.getTouches(event) > 1) { | ||
return; | ||
} | ||
var panEvent = this._activeInput.extendEvent(event); | ||
var _a = this.options, iOSEdgeSwipeThreshold = _a.iOSEdgeSwipeThreshold, releaseOnScroll = _a.releaseOnScroll; | ||
var userDirection = getDirectionByAngle(event.angle, this.options.thresholdAngle); | ||
// not support offset properties in Hammerjs - start | ||
var prevInput = this.hammer.session.prevInput; | ||
if (releaseOnScroll && !event.srcEvent.cancelable) { | ||
this.onPanend(__assign(__assign({}, event), { velocityX: 0, velocityY: 0, offsetX: 0, offsetY: 0 })); | ||
var userDirection = getDirectionByAngle(panEvent.angle, this.options.thresholdAngle); | ||
if (releaseOnScroll && !panEvent.srcEvent.cancelable) { | ||
this._onPanend(event); | ||
return; | ||
} | ||
if (prevInput && IS_IOS_SAFARI) { | ||
var swipeLeftToRight = event.center.x < 0; | ||
if (this._activeInput.prevEvent && IS_IOS_SAFARI) { | ||
var swipeLeftToRight = panEvent.center.x < 0; | ||
if (swipeLeftToRight) { | ||
// iOS swipe left => right | ||
this.onPanend(__assign(__assign({}, prevInput), { velocityX: 0, velocityY: 0, offsetX: 0, offsetY: 0 })); | ||
this._observer.release(this, this._activeInput.prevEvent, [0, 0]); | ||
return; | ||
} | ||
else if (this.isRightEdge) { | ||
clearTimeout(this.rightEdgeTimer); | ||
// - is right to left | ||
var swipeRightToLeft = event.deltaX < -iOSEdgeSwipeThreshold; | ||
else if (this._atRightEdge) { | ||
clearTimeout(this._rightEdgeTimer); | ||
var swipeRightToLeft = panEvent.deltaX < -iOSEdgeSwipeThreshold; | ||
if (swipeRightToLeft) { | ||
this.isRightEdge = false; | ||
this._atRightEdge = false; | ||
} | ||
else { | ||
// iOS swipe right => left | ||
this.rightEdgeTimer = window.setTimeout(function () { | ||
_this.onPanend(__assign(__assign({}, prevInput), { velocityX: 0, velocityY: 0, offsetX: 0, offsetY: 0 })); | ||
this._rightEdgeTimer = window.setTimeout(function () { | ||
_this._observer.release(_this, _this._activeInput.prevEvent, [0, 0]); | ||
}, 100); | ||
@@ -272,12 +151,3 @@ } | ||
} | ||
/* eslint-disable no-param-reassign */ | ||
if (prevInput) { | ||
event.offsetX = event.deltaX - prevInput.deltaX; | ||
event.offsetY = event.deltaY - prevInput.deltaY; | ||
} | ||
else { | ||
event.offsetX = 0; | ||
event.offsetY = 0; | ||
} | ||
var offset = this.getOffset([event.offsetX, event.offsetY], [ | ||
var offset = this._getOffset([panEvent.offsetX, panEvent.offsetY], [ | ||
useDirection(DIRECTION_HORIZONTAL, this._direction, userDirection), | ||
@@ -288,20 +158,26 @@ useDirection(DIRECTION_VERTICAL, this._direction, userDirection), | ||
if (prevent) { | ||
var srcEvent = event.srcEvent; | ||
if (srcEvent.cancelable !== false) { | ||
srcEvent.preventDefault(); | ||
if (panEvent.srcEvent.cancelable !== false) { | ||
panEvent.srcEvent.preventDefault(); | ||
} | ||
srcEvent.stopPropagation(); | ||
panEvent.srcEvent.stopPropagation(); | ||
} | ||
event.preventSystemEvent = prevent; | ||
prevent && this.observer.change(this, event, toAxis(this.axes, offset)); | ||
panEvent.preventSystemEvent = prevent; | ||
if (prevent) { | ||
this._observer.change(this, panEvent, toAxis(this.axes, offset)); | ||
} | ||
this._activeInput.prevEvent = panEvent; | ||
}; | ||
PanInput.prototype.onPanend = function (event) { | ||
if (!this.panFlag) { | ||
PanInput.prototype._onPanend = function (event) { | ||
this._activeInput.onEventEnd(event); | ||
if (!this._panFlag || | ||
!this._enabled || | ||
this._activeInput.getTouches(event) !== 0) { | ||
return; | ||
} | ||
clearTimeout(this.rightEdgeTimer); | ||
this.panFlag = false; | ||
var offset = this.getOffset([ | ||
Math.abs(event.velocityX) * (event.deltaX < 0 ? -1 : 1), | ||
Math.abs(event.velocityY) * (event.deltaY < 0 ? -1 : 1), | ||
this._panFlag = false; | ||
clearTimeout(this._rightEdgeTimer); | ||
var prevEvent = this._activeInput.prevEvent; | ||
var velocity = this._getOffset([ | ||
Math.abs(prevEvent.velocityX) * (prevEvent.offsetX < 0 ? -1 : 1), | ||
Math.abs(prevEvent.velocityY) * (prevEvent.offsetY < 0 ? -1 : 1), | ||
], [ | ||
@@ -311,23 +187,43 @@ useDirection(DIRECTION_HORIZONTAL, this._direction), | ||
]); | ||
offset = getNextOffset(offset, this.observer.options.deceleration); | ||
this.observer.release(this, event, toAxis(this.axes, offset)); | ||
this._observer.release(this, prevEvent, velocity); | ||
}; | ||
PanInput.prototype.attachEvent = function (observer) { | ||
this.observer = observer; | ||
this.hammer.on("hammer.input", this.onHammerInput) | ||
.on("panstart panmove", this.onPanmove); | ||
PanInput.prototype._attachEvent = function (observer) { | ||
var _this = this; | ||
var activeInput = convertInputType(this.options.inputType); | ||
this._observer = observer; | ||
this._enabled = true; | ||
this._activeInput = activeInput; | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.start.forEach(function (event) { | ||
_this.element.addEventListener(event, _this._onPanstart, false); | ||
}); | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.move.forEach(function (event) { | ||
window.addEventListener(event, _this._onPanmove, false); | ||
}); | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.end.forEach(function (event) { | ||
window.addEventListener(event, _this._onPanend, false); | ||
}); | ||
}; | ||
PanInput.prototype.dettachEvent = function () { | ||
this.hammer.off("hammer.input", this.onHammerInput) | ||
.off("panstart panmove", this.onPanmove); | ||
this.observer = null; | ||
PanInput.prototype._detachEvent = function () { | ||
var _this = this; | ||
var activeInput = this._activeInput; | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.start.forEach(function (event) { | ||
_this.element.removeEventListener(event, _this._onPanstart, false); | ||
}); | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.move.forEach(function (event) { | ||
window.removeEventListener(event, _this._onPanmove, false); | ||
}); | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.end.forEach(function (event) { | ||
window.removeEventListener(event, _this._onPanend, false); | ||
}); | ||
this._enabled = false; | ||
this._observer = null; | ||
}; | ||
PanInput.prototype.getOffset = function (properties, direction) { | ||
PanInput.prototype._getOffset = function (properties, direction) { | ||
var offset = [0, 0]; | ||
var scale = this.options.scale; | ||
if (direction[0]) { | ||
offset[0] = (properties[0] * scale[0]); | ||
offset[0] = properties[0] * scale[0]; | ||
} | ||
if (direction[1]) { | ||
offset[1] = (properties[1] * scale[1]); | ||
offset[1] = properties[1] * scale[1]; | ||
} | ||
@@ -334,0 +230,0 @@ return offset; |
@@ -12,65 +12,17 @@ var __assign = (this && this.__assign) || function () { | ||
}; | ||
import { Manager, Pinch } from "@egjs/hammerjs"; | ||
import { $ } from "../utils"; | ||
import { UNIQUEKEY, toAxis, convertInputType, createHammer } from "./InputType"; | ||
/** | ||
* @typedef {Object} PinchInputOption The option object of the eg.Axes.PinchInput module | ||
* @ko eg.Axes.PinchInput 모듈의 옵션 객체 | ||
* @property {Number} [scale=1] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
* @property {Number} [threshold=0] Minimal scale before recognizing <ko>사용자의 Pinch 동작을 인식하기 위해산 최소한의 배율</ko> | ||
* @property {Object} [hammerManagerOptions={cssProps: {userSelect: "none",touchSelect: "none",touchCallout: "none",userDrag: "none"}] Options of Hammer.Manager <ko>Hammer.Manager의 옵션</ko> | ||
**/ | ||
/** | ||
* @class eg.Axes.PinchInput | ||
* @classdesc A module that passes the amount of change to eg.Axes when two pointers are moving toward (zoom-in) or away from each other (zoom-out). use one axis. | ||
* @ko 2개의 pointer를 이용하여 zoom-in하거나 zoom-out 하는 동작의 변화량을 eg.Axes에 전달하는 모듈. 한 개 의 축을 사용한다. | ||
* @example | ||
* const pinch = new eg.Axes.PinchInput("#area", { | ||
* scale: 1 | ||
* }); | ||
* | ||
* // Connect 'something' axis when two pointers are moving toward (zoom-in) or away from each other (zoom-out). | ||
* axes.connect("something", pinch); | ||
* | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.PinchInput module <ko>eg.Axes.PinchInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {PinchInputOption} [options] The option object of the eg.Axes.PinchInput module<ko>eg.Axes.PinchInput 모듈의 옵션 객체</ko> | ||
*/ | ||
var PinchInput = /** @class */ (function () { | ||
import { $, setCssProps } from "../utils"; | ||
import { PREVENT_SCROLL_CSSPROPS } from "../const"; | ||
import { toAxis, convertInputType, } from "./InputType"; | ||
var PinchInput = (function () { | ||
function PinchInput(el, options) { | ||
this.axes = []; | ||
this.hammer = null; | ||
this.element = null; | ||
this._base = null; | ||
this._prev = null; | ||
this.pinchRecognizer = null; | ||
/** | ||
* Hammer helps you add support for touch gestures to your page | ||
* | ||
* @external Hammer | ||
* @see {@link http://hammerjs.github.io|Hammer.JS} | ||
* @see {@link http://hammerjs.github.io/jsdoc/Hammer.html|Hammer.JS API documents} | ||
* @see Hammer.JS applies specific CSS properties by {@link http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html|default} when creating an instance. The eg.Axes module removes all default CSS properties provided by Hammer.JS | ||
*/ | ||
if (typeof Manager === "undefined") { | ||
throw new Error("The Hammerjs must be loaded before eg.Axes.PinchInput.\nhttp://hammerjs.github.io/"); | ||
} | ||
this._pinchFlag = false; | ||
this._enabled = false; | ||
this._activeInput = null; | ||
this.element = $(el); | ||
this.options = __assign({ | ||
scale: 1, | ||
threshold: 0, | ||
inputType: ["touch", "pointer"], | ||
hammerManagerOptions: { | ||
// css properties were removed due to usablility issue | ||
// http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html | ||
cssProps: { | ||
userSelect: "none", | ||
touchSelect: "none", | ||
touchCallout: "none", | ||
userDrag: "none", | ||
}, | ||
}, | ||
}, options); | ||
this.onPinchStart = this.onPinchStart.bind(this); | ||
this.onPinchMove = this.onPinchMove.bind(this); | ||
this.onPinchEnd = this.onPinchEnd.bind(this); | ||
this.options = __assign({ scale: 1, threshold: 0, inputType: ["touch", "pointer"] }, options); | ||
this._onPinchStart = this._onPinchStart.bind(this); | ||
this._onPinchMove = this._onPinchMove.bind(this); | ||
this._onPinchEnd = this._onPinchEnd.bind(this); | ||
} | ||
@@ -81,121 +33,101 @@ PinchInput.prototype.mapAxes = function (axes) { | ||
PinchInput.prototype.connect = function (observer) { | ||
var hammerOption = { threshold: this.options.threshold }; | ||
if (this.hammer) { // for sharing hammer instance. | ||
// hammer remove previous PinchRecognizer. | ||
this.removeRecognizer(); | ||
this.dettachEvent(); | ||
if (this._activeInput) { | ||
this._detachEvent(); | ||
} | ||
else { | ||
var keyValue = this.element[UNIQUEKEY]; | ||
if (!keyValue) { | ||
keyValue = String(Math.round(Math.random() * new Date().getTime())); | ||
} | ||
var inputClass = convertInputType(this.options.inputType); | ||
if (!inputClass) { | ||
throw new Error("Wrong inputType parameter!"); | ||
} | ||
this.hammer = createHammer(this.element, __assign({ | ||
inputClass: inputClass, | ||
}, this.options.hammerManagerOptions)); | ||
this.element[UNIQUEKEY] = keyValue; | ||
} | ||
this.pinchRecognizer = new Pinch(hammerOption); | ||
this.hammer.add(this.pinchRecognizer); | ||
this.attachEvent(observer); | ||
this._attachEvent(observer); | ||
this._originalCssProps = setCssProps(this.element); | ||
return this; | ||
}; | ||
PinchInput.prototype.disconnect = function () { | ||
this.removeRecognizer(); | ||
if (this.hammer) { | ||
this.hammer.remove(this.pinchRecognizer); | ||
this.pinchRecognizer = null; | ||
this.dettachEvent(); | ||
this._detachEvent(); | ||
if (this._originalCssProps !== PREVENT_SCROLL_CSSPROPS) { | ||
setCssProps(this.element, this._originalCssProps); | ||
} | ||
return this; | ||
}; | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
* @method eg.Axes.PinchInput#destroy | ||
*/ | ||
PinchInput.prototype.destroy = function () { | ||
this.disconnect(); | ||
if (this.hammer && this.hammer.recognizers.length === 0) { | ||
this.hammer.destroy(); | ||
} | ||
delete this.element[UNIQUEKEY]; | ||
this.element = null; | ||
this.hammer = null; | ||
}; | ||
PinchInput.prototype.removeRecognizer = function () { | ||
if (this.hammer && this.pinchRecognizer) { | ||
this.hammer.remove(this.pinchRecognizer); | ||
this.pinchRecognizer = null; | ||
} | ||
PinchInput.prototype.enable = function () { | ||
this._enabled = true; | ||
return this; | ||
}; | ||
PinchInput.prototype.onPinchStart = function (event) { | ||
this._base = this.observer.get(this)[this.axes[0]]; | ||
var offset = this.getOffset(event.scale); | ||
this.observer.hold(this, event); | ||
this.observer.change(this, event, toAxis(this.axes, [offset])); | ||
this._prev = event.scale; | ||
PinchInput.prototype.disable = function () { | ||
this._enabled = false; | ||
return this; | ||
}; | ||
PinchInput.prototype.onPinchMove = function (event) { | ||
var offset = this.getOffset(event.scale, this._prev); | ||
this.observer.change(this, event, toAxis(this.axes, [offset])); | ||
this._prev = event.scale; | ||
PinchInput.prototype.isEnabled = function () { | ||
return this._enabled; | ||
}; | ||
PinchInput.prototype.onPinchEnd = function (event) { | ||
var offset = this.getOffset(event.scale, this._prev); | ||
this.observer.change(this, event, toAxis(this.axes, [offset])); | ||
this.observer.release(this, event, toAxis(this.axes, [0]), 0); | ||
this._base = null; | ||
this._prev = null; | ||
PinchInput.prototype._onPinchStart = function (event) { | ||
this._activeInput.onEventStart(event); | ||
if (!this._enabled || this._activeInput.getTouches(event) !== 2) { | ||
return; | ||
} | ||
this._baseValue = this._observer.get(this)[this.axes[0]]; | ||
this._observer.hold(this, event); | ||
this._pinchFlag = true; | ||
var pinchEvent = this._activeInput.extendEvent(event); | ||
this._activeInput.prevEvent = pinchEvent; | ||
}; | ||
PinchInput.prototype.getOffset = function (pinchScale, prev) { | ||
if (prev === void 0) { prev = 1; } | ||
return this._base * (pinchScale - prev) * this.options.scale; | ||
PinchInput.prototype._onPinchMove = function (event) { | ||
this._activeInput.onEventMove(event); | ||
if (!this._pinchFlag || | ||
!this._enabled || | ||
this._activeInput.getTouches(event) !== 2) { | ||
return; | ||
} | ||
var pinchEvent = this._activeInput.extendEvent(event); | ||
var offset = this._getOffset(pinchEvent.scale, this._activeInput.prevEvent.scale); | ||
this._observer.change(this, event, toAxis(this.axes, [offset])); | ||
this._activeInput.prevEvent = pinchEvent; | ||
}; | ||
PinchInput.prototype.attachEvent = function (observer) { | ||
this.observer = observer; | ||
this.hammer.on("pinchstart", this.onPinchStart) | ||
.on("pinchmove", this.onPinchMove) | ||
.on("pinchend", this.onPinchEnd); | ||
PinchInput.prototype._onPinchEnd = function (event) { | ||
this._activeInput.onEventEnd(event); | ||
if (!this._pinchFlag || | ||
!this._enabled || | ||
this._activeInput.getTouches(event) > 2) { | ||
return; | ||
} | ||
this._observer.release(this, event, [0], 0); | ||
this._baseValue = null; | ||
this._pinchFlag = false; | ||
this._activeInput.prevEvent = null; | ||
}; | ||
PinchInput.prototype.dettachEvent = function () { | ||
this.hammer.off("pinchstart", this.onPinchStart) | ||
.off("pinchmove", this.onPinchMove) | ||
.off("pinchend", this.onPinchEnd); | ||
this.observer = null; | ||
this._prev = null; | ||
PinchInput.prototype._attachEvent = function (observer) { | ||
var _this = this; | ||
var activeInput = convertInputType(this.options.inputType); | ||
this._observer = observer; | ||
this._enabled = true; | ||
this._activeInput = activeInput; | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.start.forEach(function (event) { | ||
_this.element.addEventListener(event, _this._onPinchStart, false); | ||
}); | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.move.forEach(function (event) { | ||
_this.element.addEventListener(event, _this._onPinchMove, false); | ||
}); | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.end.forEach(function (event) { | ||
_this.element.addEventListener(event, _this._onPinchEnd, false); | ||
}); | ||
}; | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @method eg.Axes.PinchInput#enable | ||
* @return {eg.Axes.PinchInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
PinchInput.prototype.enable = function () { | ||
this.hammer && (this.hammer.get("pinch").options.enable = true); | ||
return this; | ||
PinchInput.prototype._detachEvent = function () { | ||
var _this = this; | ||
var activeInput = this._activeInput; | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.start.forEach(function (event) { | ||
_this.element.removeEventListener(event, _this._onPinchStart, false); | ||
}); | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.move.forEach(function (event) { | ||
_this.element.removeEventListener(event, _this._onPinchMove, false); | ||
}); | ||
activeInput === null || activeInput === void 0 ? void 0 : activeInput.end.forEach(function (event) { | ||
_this.element.removeEventListener(event, _this._onPinchEnd, false); | ||
}); | ||
this._enabled = false; | ||
this._observer = null; | ||
}; | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @method eg.Axes.PinchInput#disable | ||
* @return {eg.Axes.PinchInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
PinchInput.prototype.disable = function () { | ||
this.hammer && (this.hammer.get("pinch").options.enable = false); | ||
return this; | ||
PinchInput.prototype._getOffset = function (pinchScale, prev) { | ||
if (prev === void 0) { prev = 1; } | ||
return this._baseValue * (pinchScale - prev) * this.options.scale; | ||
}; | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @method eg.Axes.PinchInput#isEnable | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
PinchInput.prototype.isEnable = function () { | ||
return !!(this.hammer && this.hammer.get("pinch").options.enable); | ||
}; | ||
return PinchInput; | ||
@@ -202,0 +134,0 @@ }()); |
@@ -15,31 +15,11 @@ var __extends = (this && this.__extends) || (function () { | ||
import Axes from "../Axes"; | ||
import { getAngle } from "../utils"; | ||
import { toAxis } from "./InputType"; | ||
import { PanInput } from "./PanInput"; | ||
/** | ||
* @class eg.Axes.RotatePanInput | ||
* @classdesc A module that passes the angle moved by touch to Axes and uses one axis of rotation.<br>[Details](https://github.com/naver/egjs-axes/wiki/RotatePanInput) | ||
* @ko 터치에 의해 움직인 각도를 Axes 에 전달하며 1개의 회전축만 사용한다.<br>[상세내용](https://github.com/naver/egjs-axes/wiki/RotatePanInput-%7C-%ED%95%9C%EA%B5%AD%EC%96%B4) | ||
* | ||
* @example | ||
* const input = new eg.Axes.RotatePanInput("#area"); | ||
* | ||
* var axes = new eg.Axes({ | ||
* // property name('angle') could be anything you want (eg. x, y, z...) | ||
* angle: { | ||
* range: [-180, 180] // from -180deg to 180deg | ||
* } | ||
* }); | ||
* | ||
* axes.connect("angle", input) | ||
* | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.RotatePanInput module <ko>eg.Axes.RotatePanInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {PanInputOption} [options] The option object of the eg.Axes.PanInput module<ko>eg.Axes.PanInput 모듈의 옵션 객체</ko> | ||
* @extends eg.Axes.PanInput | ||
*/ | ||
var RotatePanInput = /** @class */ (function (_super) { | ||
var RotatePanInput = (function (_super) { | ||
__extends(RotatePanInput, _super); | ||
function RotatePanInput(el, options) { | ||
var _this = _super.call(this, el, options) || this; | ||
_this.prevQuadrant = null; | ||
_this.lastDiff = 0; | ||
_this._prevQuadrant = null; | ||
_this._lastDiff = 0; | ||
return _this; | ||
@@ -51,54 +31,63 @@ } | ||
}; | ||
RotatePanInput.prototype.onHammerInput = function (event) { | ||
if (this.isEnable()) { | ||
if (event.isFirst) { | ||
this.observer.hold(this, event); | ||
this.onPanstart(event); | ||
} | ||
else if (event.isFinal) { | ||
this.onPanend(event); | ||
} | ||
RotatePanInput.prototype._onPanstart = function (event) { | ||
this._activeInput.onEventStart(event); | ||
if (!this.isEnabled) { | ||
return; | ||
} | ||
}; | ||
RotatePanInput.prototype.onPanstart = function (event) { | ||
var rect = this.element.getBoundingClientRect(); | ||
/** | ||
* Responsive | ||
*/ | ||
// TODO: how to do if element is ellipse not circle. | ||
this.coefficientForDistanceToAngle = 360 / (rect.width * Math.PI); // from 2*pi*r * x / 360 | ||
// TODO: provide a way to set origin like https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin | ||
this.rotateOrigin = [rect.left + (rect.width - 1) / 2, rect.top + (rect.height - 1) / 2]; | ||
// init angle. | ||
this.prevAngle = null; | ||
this.triggerChange(event); | ||
var panEvent = this._activeInput.extendEvent(event); | ||
this._observer.hold(this, panEvent); | ||
this._panFlag = true; | ||
this._coefficientForDistanceToAngle = 360 / (rect.width * Math.PI); | ||
this._rotateOrigin = [ | ||
rect.left + (rect.width - 1) / 2, | ||
rect.top + (rect.height - 1) / 2, | ||
]; | ||
this._prevAngle = null; | ||
this._triggerChange(panEvent); | ||
this._activeInput.prevEvent = panEvent; | ||
}; | ||
RotatePanInput.prototype.onPanmove = function (event) { | ||
this.triggerChange(event); | ||
RotatePanInput.prototype._onPanmove = function (event) { | ||
this._activeInput.onEventMove(event); | ||
if (!this._panFlag || !this.isEnabled) { | ||
return; | ||
} | ||
var panEvent = this._activeInput.extendEvent(event); | ||
if (panEvent.srcEvent.cancelable !== false) { | ||
panEvent.srcEvent.preventDefault(); | ||
} | ||
panEvent.srcEvent.stopPropagation(); | ||
this._triggerChange(panEvent); | ||
this._activeInput.prevEvent = panEvent; | ||
}; | ||
RotatePanInput.prototype.onPanend = function (event) { | ||
this.triggerChange(event); | ||
this.triggerAnimation(event); | ||
RotatePanInput.prototype._onPanend = function (event) { | ||
this._activeInput.onEventEnd(event); | ||
if (!this._panFlag || !this.isEnabled) { | ||
return; | ||
} | ||
var prevEvent = this._activeInput.prevEvent; | ||
this._triggerChange(prevEvent); | ||
var vx = prevEvent.velocityX; | ||
var vy = prevEvent.velocityY; | ||
var velocity = Math.sqrt(vx * vx + vy * vy) * (this._lastDiff > 0 ? -1 : 1); | ||
this._observer.release(this, prevEvent, [ | ||
velocity * this._coefficientForDistanceToAngle, | ||
]); | ||
this._panFlag = false; | ||
}; | ||
RotatePanInput.prototype.triggerChange = function (event) { | ||
var angle = this.getAngle(event.center.x, event.center.y); | ||
var quadrant = this.getQuadrant(event.center.x, event.center.y); | ||
var diff = this.getDifference(this.prevAngle, angle, this.prevQuadrant, quadrant); | ||
this.prevAngle = angle; | ||
this.prevQuadrant = quadrant; | ||
RotatePanInput.prototype._triggerChange = function (event) { | ||
var _a = this._getPosFromOrigin(event.center.x, event.center.y), x = _a.x, y = _a.y; | ||
var angle = getAngle(x, y); | ||
var positiveAngle = angle < 0 ? 360 + angle : angle; | ||
var quadrant = this._getQuadrant(event.center.x, event.center.y); | ||
var diff = this._getDifference(this._prevAngle, positiveAngle, this._prevQuadrant, quadrant); | ||
this._prevAngle = positiveAngle; | ||
this._prevQuadrant = quadrant; | ||
if (diff === 0) { | ||
return; | ||
} | ||
this.lastDiff = diff; | ||
this.observer.change(this, event, toAxis(this.axes, [-diff])); // minus for clockwise | ||
this._lastDiff = diff; | ||
this._observer.change(this, event, toAxis(this.axes, [-diff])); | ||
}; | ||
RotatePanInput.prototype.triggerAnimation = function (event) { | ||
var vx = event.velocityX; | ||
var vy = event.velocityY; | ||
var velocity = Math.sqrt(vx * vx + vy * vy) * (this.lastDiff > 0 ? -1 : 1); // clockwise | ||
var duration = Math.abs(velocity / -this.observer.options.deceleration); | ||
var distance = velocity / 2 * duration; | ||
this.observer.release(this, event, toAxis(this.axes, [distance * this.coefficientForDistanceToAngle])); | ||
}; | ||
RotatePanInput.prototype.getDifference = function (prevAngle, angle, prevQuadrant, quadrant) { | ||
RotatePanInput.prototype._getDifference = function (prevAngle, angle, prevQuadrant, quadrant) { | ||
var diff; | ||
@@ -112,3 +101,3 @@ if (prevAngle === null) { | ||
else if (prevQuadrant === 4 && quadrant === 1) { | ||
diff = (360 - prevAngle) + angle; | ||
diff = 360 - prevAngle + angle; | ||
} | ||
@@ -120,25 +109,10 @@ else { | ||
}; | ||
RotatePanInput.prototype.getPosFromOrigin = function (posX, posY) { | ||
RotatePanInput.prototype._getPosFromOrigin = function (posX, posY) { | ||
return { | ||
x: posX - this.rotateOrigin[0], | ||
y: this.rotateOrigin[1] - posY, | ||
x: posX - this._rotateOrigin[0], | ||
y: this._rotateOrigin[1] - posY, | ||
}; | ||
}; | ||
RotatePanInput.prototype.getAngle = function (posX, posY) { | ||
var _a = this.getPosFromOrigin(posX, posY), x = _a.x, y = _a.y; | ||
var angle = Math.atan2(y, x) * 180 / Math.PI; | ||
// console.log(angle, x, y); | ||
return angle < 0 ? 360 + angle : angle; | ||
}; | ||
/** | ||
* Quadrant | ||
* y(+) | ||
* | | ||
* 2 | 1 | ||
* --------------->x(+) | ||
* 3 | 4 | ||
* | | ||
*/ | ||
RotatePanInput.prototype.getQuadrant = function (posX, posY) { | ||
var _a = this.getPosFromOrigin(posX, posY), x = _a.x, y = _a.y; | ||
RotatePanInput.prototype._getQuadrant = function (posX, posY) { | ||
var _a = this._getPosFromOrigin(posX, posY), x = _a.x, y = _a.y; | ||
var q = 0; | ||
@@ -145,0 +119,0 @@ if (x >= 0 && y >= 0) { |
@@ -14,29 +14,8 @@ var __assign = (this && this.__assign) || function () { | ||
import { toAxis } from "./InputType"; | ||
/** | ||
* @typedef {Object} WheelInputOption The option object of the eg.Axes.WheelInput module | ||
* @ko eg.Axes.WheelInput 모듈의 옵션 객체 | ||
* @property {Number} [scale=1] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
**/ | ||
/** | ||
* @class eg.Axes.WheelInput | ||
* @classdesc A module that passes the amount of change to eg.Axes when the mouse wheel is moved. use one axis. | ||
* @ko 마우스 휠이 움직일때의 변화량을 eg.Axes에 전달하는 모듈. 한 개 의 축을 사용한다. | ||
* | ||
* @example | ||
* const wheel = new eg.Axes.WheelInput("#area", { | ||
* scale: 1 | ||
* }); | ||
* | ||
* // Connect 'something' axis when the mousewheel is moved. | ||
* axes.connect("something", wheel); | ||
* | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.WheelInput module <ko>eg.Axes.WheelInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {WheelInputOption} [options] The option object of the eg.Axes.WheelInput module<ko>eg.Axes.WheelInput 모듈의 옵션 객체</ko> | ||
*/ | ||
var WheelInput = /** @class */ (function () { | ||
var WheelInput = (function () { | ||
function WheelInput(el, options) { | ||
this.axes = []; | ||
this.element = null; | ||
this._isEnabled = false; | ||
this._isHolded = false; | ||
this._enabled = false; | ||
this._holding = false; | ||
this._timer = null; | ||
@@ -46,5 +25,6 @@ this.element = $(el); | ||
scale: 1, | ||
releaseDelay: 300, | ||
useNormalized: true, | ||
}, options); | ||
this.onWheel = this.onWheel.bind(this); | ||
this._onWheel = this._onWheel.bind(this); | ||
} | ||
@@ -55,15 +35,10 @@ WheelInput.prototype.mapAxes = function (axes) { | ||
WheelInput.prototype.connect = function (observer) { | ||
this.dettachEvent(); | ||
this.attachEvent(observer); | ||
this._detachEvent(); | ||
this._attachEvent(observer); | ||
return this; | ||
}; | ||
WheelInput.prototype.disconnect = function () { | ||
this.dettachEvent(); | ||
this._detachEvent(); | ||
return this; | ||
}; | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
* @method eg.Axes.WheelInput#destroy | ||
*/ | ||
WheelInput.prototype.destroy = function () { | ||
@@ -73,5 +48,16 @@ this.disconnect(); | ||
}; | ||
WheelInput.prototype.onWheel = function (event) { | ||
WheelInput.prototype.enable = function () { | ||
this._enabled = true; | ||
return this; | ||
}; | ||
WheelInput.prototype.disable = function () { | ||
this._enabled = false; | ||
return this; | ||
}; | ||
WheelInput.prototype.isEnabled = function () { | ||
return this._enabled; | ||
}; | ||
WheelInput.prototype._onWheel = function (event) { | ||
var _this = this; | ||
if (!this._isEnabled) { | ||
if (!this._enabled) { | ||
return; | ||
@@ -83,26 +69,27 @@ } | ||
} | ||
if (!this._isHolded) { | ||
this.observer.hold(this, event); | ||
this._isHolded = true; | ||
if (!this._holding) { | ||
this._observer.hold(this, event); | ||
this._holding = true; | ||
} | ||
var offset = (event.deltaY > 0 ? -1 : 1) * this.options.scale * (this.options.useNormalized ? 1 : Math.abs(event.deltaY)); | ||
this.observer.change(this, event, toAxis(this.axes, [offset])); | ||
var offset = (event.deltaY > 0 ? -1 : 1) * | ||
this.options.scale * | ||
(this.options.useNormalized ? 1 : Math.abs(event.deltaY)); | ||
this._observer.change(this, event, toAxis(this.axes, [offset]), true); | ||
clearTimeout(this._timer); | ||
var inst = this; | ||
this._timer = setTimeout(function () { | ||
if (_this._isHolded) { | ||
_this._isHolded = false; | ||
_this.observer.release(_this, event, toAxis(_this.axes, [0])); | ||
if (_this._holding) { | ||
_this._holding = false; | ||
_this._observer.release(_this, event, [0]); | ||
} | ||
}, 50); | ||
}, this.options.releaseDelay); | ||
}; | ||
WheelInput.prototype.attachEvent = function (observer) { | ||
this.observer = observer; | ||
this.element.addEventListener("wheel", this.onWheel); | ||
this._isEnabled = true; | ||
WheelInput.prototype._attachEvent = function (observer) { | ||
this._observer = observer; | ||
this.element.addEventListener("wheel", this._onWheel); | ||
this._enabled = true; | ||
}; | ||
WheelInput.prototype.dettachEvent = function () { | ||
this.element.removeEventListener("wheel", this.onWheel); | ||
this._isEnabled = false; | ||
this.observer = null; | ||
WheelInput.prototype._detachEvent = function () { | ||
this.element.removeEventListener("wheel", this._onWheel); | ||
this._enabled = false; | ||
this._observer = null; | ||
if (this._timer) { | ||
@@ -113,31 +100,2 @@ clearTimeout(this._timer); | ||
}; | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @method eg.Axes.WheelInput#enable | ||
* @return {eg.Axes.WheelInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
WheelInput.prototype.enable = function () { | ||
this._isEnabled = true; | ||
return this; | ||
}; | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @method eg.Axes.WheelInput#disable | ||
* @return {eg.Axes.WheelInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
WheelInput.prototype.disable = function () { | ||
this._isEnabled = false; | ||
return this; | ||
}; | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @method eg.Axes.WheelInput#isEnable | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
WheelInput.prototype.isEnable = function () { | ||
return this._isEnabled; | ||
}; | ||
return WheelInput; | ||
@@ -144,0 +102,0 @@ }()); |
@@ -1,15 +0,16 @@ | ||
var InterruptManager = /** @class */ (function () { | ||
function InterruptManager(options) { | ||
this.options = options; | ||
this._prevented = false; // check whether the animation event was prevented | ||
var InterruptManager = (function () { | ||
function InterruptManager(_options) { | ||
this._options = _options; | ||
this._prevented = false; | ||
} | ||
InterruptManager.prototype.isInterrupting = function () { | ||
// when interruptable is 'true', return value is always 'true'. | ||
return this.options.interruptable || this._prevented; | ||
return this._options.interruptable || this._prevented; | ||
}; | ||
InterruptManager.prototype.isInterrupted = function () { | ||
return !this.options.interruptable && this._prevented; | ||
return !this._options.interruptable && this._prevented; | ||
}; | ||
InterruptManager.prototype.setInterrupt = function (prevented) { | ||
!this.options.interruptable && (this._prevented = prevented); | ||
if (!this._options.interruptable) { | ||
this._prevented = prevented; | ||
} | ||
}; | ||
@@ -16,0 +17,0 @@ return InterruptManager; |
import { window } from "./browser"; | ||
export function toArray(nodes) { | ||
// const el = Array.prototype.slice.call(nodes); | ||
// for IE8 | ||
import { PREVENT_SCROLL_CSSPROPS } from "./const"; | ||
export var toArray = function (nodes) { | ||
var el = []; | ||
@@ -10,11 +9,9 @@ for (var i = 0, len = nodes.length; i < len; i++) { | ||
return el; | ||
} | ||
export function $(param, multi) { | ||
}; | ||
export var $ = function (param, multi) { | ||
if (multi === void 0) { multi = false; } | ||
var el; | ||
if (typeof param === "string") { // String (HTML, Selector) | ||
// check if string is HTML tag format | ||
if (typeof param === "string") { | ||
var match = param.match(/^<([a-z]+)\s*([^>]*)>/); | ||
// creating element | ||
if (match) { // HTML | ||
if (match) { | ||
var dummy = document.createElement("div"); | ||
@@ -24,3 +21,3 @@ dummy.innerHTML = param; | ||
} | ||
else { // Selector | ||
else { | ||
el = toArray(document.querySelectorAll(param)); | ||
@@ -32,11 +29,10 @@ } | ||
} | ||
else if (param === window) { // window | ||
else if (param === window) { | ||
el = param; | ||
} | ||
else if (param.nodeName && | ||
(param.nodeType === 1 || param.nodeType === 9)) { // HTMLElement, Document | ||
else if (param.nodeName && (param.nodeType === 1 || param.nodeType === 9)) { | ||
el = param; | ||
} | ||
else if (("jQuery" in window && param instanceof jQuery) || | ||
param.constructor.prototype.jquery) { // jQuery | ||
param.constructor.prototype.jquery) { | ||
el = multi ? param.toArray() : param.get(0); | ||
@@ -51,3 +47,3 @@ } | ||
return el; | ||
} | ||
}; | ||
var raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame; | ||
@@ -59,7 +55,7 @@ var caf = window.cancelAnimationFrame || window.webkitCancelAnimationFrame; | ||
raf = function (callback) { | ||
function wrapCallback(timestamp) { | ||
var wrapCallback = function (timestamp) { | ||
if (keyInfo_1[key]) { | ||
callback(timestamp); | ||
} | ||
} | ||
}; | ||
var key = oldraf_1(wrapCallback); | ||
@@ -76,3 +72,5 @@ keyInfo_1[key] = true; | ||
return window.setTimeout(function () { | ||
callback(window.performance && window.performance.now && window.performance.now() || new Date().getTime()); | ||
callback((window.performance && | ||
window.performance.now && | ||
window.performance.now()) || new Date().getTime()); | ||
}, 16); | ||
@@ -82,34 +80,27 @@ }; | ||
} | ||
/** | ||
* A polyfill for the window.requestAnimationFrame() method. | ||
* @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame | ||
* @private | ||
*/ | ||
export function requestAnimationFrame(fp) { | ||
export var requestAnimationFrame = function (fp) { | ||
return raf(fp); | ||
} | ||
/** | ||
* A polyfill for the window.cancelAnimationFrame() method. It cancels an animation executed through a call to the requestAnimationFrame() method. | ||
* @param {Number} key − The ID value returned through a call to the requestAnimationFrame() method. <ko>requestAnimationFrame() 메서드가 반환한 아이디 값</ko> | ||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame | ||
* @private | ||
*/ | ||
export function cancelAnimationFrame(key) { | ||
}; | ||
export var cancelAnimationFrame = function (key) { | ||
caf(key); | ||
} | ||
export function map(obj, callback) { | ||
}; | ||
export var map = function (obj, callback) { | ||
var tranformed = {}; | ||
for (var k in obj) { | ||
k && (tranformed[k] = callback(obj[k], k)); | ||
if (k) { | ||
tranformed[k] = callback(obj[k], k); | ||
} | ||
} | ||
return tranformed; | ||
} | ||
export function filter(obj, callback) { | ||
}; | ||
export var filter = function (obj, callback) { | ||
var filtered = {}; | ||
for (var k in obj) { | ||
k && callback(obj[k], k) && (filtered[k] = obj[k]); | ||
if (k && callback(obj[k], k)) { | ||
filtered[k] = obj[k]; | ||
} | ||
} | ||
return filtered; | ||
} | ||
export function every(obj, callback) { | ||
}; | ||
export var every = function (obj, callback) { | ||
for (var k in obj) { | ||
@@ -121,9 +112,8 @@ if (k && !callback(obj[k], k)) { | ||
return true; | ||
} | ||
export function equal(target, base) { | ||
}; | ||
export var equal = function (target, base) { | ||
return every(target, function (v, k) { return v === base[k]; }); | ||
} | ||
}; | ||
var roundNumFunc = {}; | ||
export function roundNumber(num, roundUnit) { | ||
// Cache for performance | ||
export var roundNumber = function (num, roundUnit) { | ||
if (!roundNumFunc[roundUnit]) { | ||
@@ -133,18 +123,17 @@ roundNumFunc[roundUnit] = getRoundFunc(roundUnit); | ||
return roundNumFunc[roundUnit](num); | ||
} | ||
export function roundNumbers(num, roundUnit) { | ||
}; | ||
export var roundNumbers = function (num, roundUnit) { | ||
if (!num || !roundUnit) { | ||
return num; | ||
} | ||
var isNumber = typeof roundUnit === "number"; | ||
return map(num, function (value, key) { return roundNumber(value, isNumber ? roundUnit : roundUnit[key]); }); | ||
} | ||
export function getDecimalPlace(val) { | ||
return map(num, function (value, key) { | ||
return roundNumber(value, typeof roundUnit === "number" ? roundUnit : roundUnit[key]); | ||
}); | ||
}; | ||
export var getDecimalPlace = function (val) { | ||
if (!isFinite(val)) { | ||
return 0; | ||
} | ||
var v = (val + ""); | ||
var v = "" + val; | ||
if (v.indexOf("e") >= 0) { | ||
// Exponential Format | ||
// 1e-10, 1e-12 | ||
var p = 0; | ||
@@ -158,12 +147,8 @@ var e = 1; | ||
} | ||
// In general, following has performance benefit. | ||
// https://jsperf.com/precision-calculation | ||
return v.indexOf(".") >= 0 ? (v.length - v.indexOf(".") - 1) : 0; | ||
} | ||
export function inversePow(n) { | ||
// replace Math.pow(10, -n) to solve floating point issue. | ||
// eg. Math.pow(10, -4) => 0.00009999999999999999 | ||
return v.indexOf(".") >= 0 ? v.length - v.indexOf(".") - 1 : 0; | ||
}; | ||
export var inversePow = function (n) { | ||
return 1 / Math.pow(10, n); | ||
} | ||
export function getRoundFunc(v) { | ||
}; | ||
export var getRoundFunc = function (v) { | ||
var p = v < 1 ? Math.pow(10, getDecimalPlace(v)) : 1; | ||
@@ -176,3 +161,19 @@ return function (n) { | ||
}; | ||
} | ||
}; | ||
export var getAngle = function (posX, posY) { | ||
return (Math.atan2(posY, posX) * 180) / Math.PI; | ||
}; | ||
export var setCssProps = function (element, originalCssProps) { | ||
var oldCssProps = {}; | ||
if (element.style) { | ||
var newCssProps_1 = originalCssProps | ||
? originalCssProps | ||
: PREVENT_SCROLL_CSSPROPS; | ||
Object.keys(newCssProps_1).forEach(function (prop) { | ||
oldCssProps[prop] = element.style[prop]; | ||
element.style[prop] = newCssProps_1[prop]; | ||
}); | ||
} | ||
return oldCssProps; | ||
}; | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "@egjs/axes", | ||
"version": "2.8.0", | ||
"version": "3.0.0", | ||
"description": "A module used to change the information of user action entered by various input devices such as touch screen or mouse into the logical virtual coordinates. You can easily create a UI that responds to user actions.", | ||
@@ -15,14 +15,16 @@ "sideEffects": false, | ||
"test:chrome": "karma start --chrome", | ||
"lint": "tslint -c tslint.json -p tsconfig.json", | ||
"lint": "eslint ./src/**/*.ts", | ||
"jsdoc": "rm -rf ./doc && rm -rf outjs && tsc -p tsconfig.json && jsdoc -c jsdoc.json", | ||
"declaration": "rm -rf declaration && tsc -p tsconfig.declaration.json", | ||
"coverage": "karma start --coverage", | ||
"demo:start": "npm run demo:prebuild-latest && npm run demo:updateVersion && jekyll serve --host=0.0.0.0 -s demo", | ||
"demo:build": "npm run demo:updateVersion && jekyll build -s demo", | ||
"demo:prebuild-version": "cpx 'dist/**/*' demo/release/$npm_package_version/dist --clean && cpx 'doc/**/*' demo/release/$npm_package_version/doc --clean", | ||
"demo:prebuild-latest": "cpx 'dist/**/*' demo/release/latest/dist --clean && cpx 'doc/**/*' demo/release/latest/doc --clean", | ||
"demo:deploy": "npm run build && npm run jsdoc && npm run demo:prebuild-version && npm run demo:prebuild-latest && npm run demo:build && gh-pages -d demo/_site --add --remote upstream", | ||
"demo:origin": "npm run build && npm run jsdoc && npm run demo:prebuild-version && npm run demo:prebuild-latest && npm run demo:build && gh-pages -d demo/_site --add --remote origin", | ||
"demo:updateVersion": "echo $npm_package_version > demo/_data/version.yml", | ||
"demo:setup": "cpx 'node_modules/@egjs/common-demo/**/*' 'demo/' && rm demo/package.json", | ||
"docs:build": "rm -rf ./demo/docs/api && jsdoc-to-mdx -c ./jsdoc-to-mdx.json", | ||
"demo:build": "run-s build demo:copy-lib docs:build && npm run demo:build-docusaurus", | ||
"demo:build-docusaurus": "npm run build --prefix demo", | ||
"demo:copy-lib": "run-s demo:copy-lib-version demo:copy-lib-latest", | ||
"demo:copy-lib-version": "cpx 'dist/**/*' demo/static/release/$npm_package_version --clean && cpx 'css/**/*' demo/static/release/$npm_package_version/css --clean", | ||
"demo:copy-lib-latest": "cpx 'dist/**/*' demo/static/release/latest --clean && cpx 'dist/**/*' demo/static/release/latest/css --clean", | ||
"gh-pages:upstream": "gh-pages -d demo/build/ --remote upstream", | ||
"gh-pages:origin": "gh-pages -d demo/build/", | ||
"demo:deploy": "run-s demo:build gh-pages:upstream", | ||
"demo:deploy-origin": "run-s demo:build gh-pages:origin", | ||
"release": "release-helper upstream", | ||
@@ -42,4 +44,3 @@ "coveralls": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js", | ||
"namespace": { | ||
"eg": "eg", | ||
"Hammer": "Hammer" | ||
"eg": "eg" | ||
}, | ||
@@ -50,9 +51,12 @@ "license": "MIT", | ||
"@egjs/agent": "^2.2.1", | ||
"@egjs/component": "^2.2.2", | ||
"@egjs/hammerjs": "^2.0.15" | ||
"@egjs/component": "^3.0.1" | ||
}, | ||
"devDependencies": { | ||
"@daybrush/jsdoc": "^0.3.12", | ||
"@egjs/build-helper": "^0.1.2", | ||
"@egjs/common-demo": "github:naver/egjs#common-demo", | ||
"@egjs/release-helper": "0.0.3", | ||
"@typescript-eslint/eslint-plugin": "^5.11.0", | ||
"@typescript-eslint/eslint-plugin-tslint": "^5.11.0", | ||
"@typescript-eslint/parser": "^5.11.0", | ||
"babel-core": "^6.26.0", | ||
@@ -67,6 +71,11 @@ "babel-loader": "^7.1.2", | ||
"egjs-jsdoc-template": "^1.4.4", | ||
"eslint": "^8.8.0", | ||
"eslint-config-prettier": "^8.3.0", | ||
"eslint-plugin-import": "^2.25.4", | ||
"eslint-plugin-jsdoc": "^37.8.0", | ||
"eslint-plugin-prefer-arrow": "^1.2.3", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"fs-extra": "^5.0.0", | ||
"gh-pages": "^1.1.0", | ||
"hammer-simulator": "0.0.1", | ||
"hammerjs-compatible": "^1.1.0", | ||
"husky": "^0.14.3", | ||
@@ -76,2 +85,3 @@ "inject-loader": "^3.0.1", | ||
"jsdoc": "^3.5.5", | ||
"jsdoc-to-mdx": "^1.1.2", | ||
"karma": "^2.0.0", | ||
@@ -89,2 +99,4 @@ "karma-chai": "^0.1.0", | ||
"mocha": "^4.1.0", | ||
"npm-run-all": "^4.1.5", | ||
"prettier": "^2.5.1", | ||
"rollup": "^0.66.1", | ||
@@ -101,5 +113,2 @@ "rollup-plugin-node-resolve": "^3.4.0", | ||
"ts-loader": "^8.0.6", | ||
"tslint": "^5.9.1", | ||
"tslint-eslint-rules": "^4.1.1", | ||
"tslint-loader": "^3.5.3", | ||
"typescript": "^3.9.7", | ||
@@ -106,0 +115,0 @@ "uglifyjs-webpack-plugin": "^1.1.6", |
# egjs-axes [](https://badge.fury.io/js/%40egjs%2Faxes) [](https://travis-ci.org/naver/egjs-axes) [](https://coveralls.io/github/naver/egjs-axes?branch=master) | ||
A module used to change the information of user action entered by various input devices such as touch screen or mouse into the logical virtual coordinates. | ||
A module used to change the information of user action entered by various input devices such as touch screen or mouse into the logical virtual coordinates. | ||
<img src="https://github.com/naver/egjs-axes/raw/master/demo/assets/image/structure.png" style="width:100%"> | ||
You can easily create a UI that responds to user actions. | ||
 | ||
## Documents | ||
@@ -24,3 +20,3 @@ - [Get Started and Demos](https://naver.github.io/egjs-axes/) | ||
Download dist files from repo directly or install it via npm. | ||
Download dist files from repo directly or install it via npm. | ||
@@ -31,4 +27,4 @@ ### For development (Uncompressed) | ||
- Latest : https://naver.github.io/egjs-axes/release/latest/dist/axes.js | ||
- Specific version : https://naver.github.io/egjs-axes/release/[VERSION]/dist/axes.js | ||
- Latest : https://naver.github.io/egjs-axes/release/latest/axes.js | ||
- Specific version : https://naver.github.io/egjs-axes/release/[VERSION]/axes.js | ||
@@ -39,4 +35,4 @@ ### For production (Compressed) | ||
- Latest : https://naver.github.io/egjs-axes/release/latest/dist/axes.min.js | ||
- Specific version : https://naver.github.io/egjs-axes/release/[VERSION]/dist/axes.min.js | ||
- Latest : https://naver.github.io/egjs-axes/release/latest/axes.min.js | ||
- Specific version : https://naver.github.io/egjs-axes/release/[VERSION]/axes.min.js | ||
@@ -48,6 +44,10 @@ ### Packaged version (with Dependencies) | ||
- **Latest** | ||
- https://naver.github.io/egjs-axes/release/latest/dist/axes.pkgd.js | ||
- https://naver.github.io/egjs-axes/release/latest/dist/axes.pkgd.min.js | ||
- https://naver.github.io/egjs-axes/release/latest/axes.pkgd.js | ||
- https://naver.github.io/egjs-axes/release/latest/axes.pkgd.min.js | ||
- **Specific version** | ||
- **Specific version(3.x)** | ||
- https://naver.github.io/egjs-axes/release/[VERSION]/axes.pkgd.js | ||
- https://naver.github.io/egjs-axes/release/[VERSION]/axes.pkgd.min.js | ||
- **Specific version(under 2.x)** | ||
- https://naver.github.io/egjs-axes/release/[VERSION]/dist/axes.pkgd.js | ||
@@ -76,5 +76,5 @@ - https://naver.github.io/egjs-axes/release/[VERSION]/dist/axes.pkgd.min.js | ||
|[egjs-component](http://github.com/naver/egjs-component)|[Hammer.JS](http://hammerjs.github.io/)| | ||
|----|----| | ||
|2.0.0+|2.0.4+| | ||
|[egjs-component](http://github.com/naver/egjs-component)| | ||
|----| | ||
|3.0.1+| | ||
@@ -81,0 +81,0 @@ |
const buildHelper = require("@egjs/build-helper"); | ||
const external = { | ||
"@egjs/hammerjs": "Hammer", | ||
"@egjs/agent": "eg.agent", | ||
@@ -6,0 +5,0 @@ "@egjs/component": "eg.Component", |
@@ -1,321 +0,482 @@ | ||
import { getInsidePosition, isCircularable, getCirculatedPos, getDuration } from "./Coordinate"; | ||
import { | ||
getInsidePosition, | ||
isCircularable, | ||
getCirculatedPos, | ||
getDuration, | ||
} from "./Coordinate"; | ||
import { Axis, AxisManager } from "./AxisManager"; | ||
import { InterruptManager } from "./InterruptManager"; | ||
import { EventManager, ChangeEventOption } from "./EventManager"; | ||
import { requestAnimationFrame, cancelAnimationFrame, map, every, filter, equal, roundNumber, getDecimalPlace, inversePow } from "./utils"; | ||
import { | ||
requestAnimationFrame, | ||
cancelAnimationFrame, | ||
map, | ||
every, | ||
filter, | ||
equal, | ||
roundNumber, | ||
getDecimalPlace, | ||
inversePow, | ||
} from "./utils"; | ||
import { AxesOption } from "./Axes"; | ||
import { AnimationParam, ObjectInterface } from "./types"; | ||
import { | ||
AnimationParam, | ||
ObjectInterface, | ||
UpdateAnimationOption, | ||
} from "./types"; | ||
function minMax(value: number, min: number, max: number): number { | ||
return Math.max(Math.min(value, max), min); | ||
} | ||
const clamp = (value: number, min: number, max: number): number => { | ||
return Math.max(Math.min(value, max), min); | ||
}; | ||
export class AnimationManager { | ||
private _raf; | ||
private _animateParam: AnimationParam; | ||
private options: AxesOption; | ||
public itm: InterruptManager; | ||
public em: EventManager; | ||
public axm: AxisManager; | ||
public interruptManager: InterruptManager; | ||
public eventManager: EventManager; | ||
public axisManager: AxisManager; | ||
private _raf: number; | ||
private _animateParam: AnimationParam; | ||
private _initialEasingPer: number; | ||
private _prevEasingPer: number; | ||
private _durationOffset: number; | ||
private _options: AxesOption; | ||
constructor({ options, itm, em, axm }) { | ||
this.options = options; | ||
this.itm = itm; | ||
this.em = em; | ||
this.axm = axm; | ||
this.animationEnd = this.animationEnd.bind(this); | ||
} | ||
getDuration(depaPos: Axis, destPos: Axis, wishDuration?: number) { | ||
let duration; | ||
if (typeof wishDuration !== "undefined") { | ||
duration = wishDuration; | ||
} else { | ||
const durations: Axis = map( | ||
destPos, | ||
(v, k) => getDuration( | ||
Math.abs(v - depaPos[k]), | ||
this.options.deceleration), | ||
); | ||
duration = Object.keys(durations).reduce((max, v) => Math.max(max, durations[v]), -Infinity); | ||
} | ||
return minMax( | ||
duration, | ||
this.options.minimumDuration, | ||
this.options.maximumDuration); | ||
} | ||
public constructor({ | ||
options, | ||
interruptManager, | ||
eventManager, | ||
axisManager, | ||
}: { | ||
options: AxesOption; | ||
interruptManager: InterruptManager; | ||
eventManager: EventManager; | ||
axisManager: AxisManager; | ||
}) { | ||
this._options = options; | ||
this.interruptManager = interruptManager; | ||
this.eventManager = eventManager; | ||
this.axisManager = axisManager; | ||
this.animationEnd = this.animationEnd.bind(this); | ||
} | ||
private createAnimationParam(pos: Axis, duration: number, option?: ChangeEventOption): AnimationParam { | ||
const depaPos: Axis = this.axm.get(); | ||
const destPos: Axis = pos; | ||
const inputEvent = option && option.event || null; | ||
return { | ||
depaPos, | ||
destPos, | ||
duration: minMax( | ||
duration, | ||
this.options.minimumDuration, | ||
this.options.maximumDuration), | ||
delta: this.axm.getDelta(depaPos, destPos), | ||
inputEvent, | ||
input: option && option.input || null, | ||
isTrusted: !!inputEvent, | ||
done: this.animationEnd, | ||
}; | ||
} | ||
public getDuration( | ||
depaPos: Axis, | ||
destPos: Axis, | ||
wishDuration?: number | ||
): number { | ||
let duration: number; | ||
if (typeof wishDuration !== "undefined") { | ||
duration = wishDuration; | ||
} else { | ||
const durations: Axis = map(destPos, (v, k) => | ||
getDuration(Math.abs(v - depaPos[k]), this._options.deceleration) | ||
); | ||
duration = Object.keys(durations).reduce( | ||
(max, v) => Math.max(max, durations[v]), | ||
-Infinity | ||
); | ||
} | ||
return clamp( | ||
duration, | ||
this._options.minimumDuration, | ||
this._options.maximumDuration | ||
); | ||
} | ||
grab(axes: string[], option?: ChangeEventOption) { | ||
if (this._animateParam && axes.length) { | ||
const orgPos: Axis = this.axm.get(axes); | ||
const pos: Axis = this.axm.map(orgPos, | ||
(v, opt) => getCirculatedPos(v, opt.range, opt.circular as boolean[])); | ||
if (!every(pos, (v, k) => orgPos[k] === v)) { | ||
this.em.triggerChange(pos, false, orgPos, option, !!option); | ||
} | ||
this._animateParam = null; | ||
this._raf && cancelAnimationFrame(this._raf); | ||
this._raf = null; | ||
this.em.triggerAnimationEnd(!!(option && option.event)); | ||
} | ||
} | ||
public getDisplacement(velocity: number[]): number[] { | ||
const totalVelocity = Math.pow( | ||
velocity.reduce((total, v) => total + v * v, 0), | ||
1 / velocity.length | ||
); | ||
const duration = Math.abs(totalVelocity / -this._options.deceleration); | ||
return velocity.map((v) => (v / 2) * duration); | ||
} | ||
getEventInfo(): ChangeEventOption { | ||
if (this._animateParam && this._animateParam.input && this._animateParam.inputEvent) { | ||
return { | ||
input: this._animateParam.input, | ||
event: this._animateParam.inputEvent, | ||
}; | ||
} else { | ||
return null; | ||
} | ||
} | ||
public interpolate(displacement: number, threshold: number): number { | ||
const initSlope = this.easing(0.00001) / 0.00001; | ||
return this.easing(displacement / (threshold * initSlope)) * threshold; | ||
} | ||
restore(option: ChangeEventOption) { | ||
const pos: Axis = this.axm.get(); | ||
const destPos: Axis = this.axm.map(pos, | ||
(v, opt) => Math.min(opt.range[1], Math.max(opt.range[0], v))); | ||
this.animateTo(destPos, this.getDuration(pos, destPos), option); | ||
} | ||
public stopAnimation(axes: string[], option?: ChangeEventOption): void { | ||
if (this._animateParam && axes.length) { | ||
const orgPos: Axis = this.axisManager.get(axes); | ||
const pos: Axis = this.axisManager.map(orgPos, (v, opt) => | ||
getCirculatedPos(v, opt.range, opt.circular as boolean[]) | ||
); | ||
if (!every(pos, (v, k) => orgPos[k] === v)) { | ||
this.eventManager.triggerChange(pos, false, orgPos, option, !!option); | ||
} | ||
this._animateParam = null; | ||
if (this._raf) { | ||
cancelAnimationFrame(this._raf); | ||
} | ||
this._raf = null; | ||
this.eventManager.triggerAnimationEnd(!!option?.event); | ||
} | ||
} | ||
animationEnd() { | ||
const beforeParam: ChangeEventOption = this.getEventInfo(); | ||
this._animateParam = null; | ||
public getEventInfo(): ChangeEventOption { | ||
if ( | ||
this._animateParam && | ||
this._animateParam.input && | ||
this._animateParam.inputEvent | ||
) { | ||
return { | ||
input: this._animateParam.input, | ||
event: this._animateParam.inputEvent, | ||
}; | ||
} else { | ||
return null; | ||
} | ||
} | ||
// for Circular | ||
const circularTargets = this.axm.filter( | ||
this.axm.get(), | ||
(v, opt) => isCircularable(v, opt.range, opt.circular as boolean[]), | ||
); | ||
Object.keys(circularTargets).length > 0 && this.setTo(this.axm.map( | ||
circularTargets, | ||
(v, opt) => getCirculatedPos(v, opt.range, opt.circular as boolean[]), | ||
)); | ||
this.itm.setInterrupt(false); | ||
this.em.triggerAnimationEnd(!!beforeParam); | ||
if (this.axm.isOutside()) { | ||
this.restore(beforeParam); | ||
} else { | ||
this.finish(!!beforeParam); | ||
} | ||
} | ||
finish(isTrusted) { | ||
this._animateParam = null; | ||
this.itm.setInterrupt(false); | ||
this.em.triggerFinish(isTrusted); | ||
} | ||
private animateLoop(param: AnimationParam, complete: () => void) { | ||
if (param.duration) { | ||
this._animateParam = { ...param }; | ||
const info: AnimationParam = this._animateParam; | ||
const self = this; | ||
let destPos = info.destPos; | ||
let prevPos = info.depaPos; | ||
let prevEasingPer = 0; | ||
const directions = map(prevPos, (value, key) => { | ||
return value <= destPos[key] ? 1 : -1; | ||
}); | ||
const originalIntendedPos = map(destPos, v => v); | ||
let prevTime = new Date().getTime(); | ||
info.startTime = prevTime; | ||
public restore(option: ChangeEventOption): void { | ||
const pos: Axis = this.axisManager.get(); | ||
const destPos: Axis = this.axisManager.map(pos, (v, opt) => | ||
Math.min(opt.range[1], Math.max(opt.range[0], v)) | ||
); | ||
this.stopAnimation(Object.keys(this.axisManager.get())); | ||
this.animateTo(destPos, this.getDuration(pos, destPos), option); | ||
} | ||
(function loop() { | ||
self._raf = null; | ||
const currentTime = new Date().getTime(); | ||
const ratio = (currentTime - info.startTime) / param.duration; | ||
const easingPer = self.easing(ratio); | ||
const toPos: Axis = self.axm.map(prevPos, (pos, options, key) => { | ||
const nextPos = ratio >= 1 | ||
? destPos[key] | ||
: pos + info.delta[key] * (easingPer - prevEasingPer); | ||
public animationEnd(): void { | ||
const beforeParam: ChangeEventOption = this.getEventInfo(); | ||
this._animateParam = null; | ||
// Subtract distance from distance already moved. | ||
// Recalculate the remaining distance. | ||
// Fix the bouncing phenomenon by changing the range. | ||
const circulatedPos = getCirculatedPos(nextPos, options.range, options.circular as boolean[]); | ||
if (nextPos !== circulatedPos) { | ||
// circular | ||
const rangeOffset = directions[key] * (options.range[1] - options.range[0]); | ||
// for Circular | ||
const circularTargets = this.axisManager.filter( | ||
this.axisManager.get(), | ||
(v, opt) => isCircularable(v, opt.range, opt.circular as boolean[]) | ||
); | ||
if (Object.keys(circularTargets).length > 0) { | ||
this.setTo( | ||
this.axisManager.map(circularTargets, (v, opt) => | ||
getCirculatedPos(v, opt.range, opt.circular as boolean[]) | ||
) | ||
); | ||
} | ||
this.interruptManager.setInterrupt(false); | ||
this.eventManager.triggerAnimationEnd(!!beforeParam); | ||
if (this.axisManager.isOutside()) { | ||
this.restore(beforeParam); | ||
} else { | ||
this.finish(!!beforeParam); | ||
} | ||
} | ||
destPos[key] -= rangeOffset; | ||
prevPos[key] -= rangeOffset; | ||
} | ||
return circulatedPos; | ||
}); | ||
const isCanceled = !self.em.triggerChange(toPos, false, prevPos); | ||
public finish(isTrusted: boolean): void { | ||
this._animateParam = null; | ||
this.interruptManager.setInterrupt(false); | ||
this.eventManager.triggerFinish(isTrusted); | ||
} | ||
prevPos = toPos; | ||
prevTime = currentTime; | ||
prevEasingPer = easingPer; | ||
if (easingPer >= 1) { | ||
destPos = self.getFinalPos(destPos, originalIntendedPos); | ||
public getUserControl(param: AnimationParam): { | ||
destPos: Axis; | ||
duration: number; | ||
} { | ||
const userWish = param.setTo(); | ||
userWish.destPos = this.axisManager.get(userWish.destPos); | ||
userWish.duration = clamp( | ||
userWish.duration, | ||
this._options.minimumDuration, | ||
this._options.maximumDuration | ||
); | ||
return userWish; | ||
} | ||
if (!equal(destPos, self.axm.get(Object.keys(destPos)))) { | ||
self.em.triggerChange(destPos, true, prevPos); | ||
} | ||
complete(); | ||
return; | ||
} else if (isCanceled) { | ||
self.finish(false); | ||
} else { | ||
// animationEnd | ||
self._raf = requestAnimationFrame(loop); | ||
} | ||
})(); | ||
} else { | ||
this.em.triggerChange(param.destPos, true); | ||
complete(); | ||
} | ||
} | ||
public animateTo( | ||
destPos: Axis, | ||
duration: number, | ||
option?: ChangeEventOption | ||
): void { | ||
const param: AnimationParam = this._createAnimationParam( | ||
destPos, | ||
duration, | ||
option | ||
); | ||
const depaPos = { ...param.depaPos }; | ||
const retTrigger = this.eventManager.triggerAnimationStart(param); | ||
/** | ||
* Get estimated final value. | ||
* | ||
* If destPos is within the 'error range' of the original intended position, the initial intended position is returned. | ||
* - eg. original intended pos: 100, destPos: 100.0000000004 ==> return 100; | ||
* If dest Pos is outside the 'range of error' compared to the originally intended pos, it is returned rounded based on the originally intended pos. | ||
* - eg. original intended pos: 100.123 destPos: 50.12345 => return 50.123 | ||
* | ||
* @param originalIntendedPos | ||
* @param destPos | ||
*/ | ||
private getFinalPos(destPos: ObjectInterface<number>, originalIntendedPos: ObjectInterface<number>) { | ||
// compare destPos and originalIntendedPos | ||
const ERROR_LIMIT = 0.000001; | ||
const finalPos = map(destPos, (value, key) => { | ||
if (value >= originalIntendedPos[key] - ERROR_LIMIT && value <= originalIntendedPos[key] + ERROR_LIMIT) { | ||
// In error range, return original intended | ||
return originalIntendedPos[key]; | ||
} else { | ||
// Out of error range, return rounded pos. | ||
const roundUnit = this.getRoundUnit(value, key); | ||
const result = roundNumber(value, roundUnit); | ||
return result; | ||
} | ||
}); | ||
return finalPos; | ||
} | ||
// to control | ||
const userWish = this.getUserControl(param); | ||
private getRoundUnit(val: number, key: string) { | ||
const roundUnit = this.options.round; // manual mode | ||
let minRoundUnit = null; // auto mode | ||
// You can't stop the 'animationStart' event when 'circular' is true. | ||
if ( | ||
!retTrigger && | ||
this.axisManager.every(userWish.destPos, (v, opt) => | ||
isCircularable(v, opt.range, opt.circular as boolean[]) | ||
) | ||
) { | ||
console.warn( | ||
"You can't stop the 'animation' event when 'circular' is true." | ||
); | ||
} | ||
// auto mode | ||
if (!roundUnit) { | ||
// Get minimum round unit | ||
const options = this.axm.getAxisOptions(key); | ||
minRoundUnit = inversePow(Math.max( | ||
getDecimalPlace(options.range[0]), | ||
getDecimalPlace(options.range[1]), | ||
getDecimalPlace(val))); | ||
} | ||
if (retTrigger && !equal(userWish.destPos, depaPos)) { | ||
const inputEvent = option?.event || null; | ||
this._animateLoop( | ||
{ | ||
depaPos, | ||
destPos: userWish.destPos, | ||
duration: userWish.duration, | ||
delta: this.axisManager.getDelta(depaPos, userWish.destPos), | ||
isTrusted: !!inputEvent, | ||
inputEvent, | ||
input: option?.input || null, | ||
}, | ||
() => this.animationEnd() | ||
); | ||
} | ||
} | ||
return minRoundUnit || roundUnit; | ||
} | ||
public easing(p: number): number { | ||
return p > 1 ? 1 : this._options.easing(p); | ||
} | ||
getUserControll(param: AnimationParam) { | ||
const userWish = param.setTo(); | ||
userWish.destPos = this.axm.get(userWish.destPos); | ||
userWish.duration = minMax( | ||
userWish.duration, | ||
this.options.minimumDuration, | ||
this.options.maximumDuration); | ||
return userWish; | ||
} | ||
public setTo(pos: Axis, duration: number = 0) { | ||
const axes: string[] = Object.keys(pos); | ||
this.stopAnimation(axes); | ||
const orgPos: Axis = this.axisManager.get(axes); | ||
animateTo(destPos: Axis, duration: number, option?: ChangeEventOption) { | ||
const param: AnimationParam = this.createAnimationParam(destPos, duration, option); | ||
const depaPos = { ...param.depaPos }; | ||
const retTrigger = this.em.triggerAnimationStart(param); | ||
if (equal(pos, orgPos)) { | ||
return this; | ||
} | ||
this.interruptManager.setInterrupt(true); | ||
let movedPos = filter(pos, (v, k) => orgPos[k] !== v); | ||
if (!Object.keys(movedPos).length) { | ||
return this; | ||
} | ||
// to control | ||
const userWish = this.getUserControll(param); | ||
movedPos = this.axisManager.map(movedPos, (v, opt) => { | ||
const { range, circular } = opt; | ||
// You can't stop the 'animationStart' event when 'circular' is true. | ||
if (!retTrigger && this.axm.every( | ||
userWish.destPos, | ||
(v, opt) => isCircularable(v, opt.range, opt.circular as boolean[]))) { | ||
console.warn("You can't stop the 'animation' event when 'circular' is true."); | ||
} | ||
if (circular && (circular[0] || circular[1])) { | ||
return v; | ||
} else { | ||
return getInsidePosition(v, range, circular as boolean[]); | ||
} | ||
}); | ||
if (retTrigger && !equal(userWish.destPos, depaPos)) { | ||
const inputEvent = option && option.event || null; | ||
this.animateLoop({ | ||
depaPos, | ||
destPos: userWish.destPos, | ||
duration: userWish.duration, | ||
delta: this.axm.getDelta(depaPos, userWish.destPos), | ||
isTrusted: !!inputEvent, | ||
inputEvent, | ||
input: option && option.input || null, | ||
}, () => this.animationEnd()); | ||
} | ||
} | ||
if (equal(movedPos, orgPos)) { | ||
return this; | ||
} | ||
easing(p) { | ||
return p > 1 ? 1 : this.options.easing(p); | ||
} | ||
if (duration > 0) { | ||
this.animateTo(movedPos, duration); | ||
} else { | ||
this.eventManager.triggerChange(movedPos); | ||
this.finish(false); | ||
} | ||
setTo(pos: Axis, duration: number = 0) { | ||
const axes: string[] = Object.keys(pos); | ||
this.grab(axes); | ||
const orgPos: Axis = this.axm.get(axes); | ||
return this; | ||
} | ||
if (equal(pos, orgPos)) { | ||
return this; | ||
} | ||
this.itm.setInterrupt(true); | ||
let movedPos = filter(pos, (v, k) => orgPos[k] !== v); | ||
if (!Object.keys(movedPos).length) { | ||
return this; | ||
} | ||
public setBy(pos: Axis, duration = 0) { | ||
return this.setTo( | ||
map(this.axisManager.get(Object.keys(pos)), (v, k) => v + pos[k]), | ||
duration | ||
); | ||
} | ||
movedPos = this.axm.map(movedPos, (v, opt) => { | ||
const { range, circular } = opt; | ||
public updateAnimation(options: UpdateAnimationOption): void { | ||
const animateParam = this._animateParam; | ||
if (!animateParam) { | ||
return; | ||
} | ||
if (circular && (circular[0] || circular[1])) { | ||
return v; | ||
} else { | ||
return getInsidePosition(v, range, circular as boolean[]); | ||
} | ||
}); | ||
const diffTime = new Date().getTime() - animateParam.startTime; | ||
const pos = options?.destPos || animateParam.destPos; | ||
const duration = options?.duration || animateParam.duration; | ||
if (options?.restart || duration <= diffTime) { | ||
this.setTo(pos, duration - diffTime); | ||
return; | ||
} | ||
if (options?.destPos) { | ||
const currentPos = this.axisManager.get(); | ||
// When destination is changed, new delta should be calculated as remaining percent. | ||
// For example, moving x:0, y:0 to x:200, y:200 and it has current easing percent of 92%. coordinate is x:184 and y:184 | ||
// If destination changes to x:300, y:300. xdelta:200, ydelta:200 changes to xdelta:116, ydelta:116 and use remaining easingPer as 100%, not 8% as previous. | ||
// Therefore, original easingPer by time is kept. And divided by (1 - self._initialEasingPer) which means new total easing percent. Like calculating 8% as 100%. | ||
this._initialEasingPer = this._prevEasingPer; | ||
animateParam.delta = this.axisManager.getDelta(currentPos, pos); | ||
animateParam.destPos = pos; | ||
} | ||
if (options?.duration) { | ||
const ratio = (diffTime + this._durationOffset) / animateParam.duration; | ||
// Use durationOffset for keeping animation ratio after duration is changed. | ||
// newRatio = (diffTime + newDurationOffset) / newDuration = oldRatio | ||
// newDurationOffset = oldRatio * newDuration - diffTime | ||
this._durationOffset = ratio * duration - diffTime; | ||
animateParam.duration = duration; | ||
} | ||
} | ||
if (equal(movedPos, orgPos)) { | ||
return this; | ||
} | ||
private _createAnimationParam( | ||
pos: Axis, | ||
duration: number, | ||
option?: ChangeEventOption | ||
): AnimationParam { | ||
const depaPos: Axis = this.axisManager.get(); | ||
const destPos: Axis = pos; | ||
const inputEvent = option?.event || null; | ||
return { | ||
depaPos, | ||
destPos, | ||
duration: clamp( | ||
duration, | ||
this._options.minimumDuration, | ||
this._options.maximumDuration | ||
), | ||
delta: this.axisManager.getDelta(depaPos, destPos), | ||
inputEvent, | ||
input: option?.input || null, | ||
isTrusted: !!inputEvent, | ||
done: this.animationEnd, | ||
}; | ||
} | ||
if (duration > 0) { | ||
this.animateTo(movedPos, duration); | ||
} else { | ||
this.em.triggerChange(movedPos); | ||
this.finish(false); | ||
} | ||
private _animateLoop(param: AnimationParam, complete: () => void): void { | ||
if (param.duration) { | ||
let prevPos = param.depaPos; | ||
this._initialEasingPer = 0; | ||
this._prevEasingPer = 0; | ||
this._durationOffset = 0; | ||
this._animateParam = { | ||
...param, | ||
startTime: new Date().getTime(), | ||
}; | ||
const directions = map(prevPos, (value, key) => { | ||
return value <= param.destPos[key] ? 1 : -1; | ||
}); | ||
const originalIntendedPos = map(param.destPos, (v) => v); | ||
const loop = () => { | ||
const animateParam = this._animateParam; | ||
const diffTime = new Date().getTime() - animateParam.startTime; | ||
const ratio = (diffTime + this._durationOffset) / animateParam.duration; | ||
const easingPer = this.easing(ratio); | ||
this._raf = null; | ||
const toPos: Axis = this.axisManager.map( | ||
prevPos, | ||
(pos, options, key) => { | ||
const nextPos = | ||
ratio >= 1 | ||
? animateParam.destPos[key] | ||
: pos + | ||
(animateParam.delta[key] * | ||
(easingPer - this._prevEasingPer)) / | ||
(1 - this._initialEasingPer); | ||
return this; | ||
} | ||
// Subtract distance from distance already moved. | ||
// Recalculate the remaining distance. | ||
// Fix the bouncing phenomenon by changing the range. | ||
const circulatedPos = getCirculatedPos( | ||
nextPos, | ||
options.range, | ||
options.circular as boolean[] | ||
); | ||
if (nextPos !== circulatedPos) { | ||
// circular | ||
const rangeOffset = | ||
directions[key] * (options.range[1] - options.range[0]); | ||
setBy(pos: Axis, duration = 0) { | ||
return this.setTo( | ||
map(this.axm.get(Object.keys(pos)), (v, k) => v + pos[k]), | ||
duration, | ||
); | ||
} | ||
animateParam.destPos[key] -= rangeOffset; | ||
prevPos[key] -= rangeOffset; | ||
} | ||
return circulatedPos; | ||
} | ||
); | ||
const isCanceled = !this.eventManager.triggerChange( | ||
toPos, | ||
false, | ||
prevPos | ||
); | ||
prevPos = toPos; | ||
this._prevEasingPer = easingPer; | ||
if (easingPer >= 1) { | ||
animateParam.destPos = this._getFinalPos( | ||
animateParam.destPos, | ||
originalIntendedPos | ||
); | ||
if ( | ||
!equal( | ||
animateParam.destPos, | ||
this.axisManager.get(Object.keys(animateParam.destPos)) | ||
) | ||
) { | ||
this.eventManager.triggerChange( | ||
animateParam.destPos, | ||
true, | ||
prevPos | ||
); | ||
} | ||
complete(); | ||
return; | ||
} else if (isCanceled) { | ||
this.finish(false); | ||
} else { | ||
// animationEnd | ||
this._raf = requestAnimationFrame(loop); | ||
} | ||
}; | ||
loop(); | ||
} else { | ||
this.eventManager.triggerChange(param.destPos, true); | ||
complete(); | ||
} | ||
} | ||
/** | ||
* Get estimated final value. | ||
* | ||
* If destPos is within the 'error range' of the original intended position, the initial intended position is returned. | ||
* - eg. original intended pos: 100, destPos: 100.0000000004 ==> return 100; | ||
* If dest Pos is outside the 'range of error' compared to the originally intended pos, it is returned rounded based on the originally intended pos. | ||
* - eg. original intended pos: 100.123 destPos: 50.12345 => return 50.123 | ||
* @param originalIntendedPos | ||
* @param destPos | ||
*/ | ||
private _getFinalPos( | ||
destPos: ObjectInterface<number>, | ||
originalIntendedPos: ObjectInterface<number> | ||
): Axis { | ||
// compare destPos and originalIntendedPos | ||
// eslint-disable-next-line @typescript-eslint/naming-convention | ||
const ERROR_LIMIT = 0.000001; | ||
const finalPos = map(destPos, (value, key) => { | ||
if ( | ||
value >= originalIntendedPos[key] - ERROR_LIMIT && | ||
value <= originalIntendedPos[key] + ERROR_LIMIT | ||
) { | ||
// In error range, return original intended | ||
return originalIntendedPos[key]; | ||
} else { | ||
// Out of error range, return rounded pos. | ||
const roundUnit = this._getRoundUnit(value, key); | ||
const result = roundNumber(value, roundUnit); | ||
return result; | ||
} | ||
}); | ||
return finalPos; | ||
} | ||
private _getRoundUnit(val: number, key: string): number { | ||
const roundUnit = this._options.round; // manual mode | ||
let minRoundUnit = null; // auto mode | ||
// auto mode | ||
if (!roundUnit) { | ||
// Get minimum round unit | ||
const options = this.axisManager.getAxisOptions(key); | ||
minRoundUnit = inversePow( | ||
Math.max( | ||
getDecimalPlace(options.range[0]), | ||
getDecimalPlace(options.range[1]), | ||
getDecimalPlace(val) | ||
) | ||
); | ||
} | ||
return minRoundUnit || roundUnit; | ||
} | ||
} |
788
src/Axes.ts
import Component from "@egjs/component"; | ||
import { AnimationManager } from "./AnimationManager"; | ||
@@ -8,16 +9,22 @@ import { EventManager } from "./EventManager"; | ||
import { | ||
TRANSFORM, | ||
DIRECTION_NONE, DIRECTION_LEFT, DIRECTION_RIGHT, | ||
DIRECTION_UP, DIRECTION_DOWN, DIRECTION_HORIZONTAL, DIRECTION_VERTICAL, DIRECTION_ALL | ||
TRANSFORM, | ||
DIRECTION_NONE, | ||
DIRECTION_LEFT, | ||
DIRECTION_RIGHT, | ||
DIRECTION_UP, | ||
DIRECTION_DOWN, | ||
DIRECTION_HORIZONTAL, | ||
DIRECTION_VERTICAL, | ||
DIRECTION_ALL, | ||
} from "./const"; | ||
import { IInputType } from "./inputType/InputType"; | ||
import { AxesEvents, ObjectInterface } from "./types"; | ||
import { InputType } from "./inputType/InputType"; | ||
import { AxesEvents, ObjectInterface, UpdateAnimationOption } from "./types"; | ||
export interface AxesOption { | ||
easing?: (x: number) => number; | ||
maximumDuration?: number; | ||
minimumDuration?: number; | ||
deceleration?: number; | ||
interruptable?: boolean; | ||
round?: number; | ||
easing?: (x: number) => number; | ||
maximumDuration?: number; | ||
minimumDuration?: number; | ||
deceleration?: number; | ||
interruptable?: boolean; | ||
round?: number; | ||
} | ||
@@ -28,12 +35,12 @@ | ||
* @ko 축 정보. 축의 키는 논리적인 가상 좌표계로 사용할 이름을 지정한다. | ||
* @property {Number[]} [range] The coordinate of range <ko>좌표 범위</ko> | ||
* @property {Number} [range.0=0] The coordinate of the minimum <ko>최소 좌표</ko> | ||
* @property {Number} [range.1=0] The coordinate of the maximum <ko>최대 좌표</ko> | ||
* @property {Number[]} [bounce] The size of bouncing area. The coordinates can exceed the coordinate area as much as the bouncing area based on user action. If the coordinates does not exceed the bouncing area when an element is dragged, the coordinates where bouncing effects are applied are retuned back into the coordinate area<ko>바운스 영역의 크기. 사용자의 동작에 따라 좌표가 좌표 영역을 넘어 바운스 영역의 크기만큼 더 이동할 수 있다. 사용자가 끌어다 놓는 동작을 했을 때 좌표가 바운스 영역에 있으면, 바운스 효과가 적용된 좌표가 다시 좌표 영역 안으로 들어온다</ko> | ||
* @property {Number} [bounce.0=0] The size of coordinate of the minimum area <ko>최소 좌표 바운스 영역의 크기</ko> | ||
* @property {Number} [bounce.1=0] The size of coordinate of the maximum area <ko>최대 좌표 바운스 영역의 크기</ko> | ||
* @property {Boolean[]} [circular] Indicates whether a circular element is available. If it is set to "true" and an element is dragged outside the coordinate area, the element will appear on the other side.<ko>순환 여부. 'true'로 설정한 방향의 좌표 영역 밖으로 엘리먼트가 이동하면 반대 방향에서 엘리먼트가 나타난다</ko> | ||
* @property {Boolean} [circular.0=false] Indicates whether to circulate to the coordinate of the minimum <ko>최소 좌표 방향의 순환 여부</ko> | ||
* @property {Boolean} [circular.1=false] Indicates whether to circulate to the coordinate of the maximum <ko>최대 좌표 방향의 순환 여부</ko> | ||
**/ | ||
* @param {Number[]} [range] The coordinate of range <ko>좌표 범위</ko> | ||
* @param {Number} [range[0]=0] The coordinate of the minimum <ko>최소 좌표</ko> | ||
* @param {Number} [range[1]=0] The coordinate of the maximum <ko>최대 좌표</ko> | ||
* @param {Number[]} [bounce] The size of bouncing area. The coordinates can exceed the coordinate area as much as the bouncing area based on user action. If the coordinates does not exceed the bouncing area when an element is dragged, the coordinates where bouncing effects are applied are retuned back into the coordinate area<ko>바운스 영역의 크기. 사용자의 동작에 따라 좌표가 좌표 영역을 넘어 바운스 영역의 크기만큼 더 이동할 수 있다. 사용자가 끌어다 놓는 동작을 했을 때 좌표가 바운스 영역에 있으면, 바운스 효과가 적용된 좌표가 다시 좌표 영역 안으로 들어온다</ko> | ||
* @param {Number} [bounce[0]=0] The size of coordinate of the minimum area <ko>최소 좌표 바운스 영역의 크기</ko> | ||
* @param {Number} [bounce[1]=0] The size of coordinate of the maximum area <ko>최대 좌표 바운스 영역의 크기</ko> | ||
* @param {Boolean[]} [circular] Indicates whether a circular element is available. If it is set to "true" and an element is dragged outside the coordinate area, the element will appear on the other side.<ko>순환 여부. 'true'로 설정한 방향의 좌표 영역 밖으로 엘리먼트가 이동하면 반대 방향에서 엘리먼트가 나타난다</ko> | ||
* @param {Boolean} [circular[0]=false] Indicates whether to circulate to the coordinate of the minimum <ko>최소 좌표 방향의 순환 여부</ko> | ||
* @param {Boolean} [circular[1]=false] Indicates whether to circulate to the coordinate of the maximum <ko>최대 좌표 방향의 순환 여부</ko> | ||
**/ | ||
@@ -43,13 +50,19 @@ /** | ||
* @ko eg.Axes 모듈의 옵션 객체 | ||
* @property {Function} [easing=easing.easeOutCubic] The easing function to apply to an animation <ko>애니메이션에 적용할 easing 함수</ko> | ||
* @property {Number} [maximumDuration=Infinity] Maximum duration of the animation <ko>가속도에 의해 애니메이션이 동작할 때의 최대 좌표 이동 시간</ko> | ||
* @property {Number} [minimumDuration=0] Minimum duration of the animation <ko>가속도에 의해 애니메이션이 동작할 때의 최소 좌표 이동 시간</ko> | ||
* @property {Number} [deceleration=0.0006] Deceleration of the animation where acceleration is manually enabled by user. A higher value indicates shorter running time. <ko>사용자의 동작으로 가속도가 적용된 애니메이션의 감속도. 값이 높을수록 애니메이션 실행 시간이 짧아진다</ko> | ||
* @property {Boolean} [interruptable=true] Indicates whether an animation is interruptible.<br>- true: It can be paused or stopped by user action or the API.<br>- false: It cannot be paused or stopped by user action or the API while it is running.<ko>진행 중인 애니메이션 중지 가능 여부.<br>- true: 사용자의 동작이나 API로 애니메이션을 중지할 수 있다.<br>- false: 애니메이션이 진행 중일 때는 사용자의 동작이나 API가 적용되지 않는다</ko> | ||
* @property {Number} [round = null] Rounding unit. For example, 0.1 rounds to 0.1 decimal point(6.1234 => 6.1), 5 rounds to 5 (93 => 95) <br>[Details](https://github.com/naver/egjs-axes/wiki/round-option)<ko>반올림 단위. 예를 들어 0.1 은 소숫점 0.1 까지 반올림(6.1234 => 6.1), 5 는 5 단위로 반올림(93 => 95).<br>[상세내용](https://github.com/naver/egjs-axes/wiki/round-option)</ko> | ||
**/ | ||
* @param {Function} [easing=easing.easeOutCubic] The easing function to apply to an animation <ko>애니메이션에 적용할 easing 함수</ko> | ||
* @param {Number} [maximumDuration=Infinity] Maximum duration of the animation <ko>가속도에 의해 애니메이션이 동작할 때의 최대 좌표 이동 시간</ko> | ||
* @param {Number} [minimumDuration=0] Minimum duration of the animation <ko>가속도에 의해 애니메이션이 동작할 때의 최소 좌표 이동 시간</ko> | ||
* @param {Number} [deceleration=0.0006] Deceleration of the animation where acceleration is manually enabled by user. A higher value indicates shorter running time. <ko>사용자의 동작으로 가속도가 적용된 애니메이션의 감속도. 값이 높을수록 애니메이션 실행 시간이 짧아진다</ko> | ||
* @param {Boolean} [interruptable=true] Indicates whether an animation is interruptible. | ||
* - true: It can be paused or stopped by user action or the API. | ||
* - false: It cannot be paused or stopped by user action or the API while it is running. | ||
* <ko>진행 중인 애니메이션 중지 가능 여부. | ||
* - true: 사용자의 동작이나 API로 애니메이션을 중지할 수 있다. | ||
* - false: 애니메이션이 진행 중일 때는 사용자의 동작이나 API가 적용되지 않는다</ko> | ||
* @param {Number} [round=null] Rounding unit. For example, 0.1 rounds to 0.1 decimal point(6.1234 => 6.1), 5 rounds to 5 (93 => 95) | ||
* [Details](https://github.com/naver/egjs-axes/wiki/round-option)<ko>반올림 단위. 예를 들어 0.1 은 소숫점 0.1 까지 반올림(6.1234 => 6.1), 5 는 5 단위로 반올림(93 => 95). | ||
* [상세내용](https://github.com/naver/egjs-axes/wiki/round-option)</ko> | ||
**/ | ||
/** | ||
* @class eg.Axes | ||
* @classdesc A module used to change the information of user action entered by various input devices such as touch screen or mouse into the logical virtual coordinates. You can easily create a UI that responds to user actions. | ||
* A module used to change the information of user action entered by various input devices such as touch screen or mouse into the logical virtual coordinates. You can easily create a UI that responds to user actions. | ||
* @ko 터치 입력 장치나 마우스와 같은 다양한 입력 장치를 통해 전달 받은 사용자의 동작을 논리적인 가상 좌표로 변경하는 모듈이다. 사용자 동작에 반응하는 UI를 손쉽게 만들수 있다. | ||
@@ -59,8 +72,8 @@ * @extends eg.Component | ||
* @param {Object.<string, AxisOption>} axis Axis information managed by eg.Axes. The key of the axis specifies the name to use as the logical virtual coordinate system. <ko>eg.Axes가 관리하는 축 정보. 축의 키는 논리적인 가상 좌표계로 사용할 이름을 지정한다.</ko> | ||
* @param {AxesOption} [options] The option object of the eg.Axes module<ko>eg.Axes 모듈의 옵션 객체</ko> | ||
* @param {Object.<string, number>} [startPos] The coordinates to be moved when creating an instance. not triggering change event.<ko>인스턴스 생성시 이동할 좌표, change 이벤트는 발생하지 않음.</ko> | ||
* @param {AxesOption} [options={}] The option object of the eg.Axes module<ko>eg.Axes 모듈의 옵션 객체</ko> | ||
* @param {Object.<string, number>} [startPos=null] The coordinates to be moved when creating an instance. not triggering change event.<ko>인스턴스 생성시 이동할 좌표, change 이벤트는 발생하지 않음.</ko> | ||
* | ||
* @support {"ie": "10+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"} | ||
* @example | ||
* | ||
* ```js | ||
* // 1. Initialize eg.Axes | ||
@@ -121,332 +134,407 @@ * const axes = new eg.Axes({ | ||
* axes.connect("something2", pinchInputArea); | ||
* ``` | ||
*/ | ||
export default class Axes extends Component<AxesEvents> { | ||
/** | ||
* Version info string | ||
* @ko 버전정보 문자열 | ||
* @name VERSION | ||
* @static | ||
* @type {String} | ||
* @example | ||
* eg.Axes.VERSION; // ex) 3.3.3 | ||
* @memberof eg.Axes | ||
*/ | ||
static VERSION = "#__VERSION__#"; | ||
// for tree shaking | ||
static PanInput; | ||
static PinchInput; | ||
static WheelInput; | ||
static MoveKeyInput; | ||
static RotatePanInput; | ||
class Axes extends Component<AxesEvents> { | ||
/** | ||
* @name VERSION | ||
* @desc Version info string | ||
* @ko 버전정보 문자열 | ||
* | ||
* @constant | ||
* @type {String} | ||
* @example | ||
* ```js | ||
* eg.Axes.VERSION; // ex) 3.3.3 | ||
* ``` | ||
*/ | ||
public static VERSION = "#__VERSION__#"; | ||
/* eslint-disable */ | ||
// for tree shaking | ||
public static PanInput; | ||
public static PinchInput; | ||
public static WheelInput; | ||
public static MoveKeyInput; | ||
public static RotatePanInput; | ||
/* eslint-enable */ | ||
/** | ||
* @name eg.Axes.TRANSFORM | ||
* @desc Returns the transform attribute with CSS vendor prefixes. | ||
* @ko CSS vendor prefixes를 붙인 transform 속성을 반환한다. | ||
* | ||
* @constant | ||
* @type {String} | ||
* @example | ||
* eg.Axes.TRANSFORM; // "transform" or "webkitTransform" | ||
*/ | ||
static TRANSFORM = TRANSFORM; | ||
/** | ||
* @name eg.Axes.DIRECTION_NONE | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
static DIRECTION_NONE = DIRECTION_NONE; | ||
/** | ||
* @name eg.Axes.DIRECTION_LEFT | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
static DIRECTION_LEFT = DIRECTION_LEFT; | ||
/** | ||
* @name eg.Axes.DIRECTION_RIGHT | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
static DIRECTION_RIGHT = DIRECTION_RIGHT; | ||
/** | ||
* @name eg.Axes.DIRECTION_UP | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
static DIRECTION_UP = DIRECTION_UP; | ||
/** | ||
* @name eg.Axes.DIRECTION_DOWN | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
static DIRECTION_DOWN = DIRECTION_DOWN; | ||
/** | ||
* @name eg.Axes.DIRECTION_HORIZONTAL | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
static DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL; | ||
/** | ||
* @name eg.Axes.DIRECTION_VERTICAL | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
static DIRECTION_VERTICAL = DIRECTION_VERTICAL; | ||
/** | ||
* @name eg.Axes.DIRECTION_ALL | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
public static DIRECTION_ALL = DIRECTION_ALL; | ||
/** | ||
* @name TRANSFORM | ||
* @desc Returns the transform attribute with CSS vendor prefixes. | ||
* @ko CSS vendor prefixes를 붙인 transform 속성을 반환한다. | ||
* | ||
* @constant | ||
* @type {String} | ||
* @example | ||
* ```js | ||
* eg.Axes.TRANSFORM; // "transform" or "webkitTransform" | ||
* ``` | ||
*/ | ||
public static TRANSFORM = TRANSFORM; | ||
/** | ||
* @name DIRECTION_NONE | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
public static DIRECTION_NONE = DIRECTION_NONE; | ||
/** | ||
* @name DIRECTION_LEFT | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
public static DIRECTION_LEFT = DIRECTION_LEFT; | ||
/** | ||
* @name DIRECTION_RIGHT | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
public static DIRECTION_RIGHT = DIRECTION_RIGHT; | ||
/** | ||
* @name DIRECTION_UP | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
public static DIRECTION_UP = DIRECTION_UP; | ||
/** | ||
* @name DIRECTION_DOWN | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
public static DIRECTION_DOWN = DIRECTION_DOWN; | ||
/** | ||
* @name DIRECTION_HORIZONTAL | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
public static DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL; | ||
/** | ||
* @name DIRECTION_VERTICAL | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
public static DIRECTION_VERTICAL = DIRECTION_VERTICAL; | ||
/** | ||
* @name DIRECTION_ALL | ||
* @constant | ||
* @type {Number} | ||
*/ | ||
public static DIRECTION_ALL = DIRECTION_ALL; | ||
public options: AxesOption; | ||
public em: EventManager; | ||
public axm: AxisManager; | ||
public itm: InterruptManager; | ||
public am: AnimationManager; | ||
public io: InputObserver; | ||
private _inputs: IInputType[] = []; | ||
public options: AxesOption; | ||
public eventManager: EventManager; | ||
public axisManager: AxisManager; | ||
public interruptManager: InterruptManager; | ||
public animationManager: AnimationManager; | ||
public inputObserver: InputObserver; | ||
private _inputs: InputType[] = []; | ||
constructor(public axis: ObjectInterface<AxisOption> = {}, options: AxesOption = {}, startPos?: Axis) { | ||
super(); | ||
this.options = { | ||
...{ | ||
easing: function easeOutCubic(x) { | ||
return 1 - Math.pow(1 - x, 3); | ||
}, | ||
interruptable: true, | ||
maximumDuration: Infinity, | ||
minimumDuration: 0, | ||
deceleration: 0.0006, | ||
round: null, | ||
}, ...options, | ||
}; | ||
/** | ||
* | ||
*/ | ||
public constructor( | ||
public axis: ObjectInterface<AxisOption> = {}, | ||
options: AxesOption = {}, | ||
startPos: Axis = null | ||
) { | ||
super(); | ||
this.options = { | ||
...{ | ||
easing: (x) => { | ||
return 1 - Math.pow(1 - x, 3); | ||
}, | ||
interruptable: true, | ||
maximumDuration: Infinity, | ||
minimumDuration: 0, | ||
deceleration: 0.0006, | ||
round: null, | ||
}, | ||
...options, | ||
}; | ||
this.itm = new InterruptManager(this.options); | ||
this.axm = new AxisManager(this.axis, this.options); | ||
this.em = new EventManager(this); | ||
this.am = new AnimationManager(this); | ||
this.io = new InputObserver(this); | ||
this.em.setAnimationManager(this.am); | ||
startPos && this.em.triggerChange(startPos); | ||
} | ||
/** | ||
* Connect the axis of eg.Axes to the inputType. | ||
* @ko eg.Axes의 축과 inputType을 연결한다 | ||
* @method eg.Axes#connect | ||
* @param {(String[]|String)} axes The name of the axis to associate with inputType <ko>inputType과 연결할 축의 이름</ko> | ||
* @param {Object} inputType The inputType instance to associate with the axis of eg.Axes <ko>eg.Axes의 축과 연결할 inputType 인스턴스<ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* } | ||
* }); | ||
* | ||
* axes.connect("x", new eg.Axes.PanInput("#area1")) | ||
* .connect("x xOther", new eg.Axes.PanInput("#area2")) | ||
* .connect(" xOther", new eg.Axes.PanInput("#area3")) | ||
* .connect(["x"], new eg.Axes.PanInput("#area4")) | ||
* .connect(["xOther", "x"], new eg.Axes.PanInput("#area5")) | ||
* .connect(["", "xOther"], new eg.Axes.PanInput("#area6")); | ||
*/ | ||
connect(axes: string[] | string, inputType: IInputType) { | ||
let mapped; | ||
if (typeof axes === "string") { | ||
mapped = axes.split(" "); | ||
} else { | ||
mapped = axes.concat(); | ||
} | ||
this.interruptManager = new InterruptManager(this.options); | ||
this.axisManager = new AxisManager(this.axis); | ||
this.eventManager = new EventManager(this); | ||
this.animationManager = new AnimationManager(this); | ||
this.inputObserver = new InputObserver(this); | ||
this.eventManager.setAnimationManager(this.animationManager); | ||
if (startPos) { | ||
this.eventManager.triggerChange(startPos); | ||
} | ||
} | ||
// check same instance | ||
if (~this._inputs.indexOf(inputType)) { | ||
this.disconnect(inputType); | ||
} | ||
/** | ||
* Connect the axis of eg.Axes to the inputType. | ||
* @ko eg.Axes의 축과 inputType을 연결한다 | ||
* @param {(String[]|String)} axes The name of the axis to associate with inputType <ko>inputType과 연결할 축의 이름</ko> | ||
* @param {Object} inputType The inputType instance to associate with the axis of eg.Axes <ko>eg.Axes의 축과 연결할 inputType 인스턴스</ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* } | ||
* }); | ||
* | ||
* axes.connect("x", new eg.Axes.PanInput("#area1")) | ||
* .connect("x xOther", new eg.Axes.PanInput("#area2")) | ||
* .connect(" xOther", new eg.Axes.PanInput("#area3")) | ||
* .connect(["x"], new eg.Axes.PanInput("#area4")) | ||
* .connect(["xOther", "x"], new eg.Axes.PanInput("#area5")) | ||
* .connect(["", "xOther"], new eg.Axes.PanInput("#area6")); | ||
* ``` | ||
*/ | ||
public connect(axes: string[] | string, inputType: InputType) { | ||
let mapped: string[]; | ||
if (typeof axes === "string") { | ||
mapped = axes.split(" "); | ||
} else { | ||
mapped = axes.concat(); | ||
} | ||
// check same element in hammer type for share | ||
if ("hammer" in inputType) { | ||
const targets = this._inputs.filter(v => v.hammer && v.element === inputType.element); | ||
if (targets.length) { | ||
inputType.hammer = targets[0].hammer; | ||
} | ||
} | ||
inputType.mapAxes(mapped); | ||
inputType.connect(this.io); | ||
this._inputs.push(inputType); | ||
return this; | ||
} | ||
/** | ||
* Disconnect the axis of eg.Axes from the inputType. | ||
* @ko eg.Axes의 축과 inputType의 연결을 끊는다. | ||
* @method eg.Axes#disconnect | ||
* @param {Object} [inputType] An inputType instance associated with the axis of eg.Axes <ko>eg.Axes의 축과 연결한 inputType 인스턴스<ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* } | ||
* }); | ||
* | ||
* const input1 = new eg.Axes.PanInput("#area1"); | ||
* const input2 = new eg.Axes.PanInput("#area2"); | ||
* const input3 = new eg.Axes.PanInput("#area3"); | ||
* | ||
* axes.connect("x", input1); | ||
* .connect("x xOther", input2) | ||
* .connect(["xOther", "x"], input3); | ||
* | ||
* axes.disconnect(input1); // disconnects input1 | ||
* axes.disconnect(); // disconnects all of them | ||
*/ | ||
disconnect(inputType?: IInputType) { | ||
if (inputType) { | ||
const index = this._inputs.indexOf(inputType); | ||
// check same instance | ||
if (~this._inputs.indexOf(inputType)) { | ||
this.disconnect(inputType); | ||
} | ||
if (index >= 0) { | ||
this._inputs[index].disconnect(); | ||
this._inputs.splice(index, 1); | ||
} | ||
} else { | ||
this._inputs.forEach(v => v.disconnect()); | ||
this._inputs = []; | ||
} | ||
return this; | ||
} | ||
inputType.mapAxes(mapped); | ||
inputType.connect(this.inputObserver); | ||
this._inputs.push(inputType); | ||
return this; | ||
} | ||
/** | ||
* Returns the current position of the coordinates. | ||
* @ko 좌표의 현재 위치를 반환한다 | ||
* @method eg.Axes#get | ||
* @param {Object} [axes] The names of the axis <ko>축 이름들</ko> | ||
* @return {Object.<string, number>} Axis coordinate information <ko>축 좌표 정보</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.get(); // {"x": 0, "xOther": -100, "zoom": 50} | ||
* axes.get(["x", "zoom"]); // {"x": 0, "zoom": 50} | ||
*/ | ||
get(axes?: string[]) { | ||
return this.axm.get(axes); | ||
} | ||
/** | ||
* Disconnect the axis of eg.Axes from the inputType. | ||
* @ko eg.Axes의 축과 inputType의 연결을 끊는다. | ||
* @param {Object} [inputType] An inputType instance associated with the axis of eg.Axes <ko>eg.Axes의 축과 연결한 inputType 인스턴스</ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* } | ||
* }); | ||
* | ||
* const input1 = new eg.Axes.PanInput("#area1"); | ||
* const input2 = new eg.Axes.PanInput("#area2"); | ||
* const input3 = new eg.Axes.PanInput("#area3"); | ||
* | ||
* axes.connect("x", input1); | ||
* .connect("x xOther", input2) | ||
* .connect(["xOther", "x"], input3); | ||
* | ||
* axes.disconnect(input1); // disconnects input1 | ||
* axes.disconnect(); // disconnects all of them | ||
* ``` | ||
*/ | ||
public disconnect(inputType?: InputType) { | ||
if (inputType) { | ||
const index = this._inputs.indexOf(inputType); | ||
/** | ||
* Moves an axis to specific coordinates. | ||
* @ko 좌표를 이동한다. | ||
* @method eg.Axes#setTo | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @param {Number} [duration=0] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.setTo({"x": 30, "zoom": 60}); | ||
* axes.get(); // {"x": 30, "xOther": -100, "zoom": 60} | ||
* | ||
* axes.setTo({"x": 100, "xOther": 60}, 1000); // animatation | ||
* | ||
* // after 1000 ms | ||
* axes.get(); // {"x": 100, "xOther": 60, "zoom": 60} | ||
*/ | ||
setTo(pos: Axis, duration = 0) { | ||
this.am.setTo(pos, duration); | ||
return this; | ||
} | ||
if (index >= 0) { | ||
this._inputs[index].disconnect(); | ||
this._inputs.splice(index, 1); | ||
} | ||
} else { | ||
this._inputs.forEach((v) => v.disconnect()); | ||
this._inputs = []; | ||
} | ||
return this; | ||
} | ||
/** | ||
* Moves an axis from the current coordinates to specific coordinates. | ||
* @ko 현재 좌표를 기준으로 좌표를 이동한다. | ||
* @method eg.Axes#setBy | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @param {Number} [duration=0] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.setBy({"x": 30, "zoom": 10}); | ||
* axes.get(); // {"x": 30, "xOther": -100, "zoom": 60} | ||
* | ||
* axes.setBy({"x": 70, "xOther": 60}, 1000); // animatation | ||
* | ||
* // after 1000 ms | ||
* axes.get(); // {"x": 100, "xOther": -40, "zoom": 60} | ||
*/ | ||
setBy(pos: Axis, duration = 0) { | ||
this.am.setBy(pos, duration); | ||
return this; | ||
} | ||
/** | ||
* Returns the current position of the coordinates. | ||
* @ko 좌표의 현재 위치를 반환한다 | ||
* @param {Object} [axes] The names of the axis <ko>축 이름들</ko> | ||
* @return {Object.<string, number>} Axis coordinate information <ko>축 좌표 정보</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.get(); // {"x": 0, "xOther": -100, "zoom": 50} | ||
* axes.get(["x", "zoom"]); // {"x": 0, "zoom": 50} | ||
* ``` | ||
*/ | ||
public get(axes?: string[]) { | ||
return this.axisManager.get(axes); | ||
} | ||
/** | ||
* Returns whether there is a coordinate in the bounce area of the target axis. | ||
* @ko 대상 축 중 bounce영역에 좌표가 존재하는지를 반환한다 | ||
* @method eg.Axes#isBounceArea | ||
* @param {Object} [axes] The names of the axis <ko>축 이름들</ko> | ||
* @return {Boolen} Whether the bounce area exists. <ko>bounce 영역 존재 여부</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.isBounceArea(["x"]); | ||
* axes.isBounceArea(["x", "zoom"]); | ||
* axes.isBounceArea(); | ||
*/ | ||
isBounceArea(axes?: string[]) { | ||
return this.axm.isOutside(axes); | ||
} | ||
/** | ||
* Moves an axis to specific coordinates. | ||
* @ko 좌표를 이동한다. | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @param {Number} [duration=0] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.setTo({"x": 30, "zoom": 60}); | ||
* axes.get(); // {"x": 30, "xOther": -100, "zoom": 60} | ||
* | ||
* axes.setTo({"x": 100, "xOther": 60}, 1000); // animatation | ||
* | ||
* // after 1000 ms | ||
* axes.get(); // {"x": 100, "xOther": 60, "zoom": 60} | ||
* ``` | ||
*/ | ||
public setTo(pos: Axis, duration = 0) { | ||
this.animationManager.setTo(pos, duration); | ||
return this; | ||
} | ||
/** | ||
* Destroys properties, and events used in a module and disconnect all connections to inputTypes. | ||
* @ko 모듈에 사용한 속성, 이벤트를 해제한다. 모든 inputType과의 연결을 끊는다. | ||
* @method eg.Axes#destroy | ||
*/ | ||
destroy() { | ||
this.disconnect(); | ||
this.em.destroy(); | ||
} | ||
/** | ||
* Moves an axis from the current coordinates to specific coordinates. | ||
* @ko 현재 좌표를 기준으로 좌표를 이동한다. | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @param {Number} [duration=0] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.setBy({"x": 30, "zoom": 10}); | ||
* axes.get(); // {"x": 30, "xOther": -100, "zoom": 60} | ||
* | ||
* axes.setBy({"x": 70, "xOther": 60}, 1000); // animatation | ||
* | ||
* // after 1000 ms | ||
* axes.get(); // {"x": 100, "xOther": -40, "zoom": 60} | ||
* ``` | ||
*/ | ||
public setBy(pos: Axis, duration = 0) { | ||
this.animationManager.setBy(pos, duration); | ||
return this; | ||
} | ||
/** | ||
* Stop an animation in progress. | ||
* @ko 재생 중인 애니메이션을 정지한다. | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* }); | ||
* | ||
* axes.setTo({"x": 10}, 1000); // start animatation | ||
* | ||
* // after 500 ms | ||
* axes.stopAnimation(); // stop animation during movement. | ||
* ``` | ||
*/ | ||
public stopAnimation() { | ||
this.animationManager.stopAnimation(Object.keys(this.axisManager.get())); | ||
return this; | ||
} | ||
/** | ||
* Change the destination of an animation in progress. | ||
* @ko 재생 중인 애니메이션의 목적지와 진행 시간을 변경한다. | ||
* @param {UpdateAnimationOption} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 200] | ||
* }, | ||
* "y": { | ||
* range: [0, 200] | ||
* } | ||
* }); | ||
* | ||
* axes.setTo({"x": 50, "y": 50}, 1000); // trigger animation by setTo | ||
* | ||
* // after 500 ms | ||
* axes.updateAnimation({destPos: {"x": 100, "y": 100}}); // animation will end after 500 ms, at {"x": 100, "y": 100} | ||
* | ||
* // after 500 ms | ||
* axes.setTo({"x": 50, "y": 50}, 1000); // trigger animation by setTo | ||
* | ||
* // after 700 ms | ||
* axes.updateAnimation({destPos: {"x": 100, "y": 100}, duration: 1500, restart: true}); // this works same as axes.setTo({"x": 100, "y": 100}, 800) since restart is true. | ||
* ``` | ||
*/ | ||
public updateAnimation(options: UpdateAnimationOption) { | ||
this.animationManager.updateAnimation(options); | ||
return this; | ||
} | ||
/** | ||
* Returns whether there is a coordinate in the bounce area of the target axis. | ||
* @ko 대상 축 중 bounce영역에 좌표가 존재하는지를 반환한다 | ||
* @param {Object} [axes] The names of the axis <ko>축 이름들</ko> | ||
* @return {Boolen} Whether the bounce area exists. <ko>bounce 영역 존재 여부</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "xOther": { | ||
* range: [-100, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }); | ||
* | ||
* axes.isBounceArea(["x"]); | ||
* axes.isBounceArea(["x", "zoom"]); | ||
* axes.isBounceArea(); | ||
* ``` | ||
*/ | ||
public isBounceArea(axes?: string[]) { | ||
return this.axisManager.isOutside(axes); | ||
} | ||
/** | ||
* Destroys properties, and events used in a module and disconnect all connections to inputTypes. | ||
* @ko 모듈에 사용한 속성, 이벤트를 해제한다. 모든 inputType과의 연결을 끊는다. | ||
*/ | ||
public destroy() { | ||
this.disconnect(); | ||
this.eventManager.destroy(); | ||
} | ||
} | ||
export default Axes; |
@@ -6,109 +6,128 @@ import { isOutside, getCirculatedPos } from "./Coordinate"; | ||
export interface Axis { | ||
[key: string]: number; | ||
[key: string]: number; | ||
} | ||
export interface AxisOption { | ||
range?: number[]; | ||
bounce?: number | number[]; | ||
circular?: boolean | boolean[]; | ||
range?: number[]; | ||
bounce?: number | number[]; | ||
circular?: boolean | boolean[]; | ||
} | ||
export class AxisManager { | ||
private _pos: Axis; | ||
constructor(private axis: ObjectInterface<AxisOption>, private options) { | ||
this._complementOptions(); | ||
this._pos = Object.keys(this.axis).reduce((acc, v) => { | ||
acc[v] = this.axis[v].range[0]; | ||
return acc; | ||
}, {}); | ||
} | ||
/** | ||
* set up 'css' expression | ||
* @private | ||
*/ | ||
private _complementOptions() { | ||
Object.keys(this.axis).forEach(axis => { | ||
this.axis[axis] = { | ||
...{ | ||
range: [0, 100], | ||
bounce: [0, 0], | ||
circular: [false, false], | ||
}, ...this.axis[axis], | ||
}; | ||
private _pos: Axis; | ||
public constructor(private _axis: ObjectInterface<AxisOption>) { | ||
this._complementOptions(); | ||
this._pos = Object.keys(this._axis).reduce((acc, v) => { | ||
acc[v] = this._axis[v].range[0]; | ||
return acc; | ||
}, {}); | ||
} | ||
["bounce", "circular"].forEach(v => { | ||
const axisOption = this.axis; | ||
const key = axisOption[axis][v]; | ||
public getDelta(depaPos: Axis, destPos: Axis): Axis { | ||
const fullDepaPos = this.get(depaPos); | ||
return map(this.get(destPos), (v, k) => v - fullDepaPos[k]); | ||
} | ||
if (/string|number|boolean/.test(typeof key)) { | ||
axisOption[axis][v] = [key, key]; | ||
} | ||
}); | ||
}); | ||
} | ||
getDelta(depaPos: Axis, destPos: Axis): Axis { | ||
const fullDepaPos = this.get(depaPos); | ||
return map(this.get(destPos), (v, k) => v - fullDepaPos[k]); | ||
} | ||
get(axes?: string[] | Axis): Axis { | ||
if (axes && Array.isArray(axes)) { | ||
return axes.reduce((acc, v) => { | ||
if (v && (v in this._pos)) { | ||
acc[v] = this._pos[v]; | ||
} | ||
return acc; | ||
}, {}); | ||
} else { | ||
return { ...this._pos, ...((axes || {}) as Axis) }; | ||
} | ||
} | ||
moveTo(pos: Axis, depaPos: Axis = this._pos): { [key: string]: Axis } { | ||
const delta = map(this._pos, (v, key) => { | ||
return key in pos && key in depaPos ? pos[key] - depaPos[key] : 0; | ||
}); | ||
public get(axes?: string[] | Axis): Axis { | ||
if (axes && Array.isArray(axes)) { | ||
return axes.reduce((acc, v) => { | ||
if (v && v in this._pos) { | ||
acc[v] = this._pos[v]; | ||
} | ||
return acc; | ||
}, {}); | ||
} else { | ||
return { ...this._pos, ...((axes || {}) as Axis) }; | ||
} | ||
} | ||
this.set(this.map(pos, (v, opt) => opt ? getCirculatedPos(v, opt.range, opt.circular as boolean[]) : 0)); | ||
return { | ||
pos: { ...this._pos }, | ||
delta, | ||
}; | ||
} | ||
set(pos: Axis) { | ||
for (const k in pos) { | ||
if (k && (k in this._pos)) { | ||
this._pos[k] = pos[k]; | ||
} | ||
} | ||
} | ||
every( | ||
pos: Axis, | ||
callback: (value: number, options: AxisOption, key: string) => boolean): boolean { | ||
const axisOptions = this.axis; | ||
public moveTo(pos: Axis, depaPos: Axis = this._pos): { [key: string]: Axis } { | ||
const delta = map(this._pos, (v, key) => { | ||
return key in pos && key in depaPos ? pos[key] - depaPos[key] : 0; | ||
}); | ||
return every(pos, (value, key) => callback(value, axisOptions[key], key)); | ||
} | ||
filter( | ||
pos: Axis, | ||
callback: (value: number, options: AxisOption, key: string) => boolean): Axis { | ||
this.set( | ||
this.map(pos, (v, opt) => | ||
opt ? getCirculatedPos(v, opt.range, opt.circular as boolean[]) : 0 | ||
) | ||
); | ||
return { | ||
pos: { ...this._pos }, | ||
delta, | ||
}; | ||
} | ||
const axisOptions = this.axis; | ||
public set(pos: Axis) { | ||
for (const k in pos) { | ||
if (k && k in this._pos) { | ||
this._pos[k] = pos[k]; | ||
} | ||
} | ||
} | ||
return filter(pos, (value, key) => callback(value, axisOptions[key], key)); | ||
} | ||
map<U>( | ||
pos: Axis, | ||
callback: (value: number, options: AxisOption, key: string) => U) { | ||
const axisOptions = this.axis; | ||
public every( | ||
pos: Axis, | ||
callback: (value: number, options: AxisOption, key: string) => boolean | ||
): boolean { | ||
const axisOptions = this._axis; | ||
return map<number, U>(pos, (value, key) => callback(value, axisOptions[key], key)); | ||
} | ||
isOutside(axes?: string[]) { | ||
return !this.every( | ||
axes ? this.get(axes) : this._pos, | ||
(v, opt) => !isOutside(v, opt.range), | ||
); | ||
} | ||
getAxisOptions(key: string) { | ||
return this.axis[key]; | ||
} | ||
return every(pos, (value, key) => callback(value, axisOptions[key], key)); | ||
} | ||
public filter( | ||
pos: Axis, | ||
callback: (value: number, options: AxisOption, key: string) => boolean | ||
): Axis { | ||
const axisOptions = this._axis; | ||
return filter(pos, (value, key) => callback(value, axisOptions[key], key)); | ||
} | ||
public map<U>( | ||
pos: Axis, | ||
callback: (value: number, options: AxisOption, key: string) => U | ||
) { | ||
const axisOptions = this._axis; | ||
return map<number, U>(pos, (value, key) => | ||
callback(value, axisOptions[key], key) | ||
); | ||
} | ||
public isOutside(axes?: string[]) { | ||
return !this.every( | ||
axes ? this.get(axes) : this._pos, | ||
(v, opt) => !isOutside(v, opt.range) | ||
); | ||
} | ||
public getAxisOptions(key: string) { | ||
return this._axis[key]; | ||
} | ||
/** | ||
* set up 'css' expression | ||
* @private | ||
*/ | ||
private _complementOptions() { | ||
Object.keys(this._axis).forEach((axis) => { | ||
this._axis[axis] = { | ||
...{ | ||
range: [0, 100], | ||
bounce: [0, 0], | ||
circular: [false, false], | ||
}, | ||
...this._axis[axis], | ||
}; | ||
["bounce", "circular"].forEach((v) => { | ||
const axisOption = this._axis; | ||
const key = axisOption[axis][v]; | ||
if (/string|number|boolean/.test(typeof key)) { | ||
axisOption[axis][v] = [key, key]; | ||
} | ||
}); | ||
}); | ||
} | ||
} |
@@ -6,13 +6,13 @@ /* eslint-disable no-new-func, no-nested-ternary */ | ||
if (typeof window === "undefined") { | ||
// window is undefined in node.js | ||
win = { | ||
navigator: { | ||
userAgent: "", | ||
}, | ||
}; | ||
// window is undefined in node.js | ||
win = { | ||
navigator: { | ||
userAgent: "", | ||
}, | ||
}; | ||
} else { | ||
win = window; | ||
win = window; | ||
} | ||
/* eslint-enable no-new-func, no-nested-ternary */ | ||
export {win as window}; | ||
export { win as window }; |
@@ -1,38 +0,42 @@ | ||
// export const DIRECTION_NONE = 1; | ||
// export const DIRECTION_LEFT = 2; | ||
// export const DIRECTION_RIGHT = 4; | ||
// export const DIRECTION_HORIZONTAL = 2 | 4; | ||
// export const DIRECTION_UP = 8; | ||
// export const DIRECTION_DOWN = 16; | ||
// export const DIRECTION_VERTICAL = 8 | 16; | ||
// export const DIRECTION_ALL = 2 | 4 | 8 | 16; | ||
export const DIRECTION_NONE = 1; | ||
export const DIRECTION_LEFT = 2; | ||
export const DIRECTION_RIGHT = 4; | ||
export const DIRECTION_HORIZONTAL = 2 | 4; | ||
export const DIRECTION_UP = 8; | ||
export const DIRECTION_DOWN = 16; | ||
export const DIRECTION_VERTICAL = 8 | 16; | ||
export const DIRECTION_ALL = 2 | 4 | 8 | 16; | ||
export { | ||
DIRECTION_NONE, | ||
DIRECTION_LEFT, | ||
DIRECTION_RIGHT, | ||
DIRECTION_UP, | ||
DIRECTION_DOWN, | ||
DIRECTION_HORIZONTAL, | ||
DIRECTION_VERTICAL, | ||
DIRECTION_ALL, | ||
} from "@egjs/hammerjs"; | ||
import getAgent from "@egjs/agent"; | ||
import { window } from "./browser"; | ||
export const IOS_EDGE_THRESHOLD = 30; | ||
export const IS_IOS_SAFARI = "ontouchstart" in window && getAgent().browser.name === "safari"; | ||
export const IS_IOS_SAFARI = | ||
"ontouchstart" in window && getAgent().browser.name === "safari"; | ||
export const TRANSFORM = (() => { | ||
if (typeof document === "undefined") { | ||
return ""; | ||
} | ||
const bodyStyle = (document.head || document.getElementsByTagName("head")[0]).style; | ||
const target = ["transform", "webkitTransform", "msTransform", "mozTransform"]; | ||
for (let i = 0, len = target.length; i < len; i++) { | ||
if (target[i] in bodyStyle) { | ||
return target[i]; | ||
} | ||
} | ||
return ""; | ||
if (typeof document === "undefined") { | ||
return ""; | ||
} | ||
const bodyStyle = (document.head || document.getElementsByTagName("head")[0]) | ||
.style; | ||
const target = [ | ||
"transform", | ||
"webkitTransform", | ||
"msTransform", | ||
"mozTransform", | ||
]; | ||
for (let i = 0, len = target.length; i < len; i++) { | ||
if (target[i] in bodyStyle) { | ||
return target[i]; | ||
} | ||
} | ||
return ""; | ||
})(); | ||
export const PREVENT_SCROLL_CSSPROPS = { | ||
"touch-action": "none", | ||
"user-select": "none", | ||
"-webkit-user-drag": "none", | ||
}; |
@@ -1,47 +0,60 @@ | ||
export function getInsidePosition( | ||
destPos: number, | ||
range: number[], | ||
circular: boolean[], | ||
bounce?: number[], | ||
): number { | ||
let toDestPos: number = destPos; | ||
const targetRange: number[] = [ | ||
circular[0] ? range[0] : (bounce ? range[0] - bounce[0] : range[0]), | ||
circular[1] ? range[1] : (bounce ? range[1] + bounce[1] : range[1]), | ||
]; | ||
export const getInsidePosition = ( | ||
destPos: number, | ||
range: number[], | ||
circular: boolean[], | ||
bounce?: number[] | ||
): number => { | ||
let toDestPos: number = destPos; | ||
const targetRange: number[] = [ | ||
circular[0] ? range[0] : bounce ? range[0] - bounce[0] : range[0], | ||
circular[1] ? range[1] : bounce ? range[1] + bounce[1] : range[1], | ||
]; | ||
toDestPos = Math.max(targetRange[0], toDestPos); | ||
toDestPos = Math.min(targetRange[1], toDestPos); | ||
toDestPos = Math.max(targetRange[0], toDestPos); | ||
toDestPos = Math.min(targetRange[1], toDestPos); | ||
return toDestPos; | ||
} | ||
return toDestPos; | ||
}; | ||
// determine outside | ||
export function isOutside(pos: number, range: number[]): boolean { | ||
return pos < range[0] || pos > range[1]; | ||
} | ||
export const isOutside = (pos: number, range: number[]): boolean => { | ||
return pos < range[0] || pos > range[1]; | ||
}; | ||
export function getDuration(distance: number, deceleration): number { | ||
const duration = Math.sqrt(distance / deceleration * 2); | ||
export const getDuration = (distance: number, deceleration): number => { | ||
const duration = Math.sqrt((distance / deceleration) * 2); | ||
// when duration is under 100, then value is zero | ||
return duration < 100 ? 0 : duration; | ||
} | ||
export function isCircularable(destPos: number, range: number[], circular: boolean[]): boolean { | ||
return (circular[1] && destPos > range[1]) || | ||
(circular[0] && destPos < range[0]); | ||
} | ||
export function getCirculatedPos(pos: number, range: number[], circular: boolean[]): number { | ||
let toPos = pos; | ||
const min = range[0]; | ||
const max = range[1]; | ||
const length = max - min; | ||
// when duration is under 100, then value is zero | ||
return duration < 100 ? 0 : duration; | ||
}; | ||
if (circular[1] && pos > max) { // right | ||
toPos = (toPos - max) % length + min; | ||
} | ||
if (circular[0] && pos < min) { // left | ||
toPos = (toPos - min) % length + max; | ||
} | ||
return toPos; | ||
} | ||
export const isCircularable = ( | ||
destPos: number, | ||
range: number[], | ||
circular: boolean[] | ||
): boolean => { | ||
return ( | ||
(circular[1] && destPos > range[1]) || (circular[0] && destPos < range[0]) | ||
); | ||
}; | ||
export const getCirculatedPos = ( | ||
pos: number, | ||
range: number[], | ||
circular: boolean[] | ||
): number => { | ||
let toPos = pos; | ||
const min = range[0]; | ||
const max = range[1]; | ||
const length = max - min; | ||
if (circular[1] && pos > max) { | ||
// right | ||
toPos = ((toPos - max) % length) + min; | ||
} | ||
if (circular[0] && pos < min) { | ||
// left | ||
toPos = ((toPos - min) % length) + max; | ||
} | ||
return toPos; | ||
}; |
@@ -1,2 +0,4 @@ | ||
import { IInputType } from "./inputType/InputType"; | ||
import { ComponentEvent } from "@egjs/component"; | ||
import { InputType } from "./inputType/InputType"; | ||
import { Axis } from "./AxisManager"; | ||
@@ -9,311 +11,368 @@ import { AnimationManager } from "./AnimationManager"; | ||
export interface ChangeEventOption { | ||
input: IInputType; | ||
event; | ||
input: InputType; | ||
event; | ||
} | ||
export class EventManager { | ||
public am: AnimationManager; | ||
constructor(private axes: Axes) {} | ||
/** | ||
* This event is fired when a user holds an element on the screen of the device. | ||
* @ko 사용자가 기기의 화면에 손을 대고 있을 때 발생하는 이벤트 | ||
* @name eg.Axes#hold | ||
* @event | ||
* @type {object} | ||
* @property {Object.<string, number>} pos coordinate <ko>좌표 정보</ko> | ||
* @property {Object} input The instance of inputType where the event occurred<ko>이벤트가 발생한 inputType 인스턴스</ko> | ||
* @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("hold", function(event) { | ||
* // event.pos | ||
* // event.input | ||
* // event.inputEvent | ||
* // isTrusted | ||
* }); | ||
*/ | ||
triggerHold(pos: Axis, option: ChangeEventOption) { | ||
const {roundPos} = this.getRoundPos(pos); | ||
public animationManager: AnimationManager; | ||
public constructor(private _axes: Axes) {} | ||
/** | ||
* This event is fired when a user holds an element on the screen of the device. | ||
* @ko 사용자가 기기의 화면에 손을 대고 있을 때 발생하는 이벤트 | ||
* @event Axes#hold | ||
* @type {object} | ||
* @property {Object.<string, number>} pos coordinate <ko>좌표 정보</ko> | ||
* @property {Object} input The instance of inputType where the event occurred<ko>이벤트가 발생한 inputType 인스턴스</ko> | ||
* @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("hold", function(event) { | ||
* // event.pos | ||
* // event.input | ||
* // event.inputEvent | ||
* // isTrusted | ||
* }); | ||
* ``` | ||
*/ | ||
public hold(pos: Axis, option: ChangeEventOption) { | ||
const { roundPos } = this._getRoundPos(pos); | ||
this.axes.trigger("hold", { | ||
pos: roundPos, | ||
input: option.input || null, | ||
inputEvent: option.event || null, | ||
isTrusted: true, | ||
}); | ||
} | ||
this._axes.trigger( | ||
new ComponentEvent("hold", { | ||
pos: roundPos, | ||
input: option.input || null, | ||
inputEvent: option.event || null, | ||
isTrusted: true, | ||
}) | ||
); | ||
} | ||
/** | ||
* Specifies the coordinates to move after the 'change' event. It works when the holding value of the change event is true. | ||
* @ko 'change' 이벤트 이후 이동할 좌표를 지정한다. change이벤트의 holding 값이 true일 경우에 동작한다 | ||
* @name set | ||
* @function | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("change", function(event) { | ||
* event.holding && event.set({x: 10}); | ||
* }); | ||
*/ | ||
/** Specifies the animation coordinates to move after the 'release' or 'animationStart' events. | ||
* @ko 'release' 또는 'animationStart' 이벤트 이후 이동할 좌표를 지정한다. | ||
* @name setTo | ||
* @function | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @param {Number} [duration] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko> | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("animationStart", function(event) { | ||
* event.setTo({x: 10}, 2000); | ||
* }); | ||
*/ | ||
/** | ||
* This event is fired when a user release an element on the screen of the device. | ||
* @ko 사용자가 기기의 화면에서 손을 뗐을 때 발생하는 이벤트 | ||
* @name eg.Axes#release | ||
* @event | ||
* @type {object} | ||
* @property {Object.<string, number>} depaPos The coordinates when releasing an element<ko>손을 뗐을 때의 좌표 </ko> | ||
* @property {Object.<string, number>} destPos The coordinates to move to after releasing an element<ko>손을 뗀 뒤에 이동할 좌표</ko> | ||
* @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko> | ||
* @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko> | ||
* @property {Object} input The instance of inputType where the event occurred<ko>이벤트가 발생한 inputType 인스턴스</ko> | ||
* @property {setTo} setTo Specifies the animation coordinates to move after the event <ko>이벤트 이후 이동할 애니메이션 좌표를 지정한다</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("release", function(event) { | ||
* // event.depaPos | ||
* // event.destPos | ||
* // event.delta | ||
* // event.input | ||
* // event.inputEvent | ||
* // event.setTo | ||
* // event.isTrusted | ||
* | ||
* // if you want to change the animation coordinates to move after the 'release' event. | ||
* event.setTo({x: 10}, 2000); | ||
* }); | ||
*/ | ||
triggerRelease(param: AnimationParam) { | ||
const {roundPos, roundDepa} = this.getRoundPos(param.destPos, param.depaPos); | ||
param.destPos = roundPos; | ||
param.depaPos = roundDepa; | ||
param.setTo = this.createUserControll(param.destPos, param.duration); | ||
this.axes.trigger("release", param as OnRelease); | ||
} | ||
/** | ||
* Specifies the coordinates to move after the 'change' event. It works when the holding value of the change event is true. | ||
* @ko 'change' 이벤트 이후 이동할 좌표를 지정한다. change이벤트의 holding 값이 true일 경우에 동작한다 | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("change", function(event) { | ||
* event.holding && event.set({x: 10}); | ||
* }); | ||
* ``` | ||
*/ | ||
/** Specifies the animation coordinates to move after the 'release' or 'animationStart' events. | ||
* @ko 'release' 또는 'animationStart' 이벤트 이후 이동할 좌표를 지정한다. | ||
* @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko> | ||
* @param {Number} [duration=0] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko> | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("animationStart", function(event) { | ||
* event.setTo({x: 10}, 2000); | ||
* }); | ||
* ``` | ||
*/ | ||
/** | ||
* This event is fired when a user release an element on the screen of the device. | ||
* @ko 사용자가 기기의 화면에서 손을 뗐을 때 발생하는 이벤트 | ||
* @event Axes#release | ||
* @type {object} | ||
* @property {Object.<string, number>} depaPos The coordinates when releasing an element<ko>손을 뗐을 때의 좌표 </ko> | ||
* @property {Object.<string, number>} destPos The coordinates to move to after releasing an element<ko>손을 뗀 뒤에 이동할 좌표</ko> | ||
* @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko> | ||
* @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko> | ||
* @property {Object} input The instance of inputType where the event occurred<ko>이벤트가 발생한 inputType 인스턴스</ko> | ||
* @property {setTo} setTo Specifies the animation coordinates to move after the event <ko>이벤트 이후 이동할 애니메이션 좌표를 지정한다</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("release", function(event) { | ||
* // event.depaPos | ||
* // event.destPos | ||
* // event.delta | ||
* // event.input | ||
* // event.inputEvent | ||
* // event.setTo | ||
* // event.isTrusted | ||
* | ||
* // if you want to change the animation coordinates to move after the 'release' event. | ||
* event.setTo({x: 10}, 2000); | ||
* }); | ||
* ``` | ||
*/ | ||
public triggerRelease(param: AnimationParam) { | ||
const { roundPos, roundDepa } = this._getRoundPos( | ||
param.destPos, | ||
param.depaPos | ||
); | ||
param.destPos = roundPos; | ||
param.depaPos = roundDepa; | ||
param.setTo = this._createUserControll(param.destPos, param.duration); | ||
this._axes.trigger( | ||
new ComponentEvent("release", { | ||
...param, | ||
bounceRatio: this._getBounceRatio(roundPos), | ||
} as OnRelease) | ||
); | ||
} | ||
/** | ||
* This event is fired when coordinate changes. | ||
* @ko 좌표가 변경됐을 때 발생하는 이벤트 | ||
* @name eg.Axes#change | ||
* @event | ||
* @type {object} | ||
* @property {Object.<string, number>} pos The coordinate <ko>좌표</ko> | ||
* @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko> | ||
* @property {Boolean} holding Indicates whether a user holds an element on the screen of the device.<ko>사용자가 기기의 화면을 누르고 있는지 여부</ko> | ||
* @property {Object} input The instance of inputType where the event occurred. If the value is changed by animation, it returns 'null'.<ko>이벤트가 발생한 inputType 인스턴스. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko> | ||
* @property {Object} inputEvent The event object received from inputType. If the value is changed by animation, it returns 'null'.<ko>inputType으로 부터 받은 이벤트 객체. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko> | ||
* @property {set} set Specifies the coordinates to move after the event. It works when the holding value is true <ko>이벤트 이후 이동할 좌표를 지정한다. holding 값이 true일 경우에 동작한다.</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("change", function(event) { | ||
* // event.pos | ||
* // event.delta | ||
* // event.input | ||
* // event.inputEvent | ||
* // event.holding | ||
* // event.set | ||
* // event.isTrusted | ||
* | ||
* // if you want to change the coordinates to move after the 'change' event. | ||
* // it works when the holding value of the change event is true. | ||
* event.holding && event.set({x: 10}); | ||
* }); | ||
*/ | ||
triggerChange(pos: Axis, isAccurate?: boolean, depaPos?: Axis, option?: ChangeEventOption, holding: boolean = false) { | ||
const am = this.am; | ||
const axm = am.axm; | ||
const eventInfo = am.getEventInfo(); | ||
const {roundPos, roundDepa} = this.getRoundPos(pos, depaPos); | ||
const moveTo = axm.moveTo(roundPos, roundDepa); | ||
const inputEvent = option && option.event || eventInfo && eventInfo.event || null; | ||
const param = { | ||
pos: moveTo.pos, | ||
delta: moveTo.delta, | ||
holding, | ||
inputEvent, | ||
isTrusted: !!inputEvent, | ||
input: option && option.input || eventInfo && eventInfo.input || null, | ||
set: inputEvent ? this.createUserControll(moveTo.pos) : () => { }, | ||
}; | ||
const result = this.axes.trigger("change", param); | ||
/** | ||
* This event is fired when coordinate changes. | ||
* @ko 좌표가 변경됐을 때 발생하는 이벤트 | ||
* @event Axes#change | ||
* @type {object} | ||
* @property {Object.<string, number>} pos The coordinate <ko>좌표</ko> | ||
* @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko> | ||
* @property {Boolean} holding Indicates whether a user holds an element on the screen of the device.<ko>사용자가 기기의 화면을 누르고 있는지 여부</ko> | ||
* @property {Object} input The instance of inputType where the event occurred. If the value is changed by animation, it returns 'null'.<ko>이벤트가 발생한 inputType 인스턴스. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko> | ||
* @property {Object} inputEvent The event object received from inputType. If the value is changed by animation, it returns 'null'.<ko>inputType으로 부터 받은 이벤트 객체. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko> | ||
* @property {set} set Specifies the coordinates to move after the event. It works when the holding value is true <ko>이벤트 이후 이동할 좌표를 지정한다. holding 값이 true일 경우에 동작한다.</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("change", function(event) { | ||
* // event.pos | ||
* // event.delta | ||
* // event.input | ||
* // event.inputEvent | ||
* // event.holding | ||
* // event.set | ||
* // event.isTrusted | ||
* | ||
* // if you want to change the coordinates to move after the 'change' event. | ||
* // it works when the holding value of the change event is true. | ||
* event.holding && event.set({x: 10}); | ||
* }); | ||
* ``` | ||
*/ | ||
public triggerChange( | ||
pos: Axis, | ||
isAccurate?: boolean, | ||
depaPos?: Axis, | ||
option?: ChangeEventOption, | ||
holding: boolean = false | ||
) { | ||
const animationManager = this.animationManager; | ||
const axisManager = animationManager.axisManager; | ||
const eventInfo = animationManager.getEventInfo(); | ||
const { roundPos, roundDepa } = this._getRoundPos(pos, depaPos); | ||
const moveTo = axisManager.moveTo(roundPos, roundDepa); | ||
const inputEvent = option?.event || eventInfo?.event || null; | ||
const param = { | ||
pos: moveTo.pos, | ||
delta: moveTo.delta, | ||
bounceRatio: this._getBounceRatio(moveTo.pos), | ||
holding, | ||
inputEvent, | ||
isTrusted: !!inputEvent, | ||
input: option?.input || eventInfo?.input || null, | ||
set: inputEvent ? this._createUserControll(moveTo.pos) : () => {}, // eslint-disable-line @typescript-eslint/no-empty-function | ||
}; | ||
const result = this._axes.trigger(new ComponentEvent("change", param)); | ||
inputEvent && axm.set(param.set()["destPos"]); | ||
if (inputEvent) { | ||
axisManager.set( | ||
(param.set() as { destPos: Axis; duration: number }).destPos | ||
); | ||
} | ||
return result; | ||
} | ||
return result; | ||
} | ||
/** | ||
* This event is fired when animation starts. | ||
* @ko 에니메이션이 시작할 때 발생한다. | ||
* @name eg.Axes#animationStart | ||
* @event | ||
* @type {object} | ||
* @property {Object.<string, number>} depaPos The coordinates when animation starts<ko>애니메이션이 시작 되었을 때의 좌표 </ko> | ||
* @property {Object.<string, number>} destPos The coordinates to move to. If you change this value, you can run the animation<ko>이동할 좌표. 이값을 변경하여 애니메이션을 동작시킬수 있다</ko> | ||
* @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko> | ||
* @property {Number} duration Duration of the animation (unit: ms). If you change this value, you can control the animation duration time.<ko>애니메이션 진행 시간(단위: ms). 이값을 변경하여 애니메이션의 이동시간을 조절할 수 있다.</ko> | ||
* @property {Object} input The instance of inputType where the event occurred. If the value is changed by animation, it returns 'null'.<ko>이벤트가 발생한 inputType 인스턴스. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko> | ||
* @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko> | ||
* @property {setTo} setTo Specifies the animation coordinates to move after the event <ko>이벤트 이후 이동할 애니메이션 좌표를 지정한다</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("release", function(event) { | ||
* // event.depaPos | ||
* // event.destPos | ||
* // event.delta | ||
* // event.input | ||
* // event.inputEvent | ||
* // event.setTo | ||
* // event.isTrusted | ||
* | ||
* // if you want to change the animation coordinates to move after the 'animationStart' event. | ||
* event.setTo({x: 10}, 2000); | ||
* }); | ||
*/ | ||
triggerAnimationStart(param: AnimationParam): boolean { | ||
const {roundPos, roundDepa} = this.getRoundPos(param.destPos, param.depaPos); | ||
param.destPos = roundPos; | ||
param.depaPos = roundDepa; | ||
param.setTo = this.createUserControll(param.destPos, param.duration); | ||
return this.axes.trigger("animationStart", param as OnAnimationStart); | ||
} | ||
/** | ||
* This event is fired when animation starts. | ||
* @ko 에니메이션이 시작할 때 발생한다. | ||
* @event Axes#animationStart | ||
* @type {object} | ||
* @property {Object.<string, number>} depaPos The coordinates when animation starts<ko>애니메이션이 시작 되었을 때의 좌표 </ko> | ||
* @property {Object.<string, number>} destPos The coordinates to move to. If you change this value, you can run the animation<ko>이동할 좌표. 이값을 변경하여 애니메이션을 동작시킬수 있다</ko> | ||
* @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko> | ||
* @property {Number} duration Duration of the animation (unit: ms). If you change this value, you can control the animation duration time.<ko>애니메이션 진행 시간(단위: ms). 이값을 변경하여 애니메이션의 이동시간을 조절할 수 있다.</ko> | ||
* @property {Object} input The instance of inputType where the event occurred. If the value is changed by animation, it returns 'null'.<ko>이벤트가 발생한 inputType 인스턴스. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko> | ||
* @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko> | ||
* @property {setTo} setTo Specifies the animation coordinates to move after the event <ko>이벤트 이후 이동할 애니메이션 좌표를 지정한다</ko> | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("release", function(event) { | ||
* // event.depaPos | ||
* // event.destPos | ||
* // event.delta | ||
* // event.input | ||
* // event.inputEvent | ||
* // event.setTo | ||
* // event.isTrusted | ||
* | ||
* // if you want to change the animation coordinates to move after the 'animationStart' event. | ||
* event.setTo({x: 10}, 2000); | ||
* }); | ||
* ``` | ||
*/ | ||
public triggerAnimationStart(param: AnimationParam): Axes { | ||
const { roundPos, roundDepa } = this._getRoundPos( | ||
param.destPos, | ||
param.depaPos | ||
); | ||
param.destPos = roundPos; | ||
param.depaPos = roundDepa; | ||
param.setTo = this._createUserControll(param.destPos, param.duration); | ||
return this._axes.trigger( | ||
new ComponentEvent("animationStart", param as OnAnimationStart) | ||
); | ||
} | ||
/** | ||
* This event is fired when animation ends. | ||
* @ko 에니메이션이 끝났을 때 발생한다. | ||
* @name eg.Axes#animationEnd | ||
* @event | ||
* @type {object} | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("animationEnd", function(event) { | ||
* // event.isTrusted | ||
* }); | ||
*/ | ||
triggerAnimationEnd(isTrusted: boolean = false) { | ||
this.axes.trigger("animationEnd", { | ||
isTrusted, | ||
}); | ||
} | ||
/** | ||
* This event is fired when all actions have been completed. | ||
* @ko 에니메이션이 끝났을 때 발생한다. | ||
* @name eg.Axes#finish | ||
* @event | ||
* @type {object} | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("finish", function(event) { | ||
* // event.isTrusted | ||
* }); | ||
*/ | ||
triggerFinish(isTrusted: boolean = false) { | ||
this.axes.trigger("finish", { | ||
isTrusted, | ||
}); | ||
} | ||
private createUserControll(pos: Axis, duration: number = 0) { | ||
// to controll | ||
const userControl = { | ||
destPos: { ...pos }, | ||
duration, | ||
}; | ||
return (toPos?: Axis, userDuration?: number): { destPos: Axis, duration: number } => { | ||
toPos && (userControl.destPos = { ...toPos }); | ||
(userDuration !== undefined) && (userControl.duration = userDuration); | ||
return userControl; | ||
}; | ||
} | ||
/** | ||
* This event is fired when animation ends. | ||
* @ko 에니메이션이 끝났을 때 발생한다. | ||
* @event Axes#animationEnd | ||
* @type {object} | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("animationEnd", function(event) { | ||
* // event.isTrusted | ||
* }); | ||
* ``` | ||
*/ | ||
public triggerAnimationEnd(isTrusted: boolean = false) { | ||
this._axes.trigger( | ||
new ComponentEvent("animationEnd", { | ||
isTrusted, | ||
}) | ||
); | ||
} | ||
setAnimationManager(am: AnimationManager) { | ||
this.am = am; | ||
} | ||
/** | ||
* This event is fired when all actions have been completed. | ||
* @ko 에니메이션이 끝났을 때 발생한다. | ||
* @event Axes#finish | ||
* @type {object} | ||
* @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko> | ||
* | ||
* @example | ||
* ```js | ||
* const axes = new eg.Axes({ | ||
* "x": { | ||
* range: [0, 100] | ||
* }, | ||
* "zoom": { | ||
* range: [50, 30] | ||
* } | ||
* }).on("finish", function(event) { | ||
* // event.isTrusted | ||
* }); | ||
* ``` | ||
*/ | ||
public triggerFinish(isTrusted: boolean = false) { | ||
this._axes.trigger( | ||
new ComponentEvent("finish", { | ||
isTrusted, | ||
}) | ||
); | ||
} | ||
destroy() { | ||
this.axes.off(); | ||
} | ||
public setAnimationManager(animationManager: AnimationManager) { | ||
this.animationManager = animationManager; | ||
} | ||
private getRoundPos(pos: Axis, depaPos?: Axis) { | ||
// round value if round exist | ||
const roundUnit = this.axes.options.round; | ||
public destroy() { | ||
this._axes.off(); | ||
} | ||
// if (round == null) { | ||
// return {pos, depaPos}; // undefined, undefined | ||
// } | ||
return { | ||
roundPos: roundNumbers(pos, roundUnit), | ||
roundDepa: roundNumbers(depaPos, roundUnit), | ||
}; | ||
} | ||
private _createUserControll(pos: Axis, duration: number = 0) { | ||
// to controll | ||
const userControl = { | ||
destPos: { ...pos }, | ||
duration, | ||
}; | ||
return ( | ||
toPos?: Axis, | ||
userDuration?: number | ||
): { destPos: Axis; duration: number } => { | ||
if (toPos) { | ||
userControl.destPos = { ...toPos }; | ||
} | ||
if (userDuration !== undefined) { | ||
userControl.duration = userDuration; | ||
} | ||
return userControl; | ||
}; | ||
} | ||
private _getRoundPos(pos: Axis, depaPos?: Axis) { | ||
// round value if round exist | ||
const roundUnit = this._axes.options.round; | ||
// if (round == null) { | ||
// return {pos, depaPos}; // undefined, undefined | ||
// } | ||
return { | ||
roundPos: roundNumbers(pos, roundUnit), | ||
roundDepa: roundNumbers(depaPos, roundUnit), | ||
}; | ||
} | ||
private _getBounceRatio(pos: Axis): Axis { | ||
return this._axes.axisManager.map(pos, (v, opt) => { | ||
if (v < opt.range[0] && opt.bounce[0] !== 0) { | ||
return (opt.range[0] - v) / opt.bounce[0]; | ||
} else if (v > opt.range[1] && opt.bounce[1] !== 0) { | ||
return (v - opt.range[1]) / opt.bounce[1]; | ||
} else { | ||
return 0; | ||
} | ||
}); | ||
} | ||
} |
import { InterruptManager } from "./InterruptManager"; | ||
import { IInputType, IInputTypeObserver } from "./inputType/InputType"; | ||
import { InputType, InputTypeObserver, toAxis } from "./inputType/InputType"; | ||
import { EventManager, ChangeEventOption } from "./EventManager"; | ||
@@ -7,154 +7,226 @@ import { AxisManager, Axis } from "./AxisManager"; | ||
import { AxesOption } from "./Axes"; | ||
import { isOutside, getInsidePosition } from "./Coordinate"; | ||
import { isOutside, getInsidePosition, getCirculatedPos } from "./Coordinate"; | ||
import { map, equal } from "./utils"; | ||
import { AnimationParam } from "./types"; | ||
export class InputObserver implements IInputTypeObserver { | ||
public options: AxesOption; | ||
private itm: InterruptManager; | ||
private em: EventManager; | ||
private axm: AxisManager; | ||
private am: AnimationManager; | ||
private isOutside = false; | ||
private moveDistance: Axis = null; | ||
private isStopped = false; | ||
constructor({ options, itm, em, axm, am }) { | ||
this.options = options; | ||
this.itm = itm; | ||
this.em = em; | ||
this.axm = axm; | ||
this.am = am; | ||
} | ||
export class InputObserver implements InputTypeObserver { | ||
public options: AxesOption; | ||
private _interruptManager: InterruptManager; | ||
private _eventManager: EventManager; | ||
private _axisManager: AxisManager; | ||
private _animationManager: AnimationManager; | ||
private _isOutside = false; | ||
private _moveDistance: Axis = null; | ||
private _isStopped = false; | ||
public constructor({ | ||
options, | ||
interruptManager, | ||
eventManager, | ||
axisManager, | ||
animationManager, | ||
}: { | ||
options: AxesOption; | ||
interruptManager: InterruptManager; | ||
eventManager: EventManager; | ||
axisManager: AxisManager; | ||
animationManager: AnimationManager; | ||
}) { | ||
this.options = options; | ||
this._interruptManager = interruptManager; | ||
this._eventManager = eventManager; | ||
this._axisManager = axisManager; | ||
this._animationManager = animationManager; | ||
} | ||
// when move pointer is held in outside | ||
private atOutside(pos: Axis) { | ||
if (this.isOutside) { | ||
return this.axm.map(pos, (v, opt) => { | ||
const tn = opt.range[0] - opt.bounce[0]; | ||
const tx = opt.range[1] + opt.bounce[1]; | ||
return v > tx ? tx : (v < tn ? tn : v); | ||
}); | ||
} else { | ||
// when start pointer is held in inside | ||
// get a initialization slope value to prevent smooth animation. | ||
const initSlope = this.am.easing(0.00001) / 0.00001; | ||
return this.axm.map(pos, (v, opt) => { | ||
const min = opt.range[0]; | ||
const max = opt.range[1]; | ||
const out = opt.bounce; | ||
const circular = opt.circular; | ||
public get(input: InputType): Axis { | ||
return this._axisManager.get(input.axes); | ||
} | ||
if (circular && (circular[0] || circular[1])) { | ||
return v; | ||
} else if (v < min) { // left | ||
return min - this.am.easing((min - v) / (out[0] * initSlope)) * out[0]; | ||
} else if (v > max) { // right | ||
return max + this.am.easing((v - max) / (out[1] * initSlope)) * out[1]; | ||
} | ||
return v; | ||
}); | ||
} | ||
} | ||
get(input: IInputType): Axis { | ||
return this.axm.get(input.axes); | ||
} | ||
hold(input: IInputType, event) { | ||
if (this.itm.isInterrupted() || !input.axes.length) { | ||
return; | ||
} | ||
const changeOption: ChangeEventOption = { | ||
input, | ||
event, | ||
}; | ||
this.isStopped = false; | ||
this.itm.setInterrupt(true); | ||
this.am.grab(input.axes, changeOption); | ||
!this.moveDistance && this.em.triggerHold(this.axm.get(), changeOption); | ||
this.isOutside = this.axm.isOutside(input.axes); | ||
this.moveDistance = this.axm.get(input.axes); | ||
} | ||
change(input: IInputType, event, offset: Axis) { | ||
if (this.isStopped || !this.itm.isInterrupting() || this.axm.every(offset, v => v === 0)) { | ||
return; | ||
} | ||
let depaPos: Axis = this.moveDistance || this.axm.get(input.axes); | ||
let destPos: Axis; | ||
public hold(input: InputType, event) { | ||
if (this._interruptManager.isInterrupted() || !input.axes.length) { | ||
return; | ||
} | ||
const changeOption: ChangeEventOption = { | ||
input, | ||
event, | ||
}; | ||
this._isStopped = false; | ||
this._interruptManager.setInterrupt(true); | ||
this._animationManager.stopAnimation(input.axes, changeOption); | ||
if (!this._moveDistance) { | ||
this._eventManager.hold(this._axisManager.get(), changeOption); | ||
} | ||
this._isOutside = this._axisManager.isOutside(input.axes); | ||
this._moveDistance = this._axisManager.get(input.axes); | ||
} | ||
// for outside logic | ||
destPos = map(depaPos, (v, k) => v + (offset[k] || 0)); | ||
this.moveDistance && (this.moveDistance = destPos); | ||
// from outside to inside | ||
if (this.isOutside && | ||
this.axm.every(depaPos, (v, opt) => !isOutside(v, opt.range))) { | ||
this.isOutside = false; | ||
} | ||
depaPos = this.atOutside(depaPos); | ||
destPos = this.atOutside(destPos); | ||
public change(input: InputType, event, offset: Axis, useDuration?: boolean) { | ||
if ( | ||
this._isStopped || | ||
!this._interruptManager.isInterrupting() || | ||
this._axisManager.every(offset, (v) => v === 0) | ||
) { | ||
return; | ||
} | ||
let depaPos: Axis = this._moveDistance || this._axisManager.get(input.axes); | ||
let destPos: Axis; | ||
const isCanceled = !this.em.triggerChange(destPos, false, depaPos, { | ||
input, | ||
event, | ||
}, true); | ||
// for outside logic | ||
destPos = map(depaPos, (v, k) => v + (offset[k] || 0)); | ||
if (this._moveDistance) { | ||
this._moveDistance = this._axisManager.map( | ||
destPos, | ||
(v, { circular, range }) => | ||
circular && (circular[0] || circular[1]) | ||
? getCirculatedPos(v, range, circular as boolean[]) | ||
: v | ||
); | ||
} | ||
// from outside to inside | ||
if ( | ||
this._isOutside && | ||
this._axisManager.every(depaPos, (v, opt) => !isOutside(v, opt.range)) | ||
) { | ||
this._isOutside = false; | ||
} | ||
depaPos = this._atOutside(depaPos); | ||
destPos = this._atOutside(destPos); | ||
const changeOption: ChangeEventOption = { | ||
input, | ||
event, | ||
}; | ||
if (useDuration) { | ||
const duration = this._animationManager.getDuration(destPos, depaPos); | ||
this._animationManager.stopAnimation(input.axes, changeOption); | ||
this._animationManager.animateTo(destPos, duration, changeOption); | ||
} else { | ||
const isCanceled = !this._eventManager.triggerChange( | ||
destPos, | ||
false, | ||
depaPos, | ||
changeOption, | ||
true | ||
); | ||
if (isCanceled) { | ||
this._isStopped = true; | ||
this._moveDistance = null; | ||
this._animationManager.finish(false); | ||
} | ||
} | ||
} | ||
if (isCanceled) { | ||
this.isStopped = true; | ||
this.moveDistance = null; | ||
this.am.finish(false); | ||
} | ||
} | ||
release(input: IInputType, event, offset: Axis, inputDuration?: number) { | ||
if (this.isStopped || !this.itm.isInterrupting() || !this.moveDistance) { | ||
return; | ||
} | ||
const pos: Axis = this.axm.get(input.axes); | ||
const depaPos: Axis = this.axm.get(); | ||
let destPos: Axis = this.axm.get(this.axm.map(offset, (v, opt, k) => { | ||
if (opt.circular && (opt.circular[0] || opt.circular[1])) { | ||
return pos[k] + v; | ||
} else { | ||
return getInsidePosition( | ||
pos[k] + v, | ||
opt.range, | ||
opt.circular as boolean[], | ||
opt.bounce as number[], | ||
); | ||
} | ||
})); | ||
const duration = this.am.getDuration(destPos, pos, inputDuration); | ||
public release( | ||
input: InputType, | ||
event, | ||
velocity: number[], | ||
inputDuration?: number | ||
) { | ||
if ( | ||
this._isStopped || | ||
!this._interruptManager.isInterrupting() || | ||
!this._moveDistance | ||
) { | ||
return; | ||
} | ||
const pos: Axis = this._axisManager.get(input.axes); | ||
const depaPos: Axis = this._axisManager.get(); | ||
const displacement = this._animationManager.getDisplacement(velocity); | ||
const offset = toAxis(input.axes, displacement); | ||
const destPos: Axis = this._axisManager.get( | ||
this._axisManager.map(offset, (v, opt, k) => { | ||
if (opt.circular && (opt.circular[0] || opt.circular[1])) { | ||
return pos[k] + v; | ||
} else { | ||
return getInsidePosition( | ||
pos[k] + v, | ||
opt.range, | ||
opt.circular as boolean[], | ||
opt.bounce as number[] | ||
); | ||
} | ||
}) | ||
); | ||
const duration = this._animationManager.getDuration( | ||
destPos, | ||
pos, | ||
inputDuration | ||
); | ||
if (duration === 0) { | ||
destPos = { ...depaPos }; | ||
} | ||
// prepare params | ||
const param: AnimationParam = { | ||
depaPos, | ||
destPos, | ||
duration, | ||
delta: this.axm.getDelta(depaPos, destPos), | ||
inputEvent: event, | ||
input, | ||
isTrusted: true, | ||
}; | ||
this.em.triggerRelease(param); | ||
this.moveDistance = null; | ||
// prepare params | ||
const param: AnimationParam = { | ||
depaPos, | ||
destPos, | ||
duration, | ||
delta: this._axisManager.getDelta(depaPos, destPos), | ||
inputEvent: event, | ||
input, | ||
isTrusted: true, | ||
}; | ||
this._eventManager.triggerRelease(param); | ||
this._moveDistance = null; | ||
// to contol | ||
const userWish = this.am.getUserControll(param); | ||
const isEqual = equal(userWish.destPos, depaPos); | ||
const changeOption: ChangeEventOption = { | ||
input, | ||
event, | ||
}; | ||
if (isEqual || userWish.duration === 0) { | ||
!isEqual && this.em.triggerChange(userWish.destPos, false, depaPos, changeOption, true); | ||
this.itm.setInterrupt(false); | ||
if (this.axm.isOutside()) { | ||
this.am.restore(changeOption); | ||
} else { | ||
this.em.triggerFinish(true); | ||
} | ||
} else { | ||
this.am.animateTo(userWish.destPos, userWish.duration, changeOption); | ||
} | ||
} | ||
// to contol | ||
const userWish = this._animationManager.getUserControl(param); | ||
const isEqual = equal(userWish.destPos, depaPos); | ||
const changeOption: ChangeEventOption = { | ||
input, | ||
event, | ||
}; | ||
if (isEqual || userWish.duration === 0) { | ||
if (!isEqual) { | ||
this._eventManager.triggerChange( | ||
userWish.destPos, | ||
false, | ||
depaPos, | ||
changeOption, | ||
true | ||
); | ||
} | ||
this._interruptManager.setInterrupt(false); | ||
if (this._axisManager.isOutside()) { | ||
this._animationManager.restore(changeOption); | ||
} else { | ||
this._eventManager.triggerFinish(true); | ||
} | ||
} else { | ||
this._animationManager.animateTo( | ||
userWish.destPos, | ||
userWish.duration, | ||
changeOption | ||
); | ||
} | ||
} | ||
// when move pointer is held in outside | ||
private _atOutside(pos: Axis) { | ||
if (this._isOutside) { | ||
return this._axisManager.map(pos, (v, opt) => { | ||
const tn = opt.range[0] - (opt.bounce[0] as number); | ||
const tx = opt.range[1] + (opt.bounce[1] as number); | ||
return v > tx ? tx : v < tn ? tn : v; | ||
}); | ||
} else { | ||
return this._axisManager.map(pos, (v, opt) => { | ||
const min = opt.range[0]; | ||
const max = opt.range[1]; | ||
const out = opt.bounce; | ||
const circular = opt.circular; | ||
if (circular && (circular[0] || circular[1])) { | ||
return v; | ||
} else if (v < min) { | ||
// left | ||
return ( | ||
min - this._animationManager.interpolate(min - v, out[0] as number) | ||
); | ||
} else if (v > max) { | ||
// right | ||
return ( | ||
max + this._animationManager.interpolate(v - max, out[1] as number) | ||
); | ||
} | ||
return v; | ||
}); | ||
} | ||
} | ||
} |
@@ -1,69 +0,75 @@ | ||
import {Manager, PointerEventInput, TouchMouseInput, TouchInput, MouseInput} from "@egjs/hammerjs"; | ||
import { Axis } from "../AxisManager"; | ||
import { AxesOption } from "../Axes"; | ||
import { window } from "../browser"; | ||
import { ActiveInput } from "../types"; | ||
import { MouseEventInput } from "../eventInput/MouseEventInput"; | ||
import { TouchEventInput } from "../eventInput/TouchEventInput"; | ||
import { PointerEventInput } from "../eventInput/PointerEventInput"; | ||
import { TouchMouseEventInput } from "../eventInput/TouchMouseEventInput"; | ||
import { | ||
SUPPORT_POINTER_EVENTS, | ||
SUPPORT_TOUCH, | ||
} from "../eventInput/EventInput"; | ||
export interface IInputType { | ||
axes: string[]; | ||
element: HTMLElement; | ||
hammer?; | ||
mapAxes(axes: string[]); | ||
connect(observer: IInputTypeObserver): IInputType; | ||
disconnect(); | ||
destroy(); | ||
enable?(); | ||
disable?(); | ||
isEnable?(): boolean; | ||
export interface InputType { | ||
axes: string[]; | ||
element: HTMLElement; | ||
mapAxes(axes: string[]); | ||
connect(observer: InputTypeObserver): InputType; | ||
disconnect(); | ||
destroy(); | ||
enable?(); | ||
disable?(); | ||
isEnable?(): boolean; | ||
} | ||
export interface IInputTypeObserver { | ||
options: AxesOption; | ||
get(inputType: IInputType): Axis; | ||
change(inputType: IInputType, event, offset: Axis); | ||
hold(inputType: IInputType, event); | ||
release(inputType: IInputType, event, offset: Axis, duration?: number); | ||
export interface InputTypeObserver { | ||
options: AxesOption; | ||
get(inputType: InputType): Axis; | ||
change(inputType: InputType, event, offset: Axis, useDuration?: boolean); | ||
hold(inputType: InputType, event); | ||
release( | ||
inputType: InputType, | ||
event, | ||
velocity: number[], | ||
inputDuration?: number | ||
); | ||
} | ||
export const SUPPORT_POINTER_EVENTS = "PointerEvent" in window || "MSPointerEvent" in window; | ||
export const SUPPORT_TOUCH = "ontouchstart" in window; | ||
export const UNIQUEKEY = "_EGJS_AXES_INPUTTYPE_"; | ||
export function toAxis(source: string[], offset: number[]): Axis { | ||
return offset.reduce((acc, v, i) => { | ||
if (source[i]) { | ||
acc[source[i]] = v; | ||
} | ||
return acc; | ||
}, {}); | ||
} | ||
export function createHammer(element: HTMLElement, options) { | ||
try { | ||
// create Hammer | ||
return new Manager(element, { ...options }); | ||
} catch (e) { | ||
return null; | ||
} | ||
} | ||
export function convertInputType(inputType: string[] = []): any { | ||
let hasTouch = false; | ||
let hasMouse = false; | ||
let hasPointer = false; | ||
export const toAxis = (source: string[], offset: number[]): Axis => { | ||
return offset.reduce((acc, v, i) => { | ||
if (source[i]) { | ||
acc[source[i]] = v; | ||
} | ||
return acc; | ||
}, {}); | ||
}; | ||
inputType.forEach(v => { | ||
switch (v) { | ||
case "mouse": hasMouse = true; break; | ||
case "touch": hasTouch = SUPPORT_TOUCH; break; | ||
case "pointer": hasPointer = SUPPORT_POINTER_EVENTS; | ||
// no default | ||
} | ||
}); | ||
if (hasPointer) { | ||
return PointerEventInput; | ||
} else if (hasTouch && hasMouse) { | ||
return TouchMouseInput; | ||
} else if (hasTouch) { | ||
return TouchInput; | ||
} else if (hasMouse) { | ||
return MouseInput; | ||
} | ||
return null; | ||
} | ||
export const convertInputType = (inputType: string[] = []): ActiveInput => { | ||
let hasTouch = false; | ||
let hasMouse = false; | ||
let hasPointer = false; | ||
inputType.forEach((v) => { | ||
switch (v) { | ||
case "mouse": | ||
hasMouse = true; | ||
break; | ||
case "touch": | ||
hasTouch = SUPPORT_TOUCH; | ||
break; | ||
case "pointer": | ||
hasPointer = SUPPORT_POINTER_EVENTS; | ||
// no default | ||
} | ||
}); | ||
if (hasPointer) { | ||
return new PointerEventInput(); | ||
} else if (hasTouch && hasMouse) { | ||
return new TouchMouseEventInput(); | ||
} else if (hasTouch) { | ||
return new TouchEventInput(); | ||
} else if (hasMouse) { | ||
return new MouseEventInput(); | ||
} | ||
return null; | ||
}; |
@@ -1,6 +0,5 @@ | ||
import { InputObserver } from "./../InputObserver"; | ||
import { $ } from "../utils"; | ||
import { toAxis, IInputType, IInputTypeObserver } from "./InputType"; | ||
import { Axis } from "../AxisManager"; | ||
import { toAxis, InputType, InputTypeObserver } from "./InputType"; | ||
export const KEY_LEFT_ARROW = 37; | ||
@@ -15,2 +14,3 @@ export const KEY_A = 65; | ||
/* eslint-disable */ | ||
const DIRECTION_REVERSE = -1; | ||
@@ -21,5 +21,6 @@ const DIRECTION_FORWARD = 1; | ||
const DELAY = 80; | ||
/* eslint-enable */ | ||
export interface MoveKeyInputOption { | ||
scale?: number[]; | ||
scale?: number[]; | ||
} | ||
@@ -30,13 +31,13 @@ | ||
* @ko eg.Axes.MoveKeyInput 모듈의 옵션 객체 | ||
* @property {Array<Number>} [scale] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
* @property {Number} [scale[0]=1] Coordinate scale for the first axis<ko>첫번째 축의 배율</ko> | ||
* @property {Number} [scale[1]=1] Coordinate scale for the decond axis<ko>두번째 축의 배율</ko> | ||
**/ | ||
* @param {Array<Number>} [scale] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
* @param {Number} [scale[0]=1] Coordinate scale for the first axis<ko>첫번째 축의 배율</ko> | ||
* @param {Number} [scale[1]=1] Coordinate scale for the decond axis<ko>두번째 축의 배율</ko> | ||
**/ | ||
/** | ||
* @class eg.Axes.MoveKeyInput | ||
* @classdesc A module that passes the amount of change to eg.Axes when the move key stroke is occured. use two axis. | ||
* A module that passes the amount of change to eg.Axes when the move key stroke is occured. use two axis. | ||
* @ko 이동키 입력이 발생했을 때의 변화량을 eg.Axes에 전달하는 모듈. 두 개 의 축을 사용한다. | ||
* | ||
* @example | ||
* ```js | ||
* const moveKey = new eg.Axes.MoveKeyInput("#area", { | ||
@@ -48,157 +49,167 @@ * scale: [1, 1] | ||
* axes.connect(["x", "y"], moveKey); | ||
* | ||
* ``` | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.MoveKeyInput module <ko>eg.Axes.MoveKeyInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {MoveKeyInputOption} [options] The option object of the eg.Axes.MoveKeyInput module<ko>eg.Axes.MoveKeyInput 모듈의 옵션 객체</ko> | ||
*/ | ||
export class MoveKeyInput implements IInputType { | ||
options: MoveKeyInputOption; | ||
axes: string[] = []; | ||
element: HTMLElement = null; | ||
private _isEnabled = false; | ||
private _isHolded = false; | ||
private _timer = null; | ||
private observer: IInputTypeObserver; | ||
constructor(el, options?: MoveKeyInputOption) { | ||
this.element = $(el); | ||
this.options = { | ||
...{ | ||
scale: [1, 1], | ||
}, ...options, | ||
}; | ||
this.onKeydown = this.onKeydown.bind(this); | ||
this.onKeyup = this.onKeyup.bind(this); | ||
} | ||
export class MoveKeyInput implements InputType { | ||
public options: MoveKeyInputOption; | ||
public axes: string[] = []; | ||
public element: HTMLElement = null; | ||
private _observer: InputTypeObserver; | ||
private _enabled = false; | ||
private _holding = false; | ||
private _timer: NodeJS.Timeout = null; | ||
mapAxes(axes: string[]) { | ||
this.axes = axes; | ||
} | ||
/** | ||
* | ||
*/ | ||
public constructor(el, options?: MoveKeyInputOption) { | ||
this.element = $(el); | ||
this.options = { | ||
...{ | ||
scale: [1, 1], | ||
}, | ||
...options, | ||
}; | ||
this._onKeydown = this._onKeydown.bind(this); | ||
this._onKeyup = this._onKeyup.bind(this); | ||
} | ||
connect(observer: IInputTypeObserver): IInputType { | ||
this.dettachEvent(); | ||
public mapAxes(axes: string[]) { | ||
this.axes = axes; | ||
} | ||
// add tabindex="0" to the container for making it focusable | ||
if (this.element.getAttribute("tabindex") !== "0") { | ||
this.element.setAttribute("tabindex", "0"); | ||
} | ||
public connect(observer: InputTypeObserver): InputType { | ||
this._detachEvent(); | ||
this.attachEvent(observer); | ||
return this; | ||
} | ||
// add tabindex="0" to the container for making it focusable | ||
if (this.element.getAttribute("tabindex") !== "0") { | ||
this.element.setAttribute("tabindex", "0"); | ||
} | ||
disconnect() { | ||
this.dettachEvent(); | ||
return this; | ||
} | ||
this._attachEvent(observer); | ||
return this; | ||
} | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
* @method eg.Axes.MoveKeyInput#destroy | ||
*/ | ||
destroy() { | ||
this.disconnect(); | ||
this.element = null; | ||
} | ||
public disconnect() { | ||
this._detachEvent(); | ||
return this; | ||
} | ||
private onKeydown(e) { | ||
if (!this._isEnabled) { | ||
return; | ||
} | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
*/ | ||
public destroy() { | ||
this.disconnect(); | ||
this.element = null; | ||
} | ||
let isMoveKey = true; | ||
let direction = DIRECTION_FORWARD; | ||
let move = DIRECTION_HORIZONTAL; | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @return {MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public enable() { | ||
this._enabled = true; | ||
return this; | ||
} | ||
switch (e.keyCode) { | ||
case KEY_LEFT_ARROW: | ||
case KEY_A: | ||
direction = DIRECTION_REVERSE; | ||
break; | ||
case KEY_RIGHT_ARROW: | ||
case KEY_D: | ||
break; | ||
case KEY_DOWN_ARROW: | ||
case KEY_S: | ||
direction = DIRECTION_REVERSE; | ||
move = DIRECTION_VERTICAL; | ||
break; | ||
case KEY_UP_ARROW: | ||
case KEY_W: | ||
move = DIRECTION_VERTICAL; | ||
break; | ||
default: | ||
isMoveKey = false; | ||
} | ||
if ((move === DIRECTION_HORIZONTAL && !this.axes[0]) || | ||
(move === DIRECTION_VERTICAL && !this.axes[1])) { | ||
isMoveKey = false; | ||
} | ||
if (!isMoveKey) { | ||
return; | ||
} | ||
const offsets = move === DIRECTION_HORIZONTAL ? [+this.options.scale[0] * direction, 0] : [0, +this.options.scale[1] * direction]; | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @return {MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public disable() { | ||
this._enabled = false; | ||
return this; | ||
} | ||
if (!this._isHolded) { | ||
this.observer.hold(this, event); | ||
this._isHolded = true; | ||
} | ||
clearTimeout(this._timer); | ||
this.observer.change(this, event, toAxis(this.axes, offsets)); | ||
} | ||
private onKeyup(e) { | ||
if (!this._isHolded) { | ||
return; | ||
} | ||
clearTimeout(this._timer); | ||
this._timer = setTimeout(() => { | ||
this.observer.release(this, e, toAxis(this.axes, [0, 0])); | ||
this._isHolded = false; | ||
}, DELAY); | ||
} | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
public isEnabled() { | ||
return this._enabled; | ||
} | ||
private attachEvent(observer: IInputTypeObserver) { | ||
this.observer = observer; | ||
this.element.addEventListener("keydown", this.onKeydown, false); | ||
this.element.addEventListener("keypress", this.onKeydown, false); | ||
this.element.addEventListener("keyup", this.onKeyup, false); | ||
this._isEnabled = true; | ||
} | ||
private _onKeydown(event: KeyboardEvent) { | ||
if (!this._enabled) { | ||
return; | ||
} | ||
private dettachEvent() { | ||
this.element.removeEventListener("keydown", this.onKeydown, false); | ||
this.element.removeEventListener("keypress", this.onKeydown, false); | ||
this.element.removeEventListener("keyup", this.onKeyup, false); | ||
this._isEnabled = false; | ||
this.observer = null; | ||
} | ||
let isMoveKey = true; | ||
let direction = DIRECTION_FORWARD; | ||
let move = DIRECTION_HORIZONTAL; | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @method eg.Axes.MoveKeyInput#enable | ||
* @return {eg.Axes.MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
enable() { | ||
this._isEnabled = true; | ||
return this; | ||
} | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @method eg.Axes.MoveKeyInput#disable | ||
* @return {eg.Axes.MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
disable() { | ||
this._isEnabled = false; | ||
return this; | ||
} | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @method eg.Axes.MoveKeyInput#isEnable | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
isEnable() { | ||
return this._isEnabled; | ||
} | ||
switch (event.keyCode) { | ||
case KEY_LEFT_ARROW: | ||
case KEY_A: | ||
direction = DIRECTION_REVERSE; | ||
break; | ||
case KEY_RIGHT_ARROW: | ||
case KEY_D: | ||
break; | ||
case KEY_DOWN_ARROW: | ||
case KEY_S: | ||
direction = DIRECTION_REVERSE; | ||
move = DIRECTION_VERTICAL; | ||
break; | ||
case KEY_UP_ARROW: | ||
case KEY_W: | ||
move = DIRECTION_VERTICAL; | ||
break; | ||
default: | ||
isMoveKey = false; | ||
} | ||
if ( | ||
(move === DIRECTION_HORIZONTAL && !this.axes[0]) || | ||
(move === DIRECTION_VERTICAL && !this.axes[1]) | ||
) { | ||
isMoveKey = false; | ||
} | ||
if (!isMoveKey) { | ||
return; | ||
} | ||
event.preventDefault(); | ||
const offsets = | ||
move === DIRECTION_HORIZONTAL | ||
? [+this.options.scale[0] * direction, 0] | ||
: [0, +this.options.scale[1] * direction]; | ||
if (!this._holding) { | ||
this._observer.hold(this, event); | ||
this._holding = true; | ||
} | ||
clearTimeout(this._timer); | ||
this._observer.change(this, event, toAxis(this.axes, offsets)); | ||
} | ||
private _onKeyup(event: KeyboardEvent) { | ||
if (!this._holding) { | ||
return; | ||
} | ||
clearTimeout(this._timer); | ||
this._timer = setTimeout(() => { | ||
this._observer.release(this, event, [0, 0]); | ||
this._holding = false; | ||
}, DELAY); | ||
} | ||
private _attachEvent(observer: InputTypeObserver) { | ||
this._observer = observer; | ||
this.element.addEventListener("keydown", this._onKeydown, false); | ||
this.element.addEventListener("keypress", this._onKeydown, false); | ||
this.element.addEventListener("keyup", this._onKeyup, false); | ||
this._enabled = true; | ||
} | ||
private _detachEvent() { | ||
this.element.removeEventListener("keydown", this._onKeydown, false); | ||
this.element.removeEventListener("keypress", this._onKeydown, false); | ||
this.element.removeEventListener("keyup", this._onKeyup, false); | ||
this._enabled = false; | ||
this._observer = null; | ||
} | ||
} |
@@ -1,69 +0,76 @@ | ||
import { DIRECTION_ALL, DIRECTION_HORIZONTAL, DIRECTION_NONE, DIRECTION_VERTICAL, Manager, Pan } from "@egjs/hammerjs"; | ||
import { $ } from "../utils"; | ||
import { convertInputType, createHammer, IInputType, IInputTypeObserver, toAxis, UNIQUEKEY } from "./InputType"; | ||
import { IS_IOS_SAFARI, IOS_EDGE_THRESHOLD } from "../const"; | ||
import { ObjectInterface } from "../types"; | ||
import { $, setCssProps } from "../utils"; | ||
import { | ||
IS_IOS_SAFARI, | ||
IOS_EDGE_THRESHOLD, | ||
DIRECTION_NONE, | ||
DIRECTION_VERTICAL, | ||
DIRECTION_HORIZONTAL, | ||
DIRECTION_ALL, | ||
PREVENT_SCROLL_CSSPROPS, | ||
} from "../const"; | ||
import { ActiveInput, InputEventType } from "../types"; | ||
import { | ||
convertInputType, | ||
InputType, | ||
InputTypeObserver, | ||
toAxis, | ||
} from "./InputType"; | ||
export interface PanInputOption { | ||
inputType?: string[]; | ||
scale?: number[]; | ||
thresholdAngle?: number; | ||
threshold?: number; | ||
hammerManagerOptions?: ObjectInterface; | ||
iOSEdgeSwipeThreshold?: number; | ||
releaseOnScroll?: boolean; | ||
inputType?: string[]; | ||
scale?: number[]; | ||
thresholdAngle?: number; | ||
threshold?: number; | ||
iOSEdgeSwipeThreshold?: number; | ||
releaseOnScroll?: boolean; | ||
} | ||
// get user's direction | ||
export function getDirectionByAngle(angle: number, thresholdAngle: number) { | ||
if (thresholdAngle < 0 || thresholdAngle > 90) { | ||
return DIRECTION_NONE; | ||
} | ||
const toAngle = Math.abs(angle); | ||
export const getDirectionByAngle = ( | ||
angle: number, | ||
thresholdAngle: number | ||
): number => { | ||
if (thresholdAngle < 0 || thresholdAngle > 90) { | ||
return DIRECTION_NONE; | ||
} | ||
const toAngle = Math.abs(angle); | ||
return toAngle > thresholdAngle && toAngle < 180 - thresholdAngle ? | ||
DIRECTION_VERTICAL : DIRECTION_HORIZONTAL; | ||
} | ||
return toAngle > thresholdAngle && toAngle < 180 - thresholdAngle | ||
? DIRECTION_VERTICAL | ||
: DIRECTION_HORIZONTAL; | ||
}; | ||
export function getNextOffset(speeds: number[], deceleration: number) { | ||
const normalSpeed = Math.sqrt( | ||
speeds[0] * speeds[0] + speeds[1] * speeds[1], | ||
); | ||
const duration = Math.abs(normalSpeed / -deceleration); | ||
return [ | ||
speeds[0] / 2 * duration, | ||
speeds[1] / 2 * duration, | ||
]; | ||
} | ||
export const useDirection = (checkType, direction, userDirection?): boolean => { | ||
if (userDirection) { | ||
return !!( | ||
direction === DIRECTION_ALL || | ||
(direction & checkType && userDirection & checkType) | ||
); | ||
} else { | ||
return !!(direction & checkType); | ||
} | ||
}; | ||
export function useDirection( | ||
checkType, | ||
direction, | ||
userDirection?): boolean { | ||
if (userDirection) { | ||
return !!((direction === DIRECTION_ALL) || | ||
((direction & checkType) && (userDirection & checkType))); | ||
} else { | ||
return !!(direction & checkType); | ||
} | ||
} | ||
/** | ||
* @typedef {Object} PanInputOption The option object of the eg.Axes.PanInput module. | ||
* @ko eg.Axes.PanInput 모듈의 옵션 객체 | ||
* @property {String[]} [inputType=["touch","mouse", "pointer"]] Types of input devices.<br>- touch: Touch screen<br>- mouse: Mouse <ko>입력 장치 종류.<br>- touch: 터치 입력 장치<br>- mouse: 마우스</ko> | ||
* @property {Number[]} [scale] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
* @property {Number} [scale.0=1] horizontal axis scale <ko>수평축 배율</ko> | ||
* @property {Number} [scale.1=1] vertical axis scale <ko>수직축 배율</ko> | ||
* @property {Number} [thresholdAngle=45] The threshold value that determines whether user action is horizontal or vertical (0~90) <ko>사용자의 동작이 가로 방향인지 세로 방향인지 판단하는 기준 각도(0~90)</ko> | ||
* @property {Number} [threshold=0] Minimal pan distance required before recognizing <ko>사용자의 Pan 동작을 인식하기 위해산 최소한의 거리</ko> | ||
* @property {Number} [iOSEdgeSwipeThreshold=30] Area (px) that can go to the next page when swiping the right edge in iOS safari <ko>iOS Safari에서 오른쪽 엣지를 스와이프 하는 경우 다음 페이지로 넘어갈 수 있는 영역(px)</ko> | ||
* @property {Object} [hammerManagerOptions={cssProps: {userSelect: "none",touchSelect: "none",touchCallout: "none",userDrag: "none"}] Options of Hammer.Manager <ko>Hammer.Manager의 옵션</ko> | ||
**/ | ||
* @param {String[]} [inputType=["touch","mouse", "pointer"]] Types of input devices. | ||
* - touch: Touch screen | ||
* - mouse: Mouse <ko>입력 장치 종류. | ||
* - touch: 터치 입력 장치 | ||
* - mouse: 마우스</ko> | ||
* @param {Number[]} [scale] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
* @param {Number} [scale[0]=1] horizontal axis scale <ko>수평축 배율</ko> | ||
* @param {Number} [scale[1]=1] vertical axis scale <ko>수직축 배율</ko> | ||
* @param {Number} [thresholdAngle=45] The threshold value that determines whether user action is horizontal or vertical (0~90) <ko>사용자의 동작이 가로 방향인지 세로 방향인지 판단하는 기준 각도(0~90)</ko> | ||
* @param {Number} [threshold=0] Minimal pan distance required before recognizing <ko>사용자의 Pan 동작을 인식하기 위해산 최소한의 거리</ko> | ||
* @param {Number} [iOSEdgeSwipeThreshold=30] Area (px) that can go to the next page when swiping the right edge in iOS safari <ko>iOS Safari에서 오른쪽 엣지를 스와이프 하는 경우 다음 페이지로 넘어갈 수 있는 영역(px)</ko> | ||
**/ | ||
/** | ||
* @class eg.Axes.PanInput | ||
* @classdesc A module that passes the amount of change to eg.Axes when the mouse or touchscreen is down and moved. use less than two axes. | ||
* A module that passes the amount of change to eg.Axes when the mouse or touchscreen is down and moved. use less than two axes. | ||
* @ko 마우스나 터치 스크린을 누르고 움직일때의 변화량을 eg.Axes에 전달하는 모듈. 두개 이하의 축을 사용한다. | ||
* | ||
* @example | ||
* ```js | ||
* const pan = new eg.Axes.PanInput("#area", { | ||
@@ -83,313 +90,264 @@ * inputType: ["touch"], | ||
* axes.connect(["", "something2"], pan); // or axes.connect(" something2", pan); | ||
* | ||
* ``` | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.PanInput module <ko>eg.Axes.PanInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {PanInputOption} [options] The option object of the eg.Axes.PanInput module<ko>eg.Axes.PanInput 모듈의 옵션 객체</ko> | ||
* @param {PanInputOption} [options={}] The option object of the eg.Axes.PanInput module<ko>eg.Axes.PanInput 모듈의 옵션 객체</ko> | ||
*/ | ||
export class PanInput implements IInputType { | ||
options: PanInputOption; | ||
axes: string[] = []; | ||
hammer = null; | ||
element: HTMLElement = null; | ||
protected observer: IInputTypeObserver; | ||
protected _direction; | ||
private panRecognizer = null; | ||
private isRightEdge = false; | ||
private rightEdgeTimer = 0; | ||
private panFlag = false; | ||
export class PanInput implements InputType { | ||
public options: PanInputOption; | ||
public axes: string[] = []; | ||
public element: HTMLElement = null; | ||
protected _observer: InputTypeObserver; | ||
protected _direction; | ||
protected _panFlag = false; | ||
protected _enabled = false; | ||
protected _activeInput: ActiveInput = null; | ||
private _originalCssProps: { [key: string]: string }; | ||
private _atRightEdge = false; | ||
private _rightEdgeTimer = 0; | ||
constructor(el: string | HTMLElement, options?: PanInputOption) { | ||
/** | ||
* Hammer helps you add support for touch gestures to your page | ||
* | ||
* @external Hammer | ||
* @see {@link http://hammerjs.github.io|Hammer.JS} | ||
* @see {@link http://hammerjs.github.io/jsdoc/Hammer.html|Hammer.JS API documents} | ||
* @see Hammer.JS applies specific CSS properties by {@link http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html|default} when creating an instance. The eg.Axes module removes all default CSS properties provided by Hammer.JS | ||
*/ | ||
if (typeof Manager === "undefined") { | ||
throw new Error(`The Hammerjs must be loaded before eg.Axes.PanInput.\nhttp://hammerjs.github.io/`); | ||
} | ||
this.element = $(el); | ||
/** | ||
* | ||
*/ | ||
public constructor(el: string | HTMLElement, options?: PanInputOption) { | ||
this.element = $(el); | ||
this.options = { | ||
inputType: ["touch", "mouse", "pointer"], | ||
scale: [1, 1], | ||
thresholdAngle: 45, | ||
threshold: 0, | ||
iOSEdgeSwipeThreshold: IOS_EDGE_THRESHOLD, | ||
releaseOnScroll: false, | ||
...options, | ||
}; | ||
this._onPanstart = this._onPanstart.bind(this); | ||
this._onPanmove = this._onPanmove.bind(this); | ||
this._onPanend = this._onPanend.bind(this); | ||
} | ||
this.options = { | ||
inputType: ["touch", "mouse", "pointer"], | ||
scale: [1, 1], | ||
thresholdAngle: 45, | ||
threshold: 0, | ||
iOSEdgeSwipeThreshold: IOS_EDGE_THRESHOLD, | ||
releaseOnScroll: false, | ||
hammerManagerOptions: { | ||
// css properties were removed due to usablility issue | ||
// http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html | ||
cssProps: { | ||
userSelect: "none", | ||
touchSelect: "none", | ||
touchCallout: "none", | ||
userDrag: "none", | ||
}, | ||
}, | ||
...options, | ||
}; | ||
this.onHammerInput = this.onHammerInput.bind(this); | ||
this.onPanmove = this.onPanmove.bind(this); | ||
this.onPanend = this.onPanend.bind(this); | ||
} | ||
public mapAxes(axes: string[]) { | ||
const useHorizontal = !!axes[0]; | ||
const useVertical = !!axes[1]; | ||
if (useHorizontal && useVertical) { | ||
this._direction = DIRECTION_ALL; | ||
} else if (useHorizontal) { | ||
this._direction = DIRECTION_HORIZONTAL; | ||
} else if (useVertical) { | ||
this._direction = DIRECTION_VERTICAL; | ||
} else { | ||
this._direction = DIRECTION_NONE; | ||
} | ||
this.axes = axes; | ||
} | ||
public mapAxes(axes: string[]) { | ||
const useHorizontal = !!axes[0]; | ||
const useVertical = !!axes[1]; | ||
if (useHorizontal && useVertical) { | ||
this._direction = DIRECTION_ALL; | ||
} else if (useHorizontal) { | ||
this._direction = DIRECTION_HORIZONTAL; | ||
} else if (useVertical) { | ||
this._direction = DIRECTION_VERTICAL; | ||
} else { | ||
this._direction = DIRECTION_NONE; | ||
} | ||
this.axes = axes; | ||
} | ||
public connect(observer: InputTypeObserver): InputType { | ||
if (this._activeInput) { | ||
this._detachEvent(); | ||
} | ||
this._attachEvent(observer); | ||
this._originalCssProps = setCssProps(this.element); | ||
return this; | ||
} | ||
public connect(observer: IInputTypeObserver): IInputType { | ||
const hammerOption = { | ||
direction: this._direction, | ||
threshold: this.options.threshold, | ||
}; | ||
if (this.hammer) { // for sharing hammer instance. | ||
// hammer remove previous PanRecognizer. | ||
this.removeRecognizer(); | ||
this.dettachEvent(); | ||
} else { | ||
let keyValue: string = this.element[UNIQUEKEY]; | ||
if (!keyValue) { | ||
keyValue = String(Math.round(Math.random() * new Date().getTime())); | ||
} | ||
const inputClass = convertInputType(this.options.inputType); | ||
if (!inputClass) { | ||
throw new Error("Wrong inputType parameter!"); | ||
} | ||
this.hammer = createHammer(this.element, { | ||
...{ | ||
inputClass, | ||
}, ... this.options.hammerManagerOptions, | ||
}); | ||
this.element[UNIQUEKEY] = keyValue; | ||
} | ||
this.panRecognizer = new Pan(hammerOption); | ||
public disconnect() { | ||
this._detachEvent(); | ||
if (this._originalCssProps !== PREVENT_SCROLL_CSSPROPS) { | ||
setCssProps(this.element, this._originalCssProps); | ||
} | ||
this._direction = DIRECTION_NONE; | ||
return this; | ||
} | ||
this.hammer.add(this.panRecognizer); | ||
this.attachEvent(observer); | ||
return this; | ||
} | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
*/ | ||
public destroy() { | ||
this.disconnect(); | ||
this.element = null; | ||
} | ||
public disconnect() { | ||
this.removeRecognizer(); | ||
if (this.hammer) { | ||
this.dettachEvent(); | ||
} | ||
this._direction = DIRECTION_NONE; | ||
return this; | ||
} | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @return {PanInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public enable() { | ||
this._enabled = true; | ||
return this; | ||
} | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
* @method eg.Axes.PanInput#destroy | ||
*/ | ||
public destroy() { | ||
this.disconnect(); | ||
if (this.hammer && this.hammer.recognizers.length === 0) { | ||
this.hammer.destroy(); | ||
} | ||
delete this.element[UNIQUEKEY]; | ||
this.element = null; | ||
this.hammer = null; | ||
} | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @return {PanInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public disable() { | ||
this._enabled = false; | ||
return this; | ||
} | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @method eg.Axes.PanInput#enable | ||
* @return {eg.Axes.PanInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public enable() { | ||
this.hammer && (this.hammer.get("pan").options.enable = true); | ||
return this; | ||
} | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @method eg.Axes.PanInput#disable | ||
* @return {eg.Axes.PanInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public disable() { | ||
this.hammer && (this.hammer.get("pan").options.enable = false); | ||
return this; | ||
} | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @method eg.Axes.PanInput#isEnable | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
public isEnable() { | ||
return !!(this.hammer && this.hammer.get("pan").options.enable); | ||
} | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
public isEnabled() { | ||
return this._enabled; | ||
} | ||
private removeRecognizer() { | ||
if (this.hammer && this.panRecognizer) { | ||
this.hammer.remove(this.panRecognizer); | ||
this.panRecognizer = null; | ||
} | ||
} | ||
protected _onPanstart(event: InputEventType) { | ||
this._activeInput.onEventStart(event); | ||
if (!this._enabled || this._activeInput.getTouches(event) > 1) { | ||
return; | ||
} | ||
protected onHammerInput(event) { | ||
if (this.isEnable()) { | ||
if (event.isFirst) { | ||
this.panFlag = false; | ||
const panEvent = this._activeInput.extendEvent(event); | ||
this._panFlag = false; | ||
if (event.srcEvent.cancelable !== false) { | ||
const edgeThreshold = this.options.iOSEdgeSwipeThreshold!; | ||
if (panEvent.srcEvent.cancelable !== false) { | ||
const edgeThreshold = this.options.iOSEdgeSwipeThreshold; | ||
this.observer.hold(this, event); | ||
this.isRightEdge = IS_IOS_SAFARI && event.center.x > window.innerWidth - edgeThreshold; | ||
this.panFlag = true; | ||
} | ||
} else if (event.isFinal) { | ||
this.onPanend(event); | ||
} | ||
} | ||
} | ||
this._observer.hold(this, panEvent); | ||
this._atRightEdge = | ||
IS_IOS_SAFARI && panEvent.center.x > window.innerWidth - edgeThreshold; | ||
this._panFlag = true; | ||
this._activeInput.prevEvent = panEvent; | ||
} | ||
} | ||
protected onPanmove(event) { | ||
if (!this.panFlag) { | ||
return; | ||
} | ||
protected _onPanmove(event: InputEventType) { | ||
this._activeInput.onEventMove(event); | ||
if ( | ||
!this._panFlag || | ||
!this._enabled || | ||
this._activeInput.getTouches(event) > 1 | ||
) { | ||
return; | ||
} | ||
const { iOSEdgeSwipeThreshold, releaseOnScroll } = this.options; | ||
const userDirection = getDirectionByAngle( | ||
event.angle, this.options.thresholdAngle); | ||
const panEvent = this._activeInput.extendEvent(event); | ||
const { iOSEdgeSwipeThreshold, releaseOnScroll } = this.options; | ||
const userDirection = getDirectionByAngle( | ||
panEvent.angle, | ||
this.options.thresholdAngle | ||
); | ||
// not support offset properties in Hammerjs - start | ||
const prevInput = this.hammer.session.prevInput; | ||
if (releaseOnScroll && !panEvent.srcEvent.cancelable) { | ||
this._onPanend(event); | ||
return; | ||
} | ||
if (releaseOnScroll && !event.srcEvent.cancelable) { | ||
this.onPanend({ | ||
...event, | ||
velocityX: 0, | ||
velocityY: 0, | ||
offsetX: 0, | ||
offsetY: 0, | ||
}); | ||
return; | ||
} | ||
if (this._activeInput.prevEvent && IS_IOS_SAFARI) { | ||
const swipeLeftToRight = panEvent.center.x < 0; | ||
if (prevInput && IS_IOS_SAFARI) { | ||
const swipeLeftToRight = event.center.x < 0; | ||
if (swipeLeftToRight) { | ||
// iOS swipe left => right | ||
this._observer.release(this, this._activeInput.prevEvent, [0, 0]); | ||
return; | ||
} else if (this._atRightEdge) { | ||
clearTimeout(this._rightEdgeTimer); | ||
if (swipeLeftToRight) { | ||
// iOS swipe left => right | ||
this.onPanend({ | ||
...prevInput, | ||
velocityX: 0, | ||
velocityY: 0, | ||
offsetX: 0, | ||
offsetY: 0, | ||
}); | ||
return; | ||
} else if (this.isRightEdge) { | ||
clearTimeout(this.rightEdgeTimer); | ||
// - is right to left | ||
const swipeRightToLeft = panEvent.deltaX < -iOSEdgeSwipeThreshold; | ||
// - is right to left | ||
const swipeRightToLeft = event.deltaX < -iOSEdgeSwipeThreshold; | ||
if (swipeRightToLeft) { | ||
this._atRightEdge = false; | ||
} else { | ||
// iOS swipe right => left | ||
this._rightEdgeTimer = window.setTimeout(() => { | ||
this._observer.release(this, this._activeInput.prevEvent, [0, 0]); | ||
}, 100); | ||
} | ||
} | ||
} | ||
const offset: number[] = this._getOffset( | ||
[panEvent.offsetX, panEvent.offsetY], | ||
[ | ||
useDirection(DIRECTION_HORIZONTAL, this._direction, userDirection), | ||
useDirection(DIRECTION_VERTICAL, this._direction, userDirection), | ||
] | ||
); | ||
const prevent = offset.some((v) => v !== 0); | ||
if (swipeRightToLeft) { | ||
this.isRightEdge = false; | ||
} else { | ||
// iOS swipe right => left | ||
this.rightEdgeTimer = window.setTimeout(() => { | ||
this.onPanend({ | ||
...prevInput, | ||
velocityX: 0, | ||
velocityY: 0, | ||
offsetX: 0, | ||
offsetY: 0, | ||
}); | ||
}, 100); | ||
} | ||
} | ||
} | ||
/* eslint-disable no-param-reassign */ | ||
if (prevInput) { | ||
event.offsetX = event.deltaX - prevInput.deltaX; | ||
event.offsetY = event.deltaY - prevInput.deltaY; | ||
} else { | ||
event.offsetX = 0; | ||
event.offsetY = 0; | ||
} | ||
const offset: number[] = this.getOffset( | ||
[event.offsetX, event.offsetY], | ||
[ | ||
useDirection(DIRECTION_HORIZONTAL, this._direction, userDirection), | ||
useDirection(DIRECTION_VERTICAL, this._direction, userDirection), | ||
]); | ||
const prevent = offset.some(v => v !== 0); | ||
if (prevent) { | ||
if (panEvent.srcEvent.cancelable !== false) { | ||
panEvent.srcEvent.preventDefault(); | ||
} | ||
panEvent.srcEvent.stopPropagation(); | ||
} | ||
panEvent.preventSystemEvent = prevent; | ||
if (prevent) { | ||
this._observer.change(this, panEvent, toAxis(this.axes, offset)); | ||
} | ||
this._activeInput.prevEvent = panEvent; | ||
} | ||
if (prevent) { | ||
const srcEvent = event.srcEvent; | ||
protected _onPanend(event: InputEventType) { | ||
this._activeInput.onEventEnd(event); | ||
if ( | ||
!this._panFlag || | ||
!this._enabled || | ||
this._activeInput.getTouches(event) !== 0 | ||
) { | ||
return; | ||
} | ||
this._panFlag = false; | ||
clearTimeout(this._rightEdgeTimer); | ||
const prevEvent = this._activeInput.prevEvent; | ||
const velocity = this._getOffset( | ||
[ | ||
Math.abs(prevEvent.velocityX) * (prevEvent.offsetX < 0 ? -1 : 1), | ||
Math.abs(prevEvent.velocityY) * (prevEvent.offsetY < 0 ? -1 : 1), | ||
], | ||
[ | ||
useDirection(DIRECTION_HORIZONTAL, this._direction), | ||
useDirection(DIRECTION_VERTICAL, this._direction), | ||
] | ||
); | ||
this._observer.release(this, prevEvent, velocity); | ||
} | ||
if (srcEvent.cancelable !== false) { | ||
srcEvent.preventDefault(); | ||
} | ||
srcEvent.stopPropagation(); | ||
} | ||
event.preventSystemEvent = prevent; | ||
prevent && this.observer.change(this, event, toAxis(this.axes, offset)); | ||
} | ||
private _attachEvent(observer: InputTypeObserver) { | ||
const activeInput = convertInputType(this.options.inputType); | ||
this._observer = observer; | ||
this._enabled = true; | ||
this._activeInput = activeInput; | ||
activeInput?.start.forEach((event) => { | ||
this.element.addEventListener(event, this._onPanstart, false); | ||
}); | ||
activeInput?.move.forEach((event) => { | ||
window.addEventListener(event, this._onPanmove, false); | ||
}); | ||
activeInput?.end.forEach((event) => { | ||
window.addEventListener(event, this._onPanend, false); | ||
}); | ||
} | ||
protected onPanend(event) { | ||
if (!this.panFlag) { | ||
return; | ||
} | ||
clearTimeout(this.rightEdgeTimer); | ||
this.panFlag = false; | ||
let offset: number[] = this.getOffset( | ||
[ | ||
Math.abs(event.velocityX) * (event.deltaX < 0 ? -1 : 1), | ||
Math.abs(event.velocityY) * (event.deltaY < 0 ? -1 : 1), | ||
], | ||
[ | ||
useDirection(DIRECTION_HORIZONTAL, this._direction), | ||
useDirection(DIRECTION_VERTICAL, this._direction), | ||
]); | ||
offset = getNextOffset(offset, this.observer.options.deceleration); | ||
this.observer.release(this, event, toAxis(this.axes, offset)); | ||
} | ||
private _detachEvent() { | ||
const activeInput = this._activeInput; | ||
activeInput?.start.forEach((event) => { | ||
this.element.removeEventListener(event, this._onPanstart, false); | ||
}); | ||
activeInput?.move.forEach((event) => { | ||
window.removeEventListener(event, this._onPanmove, false); | ||
}); | ||
activeInput?.end.forEach((event) => { | ||
window.removeEventListener(event, this._onPanend, false); | ||
}); | ||
this._enabled = false; | ||
this._observer = null; | ||
} | ||
private attachEvent(observer: IInputTypeObserver) { | ||
this.observer = observer; | ||
this.hammer.on("hammer.input", this.onHammerInput) | ||
.on("panstart panmove", this.onPanmove); | ||
} | ||
private _getOffset(properties: number[], direction: boolean[]): number[] { | ||
const offset: number[] = [0, 0]; | ||
const scale = this.options.scale; | ||
private dettachEvent() { | ||
this.hammer.off("hammer.input", this.onHammerInput) | ||
.off("panstart panmove", this.onPanmove); | ||
this.observer = null; | ||
} | ||
private getOffset( | ||
properties: number[], | ||
direction: boolean[]): number[] { | ||
const offset: number[] = [0, 0]; | ||
const scale = this.options.scale; | ||
if (direction[0]) { | ||
offset[0] = (properties[0] * scale[0]); | ||
} | ||
if (direction[1]) { | ||
offset[1] = (properties[1] * scale[1]); | ||
} | ||
return offset; | ||
} | ||
if (direction[0]) { | ||
offset[0] = properties[0] * scale[0]; | ||
} | ||
if (direction[1]) { | ||
offset[1] = properties[1] * scale[1]; | ||
} | ||
return offset; | ||
} | ||
} |
@@ -1,11 +0,16 @@ | ||
import { Manager, Pinch } from "@egjs/hammerjs"; | ||
import { $ } from "../utils"; | ||
import { UNIQUEKEY, toAxis, convertInputType, createHammer, IInputType, IInputTypeObserver } from "./InputType"; | ||
import { ObjectInterface } from "../types"; | ||
import { $, setCssProps } from "../utils"; | ||
import { ActiveInput, InputEventType } from "../types"; | ||
import { PREVENT_SCROLL_CSSPROPS } from "../const"; | ||
import { | ||
toAxis, | ||
convertInputType, | ||
InputType, | ||
InputTypeObserver, | ||
} from "./InputType"; | ||
export interface PinchInputOption { | ||
scale?: number; | ||
threshold?: number; | ||
inputType?: string[]; | ||
hammerManagerOptions?: ObjectInterface; | ||
scale?: number; | ||
threshold?: number; | ||
inputType?: string[]; | ||
} | ||
@@ -16,12 +21,11 @@ | ||
* @ko eg.Axes.PinchInput 모듈의 옵션 객체 | ||
* @property {Number} [scale=1] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
* @property {Number} [threshold=0] Minimal scale before recognizing <ko>사용자의 Pinch 동작을 인식하기 위해산 최소한의 배율</ko> | ||
* @property {Object} [hammerManagerOptions={cssProps: {userSelect: "none",touchSelect: "none",touchCallout: "none",userDrag: "none"}] Options of Hammer.Manager <ko>Hammer.Manager의 옵션</ko> | ||
**/ | ||
* @param {Number} [scale=1] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko> | ||
* @param {Number} [threshold=0] Minimal scale before recognizing <ko>사용자의 Pinch 동작을 인식하기 위해산 최소한의 배율</ko> | ||
**/ | ||
/** | ||
* @class eg.Axes.PinchInput | ||
* @classdesc A module that passes the amount of change to eg.Axes when two pointers are moving toward (zoom-in) or away from each other (zoom-out). use one axis. | ||
* A module that passes the amount of change to eg.Axes when two pointers are moving toward (zoom-in) or away from each other (zoom-out). use one axis. | ||
* @ko 2개의 pointer를 이용하여 zoom-in하거나 zoom-out 하는 동작의 변화량을 eg.Axes에 전달하는 모듈. 한 개 의 축을 사용한다. | ||
* @example | ||
* ```js | ||
* const pinch = new eg.Axes.PinchInput("#area", { | ||
@@ -33,189 +37,174 @@ * scale: 1 | ||
* axes.connect("something", pinch); | ||
* | ||
* ``` | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.PinchInput module <ko>eg.Axes.PinchInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {PinchInputOption} [options] The option object of the eg.Axes.PinchInput module<ko>eg.Axes.PinchInput 모듈의 옵션 객체</ko> | ||
*/ | ||
export class PinchInput implements IInputType { | ||
export class PinchInput implements InputType { | ||
public options: PinchInputOption; | ||
public axes: string[] = []; | ||
public element: HTMLElement = null; | ||
private _observer: InputTypeObserver; | ||
private _pinchFlag = false; | ||
private _enabled = false; | ||
private _originalCssProps: { [key: string]: string }; | ||
private _activeInput: ActiveInput = null; | ||
private _baseValue: number; | ||
options: PinchInputOption; | ||
axes: string[] = []; | ||
hammer = null; | ||
element: HTMLElement = null; | ||
/** | ||
* | ||
*/ | ||
public constructor(el: string | HTMLElement, options?: PinchInputOption) { | ||
this.element = $(el); | ||
this.options = { | ||
scale: 1, | ||
threshold: 0, | ||
inputType: ["touch", "pointer"], | ||
...options, | ||
}; | ||
this._onPinchStart = this._onPinchStart.bind(this); | ||
this._onPinchMove = this._onPinchMove.bind(this); | ||
this._onPinchEnd = this._onPinchEnd.bind(this); | ||
} | ||
private observer: IInputTypeObserver; | ||
private _base: number = null; | ||
private _prev: number = null; | ||
private pinchRecognizer = null; | ||
public mapAxes(axes: string[]) { | ||
this.axes = axes; | ||
} | ||
constructor(el, options?: PinchInputOption) { | ||
/** | ||
* Hammer helps you add support for touch gestures to your page | ||
* | ||
* @external Hammer | ||
* @see {@link http://hammerjs.github.io|Hammer.JS} | ||
* @see {@link http://hammerjs.github.io/jsdoc/Hammer.html|Hammer.JS API documents} | ||
* @see Hammer.JS applies specific CSS properties by {@link http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html|default} when creating an instance. The eg.Axes module removes all default CSS properties provided by Hammer.JS | ||
*/ | ||
if (typeof Manager === "undefined") { | ||
throw new Error(`The Hammerjs must be loaded before eg.Axes.PinchInput.\nhttp://hammerjs.github.io/`); | ||
} | ||
this.element = $(el); | ||
this.options = { | ||
...{ | ||
scale: 1, | ||
threshold: 0, | ||
inputType: ["touch", "pointer"], | ||
hammerManagerOptions: { | ||
// css properties were removed due to usablility issue | ||
// http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html | ||
cssProps: { | ||
userSelect: "none", | ||
touchSelect: "none", | ||
touchCallout: "none", | ||
userDrag: "none", | ||
}, | ||
}, | ||
}, | ||
...options, | ||
}; | ||
this.onPinchStart = this.onPinchStart.bind(this); | ||
this.onPinchMove = this.onPinchMove.bind(this); | ||
this.onPinchEnd = this.onPinchEnd.bind(this); | ||
} | ||
public connect(observer: InputTypeObserver): InputType { | ||
if (this._activeInput) { | ||
this._detachEvent(); | ||
} | ||
this._attachEvent(observer); | ||
this._originalCssProps = setCssProps(this.element); | ||
return this; | ||
} | ||
mapAxes(axes: string[]) { | ||
this.axes = axes; | ||
} | ||
public disconnect() { | ||
this._detachEvent(); | ||
if (this._originalCssProps !== PREVENT_SCROLL_CSSPROPS) { | ||
setCssProps(this.element, this._originalCssProps); | ||
} | ||
return this; | ||
} | ||
connect(observer: IInputTypeObserver): IInputType { | ||
const hammerOption = { threshold: this.options.threshold }; | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
*/ | ||
public destroy() { | ||
this.disconnect(); | ||
this.element = null; | ||
} | ||
if (this.hammer) { // for sharing hammer instance. | ||
// hammer remove previous PinchRecognizer. | ||
this.removeRecognizer(); | ||
this.dettachEvent(); | ||
} else { | ||
let keyValue: string = this.element[UNIQUEKEY]; | ||
if (!keyValue) { | ||
keyValue = String(Math.round(Math.random() * new Date().getTime())); | ||
} | ||
const inputClass = convertInputType(this.options.inputType); | ||
if (!inputClass) { | ||
throw new Error("Wrong inputType parameter!"); | ||
} | ||
this.hammer = createHammer( | ||
this.element, | ||
{ | ||
...{ | ||
inputClass, | ||
}, ...this.options.hammerManagerOptions, | ||
}, | ||
); | ||
this.element[UNIQUEKEY] = keyValue; | ||
} | ||
this.pinchRecognizer = new Pinch(hammerOption); | ||
this.hammer.add(this.pinchRecognizer); | ||
this.attachEvent(observer); | ||
return this; | ||
} | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @return {PinchInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public enable() { | ||
this._enabled = true; | ||
return this; | ||
} | ||
disconnect() { | ||
this.removeRecognizer(); | ||
if (this.hammer) { | ||
this.hammer.remove(this.pinchRecognizer); | ||
this.pinchRecognizer = null; | ||
this.dettachEvent(); | ||
} | ||
return this; | ||
} | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @return {PinchInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public disable() { | ||
this._enabled = false; | ||
return this; | ||
} | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
* @method eg.Axes.PinchInput#destroy | ||
*/ | ||
destroy() { | ||
this.disconnect(); | ||
if (this.hammer && this.hammer.recognizers.length === 0) { | ||
this.hammer.destroy(); | ||
} | ||
delete this.element[UNIQUEKEY]; | ||
this.element = null; | ||
this.hammer = null; | ||
} | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
public isEnabled() { | ||
return this._enabled; | ||
} | ||
private removeRecognizer() { | ||
if (this.hammer && this.pinchRecognizer) { | ||
this.hammer.remove(this.pinchRecognizer); | ||
this.pinchRecognizer = null; | ||
} | ||
} | ||
private _onPinchStart(event: InputEventType) { | ||
this._activeInput.onEventStart(event); | ||
if (!this._enabled || this._activeInput.getTouches(event) !== 2) { | ||
return; | ||
} | ||
private onPinchStart(event) { | ||
this._base = this.observer.get(this)[this.axes[0]]; | ||
const offset = this.getOffset(event.scale); | ||
this.observer.hold(this, event); | ||
this.observer.change(this, event, toAxis(this.axes, [offset])); | ||
this._prev = event.scale; | ||
} | ||
private onPinchMove(event) { | ||
const offset = this.getOffset(event.scale, this._prev); | ||
this.observer.change(this, event, toAxis(this.axes, [offset])); | ||
this._prev = event.scale; | ||
} | ||
private onPinchEnd(event) { | ||
const offset = this.getOffset(event.scale, this._prev); | ||
this.observer.change(this, event, toAxis(this.axes, [offset])); | ||
this.observer.release(this, event, toAxis(this.axes, [0]), 0); | ||
this._base = null; | ||
this._prev = null; | ||
} | ||
private getOffset(pinchScale: number, prev: number = 1): number { | ||
return this._base * (pinchScale - prev) * this.options.scale; | ||
} | ||
this._baseValue = this._observer.get(this)[this.axes[0]]; | ||
this._observer.hold(this, event); | ||
this._pinchFlag = true; | ||
const pinchEvent = this._activeInput.extendEvent(event); | ||
this._activeInput.prevEvent = pinchEvent; | ||
} | ||
private attachEvent(observer: IInputTypeObserver) { | ||
this.observer = observer; | ||
this.hammer.on("pinchstart", this.onPinchStart) | ||
.on("pinchmove", this.onPinchMove) | ||
.on("pinchend", this.onPinchEnd); | ||
} | ||
private _onPinchMove(event: InputEventType) { | ||
this._activeInput.onEventMove(event); | ||
if ( | ||
!this._pinchFlag || | ||
!this._enabled || | ||
this._activeInput.getTouches(event) !== 2 | ||
) { | ||
return; | ||
} | ||
private dettachEvent() { | ||
this.hammer.off("pinchstart", this.onPinchStart) | ||
.off("pinchmove", this.onPinchMove) | ||
.off("pinchend", this.onPinchEnd); | ||
this.observer = null; | ||
this._prev = null; | ||
} | ||
const pinchEvent = this._activeInput.extendEvent(event); | ||
const offset = this._getOffset( | ||
pinchEvent.scale, | ||
this._activeInput.prevEvent.scale | ||
); | ||
this._observer.change(this, event, toAxis(this.axes, [offset])); | ||
this._activeInput.prevEvent = pinchEvent; | ||
} | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @method eg.Axes.PinchInput#enable | ||
* @return {eg.Axes.PinchInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
enable() { | ||
this.hammer && (this.hammer.get("pinch").options.enable = true); | ||
return this; | ||
} | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @method eg.Axes.PinchInput#disable | ||
* @return {eg.Axes.PinchInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
disable() { | ||
this.hammer && (this.hammer.get("pinch").options.enable = false); | ||
return this; | ||
} | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @method eg.Axes.PinchInput#isEnable | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
isEnable() { | ||
return !!(this.hammer && this.hammer.get("pinch").options.enable); | ||
} | ||
private _onPinchEnd(event: InputEventType) { | ||
this._activeInput.onEventEnd(event); | ||
if ( | ||
!this._pinchFlag || | ||
!this._enabled || | ||
this._activeInput.getTouches(event) > 2 | ||
) { | ||
return; | ||
} | ||
this._observer.release(this, event, [0], 0); | ||
this._baseValue = null; | ||
this._pinchFlag = false; | ||
this._activeInput.prevEvent = null; | ||
} | ||
private _attachEvent(observer: InputTypeObserver) { | ||
const activeInput = convertInputType(this.options.inputType); | ||
this._observer = observer; | ||
this._enabled = true; | ||
this._activeInput = activeInput; | ||
activeInput?.start.forEach((event) => { | ||
this.element.addEventListener(event, this._onPinchStart, false); | ||
}); | ||
activeInput?.move.forEach((event) => { | ||
this.element.addEventListener(event, this._onPinchMove, false); | ||
}); | ||
activeInput?.end.forEach((event) => { | ||
this.element.addEventListener(event, this._onPinchEnd, false); | ||
}); | ||
} | ||
private _detachEvent() { | ||
const activeInput = this._activeInput; | ||
activeInput?.start.forEach((event) => { | ||
this.element.removeEventListener(event, this._onPinchStart, false); | ||
}); | ||
activeInput?.move.forEach((event) => { | ||
this.element.removeEventListener(event, this._onPinchMove, false); | ||
}); | ||
activeInput?.end.forEach((event) => { | ||
this.element.removeEventListener(event, this._onPinchEnd, false); | ||
}); | ||
this._enabled = false; | ||
this._observer = null; | ||
} | ||
private _getOffset(pinchScale: number, prev: number = 1): number { | ||
return this._baseValue * (pinchScale - prev) * this.options.scale; | ||
} | ||
} |
@@ -0,2 +1,5 @@ | ||
import { ExtendedEvent } from "../types"; | ||
import Axes from "../Axes"; | ||
import { getAngle } from "../utils"; | ||
import { toAxis } from "./InputType"; | ||
@@ -6,7 +9,9 @@ import { PanInput, PanInputOption } from "./PanInput"; | ||
/** | ||
* @class eg.Axes.RotatePanInput | ||
* @classdesc A module that passes the angle moved by touch to Axes and uses one axis of rotation.<br>[Details](https://github.com/naver/egjs-axes/wiki/RotatePanInput) | ||
* @ko 터치에 의해 움직인 각도를 Axes 에 전달하며 1개의 회전축만 사용한다.<br>[상세내용](https://github.com/naver/egjs-axes/wiki/RotatePanInput-%7C-%ED%95%9C%EA%B5%AD%EC%96%B4) | ||
* A module that passes the angle moved by touch to Axes and uses one axis of rotation. | ||
* [Details](https://github.com/naver/egjs-axes/wiki/RotatePanInput) | ||
* @ko 터치에 의해 움직인 각도를 Axes 에 전달하며 1개의 회전축만 사용한다. | ||
* [상세내용](https://github.com/naver/egjs-axes/wiki/RotatePanInput-%7C-%ED%95%9C%EA%B5%AD%EC%96%B4) | ||
* | ||
* @example | ||
* ```js | ||
* const input = new eg.Axes.RotatePanInput("#area"); | ||
@@ -22,144 +27,160 @@ * | ||
* axes.connect("angle", input) | ||
* | ||
* ``` | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.RotatePanInput module <ko>eg.Axes.RotatePanInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {PanInputOption} [options] The option object of the eg.Axes.PanInput module<ko>eg.Axes.PanInput 모듈의 옵션 객체</ko> | ||
* @extends eg.Axes.PanInput | ||
* @extends PanInput | ||
*/ | ||
export class RotatePanInput extends PanInput { | ||
private rotateOrigin: number[]; | ||
private prevAngle: number; | ||
private prevQuadrant: number; | ||
private lastDiff: number; | ||
private coefficientForDistanceToAngle: number; | ||
private _rotateOrigin: number[]; | ||
private _prevAngle: number; | ||
private _prevQuadrant: number = null; | ||
private _lastDiff = 0; | ||
private _coefficientForDistanceToAngle: number; | ||
constructor(el: string | HTMLElement, options?: PanInputOption) { | ||
super(el, options); | ||
/** | ||
* | ||
*/ | ||
public constructor(el: string | HTMLElement, options?: PanInputOption) { | ||
super(el, options); | ||
} | ||
this.prevQuadrant = null; | ||
this.lastDiff = 0; | ||
} | ||
public mapAxes(axes: string[]) { | ||
this._direction = Axes.DIRECTION_ALL; | ||
this.axes = axes; | ||
} | ||
mapAxes(axes: string[]) { | ||
this._direction = Axes.DIRECTION_ALL; | ||
this.axes = axes; | ||
} | ||
protected _onPanstart(event: MouseEvent) { | ||
this._activeInput.onEventStart(event); | ||
if (!this.isEnabled) { | ||
return; | ||
} | ||
onHammerInput(event) { | ||
if (this.isEnable()) { | ||
if (event.isFirst) { | ||
this.observer.hold(this, event); | ||
this.onPanstart(event); | ||
} else if (event.isFinal) { | ||
this.onPanend(event); | ||
} | ||
} | ||
} | ||
const rect = this.element.getBoundingClientRect(); | ||
const panEvent = this._activeInput.extendEvent(event); | ||
onPanstart(event) { | ||
const rect = this.element.getBoundingClientRect(); | ||
this._observer.hold(this, panEvent); | ||
this._panFlag = true; | ||
// TODO: how to do if element is ellipse not circle. | ||
this._coefficientForDistanceToAngle = 360 / (rect.width * Math.PI); // from 2*pi*r * x / 360 | ||
// TODO: provide a way to set origin like https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin | ||
this._rotateOrigin = [ | ||
rect.left + (rect.width - 1) / 2, | ||
rect.top + (rect.height - 1) / 2, | ||
]; | ||
/** | ||
* Responsive | ||
*/ | ||
// TODO: how to do if element is ellipse not circle. | ||
this.coefficientForDistanceToAngle = 360 / (rect.width * Math.PI); // from 2*pi*r * x / 360 | ||
// TODO: provide a way to set origin like https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin | ||
this.rotateOrigin = [rect.left + (rect.width - 1) / 2, rect.top + (rect.height - 1) / 2]; | ||
// init angle. | ||
this._prevAngle = null; | ||
// init angle. | ||
this.prevAngle = null; | ||
this._triggerChange(panEvent); | ||
this._activeInput.prevEvent = panEvent; | ||
} | ||
this.triggerChange(event); | ||
} | ||
protected _onPanmove(event: MouseEvent) { | ||
this._activeInput.onEventMove(event); | ||
if (!this._panFlag || !this.isEnabled) { | ||
return; | ||
} | ||
onPanmove(event) { | ||
this.triggerChange(event); | ||
} | ||
const panEvent = this._activeInput.extendEvent(event); | ||
onPanend(event) { | ||
this.triggerChange(event); | ||
this.triggerAnimation(event); | ||
} | ||
if (panEvent.srcEvent.cancelable !== false) { | ||
panEvent.srcEvent.preventDefault(); | ||
} | ||
panEvent.srcEvent.stopPropagation(); | ||
this._triggerChange(panEvent); | ||
this._activeInput.prevEvent = panEvent; | ||
} | ||
private triggerChange(event) { | ||
const angle = this.getAngle(event.center.x, event.center.y); | ||
const quadrant = this.getQuadrant(event.center.x, event.center.y); | ||
const diff = this.getDifference(this.prevAngle, angle, this.prevQuadrant, quadrant); | ||
protected _onPanend(event: MouseEvent) { | ||
this._activeInput.onEventEnd(event); | ||
if (!this._panFlag || !this.isEnabled) { | ||
return; | ||
} | ||
const prevEvent = this._activeInput.prevEvent; | ||
this._triggerChange(prevEvent); | ||
const vx = prevEvent.velocityX; | ||
const vy = prevEvent.velocityY; | ||
const velocity = | ||
Math.sqrt(vx * vx + vy * vy) * (this._lastDiff > 0 ? -1 : 1); // clockwise | ||
this._observer.release(this, prevEvent, [ | ||
velocity * this._coefficientForDistanceToAngle, | ||
]); | ||
this._panFlag = false; | ||
} | ||
this.prevAngle = angle; | ||
this.prevQuadrant = quadrant; | ||
private _triggerChange(event: ExtendedEvent) { | ||
const { x, y } = this._getPosFromOrigin(event.center.x, event.center.y); | ||
const angle = getAngle(x, y); | ||
const positiveAngle = angle < 0 ? 360 + angle : angle; | ||
const quadrant = this._getQuadrant(event.center.x, event.center.y); | ||
const diff = this._getDifference( | ||
this._prevAngle, | ||
positiveAngle, | ||
this._prevQuadrant, | ||
quadrant | ||
); | ||
if (diff === 0) { | ||
return; | ||
} | ||
this._prevAngle = positiveAngle; | ||
this._prevQuadrant = quadrant; | ||
this.lastDiff = diff; | ||
this.observer.change(this, event, toAxis(this.axes, [-diff])); // minus for clockwise | ||
} | ||
if (diff === 0) { | ||
return; | ||
} | ||
private triggerAnimation(event) { | ||
const vx = event.velocityX; | ||
const vy = event.velocityY; | ||
const velocity = Math.sqrt(vx * vx + vy * vy) * (this.lastDiff > 0 ? -1 : 1); // clockwise | ||
const duration = Math.abs(velocity / -this.observer.options.deceleration); | ||
const distance = velocity / 2 * duration; | ||
this._lastDiff = diff; | ||
this._observer.change(this, event, toAxis(this.axes, [-diff])); // minus for clockwise | ||
} | ||
this.observer.release(this, event, toAxis(this.axes, [distance * this.coefficientForDistanceToAngle])); | ||
} | ||
private _getDifference( | ||
prevAngle: number, | ||
angle: number, | ||
prevQuadrant: number, | ||
quadrant: number | ||
) { | ||
let diff: number; | ||
private getDifference(prevAngle: number, angle: number, prevQuadrant: number, quadrant: number) { | ||
let diff: number; | ||
if (prevAngle === null) { | ||
diff = 0; | ||
} else if (prevQuadrant === 1 && quadrant === 4) { | ||
diff = -prevAngle - (360 - angle); | ||
} else if (prevQuadrant === 4 && quadrant === 1) { | ||
diff = 360 - prevAngle + angle; | ||
} else { | ||
diff = angle - prevAngle; | ||
} | ||
if (prevAngle === null) { | ||
diff = 0; | ||
} else if (prevQuadrant === 1 && quadrant === 4) { | ||
diff = -prevAngle - (360 - angle); | ||
} else if (prevQuadrant === 4 && quadrant === 1) { | ||
diff = (360 - prevAngle) + angle; | ||
} else { | ||
diff = angle - prevAngle; | ||
} | ||
return diff; | ||
} | ||
return diff; | ||
} | ||
private _getPosFromOrigin(posX: number, posY: number) { | ||
return { | ||
x: posX - this._rotateOrigin[0], | ||
y: this._rotateOrigin[1] - posY, | ||
}; | ||
} | ||
private getPosFromOrigin(posX: number, posY: number) { | ||
return { | ||
x: posX - this.rotateOrigin[0], | ||
y: this.rotateOrigin[1] - posY, | ||
}; | ||
} | ||
private _getQuadrant(posX: number, posY: number) { | ||
/** | ||
* Quadrant | ||
* y(+) | ||
* | | ||
* 2 | 1 | ||
* --------------->x(+) | ||
* 3 | 4 | ||
* | | ||
*/ | ||
const { x, y } = this._getPosFromOrigin(posX, posY); | ||
let q = 0; | ||
private getAngle(posX: number, posY: number) { | ||
const { x, y } = this.getPosFromOrigin(posX, posY); | ||
const angle = Math.atan2(y, x) * 180 / Math.PI; | ||
// console.log(angle, x, y); | ||
return angle < 0 ? 360 + angle : angle; | ||
} | ||
/** | ||
* Quadrant | ||
* y(+) | ||
* | | ||
* 2 | 1 | ||
* --------------->x(+) | ||
* 3 | 4 | ||
* | | ||
*/ | ||
private getQuadrant(posX: number, posY: number) { | ||
const { x, y } = this.getPosFromOrigin(posX, posY); | ||
let q = 0; | ||
if (x >= 0 && y >= 0) { | ||
q = 1; | ||
} else if (x < 0 && y >= 0) { | ||
q = 2; | ||
} else if (x < 0 && y < 0) { | ||
q = 3; | ||
} else if (x >= 0 && y < 0) { | ||
q = 4; | ||
} | ||
return q; | ||
} | ||
if (x >= 0 && y >= 0) { | ||
q = 1; | ||
} else if (x < 0 && y >= 0) { | ||
q = 2; | ||
} else if (x < 0 && y < 0) { | ||
q = 3; | ||
} else if (x >= 0 && y < 0) { | ||
q = 4; | ||
} | ||
return q; | ||
} | ||
} |
@@ -1,9 +0,9 @@ | ||
import { InputObserver } from "./../InputObserver"; | ||
import { $ } from "../utils"; | ||
import { UNIQUEKEY, toAxis, IInputType, IInputTypeObserver } from "./InputType"; | ||
import { Axis } from "../AxisManager"; | ||
import { toAxis, InputType, InputTypeObserver } from "./InputType"; | ||
export interface WheelInputOption { | ||
scale?: number; | ||
useNormalized?: boolean; | ||
scale?: number; | ||
releaseDelay?: number; | ||
useNormalized?: boolean; | ||
} | ||
@@ -14,11 +14,12 @@ | ||
* @ko eg.Axes.WheelInput 모듈의 옵션 객체 | ||
* @property {Number} [scale=1] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</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> | ||
**/ | ||
/** | ||
* @class eg.Axes.WheelInput | ||
* @classdesc A module that passes the amount of change to eg.Axes when the mouse wheel is moved. use one axis. | ||
* A module that passes the amount of change to eg.Axes when the mouse wheel is moved. use one axis. | ||
* @ko 마우스 휠이 움직일때의 변화량을 eg.Axes에 전달하는 모듈. 한 개 의 축을 사용한다. | ||
* | ||
* @example | ||
* ```js | ||
* const wheel = new eg.Axes.WheelInput("#area", { | ||
@@ -30,124 +31,129 @@ * scale: 1 | ||
* axes.connect("something", wheel); | ||
* | ||
* ``` | ||
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.WheelInput module <ko>eg.Axes.WheelInput 모듈을 사용할 엘리먼트</ko> | ||
* @param {WheelInputOption} [options] The option object of the eg.Axes.WheelInput module<ko>eg.Axes.WheelInput 모듈의 옵션 객체</ko> | ||
*/ | ||
export class WheelInput implements IInputType { | ||
options: WheelInputOption; | ||
axes: string[] = []; | ||
element: HTMLElement = null; | ||
private _isEnabled = false; | ||
private _isHolded = false; | ||
private _timer = null; | ||
private observer: IInputTypeObserver; | ||
constructor(el, options?: WheelInputOption) { | ||
this.element = $(el); | ||
this.options = { | ||
...{ | ||
scale: 1, | ||
useNormalized: true, | ||
}, ...options, | ||
}; | ||
this.onWheel = this.onWheel.bind(this); | ||
} | ||
export class WheelInput implements InputType { | ||
public options: WheelInputOption; | ||
public axes: string[] = []; | ||
public element: HTMLElement = null; | ||
private _observer: InputTypeObserver; | ||
private _enabled = false; | ||
private _holding = false; | ||
private _timer: NodeJS.Timeout = null; | ||
mapAxes(axes: string[]) { | ||
this.axes = axes; | ||
} | ||
/** | ||
* | ||
*/ | ||
public constructor(el, options?: WheelInputOption) { | ||
this.element = $(el); | ||
this.options = { | ||
...{ | ||
scale: 1, | ||
releaseDelay: 300, | ||
useNormalized: true, | ||
}, | ||
...options, | ||
}; | ||
this._onWheel = this._onWheel.bind(this); | ||
} | ||
connect(observer: IInputTypeObserver): IInputType { | ||
this.dettachEvent(); | ||
this.attachEvent(observer); | ||
return this; | ||
} | ||
public mapAxes(axes: string[]) { | ||
this.axes = axes; | ||
} | ||
disconnect() { | ||
this.dettachEvent(); | ||
return this; | ||
} | ||
public connect(observer: InputTypeObserver): InputType { | ||
this._detachEvent(); | ||
this._attachEvent(observer); | ||
return this; | ||
} | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
* @method eg.Axes.WheelInput#destroy | ||
*/ | ||
destroy() { | ||
this.disconnect(); | ||
this.element = null; | ||
} | ||
public disconnect() { | ||
this._detachEvent(); | ||
return this; | ||
} | ||
private onWheel(event) { | ||
if (!this._isEnabled) { | ||
return; | ||
} | ||
event.preventDefault(); | ||
/** | ||
* Destroys elements, properties, and events used in a module. | ||
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다. | ||
*/ | ||
public destroy() { | ||
this.disconnect(); | ||
this.element = null; | ||
} | ||
if (event.deltaY === 0) { | ||
return; | ||
} | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @return {WheelInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public enable() { | ||
this._enabled = true; | ||
return this; | ||
} | ||
if (!this._isHolded) { | ||
this.observer.hold(this, event); | ||
this._isHolded = true; | ||
} | ||
const offset = (event.deltaY > 0 ? -1 : 1) * this.options.scale * (this.options.useNormalized ? 1 : Math.abs(event.deltaY)); | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @return {WheelInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
public disable() { | ||
this._enabled = false; | ||
return this; | ||
} | ||
this.observer.change(this, event, toAxis(this.axes, [offset])); | ||
clearTimeout(this._timer); | ||
const inst = this; | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
public isEnabled() { | ||
return this._enabled; | ||
} | ||
this._timer = setTimeout(() => { | ||
if (this._isHolded) { | ||
this._isHolded = false; | ||
this.observer.release(this, event, toAxis(this.axes, [0])); | ||
} | ||
}, 50); | ||
} | ||
private _onWheel(event: WheelEvent) { | ||
if (!this._enabled) { | ||
return; | ||
} | ||
event.preventDefault(); | ||
private attachEvent(observer: IInputTypeObserver) { | ||
this.observer = observer; | ||
this.element.addEventListener("wheel", this.onWheel); | ||
this._isEnabled = true; | ||
} | ||
if (event.deltaY === 0) { | ||
return; | ||
} | ||
private dettachEvent() { | ||
this.element.removeEventListener("wheel", this.onWheel); | ||
this._isEnabled = false; | ||
this.observer = null; | ||
if (!this._holding) { | ||
this._observer.hold(this, event); | ||
this._holding = true; | ||
} | ||
const offset = | ||
(event.deltaY > 0 ? -1 : 1) * | ||
this.options.scale * | ||
(this.options.useNormalized ? 1 : Math.abs(event.deltaY)); | ||
this._observer.change(this, event, toAxis(this.axes, [offset]), true); | ||
clearTimeout(this._timer); | ||
if (this._timer) { | ||
clearTimeout(this._timer); | ||
this._timer = null; | ||
} | ||
} | ||
this._timer = setTimeout(() => { | ||
if (this._holding) { | ||
this._holding = false; | ||
this._observer.release(this, event, [0]); | ||
} | ||
}, this.options.releaseDelay); | ||
} | ||
/** | ||
* Enables input devices | ||
* @ko 입력 장치를 사용할 수 있게 한다 | ||
* @method eg.Axes.WheelInput#enable | ||
* @return {eg.Axes.WheelInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
enable() { | ||
this._isEnabled = true; | ||
return this; | ||
} | ||
/** | ||
* Disables input devices | ||
* @ko 입력 장치를 사용할 수 없게 한다. | ||
* @method eg.Axes.WheelInput#disable | ||
* @return {eg.Axes.WheelInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko> | ||
*/ | ||
disable() { | ||
this._isEnabled = false; | ||
return this; | ||
} | ||
/** | ||
* Returns whether to use an input device | ||
* @ko 입력 장치를 사용 여부를 반환한다. | ||
* @method eg.Axes.WheelInput#isEnable | ||
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko> | ||
*/ | ||
isEnable() { | ||
return this._isEnabled; | ||
} | ||
private _attachEvent(observer: InputTypeObserver) { | ||
this._observer = observer; | ||
this.element.addEventListener("wheel", this._onWheel); | ||
this._enabled = true; | ||
} | ||
private _detachEvent() { | ||
this.element.removeEventListener("wheel", this._onWheel); | ||
this._enabled = false; | ||
this._observer = null; | ||
if (this._timer) { | ||
clearTimeout(this._timer); | ||
this._timer = null; | ||
} | ||
} | ||
} |
import { AxesOption } from "./Axes"; | ||
export class InterruptManager { | ||
private _prevented = false; // check whether the animation event was prevented | ||
constructor(private options: AxesOption) { } | ||
private _prevented = false; // check whether the animation event was prevented | ||
public constructor(private _options: AxesOption) {} | ||
isInterrupting() { | ||
// when interruptable is 'true', return value is always 'true'. | ||
return this.options.interruptable || this._prevented; | ||
} | ||
public isInterrupting() { | ||
// when interruptable is 'true', return value is always 'true'. | ||
return this._options.interruptable || this._prevented; | ||
} | ||
isInterrupted() { | ||
return !this.options.interruptable && this._prevented; | ||
} | ||
public isInterrupted() { | ||
return !this._options.interruptable && this._prevented; | ||
} | ||
setInterrupt(prevented) { | ||
!this.options.interruptable && (this._prevented = prevented); | ||
} | ||
public setInterrupt(prevented) { | ||
if (!this._options.interruptable) { | ||
this._prevented = prevented; | ||
} | ||
} | ||
} |
179
src/types.ts
import { Axis } from "./AxisManager"; | ||
import { IInputType } from "./inputType/InputType"; | ||
import { MouseEventInput } from "./eventInput/MouseEventInput"; | ||
import { TouchEventInput } from "./eventInput/TouchEventInput"; | ||
import { PointerEventInput } from "./eventInput/PointerEventInput"; | ||
import { TouchMouseEventInput } from "./eventInput/TouchMouseEventInput"; | ||
import { InputType } from "./inputType/InputType"; | ||
export type ObjectInterface<T = any> = Record<string | number, T>; | ||
export type AxesEvents = { | ||
hold: OnHold; | ||
change: OnChange; | ||
release: OnRelease; | ||
animationStart: OnAnimationStart; | ||
animationEnd: OnAnimationEnd; | ||
finish: OnFinish; | ||
}; | ||
export type AnimationParam = { | ||
depaPos: Axis; | ||
destPos: Axis; | ||
duration: number; | ||
delta: Axis; | ||
isTrusted?: boolean; | ||
stop?: () => void; | ||
setTo?: (destPos?: Axis, duration?: number) => { destPos: Axis, duration: number }; | ||
done?: () => void; | ||
startTime?: number; | ||
inputEvent?; | ||
input?: IInputType; | ||
}; | ||
export type InputEventType = PointerEvent | MouseEvent | TouchEvent; | ||
export type OnHold = { | ||
pos: Record<string, any>; | ||
input: IInputType | null; | ||
inputEvent: any; | ||
isTrusted: boolean; | ||
}; | ||
export type ActiveInput = | ||
| MouseEventInput | ||
| TouchEventInput | ||
| TouchMouseEventInput | ||
| PointerEventInput; | ||
export type OnAnimationStart = { | ||
depaPos: Axis; | ||
destPos: Axis; | ||
duration: number; | ||
delta: Axis; | ||
isTrusted: boolean; | ||
startTime?: number; | ||
inputEvent?: any; | ||
input?: IInputType | null; | ||
setTo(destPos?: Axis, duration?: number): void; | ||
done(): void; | ||
stop(): void; | ||
}; | ||
export interface AxesEvents { | ||
hold: OnHold; | ||
change: OnChange; | ||
release: OnRelease; | ||
animationStart: OnAnimationStart; | ||
animationEnd: OnAnimationEnd; | ||
finish: OnFinish; | ||
} | ||
export type OnChange = { | ||
pos: Axis; | ||
delta: Axis; | ||
holding: boolean; | ||
inputEvent: any; | ||
isTrusted: boolean; | ||
input: IInputType | null; | ||
set(toPos?: Axis, userDuration?: number): void; | ||
stop(): void; | ||
}; | ||
export interface AnimationParam { | ||
depaPos: Axis; | ||
destPos: Axis; | ||
duration: number; | ||
delta: Axis; | ||
isTrusted?: boolean; | ||
stop?: () => void; | ||
setTo?: ( | ||
destPos?: Axis, | ||
duration?: number | ||
) => { destPos: Axis; duration: number }; | ||
done?: () => void; | ||
startTime?: number; | ||
inputEvent?; | ||
input?: InputType; | ||
} | ||
export type OnRelease = { | ||
depaPos: Axis; | ||
destPos: Axis; | ||
duration: number; | ||
delta: Axis; | ||
isTrusted?: boolean; | ||
startTime?: number; | ||
inputEvent?: any; | ||
input?: IInputType | null; | ||
setTo(destPos?: Axis, duration?: number): void; | ||
done(): void; | ||
}; | ||
export type OnAnimationEnd = { | ||
isTrusted: boolean; | ||
}; | ||
export interface UpdateAnimationOption { | ||
destPos?: Axis; | ||
duration?: number; | ||
restart?: boolean; | ||
} | ||
export type OnFinish = { | ||
isTrusted: boolean; | ||
}; | ||
export interface OnHold { | ||
pos: Record<string, any>; | ||
input: InputType | null; | ||
inputEvent: any; | ||
isTrusted: boolean; | ||
} | ||
export interface OnAnimationStart { | ||
depaPos: Axis; | ||
destPos: Axis; | ||
duration: number; | ||
delta: Axis; | ||
isTrusted: boolean; | ||
startTime?: number; | ||
inputEvent?: any; | ||
input?: InputType | null; | ||
setTo(destPos?: Axis, duration?: number): void; | ||
done(): void; | ||
stop(): void; | ||
} | ||
export interface OnChange { | ||
pos: Axis; | ||
delta: Axis; | ||
bounceRatio: Axis; | ||
holding: boolean; | ||
inputEvent: any; | ||
isTrusted: boolean; | ||
input: InputType | null; | ||
set(toPos?: Axis, userDuration?: number): void; | ||
stop(): void; | ||
} | ||
export interface OnRelease { | ||
depaPos: Axis; | ||
destPos: Axis; | ||
duration: number; | ||
delta: Axis; | ||
bounceRatio: Axis; | ||
isTrusted?: boolean; | ||
startTime?: number; | ||
inputEvent?: any; | ||
input?: InputType | null; | ||
setTo(destPos?: Axis, duration?: number): void; | ||
done(): void; | ||
} | ||
export interface OnAnimationEnd { | ||
isTrusted: boolean; | ||
} | ||
export interface OnFinish { | ||
isTrusted: boolean; | ||
} | ||
export interface ExtendedEvent { | ||
srcEvent: InputEventType; | ||
angle: number; | ||
scale: number; | ||
center: { | ||
x: number; | ||
y: number; | ||
}; | ||
deltaX: number; | ||
deltaY: number; | ||
offsetX: number; | ||
offsetY: number; | ||
velocityX: number; | ||
velocityY: number; | ||
preventSystemEvent: boolean; | ||
} |
353
src/utils.ts
@@ -1,52 +0,59 @@ | ||
import {window} from "./browser"; | ||
import { window } from "./browser"; | ||
import { PREVENT_SCROLL_CSSPROPS } from "./const"; | ||
import { ObjectInterface } from "./types"; | ||
declare var jQuery: any; | ||
declare let jQuery: any; | ||
export function toArray(nodes: NodeList): HTMLElement[] { | ||
// const el = Array.prototype.slice.call(nodes); | ||
// for IE8 | ||
const el = []; | ||
for (let i = 0, len = nodes.length; | ||
i < len; i++) { | ||
el.push(nodes[i]); | ||
} | ||
return el; | ||
} | ||
export const toArray = (nodes: NodeList): HTMLElement[] => { | ||
// const el = Array.prototype.slice.call(nodes); | ||
// for IE8 | ||
const el = []; | ||
for (let i = 0, len = nodes.length; i < len; i++) { | ||
el.push(nodes[i]); | ||
} | ||
return el; | ||
}; | ||
export function $(param, multi = false) { | ||
let el; | ||
export const $ = (param, multi = false) => { | ||
let el; | ||
if (typeof param === "string") { // String (HTML, Selector) | ||
// check if string is HTML tag format | ||
const match = param.match(/^<([a-z]+)\s*([^>]*)>/); | ||
if (typeof param === "string") { | ||
// String (HTML, Selector) | ||
// check if string is HTML tag format | ||
const match = param.match(/^<([a-z]+)\s*([^>]*)>/); | ||
// creating element | ||
if (match) { // HTML | ||
const dummy = document.createElement("div"); | ||
// creating element | ||
if (match) { | ||
// HTML | ||
const dummy = document.createElement("div"); | ||
dummy.innerHTML = param; | ||
el = toArray(dummy.childNodes); | ||
} else { // Selector | ||
el = toArray(document.querySelectorAll(param)); | ||
} | ||
if (!multi) { | ||
el = el.length >= 1 ? el[0] : undefined; | ||
} | ||
} else if (param === window) { // window | ||
el = param; | ||
} else if (param.nodeName && | ||
(param.nodeType === 1 || param.nodeType === 9)) { // HTMLElement, Document | ||
el = param; | ||
} else if (("jQuery" in window && param instanceof jQuery) || | ||
param.constructor.prototype.jquery) { // jQuery | ||
el = multi ? param.toArray() : param.get(0); | ||
} else if (Array.isArray(param)) { | ||
el = param.map(v => $(v)); | ||
if (!multi) { | ||
el = el.length >= 1 ? el[0] : undefined; | ||
} | ||
} | ||
return el; | ||
} | ||
dummy.innerHTML = param; | ||
el = toArray(dummy.childNodes); | ||
} else { | ||
// Selector | ||
el = toArray(document.querySelectorAll(param)); | ||
} | ||
if (!multi) { | ||
el = el.length >= 1 ? el[0] : undefined; | ||
} | ||
} else if (param === window) { | ||
// window | ||
el = param; | ||
} else if (param.nodeName && (param.nodeType === 1 || param.nodeType === 9)) { | ||
// HTMLElement, Document | ||
el = param; | ||
} else if ( | ||
("jQuery" in window && param instanceof jQuery) || | ||
param.constructor.prototype.jquery | ||
) { | ||
// jQuery | ||
el = multi ? param.toArray() : param.get(0); | ||
} else if (Array.isArray(param)) { | ||
el = param.map((v) => $(v)); | ||
if (!multi) { | ||
el = el.length >= 1 ? el[0] : undefined; | ||
} | ||
} | ||
return el; | ||
}; | ||
@@ -56,24 +63,28 @@ let raf = window.requestAnimationFrame || window.webkitRequestAnimationFrame; | ||
if (raf && !caf) { | ||
const keyInfo = {}; | ||
const oldraf = raf; | ||
raf = (callback: FrameRequestCallback) => { | ||
function wrapCallback(timestamp) { | ||
if (keyInfo[key]) { | ||
callback(timestamp); | ||
} | ||
} | ||
const key = oldraf(wrapCallback); | ||
keyInfo[key] = true; | ||
return key; | ||
}; | ||
caf = (key: number) => { | ||
delete keyInfo[key]; | ||
}; | ||
const keyInfo = {}; | ||
const oldraf = raf; | ||
raf = (callback: FrameRequestCallback) => { | ||
const wrapCallback = (timestamp: number) => { | ||
if (keyInfo[key]) { | ||
callback(timestamp); | ||
} | ||
}; | ||
const key = oldraf(wrapCallback); | ||
keyInfo[key] = true; | ||
return key; | ||
}; | ||
caf = (key: number) => { | ||
delete keyInfo[key]; | ||
}; | ||
} else if (!(raf && caf)) { | ||
raf = (callback: FrameRequestCallback) => { | ||
return window.setTimeout(() => { | ||
callback(window.performance && window.performance.now && window.performance.now() || new Date().getTime()); | ||
}, 16); | ||
}; | ||
caf = window.clearTimeout; | ||
raf = (callback: FrameRequestCallback) => { | ||
return window.setTimeout(() => { | ||
callback( | ||
((window.performance && | ||
window.performance.now && | ||
window.performance.now()) as number) || new Date().getTime() | ||
); | ||
}, 16); | ||
}; | ||
caf = window.clearTimeout; | ||
} | ||
@@ -86,105 +97,149 @@ | ||
*/ | ||
export function requestAnimationFrame(fp) { | ||
return raf(fp); | ||
} | ||
export const requestAnimationFrame = (fp) => { | ||
return raf(fp); | ||
}; | ||
/** | ||
* A polyfill for the window.cancelAnimationFrame() method. It cancels an animation executed through a call to the requestAnimationFrame() method. | ||
* @param {Number} key − The ID value returned through a call to the requestAnimationFrame() method. <ko>requestAnimationFrame() 메서드가 반환한 아이디 값</ko> | ||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame | ||
* @private | ||
*/ | ||
export function cancelAnimationFrame(key) { | ||
caf(key); | ||
} | ||
* A polyfill for the window.cancelAnimationFrame() method. It cancels an animation executed through a call to the requestAnimationFrame() method. | ||
* @param {Number} key − The ID value returned through a call to the requestAnimationFrame() method. <ko>requestAnimationFrame() 메서드가 반환한 아이디 값</ko> | ||
* @see https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame | ||
* @private | ||
*/ | ||
export const cancelAnimationFrame = (key) => { | ||
caf(key); | ||
}; | ||
export function map<T, U>(obj: ObjectInterface<T>, callback: (value: T, key: string) => U): ObjectInterface<U> { | ||
const tranformed: ObjectInterface<U> = {}; | ||
export const map = <T, U>( | ||
obj: ObjectInterface<T>, | ||
callback: (value: T, key: string) => U | ||
): ObjectInterface<U> => { | ||
const tranformed: ObjectInterface<U> = {}; | ||
for (const k in obj) { | ||
k && (tranformed[k] = callback(obj[k], k)); | ||
} | ||
return tranformed; | ||
} | ||
for (const k in obj) { | ||
if (k) { | ||
tranformed[k] = callback(obj[k], k); | ||
} | ||
} | ||
return tranformed; | ||
}; | ||
export function filter<T>(obj: ObjectInterface<T>, callback: (value: T, key: string) => boolean): ObjectInterface<T> { | ||
const filtered: ObjectInterface<T> = {}; | ||
export const filter = <T>( | ||
obj: ObjectInterface<T>, | ||
callback: (value: T, key: string) => boolean | ||
): ObjectInterface<T> => { | ||
const filtered: ObjectInterface<T> = {}; | ||
for (const k in obj) { | ||
k && callback(obj[k], k) && (filtered[k] = obj[k]); | ||
} | ||
return filtered; | ||
} | ||
export function every<T>(obj: ObjectInterface<T>, callback: (value: T, key: string) => boolean) { | ||
for (const k in obj) { | ||
if (k && !callback(obj[k], k)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
export function equal(target: ObjectInterface, base: ObjectInterface): boolean { | ||
return every(target, (v, k) => v === base[k]); | ||
} | ||
for (const k in obj) { | ||
if (k && callback(obj[k], k)) { | ||
filtered[k] = obj[k]; | ||
} | ||
} | ||
return filtered; | ||
}; | ||
export const every = <T>( | ||
obj: ObjectInterface<T>, | ||
callback: (value: T, key: string) => boolean | ||
) => { | ||
for (const k in obj) { | ||
if (k && !callback(obj[k], k)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
}; | ||
export const equal = ( | ||
target: ObjectInterface, | ||
base: ObjectInterface | ||
): boolean => { | ||
return every(target, (v, k) => v === base[k]); | ||
}; | ||
const roundNumFunc = {}; | ||
export function roundNumber(num: number, roundUnit: number) { | ||
// Cache for performance | ||
if (!roundNumFunc[roundUnit]) { | ||
roundNumFunc[roundUnit] = getRoundFunc(roundUnit); | ||
} | ||
export const roundNumber = (num: number, roundUnit: number) => { | ||
// Cache for performance | ||
if (!roundNumFunc[roundUnit]) { | ||
roundNumFunc[roundUnit] = getRoundFunc(roundUnit); | ||
} | ||
return roundNumFunc[roundUnit](num); | ||
} | ||
return roundNumFunc[roundUnit](num); | ||
}; | ||
export function roundNumbers(num: ObjectInterface<number>, roundUnit: ObjectInterface<number> | number) { | ||
if (!num || !roundUnit) { | ||
return num; | ||
} | ||
const isNumber = typeof roundUnit === "number"; | ||
return map(num, (value, key) => roundNumber(value, isNumber ? roundUnit : roundUnit[key])); | ||
} | ||
export const roundNumbers = ( | ||
num: ObjectInterface<number>, | ||
roundUnit: ObjectInterface<number> | number | ||
): ObjectInterface<number> => { | ||
if (!num || !roundUnit) { | ||
return num; | ||
} | ||
return map(num, (value, key) => | ||
roundNumber( | ||
value, | ||
typeof roundUnit === "number" ? roundUnit : roundUnit[key] | ||
) | ||
); | ||
}; | ||
export function getDecimalPlace(val: number): number { | ||
if (!isFinite(val)) { | ||
return 0; | ||
} | ||
export const getDecimalPlace = (val: number): number => { | ||
if (!isFinite(val)) { | ||
return 0; | ||
} | ||
const v = (val + ""); | ||
const v = `${val}`; | ||
if (v.indexOf("e") >= 0) { | ||
// Exponential Format | ||
// 1e-10, 1e-12 | ||
let p = 0; | ||
let e = 1; | ||
if (v.indexOf("e") >= 0) { | ||
// Exponential Format | ||
// 1e-10, 1e-12 | ||
let p = 0; | ||
let e = 1; | ||
while (Math.round(val * e) / e !== val) { | ||
e *= 10; | ||
p++; | ||
} | ||
while (Math.round(val * e) / e !== val) { | ||
e *= 10; | ||
p++; | ||
} | ||
return p; | ||
} | ||
return p; | ||
} | ||
// In general, following has performance benefit. | ||
// https://jsperf.com/precision-calculation | ||
return v.indexOf(".") >= 0 ? (v.length - v.indexOf(".") - 1) : 0; | ||
} | ||
// In general, following has performance benefit. | ||
// https://jsperf.com/precision-calculation | ||
return v.indexOf(".") >= 0 ? v.length - v.indexOf(".") - 1 : 0; | ||
}; | ||
export function inversePow(n: number) { | ||
// replace Math.pow(10, -n) to solve floating point issue. | ||
// eg. Math.pow(10, -4) => 0.00009999999999999999 | ||
return 1 / Math.pow(10, n); | ||
} | ||
export const inversePow = (n: number) => { | ||
// replace Math.pow(10, -n) to solve floating point issue. | ||
// eg. Math.pow(10, -4) => 0.00009999999999999999 | ||
return 1 / Math.pow(10, n); | ||
}; | ||
export function getRoundFunc(v: number) { | ||
const p = v < 1 ? Math.pow(10, getDecimalPlace(v)) : 1; | ||
export const getRoundFunc = (v: number) => { | ||
const p = v < 1 ? Math.pow(10, getDecimalPlace(v)) : 1; | ||
return (n: number) => { | ||
if (v === 0) { | ||
return 0; | ||
} | ||
return (n: number) => { | ||
if (v === 0) { | ||
return 0; | ||
} | ||
return Math.round(Math.round(n / v) * v * p) / p; | ||
}; | ||
} | ||
return Math.round(Math.round(n / v) * v * p) / p; | ||
}; | ||
}; | ||
export const getAngle = (posX: number, posY: number) => { | ||
return (Math.atan2(posY, posX) * 180) / Math.PI; | ||
}; | ||
export const setCssProps = ( | ||
element: HTMLElement, | ||
originalCssProps?: { [key: string]: string } | ||
): { [key: string]: string } => { | ||
const oldCssProps = {}; | ||
if (element.style) { | ||
const newCssProps = originalCssProps | ||
? originalCssProps | ||
: PREVENT_SCROLL_CSSPROPS; | ||
Object.keys(newCssProps).forEach((prop) => { | ||
oldCssProps[prop] = element.style[prop]; | ||
element.style[prop] = newCssProps[prop]; | ||
}); | ||
} | ||
return oldCssProps; | ||
}; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
1664189
2
115
0
62
16352
+ Added@egjs/component@3.0.5(transitive)
- Removed@egjs/hammerjs@^2.0.15
- Removed@egjs/component@2.2.2(transitive)
- Removed@egjs/hammerjs@2.0.17(transitive)
- Removed@types/hammerjs@2.0.46(transitive)
Updated@egjs/component@^3.0.1