Skip to content

Commit

Permalink
feat: add useAnimation option to WheelInput (#189)
Browse files Browse the repository at this point in the history
* feat: add useAnimation option to WheelInput

* fix: remove inappropriate inline functions

* refactor: change access modifier and name of applyScale

* skip: apply reviews

* test: update manual test

* chore: set default value of useAnimation to false

* test: update mouse wheel test
  • Loading branch information
malangfox committed Jun 13, 2022
1 parent a257335 commit eab8545
Show file tree
Hide file tree
Showing 9 changed files with 246 additions and 24 deletions.
4 changes: 2 additions & 2 deletions src/InputObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class InputObserver implements InputTypeObserver {
this._moveDistance = this._axisManager.get(input.axes);
}

public change(input: InputType, event, offset: Axis, useDuration?: boolean) {
public change(input: InputType, event, offset: Axis, useAnimation?: boolean) {
if (
this._isStopped ||
!this._interruptManager.isInterrupting() ||
Expand Down Expand Up @@ -108,7 +108,7 @@ export class InputObserver implements InputTypeObserver {
input,
event,
};
if (useDuration) {
if (useAnimation) {
const duration = this._animationManager.getDuration(destPos, depaPos);
this._animationManager.animateTo(destPos, duration, changeOption);
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/inputType/InputType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface InputType {
export interface InputTypeObserver {
options: AxesOption;
get(inputType: InputType): Axis;
change(inputType: InputType, event, offset: Axis, useDuration?: boolean);
change(inputType: InputType, event, offset: Axis, useAnimation?: boolean);
hold(inputType: InputType, event);
release(
inputType: InputType,
Expand Down
38 changes: 20 additions & 18 deletions src/inputType/PanInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ export class PanInput implements InputType {
}
}
}
const offset: number[] = this._applyScale(
const offset: number[] = this._getOffset(
[panEvent.offsetX, panEvent.offsetY],
[
useDirection(DIRECTION_HORIZONTAL, this._direction, userDirection),
Expand Down Expand Up @@ -306,7 +306,7 @@ export class PanInput implements InputType {
this._detachWindowEvent(activeEvent);
clearTimeout(this._rightEdgeTimer);
const prevEvent = activeEvent.prevEvent;
const velocity = this._applyScale(
const velocity = this._getOffset(
[
Math.abs(prevEvent.velocityX) * (prevEvent.offsetX < 0 ? -1 : 1),
Math.abs(prevEvent.velocityY) * (prevEvent.offsetY < 0 ? -1 : 1),
Expand Down Expand Up @@ -338,6 +338,19 @@ export class PanInput implements InputType {
});
}

protected _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;
}

private _attachElementEvent(observer: InputTypeObserver) {
const activeEvent = convertInputType(this.options.inputType);
if (!activeEvent) {
Expand All @@ -351,7 +364,7 @@ export class PanInput implements InputType {
});
// adding event listener to element prevents invalid behavior in iOS Safari
activeEvent.move.forEach((event) => {
this.element?.addEventListener(event, () => {});
this.element?.addEventListener(event, this._voidFunction);
});
}

Expand All @@ -361,30 +374,19 @@ export class PanInput implements InputType {
this.element?.removeEventListener(event, this._onPanstart);
});
activeEvent?.move.forEach((event) => {
this.element?.removeEventListener(event, () => {});
this.element?.removeEventListener(event, this._voidFunction);
});
this._enabled = false;
this._observer = null;
}

private _applyScale(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;
}

private _forceRelease = () => {
const activeEvent = this._activeEvent;
const prevEvent = activeEvent.prevEvent;
this._detachWindowEvent(activeEvent);
activeEvent.onRelease();
this._observer.release(this, prevEvent, [0, 0]);
this._detachWindowEvent(activeEvent);
};

private _voidFunction = () => {};
}
11 changes: 10 additions & 1 deletion src/inputType/WheelInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ export interface WheelInputOption {
scale?: number;
releaseDelay?: number;
useNormalized?: boolean;
useAnimation?: boolean;
}

/**
* @typedef {Object} WheelInputOption The option object of the eg.Axes.WheelInput module
* @ko eg.Axes.WheelInput 모듈의 옵션 객체
* @param {Number} [scale=1] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko>
* @param {Number} [releaseDelay=300] Millisecond that trigger release event after last input<ko>마지막 입력 이후 release 이벤트가 트리거되기까지의 밀리초</ko>
* @param {Boolean} [useNormalized=true] Whether to calculate scroll speed the same in all browsers<ko>모든 브라우저에서 스크롤 속도를 동일하게 처리할지 여부</ko>
* @param {Boolean} [useAnimation=false] Whether to process coordinate changes through the mouse wheel as a continuous animation<ko>마우스 휠을 통한 좌표 변화를 연속적인 애니메이션으로 처리할지 여부</ko>
**/

/**
Expand Down Expand Up @@ -50,6 +53,7 @@ export class WheelInput implements InputType {
scale: 1,
releaseDelay: 300,
useNormalized: true,
useAnimation: false,
},
...options,
};
Expand Down Expand Up @@ -127,7 +131,12 @@ export class WheelInput implements InputType {
(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);
this._observer.change(
this,
event,
toAxis(this.axes, [offset]),
this.options.useAnimation
);
clearTimeout(this._timer);

this._timer = setTimeout(() => {
Expand Down
67 changes: 67 additions & 0 deletions test/manual/js/wheel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
const wrapper = document.getElementById("content");
const ui0 = document.getElementById("ui0");
const ui1 = document.getElementById("ui1");

const axes0 = new eg.Axes(
{
zoom: {
range: [1, 4],
},
},
{
deceleration: 0.00002,
}
);

axes0.on({
animationStart: (e) => {
if (e && e.inputEvent) {
e.inputEvent.__childrenAxesAlreadyChanged = false;
}
},
change: (e) => {
var pos = e.pos;

ui0.style[
eg.Axes.TRANSFORM
] = `translate3d(200px, 200px, 0) scale(${pos.zoom})`;
ui0.innerHTML = `${pos.zoom.toFixed(2)}`;
},
});

axes0.connect(
"zoom",
new eg.Axes.WheelInput(wrapper, {
scale: 1 / 1000,
useNormalized: false,
useAnimation: true,
})
);
axes0.setTo({ zoom: 3 });

const axes1 = new eg.Axes({
zoom: {
range: [1, 4],
},
});

axes1.on({
change: (e) => {
var pos = e.pos;

ui1.style[
eg.Axes.TRANSFORM
] = `translate3d(200px, 200px, 0) scale(${pos.zoom})`;
ui1.innerHTML = `${pos.zoom.toFixed(2)}`;
},
});

axes1.connect(
"zoom",
new eg.Axes.WheelInput(wrapper, {
scale: 1 / 1000,
useNormalized: false,
useAnimation: false,
})
);
axes1.setTo({ zoom: 3 });
73 changes: 73 additions & 0 deletions test/manual/wheel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<!DOCTYPE html>

<head>
<meta charset="UTF-8">
<title>egjs-axes</title>
<meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=no">
<style>
.content {
display: flex;
flex-direction: row;
}

.uiWrapper {
overflow: hidden;
position: relative;
width: 400px;
height: 400px;
background-color: #eebf3f;
border-radius: 5px;
margin-bottom: 20px;
box-shadow: 0px 1px 2px #8c532e;
float: left;
}

.uiWrapper .ui {
width: 100px;
height: 100px;
left: -50px;
top: -50px;
position: absolute;
background-color: black;
color: white;
border-radius: 50px;
line-height: 100px;
text-align: center;
}

.uiWrapper .ui img {
width: 45px;
height: 75px;
}
</style>
</head>

<body>
<h1>Pan Input</h1>
<div id="content" class="content">
<div>
<h3>UseAnimation: true</h3>
<div id="delegateTarget0">
<div id="uiWrapper" class="uiWrapper">
<div id="ui0" class="ui">
3.0
</div>
</div>
</div>
</div>
<div>
<h3>UseAnimation: false</h3>
<div id="delegateTarget1">
<div id="uiWrapper" class="uiWrapper">
<div id="ui1" class="ui">
3.0
</div>
</div>
</div>
</div>
</div>
<script src="../../dist/axes.pkgd.js"></script>
<script src="js/wheel.js"></script>
</body>

</html>
2 changes: 1 addition & 1 deletion test/unit/inputType/PanInput.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ describe("PanInput", () => {
});
});

describe("options test", () => {
describe("Options", () => {
beforeEach(() => {
el = sandbox();
inst = new Axes({
Expand Down
2 changes: 1 addition & 1 deletion test/unit/inputType/PinchInput.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ describe("PinchInput", () => {
});
});

describe("options test", () => {
describe("Options", () => {
beforeEach(() => {
el = sandbox();
inst = new Axes({
Expand Down
71 changes: 71 additions & 0 deletions test/unit/inputType/WheelInput.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,75 @@ describe("WheelInput", () => {
});
});
});

describe("Options", () => {
beforeEach(() => {
el = sandbox();
inst = new Axes({
x: {
range: [0, 200],
},
});
});
afterEach(() => {
if (inst) {
inst.destroy();
inst = null;
}
if (input) {
input.destroy();
input = null;
}
cleanup();
});
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;
input = new WheelInput(el, { scale: -10, useAnimation: true });
inst.connect(["x"], input);

// When
TestHelper.wheelVertical(el, deltaY, () => {
// 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);
});
});

it("should change coordinate immediately when useAnimation is false", (done) => {
// Given
const deltaY = 1;
input = new WheelInput(el, { scale: -10, useAnimation: false });
inst.connect(["x"], input);

// When
TestHelper.wheelVertical(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);
});
});
});
});
});

0 comments on commit eab8545

Please sign in to comment.