Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add useAcceleration option to PanInput #205

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/run-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Run tests
on: [push, pull_request]
jobs:
unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/[email protected]
with:
node-version: 14.15.4
- name: install
run: npm install
working-directory: ./packages/axes
- name: test
run: npm run coverage
working-directory: ./packages/axes
- name: Coveralls GitHub Action
uses: coverallsapp/[email protected]
with:
path-to-lcov: ./packages/axes/coverage/lcov.info
github-token: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
{
"basePath": "packages/axes/dist",
"dists": [
"demo/dist"
"packages/demo/dist"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will manage dist by version like cdn.

Check the latest and version folders.

]
}
],
Expand Down
26 changes: 13 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
"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.",
"private": true,
"scripts": {
"lint": "eslint ./packages/axes/src/**/*.ts",
"lint": "eslint ./packages/axes/src/**/*.ts",
"packages": "npm run packages:update && npm run packages:build && npm run packages:publish",
"packages:update": "lerna-helper version",
"packages:build": "lerna run build --ignore demo",
"packages:publish": "lerna-helper publish --commit 'chore: update packages versions'",
"docs:build": "rm -rf ./packages/demo/docs/api && jsdoc-to-mdx -c ./jsdoc-to-mdx.json",
"demo:build": "npm run docs:build && npm run build --prefix packages/demo",
"demo:build-docusaurus": "npm run build --prefix demo",
"demo:deploy": "lerna-helper deploy --base @egjs/axes --remote upstream",
"demo:deploy-origin": "lerna-helper deploy --base @egjs/axes --remote origin",
"demo:deploy": "lerna-helper deploy --base @egjs/axes --src packages/demo/build/ --remote upstream",
"demo:deploy-origin": "lerna-helper deploy --base @egjs/axes --src packages/demo/build/ --remote origin",
"release": "lerna-helper release --base @egjs/axes --remote upstream --branch master",
"prepush": "npm run lint",
"commitmsg": "node config/validate-commit-msg.js"
Expand All @@ -33,16 +33,16 @@
"jsdoc-to-mdx": "^1.1.2",
"lerna": "^5.1.4",
"typescript": "^4.6.2",
"eslint": "^7.32.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",
"eslint-plugin-react": "^7.22.0",
"@typescript-eslint/eslint-plugin": "^5.11.0",
"@typescript-eslint/eslint-plugin-tslint": "^5.11.0",
"@typescript-eslint/parser": "^5.11.0"
"eslint": "^7.32.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",
"eslint-plugin-react": "^7.22.0",
"@typescript-eslint/eslint-plugin": "^5.11.0",
"@typescript-eslint/eslint-plugin-tslint": "^5.11.0",
"@typescript-eslint/parser": "^5.11.0"
},
"workspaces": {
"packages": [
Expand Down
24 changes: 20 additions & 4 deletions packages/axes/src/InputObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,13 @@ export class InputObserver implements InputTypeObserver {
this._moveDistance = this._axisManager.get(input.axes);
}

public change(input: InputType, event, offset: Axis, useAnimation?: boolean) {
public change(
input: InputType,
event,
offset: Axis,
useAnimation?: boolean,
velocity?: number[]
) {
if (
this._isStopped ||
!this._interruptManager.isInterrupting() ||
Expand All @@ -80,7 +86,10 @@ export class InputObserver implements InputTypeObserver {
if (nativeEvent.__childrenAxesAlreadyChanged) {
return;
}
let depaPos: Axis = this._moveDistance || this._axisManager.get(input.axes);
let depaPos: Axis =
!this._moveDistance || velocity
? this._axisManager.get(input.axes)
: this._moveDistance;
let destPos: Axis;

// for outside logic
Expand Down Expand Up @@ -113,8 +122,7 @@ export class InputObserver implements InputTypeObserver {
event,
};
if (useAnimation) {
const duration = this._animationManager.getDuration(destPos, depaPos);
this._animationManager.animateTo(destPos, duration, changeOption);
this._animationManager.changeTo(destPos, changeOption);
} else {
const isCanceled = !this._eventManager.triggerChange(
destPos,
Expand All @@ -126,6 +134,13 @@ export class InputObserver implements InputTypeObserver {
this._isStopped = true;
this._moveDistance = null;
this._animationManager.finish(false);
} else if (velocity) {
const displacement = this._animationManager.getDisplacement(velocity);
const nextOffset = toAxis(input.axes, displacement);
destPos = this._atOutside(
map(destPos, (v, k) => v + (nextOffset[k] || 0))
);
this._animationManager.changeTo(destPos, changeOption);
}
}
}
Expand Down Expand Up @@ -181,6 +196,7 @@ export class InputObserver implements InputTypeObserver {
destPos,
duration,
delta: this._axisManager.getDelta(depaPos, destPos),
triggerAnimationEvent: true,
inputEvent: event,
input,
isTrusted: true,
Expand Down
39 changes: 34 additions & 5 deletions packages/axes/src/animation/AnimationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,10 @@ export abstract class AnimationManager {
if (!every(pos, (v, k) => orgPos[k] === v)) {
this.eventManager.triggerChange(pos, orgPos, option, !!option);
}
this._animateParam = null;
if (this._raf) {
cancelAnimationFrame(this._raf);
if (this._animateParam.triggerAnimationEvent) {
this.eventManager.triggerAnimationEnd(!!option?.event);
}
this._raf = null;
this.eventManager.triggerAnimationEnd(!!option?.event);
this._removeAnimationParam();
}
}

Expand Down Expand Up @@ -189,6 +187,27 @@ export abstract class AnimationManager {
return userWish;
}

public changeTo(
destPos: Axis,
option: ChangeEventOption
): void {
const depaPos = this.axisManager.get(option.input.axes);
if (this._raf) {
cancelAnimationFrame(this._raf);
}

if (!equal(destPos, depaPos)) {
const newParam = {
depaPos,
destPos: destPos,
duration: this.getDuration(destPos, depaPos),
delta: this.axisManager.getDelta(depaPos, destPos),
triggerAnimationEvent: false,
};
this._animateLoop(newParam, () => this._removeAnimationParam());
}
}

public animateTo(
destPos: Axis,
duration: number,
Expand Down Expand Up @@ -226,6 +245,7 @@ export abstract class AnimationManager {
destPos: userWish.destPos,
duration: userWish.duration,
delta: this.axisManager.getDelta(depaPos, userWish.destPos),
triggerAnimationEvent: true,
isTrusted: !!inputEvent,
inputEvent,
input: option?.input || null,
Expand Down Expand Up @@ -297,13 +317,22 @@ export abstract class AnimationManager {
this._options.maximumDuration
),
delta: this.axisManager.getDelta(depaPos, destPos),
triggerAnimationEvent: true,
inputEvent,
input: option?.input || null,
isTrusted: !!inputEvent,
done: this.animationEnd,
};
}

private _removeAnimationParam() {
this._animateParam = null;
if (this._raf) {
cancelAnimationFrame(this._raf);
}
this._raf = null;
}

private _animateLoop(param: AnimationParam, complete: () => void): void {
if (param.duration) {
this._animateParam = {
Expand Down
2 changes: 1 addition & 1 deletion packages/axes/src/inputType/InputType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface InputType {
export interface InputTypeObserver {
options: AxesOption;
get(inputType: InputType): Axis;
change(inputType: InputType, event, offset: Axis, useAnimation?: boolean);
change(inputType: InputType, event, offset: Axis, useAnimation?: boolean, velocity?: number[]);
hold(inputType: InputType, event);
release(
inputType: InputType,
Expand Down
56 changes: 42 additions & 14 deletions packages/axes/src/inputType/PanInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ import {
MOUSE_LEFT,
ANY,
} from "../const";
import { ActiveEvent, ElementType, InputEventType } from "../types";
import {
ActiveEvent,
ElementType,
ExtendedEvent,
InputEventType,
} from "../types";

import {
convertInputType,
Expand All @@ -40,6 +45,7 @@ export interface PanInputOption {
preventClickOnDrag?: boolean;
iOSEdgeSwipeThreshold?: number;
releaseOnScroll?: boolean;
useAcceleration?: boolean;
touchAction?: string;
}

Expand Down Expand Up @@ -93,8 +99,9 @@ export const getDirectionByAngle = (
* @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 {Boolean} [preventClickOnDrag=false] Whether to cancel the {@link https://developer.mozilla.org/en/docs/Web/API/Element/click_event click} event when the user finishes dragging more than 1 pixel <ko>사용자가 1픽셀 이상 드래그를 마쳤을 때 {@link https://developer.mozilla.org/ko/docs/Web/API/Element/click_event click} 이벤트 취소 여부</ko>
* @param {Boolean} [preventClickOnDrag=false] Whether to cancel the {@link https://developer.mozilla.org/en/docs/Web/API/Element/click_event click} event when the user finishes dragging more than threshold <ko>사용자가 threshold 이상 드래그를 마쳤을 때 {@link https://developer.mozilla.org/ko/docs/Web/API/Element/click_event click} 이벤트 취소 여부</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>
* @param {Boolean} [useAcceleration=false] Whether to apply the dragging speed to coordinate changes. <ko>사용자의 드래그 속도를 좌표 변화에 반영할지 여부</ko>
* @param {String} [touchAction=null] Value that overrides the element's "touch-action" css property. If set to null, it is automatically set to prevent scrolling in the direction of the connected axis. <ko>엘리먼트의 "touch-action" CSS 속성을 덮어쓰는 값. 만약 null로 설정된 경우, 연결된 축 방향으로의 스크롤을 방지하게끔 자동으로 설정된다.</ko>
**/
/**
Expand Down Expand Up @@ -150,6 +157,7 @@ export class PanInput implements InputType {
preventClickOnDrag: false,
iOSEdgeSwipeThreshold: IOS_EDGE_THRESHOLD,
releaseOnScroll: false,
useAcceleration: false,
touchAction: null,
...options,
};
Expand Down Expand Up @@ -267,6 +275,7 @@ export class PanInput implements InputType {
const {
iOSEdgeSwipeThreshold,
releaseOnScroll,
useAcceleration,
inputKey,
inputButton,
threshold,
Expand Down Expand Up @@ -339,9 +348,18 @@ export class PanInput implements InputType {
}
panEvent.preventSystemEvent = prevent;
if (prevent && (this._isOverThreshold || distance >= threshold)) {
const velocity = useAcceleration
? this._getVelocity(panEvent)
: undefined;
this._dragged = true;
this._isOverThreshold = true;
this._observer.change(this, panEvent, toAxis(this.axes, offset));
this._observer.change(
this,
panEvent,
toAxis(this.axes, offset),
false,
velocity
);
}
activeEvent.prevEvent = panEvent;
}
Expand All @@ -356,16 +374,7 @@ export class PanInput implements InputType {
this._detachWindowEvent(activeEvent);
clearTimeout(this._rightEdgeTimer);
const prevEvent = activeEvent.prevEvent;
const velocity = this._isOverThreshold ? 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),
]
) : [0, 0];
const velocity = this._getVelocity(prevEvent);
activeEvent.onRelease();
this._observer.release(this, prevEvent, velocity);
}
Expand Down Expand Up @@ -396,6 +405,21 @@ export class PanInput implements InputType {
];
}

private _getVelocity(event: ExtendedEvent): number[] {
return this._isOverThreshold
? this._getOffset(
[
Math.abs(event.velocityX) * (event.offsetX < 0 ? -1 : 1),
Math.abs(event.velocityY) * (event.offsetY < 0 ? -1 : 1),
],
[
useDirection(DIRECTION_HORIZONTAL, this._direction),
useDirection(DIRECTION_VERTICAL, this._direction),
]
)
: [0, 0];
}

private _getDistance(delta: number[], direction: boolean[]): number {
return Math.sqrt(
Number(direction[0]) * Math.pow(delta[0], 2) +
Expand Down Expand Up @@ -432,7 +456,11 @@ export class PanInput implements InputType {
const element = this.element;
if (element) {
if (this.options.preventClickOnDrag) {
element.removeEventListener("click", this._preventClickWhenDragged, true);
element.removeEventListener(
"click",
this._preventClickWhenDragged,
true
);
}
activeEvent?.start.forEach((event) => {
element.removeEventListener(event, this._onPanstart);
Expand Down
1 change: 1 addition & 0 deletions packages/axes/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export interface AnimationParam {
destPos: Axis;
duration: number;
delta: Axis;
triggerAnimationEvent: boolean;
isTrusted?: boolean;
stop?: () => void;
setTo?: (
Expand Down
7 changes: 4 additions & 3 deletions packages/axes/test/unit/Axes.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ describe("Axes", () => {
});
});

describe("Nested Axes Test", () => {
describe("nested", () => {
beforeEach(() => {
inst = new Axes({
x: {
Expand Down Expand Up @@ -600,6 +600,7 @@ describe("Axes", () => {
});
input = new MockPanInputInjector.PanInput(el, {
iOSEdgeSwipeThreshold,
inputKey: ["any"],
inputType: ["touch"],
});
inst
Expand Down Expand Up @@ -649,8 +650,8 @@ describe("Axes", () => {
// Then
// for test animation event
setTimeout(() => {
const releaseEvent = releaseHandler.getCall(0).args[0];
expect(releaseHandler.calledOnce).to.be.true;
const releaseEvent = releaseHandler.getCall(0).args[0];
// expect(releaseEvent.inputEvent.isFinal).to.be.false;
expect(releaseEvent.isTrusted).to.be.true;

Expand Down Expand Up @@ -678,8 +679,8 @@ describe("Axes", () => {
// Then
// for test animation event
setTimeout(() => {
const releaseEvent = releaseHandler.getCall(0).args[0];
expect(releaseHandler.calledOnce).to.be.true;
const releaseEvent = releaseHandler.getCall(0).args[0];
// expect(releaseEvent.inputEvent.isFinal).to.be.false;
expect(releaseEvent.isTrusted).to.be.true;

Expand Down
Loading