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 4 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
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
8 changes: 8 additions & 0 deletions packages/axes/src/Axes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export interface AxesOption {
deceleration?: number;
interruptable?: boolean;
round?: number;
animateOn?: string;
nested?: boolean;
}

Expand Down Expand Up @@ -71,6 +72,12 @@ export interface AxesOption {
* @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>
* @param {Boolean} [animateOn="release"] When to start the animation.
* - "change": When the coordinates change with the "change" event.
* - "release": When the input is finished with the "release" event.
* <ko>애니메이션 재생을 시작하는 시점
* - "change": 입력을 통해 좌표가 변하며 "change" 이벤트가 발생할 때.
* - "release": 입력을 마치고 "release" 이벤트가 발생할 때.</ko>
* @param {Boolean} [nested=false] Whether the event propagates to other instances when the coordinates reach the end of the movable area <ko>좌표가 이동 가능한 영역의 끝까지 도달했을 때 다른 인스턴스들로의 이벤트 전파 여부</ko>
**/

Expand Down Expand Up @@ -256,6 +263,7 @@ class Axes extends Component<AxesEvents> {
minimumDuration: 0,
deceleration: 0.0006,
round: null,
animateOn: "release",
nested: false,
},
...options,
Expand Down
5 changes: 2 additions & 3 deletions packages/axes/src/InputObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,8 @@ export class InputObserver implements InputTypeObserver {
input,
event,
};
if (useAnimation) {
const duration = this._animationManager.getDuration(destPos, depaPos);
this._animationManager.animateTo(destPos, duration, changeOption);
if (this.options.animateOn === "change" || useAnimation) {
this._animationManager.changeTo(destPos, offset, changeOption);
} else {
const isCanceled = !this._eventManager.triggerChange(
destPos,
Expand Down
46 changes: 41 additions & 5 deletions packages/axes/src/animation/AnimationManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,7 @@ 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);
}
this._raf = null;
this._removeAnimationParam();
this.eventManager.triggerAnimationEnd(!!option?.event);
}
}
Expand Down Expand Up @@ -189,6 +185,38 @@ export abstract class AnimationManager {
return userWish;
}

public changeTo(
destPos: Axis,
offset: Axis,
option: ChangeEventOption
): void {
const depaPos = this.axisManager.get(option.input.axes);
const nextPos = this._animateParam
? this.axisManager.map(this._animateParam.destPos, (v, opt, k) => {
const pos = v + (offset[k] || 0);
return isCircularable(pos, opt.range, opt.circular as boolean[])
? pos
: destPos[k];
})
: destPos;

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

public animateTo(
destPos: Axis,
duration: number,
Expand Down Expand Up @@ -304,6 +332,14 @@ export abstract class AnimationManager {
};
}

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/PanInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ 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 {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
97 changes: 94 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 @@ -568,6 +568,97 @@ describe("Axes", () => {
});
});

describe("animateOn", () => {
beforeEach(() => {
el = sandbox();
});
afterEach(() => {
if (inst) {
inst.destroy();
inst = null;
}
cleanup();
});

it(`should change value of coordinates immediately without animation if animateOn is "release"`, (done) => {
// Given
const target = document.querySelector("#sandbox");
const panInput = new PanInput(target, { inputType: ["touch"], scale: [10, 0] });
const result = [];
inst = new Axes({
x: {
range: [0, 300],
},
}, {
animateOn: "release",
});

inst.connect(["x"], panInput);

// When
Simulator.gestures.pan(
target,
{
pos: [0, 0],
deltaX: 300,
deltaY: 0,
duration: 200,
easing: "linear",
},
);

inst.on({
change: (e) => {
result.push(e.pos.x);
},
finish: () => {
// Then
expect(result.every(x => x % 10 === 0)).to.be.equal(true);
done();
},
});
});

it(`should change value of coordinates continuously with animation for change event if animateOn is "change"`, (done) => {
// Given
const target = document.querySelector("#sandbox");
const panInput = new PanInput(target, { inputType: ["touch"], scale: [10, 0] });
const result = [];
inst = new Axes({
x: {
range: [0, 300],
},
}, {
animateOn: "change",
});

inst.connect(["x"], panInput);

// When
Simulator.gestures.pan(
target,
{
pos: [0, 0],
deltaX: 300,
deltaY: 0,
duration: 200,
easing: "linear",
},
);

inst.on({
change: (e) => {
result.push(e.pos.x);
},
finish: () => {
// Then
expect(result.every(x => x % 10 === 0)).to.be.equal(false);
done();
},
});
});
});

[20, 30, 40, 50].forEach((iOSEdgeSwipeThreshold) => {
describe(`Axes iOS Edge Test (iOSEdgeSwipeThreshold: ${iOSEdgeSwipeThreshold})`, () => {
beforeEach(() => {
Expand Down Expand Up @@ -649,8 +740,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 +769,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
18 changes: 0 additions & 18 deletions packages/axes/test/unit/inputType/WheelInput.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -363,17 +363,6 @@ describe("WheelInput", () => {
});

describe("useAnimation", () => {
let animationStartHandler;
let animationEndHandler;
beforeEach(() => {
animationStartHandler = sinon.spy();
animationEndHandler = sinon.spy();
inst.on({
animationStart: animationStartHandler,
animationEnd: animationEndHandler,
});
});

it("should change coordinate smoothly by animation when useAnimation is true", (done) => {
// Given
const deltaY = 1;
Expand All @@ -385,8 +374,6 @@ describe("WheelInput", () => {
// Then
expect(inst.axisManager.get().x).to.be.not.equal(10);
setTimeout(() => {
expect(animationStartHandler.calledOnce).to.be.true;
expect(animationEndHandler.calledOnce).to.be.true;
expect(inst.axisManager.get().x).to.be.equal(10);
done();
}, 200);
Expand All @@ -403,11 +390,6 @@ describe("WheelInput", () => {
TestHelper.dispatchWheel(el, { deltaY }, () => {
// Then
expect(inst.axisManager.get().x).to.be.equal(10);
setTimeout(() => {
expect(animationStartHandler.called).to.be.false;
expect(animationEndHandler.called).to.be.false;
done();
}, 200);
});
});
});
Expand Down
27 changes: 27 additions & 0 deletions packages/demo/src/pages/Options.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,33 @@ Rounding unit. For example, 0.1 rounds to 0.1 decimal point(6.1234 => 6.1), 5 ro
</div>
</div>


### animateOn
When to start the animation.
- "change": When the coordinates change with the "change" event.
- "release": When the input is finished with the "release" event.

<div className="columns">
<div className="column is-6">
<div>

```js
animateOn: "release"
```
</div>
<AxesBoard options={{ animateOn: "release", minimumDuration: 100 }}/>
</div>
<div className="column is-6">
<div>

```js
animateOn: "change"
```
</div>
<AxesBoard options={{ animateOn: "change", minimumDuration: 100 }}/>
</div>
</div>

### nested
Whether the event propagates to other instances when the coordinates reach the end of the movable area.

Expand Down