Skip to content

Commit ab84e1d

Browse files
authored
(#130) Introduce EasingFunction interface (#304)
* (#130) Updated implementation * (#130) Easing function refinement
1 parent faa9ef5 commit ab84e1d

File tree

7 files changed

+316
-640
lines changed

7 files changed

+316
-640
lines changed

index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export {Button} from "./lib/button.enum";
3131
export {centerOf, randomPointIn} from "./lib/location.function";
3232
export {LocationParameters} from "./lib/locationparameters.class";
3333
export {OptionalSearchParameters} from "./lib/optionalsearchparameters.class";
34-
export {linear} from "./lib/movementtype.function";
34+
export {EasingFunction, linear} from "./lib/mouse-movement.function";
3535
export {Point} from "./lib/point.class";
3636
export {Region} from "./lib/region.class";
3737
export {Window} from "./lib/window.class";
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import {
2+
calculateStepDuration,
3+
linear,
4+
calculateMovementTimesteps, EasingFunction
5+
} from "./mouse-movement.function";
6+
7+
describe("MovementType", () => {
8+
describe("baseStepDuration", () => {
9+
it("should calculate the base step duration in nanoseconds", () => {
10+
// GIVEN
11+
const speedInPixelsPerSecond = 1000;
12+
const expectedBaseStepDuration = 1_000_000;
13+
14+
// WHEN
15+
const result = calculateStepDuration(speedInPixelsPerSecond);
16+
17+
// THEN
18+
expect(result).toBe(expectedBaseStepDuration);
19+
});
20+
});
21+
22+
describe("stepDuration", () => {
23+
it("should call easing function progress to calculate current step duration", () => {
24+
// GIVEN
25+
const amountOfSteps = 100;
26+
const speedInPixelsPerSecond = 1000;
27+
const easingFunction = jest.fn(() => 0);
28+
29+
// WHEN
30+
calculateMovementTimesteps(amountOfSteps, speedInPixelsPerSecond, easingFunction);
31+
32+
// THEN
33+
expect(easingFunction).toBeCalledTimes(amountOfSteps);
34+
})
35+
});
36+
37+
describe('linear', () => {
38+
it("should return a set of linear timesteps, 1000000 nanosecond per step.", () => {
39+
// GIVEN
40+
const expected = [1000000, 1000000, 1000000, 1000000, 1000000, 1000000];
41+
42+
// WHEN
43+
const result = calculateMovementTimesteps(6, 1000, linear);
44+
45+
// THEN
46+
expect(result).toEqual(expected);
47+
});
48+
49+
it("should should return a set of linear timesteps, 2000000 nanoseconds per step.", () => {
50+
// GIVEN
51+
const expected = [2000000, 2000000, 2000000, 2000000, 2000000, 2000000];
52+
53+
// WHEN
54+
const result = calculateMovementTimesteps(6, 500, linear);
55+
56+
// THEN
57+
expect(result).toEqual(expected);
58+
});
59+
});
60+
61+
describe('non-linear', () => {
62+
it("should return progress slowly in the first half, 2000000 nanoseconds per step, then continue with normal speed, 1000000 nanoseconds per step", () => {
63+
// GIVEN
64+
const mouseSpeed = 1000;
65+
const easingFunction: EasingFunction = (p: number) => {
66+
if (p < 0.5) {
67+
return -0.5 * mouseSpeed;
68+
}
69+
return 0;
70+
};
71+
const expected = [2000000, 2000000, 2000000, 1000000, 1000000, 1000000];
72+
73+
// WHEN
74+
const result = calculateMovementTimesteps(6, mouseSpeed, easingFunction);
75+
76+
// THEN
77+
expect(result).toEqual(expected);
78+
});
79+
});
80+
});

lib/mouse-movement.function.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* {@link EasingFunction}s are used to modify movement behaviour.
3+
*
4+
* See https://easings.net/ for reference
5+
*/
6+
export interface EasingFunction {
7+
(progressPercentage: number): number;
8+
}
9+
10+
export const calculateStepDuration = (speedInPixelsPerSecond: number) => (1 / speedInPixelsPerSecond) * 1_000_000_000;
11+
12+
export const calculateMovementTimesteps = (
13+
amountOfSteps: number,
14+
speedInPixelsPerSecond: number,
15+
easingFunction: EasingFunction = linear
16+
): number[] => {
17+
return Array(amountOfSteps)
18+
.fill(speedInPixelsPerSecond)
19+
.map((speed: number, idx: number) => {
20+
let speedInPixels = speed;
21+
if (typeof easingFunction === "function") {
22+
speedInPixels += easingFunction(idx / amountOfSteps);
23+
}
24+
const stepDuration = calculateStepDuration(speedInPixels);
25+
return (isFinite(stepDuration) && stepDuration > 0) ? stepDuration : 0;
26+
});
27+
};
28+
29+
export const linear: EasingFunction = (_: number): number => {
30+
return 0;
31+
};

0 commit comments

Comments
 (0)