Skip to content

Commit

Permalink
fix: fix endPos and endRotation error
Browse files Browse the repository at this point in the history
  • Loading branch information
D-Sketon committed Feb 1, 2025
1 parent f036f17 commit 10bdc1a
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 24 deletions.
2 changes: 2 additions & 0 deletions src/entity/BaseEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export default abstract class BaseEntity {
radius: number;
alpha: number;
lineWidth?: number;
endPos?: { x: number; y: number };
endRotation?: number;

constructor(
ctx: CanvasRenderingContext2D,
Expand Down
5 changes: 4 additions & 1 deletion src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Circle from "./entity/Circle";
import Polygon from "./entity/Polygon";
import Star from "./entity/Star";
import { ParticleOptions, StarOptions, PolygonOptions } from "./types";
import { formatAlpha, sample } from "./utils";
import { formatAlpha, sample, setEndPos, setEndRotation } from "./utils";

const ENTITY_MAP = {
circle: Circle,
Expand Down Expand Up @@ -59,6 +59,9 @@ const preProcess = (
// @ts-expect-error
const p = new shapeType(...shapeArgs, sample(lineWidth));

setEndPos(p, particle);
setEndRotation(p, particle);

shapes.push(p);
}
return shapes;
Expand Down
32 changes: 16 additions & 16 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type {
RotateOptions,
FireworkOptions,
ParticleOptions,
Move,
MoveOptions,
} from "./types";
import { formatAlpha, hasAncestor, sample } from "./utils";
import BaseEntity from "./entity/BaseEntity";
Expand Down Expand Up @@ -48,31 +50,23 @@ const setParticleMovement = (
x: number,
y: number
) => {
let { move, moveOptions } = particle;
if (!Array.isArray(move)) {
move = [move];
}
if (!moveOptions) moveOptions = [];
if (!Array.isArray(moveOptions)) {
moveOptions = [moveOptions];
}
const { move, moveOptions } = particle as {
move: Move[],
moveOptions: MoveOptions[],
};
let dist: Record<string, any> = {};
move.forEach((m, i) => {
if (m === "emit") {
const {
emitRadius = [50, 180],
radius = 0.1,
alphaChange = false,
alphaEasing = "linear",
alphaDuration = [600, 800],
alpha = 0,
} = (moveOptions[i] as EmitOptions) ?? {};
const emitAngle = (anime.random(0, 360) * Math.PI) / 180;
const sampledEmitRadius =
[-1, 1][anime.random(0, 1)] * sample(emitRadius);
dist = {
x: () => x + sampledEmitRadius * Math.cos(emitAngle),
y: () => y + sampledEmitRadius * Math.sin(emitAngle),
x: (p: BaseEntity) => p.endPos!.x,
y: (p: BaseEntity) => p.endPos!.y,
radius: sample(radius),
};
if (alphaChange) {
Expand Down Expand Up @@ -100,8 +94,7 @@ const setParticleMovement = (
},
};
} else if (m === "rotate") {
const { angle = [-180, 180] } = (moveOptions[i] as RotateOptions) ?? {};
dist.rotation = () => sample(angle);
dist.rotation = (p: BaseEntity) => p.endRotation!;
}
});
return dist;
Expand Down Expand Up @@ -152,6 +145,13 @@ const animateParticles = (x: number, y: number): void => {
const { particles } = globalOptions;
const timeLine = anime().timeline();
particles.forEach((particle) => {
if (!Array.isArray(particle.move)) {
particle.move = [particle.move];
}
if (!particle.moveOptions) particle.moveOptions = [];
if (!Array.isArray(particle.moveOptions)) {
particle.moveOptions = [particle.moveOptions];
}
timeLine.add({
targets: entityFactory(ctx, x, y, particle),
duration: sample(particle.duration),
Expand Down
8 changes: 4 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ export type RotateOptions = {
angle?: number | [number, number]; // default [-180, 180]
};

type Move = "emit" | "diffuse" | "rotate";
type moveOptions = EmitOptions | DiffuseOptions | RotateOptions;
export type Move = "emit" | "diffuse" | "rotate";
export type MoveOptions = EmitOptions | DiffuseOptions | RotateOptions;

interface BaseParticleOptions {
export interface BaseParticleOptions {
move: Move | Move[];
moveOptions?: moveOptions | moveOptions[];
moveOptions?: MoveOptions | MoveOptions[];
easing?: EasingTypes;
colors: string[];
number: number | [number, number];
Expand Down
31 changes: 29 additions & 2 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import anime from "theme-shokax-anime";
// import anime from "./anime";
import BaseEntity from "./entity/BaseEntity";
import { ParticleOptions, EmitOptions, RotateOptions } from "./types";

export const sample = (raw: number | [number, number]): number => {
return Array.isArray(raw) ? anime.random(raw[0], raw[1]) : raw;
Expand All @@ -14,9 +16,34 @@ export const hasAncestor = (node: Element, name: string): boolean => {
return false;
};

export const formatAlpha = (alpha: number | [number, number]): [number, number] => {
export const setEndPos = (p: BaseEntity, particle: ParticleOptions) => {
let index;
if ((index = particle.move.indexOf("emit")) !== -1) {
const { emitRadius = [50, 180] } =
(particle.moveOptions as EmitOptions[])[index] ?? {};
const angle = (anime.random(0, 360) * Math.PI) / 180;
const radius = [-1, 1][anime.random(0, 1)] * sample(emitRadius);
p.endPos = {
x: p.x + radius * Math.cos(angle),
y: p.y + radius * Math.sin(angle),
};
}
};

export const setEndRotation = (p: BaseEntity, particle: ParticleOptions) => {
let index;
if ((index = particle.move.indexOf("rotate")) !== -1) {
const { angle = [-180, 180] } =
(particle.moveOptions as RotateOptions[])[index] ?? {};
p.endRotation = sample(angle);
}
};

export const formatAlpha = (
alpha: number | [number, number]
): [number, number] => {
if (Array.isArray(alpha)) {
return alpha.map((a) => a * 100) as [number, number];
}
return [alpha * 100, alpha * 100];
}
};
112 changes: 111 additions & 1 deletion test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ describe("firework", () => {
const rotateSpy = sinon.spy();
mockCanvas.rotate = (...args) => {
rotateSpy(...args);
rotateSpy.args[i][0].should.eql(Math.PI / 5 * i);
rotateSpy.args[i][0].should.eql((Math.PI / 5) * i);
i++;
};

Expand Down Expand Up @@ -468,4 +468,114 @@ describe("firework", () => {
document.dispatchEvent(new window.MouseEvent("click", { bubbles: true }));
await wait(1200);
});

it("move with string type", async () => {
let i = 0;
const translateSpy = sinon.spy();
const arcSpy = sinon.spy();
mockCanvas.rotate = () => {};
mockCanvas.translate = translateSpy;
mockCanvas.arc = (...args) => {
arcSpy(...args);
const radius =
translateSpy.args[i][0] ** 2 + translateSpy.args[i][1] ** 2;
(Math.abs(radius - (i * 2) ** 2) < 1e-10).should.be.true;
arcSpy.args[i][2].should.eql(10 - 2 * i);
if (i < 3) {
mockCanvas.globalAlpha.should.eql(1 - i / 3);
}
i++;
};

Date.now = () => i * 200;
global.requestAnimationFrame = (cb) => {
if (i > 5) {
global.requestAnimationFrame = () => 0;
}
setTimeout(cb, 0);
return 0;
};
const { default: firework } = await import("../src/index");
firework({
excludeElements: ["button"],
particles: [
{
shape: "circle",
move: "emit",
colors: ["rgba(255,182,185)"],
number: 1,
duration: 1000,
shapeOptions: {
radius: 10,
},
moveOptions: {
emitRadius: 10,
radius: 0,
alphaChange: true,
alpha: 0,
alphaEasing: "linear",
alphaDuration: 600,
},
},
],
});
document.dispatchEvent(new window.MouseEvent("click", { bubbles: true }));
await wait(1200);
});

it("moveOptions with array type", async () => {
let i = 0;
const translateSpy = sinon.spy();
const arcSpy = sinon.spy();
mockCanvas.rotate = () => {};
mockCanvas.translate = translateSpy;
mockCanvas.arc = (...args) => {
arcSpy(...args);
const radius =
translateSpy.args[i][0] ** 2 + translateSpy.args[i][1] ** 2;
(Math.abs(radius - (i * 2) ** 2) < 1e-10).should.be.true;
arcSpy.args[i][2].should.eql(10 - 2 * i);
if (i < 3) {
mockCanvas.globalAlpha.should.eql(1 - i / 3);
}
i++;
};

Date.now = () => i * 200;
global.requestAnimationFrame = (cb) => {
if (i > 5) {
global.requestAnimationFrame = () => 0;
}
setTimeout(cb, 0);
return 0;
};
const { default: firework } = await import("../src/index");
firework({
excludeElements: ["button"],
particles: [
{
shape: "circle",
move: "emit",
colors: ["rgba(255,182,185)"],
number: 1,
duration: 1000,
shapeOptions: {
radius: 10,
},
moveOptions: [
{
emitRadius: 10,
radius: 0,
alphaChange: true,
alpha: 0,
alphaEasing: "linear",
alphaDuration: 600,
},
],
},
],
});
document.dispatchEvent(new window.MouseEvent("click", { bubbles: true }));
await wait(1200);
});
});

0 comments on commit 10bdc1a

Please sign in to comment.