Skip to content

Commit

Permalink
feat: added new tspRandom function and setRandom for customizing all …
Browse files Browse the repository at this point in the history
…the random behaviors

fix: fixed new rotation method with rotate.path enabled
  • Loading branch information
matteobruni committed Jul 15, 2022
1 parent 389d82c commit bd83a57
Show file tree
Hide file tree
Showing 34 changed files with 133 additions and 105 deletions.
6 changes: 3 additions & 3 deletions components/jquery/src/particles.ts
@@ -1,4 +1,4 @@
import { tsParticles } from "tsparticles-engine";
import { tsParticles, tspRandom } from "tsparticles-engine";
import type { ISourceOptions, Container } from "tsparticles-engine";

/**
Expand Down Expand Up @@ -26,7 +26,7 @@ $.fn.particles = function (): ParticlesResult {
const init = (options: IParticlesProps, callback: (container: Container | undefined) => Promise<void>): void => {
this.each((index, element) => {
if (element.id === undefined) {
element.id = baseId + Math.floor(Math.random() * 1000);
element.id = baseId + Math.floor(tspRandom() * 1000);
}

tsParticles.load(element.id, options).then(callback);
Expand All @@ -36,7 +36,7 @@ $.fn.particles = function (): ParticlesResult {
const ajax = (jsonUrl: string, callback: (container: Container | undefined) => Promise<void>): void => {
this.each((index, element) => {
if (element.id === undefined) {
element.id = baseId + Math.floor(Math.random() * 1000);
element.id = baseId + Math.floor(tspRandom() * 1000);
}

tsParticles.loadJSON(element.id, jsonUrl).then(callback);
Expand Down
3 changes: 2 additions & 1 deletion engine/src/Core/Loader.ts
Expand Up @@ -5,6 +5,7 @@ import type { RecursivePartial } from "../Types/RecursivePartial";
import type { SingleOrMultiple } from "../Types/SingleOrMultiple";
import { generatedAttribute } from "./Utils/Constants";
import { itemFromArray } from "../Utils/Utils";
import { tspRandom } from "../Utils/NumberUtils";

/**
* Default fetch error catcher
Expand Down Expand Up @@ -148,7 +149,7 @@ export class Loader {
* @param params all the parameters required for loading options in the current animation
*/
async loadOptions(params: LoaderParams): Promise<Container | undefined> {
const tagId = params.tagId ?? `tsparticles${Math.floor(Math.random() * 10000)}`,
const tagId = params.tagId ?? `tsparticles${Math.floor(tspRandom() * 10000)}`,
{ index, url: jsonUrl, remote } = params,
options = remote ? await getDataFromUrl(jsonUrl, index) : params.options;

Expand Down
7 changes: 4 additions & 3 deletions engine/src/Core/Particle.ts
Expand Up @@ -12,6 +12,7 @@ import {
getValue,
randomInRange,
setRangeValue,
tspRandom,
} from "../Utils/NumberUtils";
import { deepExtend, isInArray, itemFromArray } from "../Utils/Utils";
import { getHslFromAnimation, rangeColorToRgb } from "../Utils/ColorUtils";
Expand Down Expand Up @@ -378,7 +379,7 @@ export class Particle implements IParticle {

case StartValueType.random:
this.size.value = randomInRange(this.size) * pxRatio;
this.size.status = Math.random() >= 0.5 ? AnimationStatus.increasing : AnimationStatus.decreasing;
this.size.status = tspRandom() >= 0.5 ? AnimationStatus.increasing : AnimationStatus.decreasing;

break;

Expand All @@ -395,7 +396,7 @@ export class Particle implements IParticle {
container.retina.reduceFactor;

if (!sizeAnimation.sync) {
this.size.velocity *= Math.random();
this.size.velocity *= tspRandom();
}
}

Expand Down Expand Up @@ -665,7 +666,7 @@ export class Particle implements IParticle {
}

if (moveOptions.random && typeof moveOptions.speed === "number") {
res.length *= Math.random();
res.length *= tspRandom();
}

return res;
Expand Down
5 changes: 3 additions & 2 deletions engine/src/Core/Particles.ts
Expand Up @@ -5,6 +5,7 @@ import {
getValue,
randomInRange,
setRangeValue,
tspRandom,
} from "../Utils/NumberUtils";
import type { ClickMode } from "../Enums/Modes/ClickMode";
import type { Container } from "./Container";
Expand Down Expand Up @@ -236,7 +237,7 @@ export class Particles {
let res = this.freqs.links.get(key);

if (res === undefined) {
res = Math.random();
res = tspRandom();

this.freqs.links.set(key, res);
}
Expand Down Expand Up @@ -264,7 +265,7 @@ export class Particles {
let res = this.freqs.triangles.get(key);

if (res === undefined) {
res = Math.random();
res = tspRandom();

this.freqs.triangles.set(key, res);
}
Expand Down
6 changes: 4 additions & 2 deletions engine/src/Utils/CanvasUtils.ts
Expand Up @@ -184,8 +184,10 @@ export function drawParticle(data: DrawParticleParams): void {

context.beginPath();

if (particle.rotation) {
context.rotate(particle.rotation);
const angle = particle.rotation + (particle.options.rotate.path ? particle.velocity.angle : 0);

if (angle !== 0) {
context.rotate(angle);
}

if (backgroundMask) {
Expand Down
6 changes: 3 additions & 3 deletions engine/src/Utils/ColorUtils.ts
Expand Up @@ -13,7 +13,7 @@ import type {
IRgba,
IValueColor,
} from "../Core/Interfaces/Colors";
import { getRangeValue, mix, randomInRange, setRangeValue } from "./NumberUtils";
import { getRangeValue, mix, randomInRange, setRangeValue, tspRandom } from "./NumberUtils";
import { midColorValue, randomColorValue } from "../Core/Utils/Constants";
import { AnimationStatus } from "../Enums/AnimationStatus";
import type { HslAnimation } from "../Options/Classes/HslAnimation";
Expand Down Expand Up @@ -708,8 +708,8 @@ function setColorAnimation(
colorValue.status = AnimationStatus.increasing;

if (!colorAnimation.sync) {
colorValue.velocity *= Math.random();
colorValue.value *= Math.random();
colorValue.velocity *= tspRandom();
colorValue.value *= tspRandom();
}
} else {
colorValue.velocity = 0;
Expand Down
22 changes: 16 additions & 6 deletions engine/src/Utils/NumberUtils.ts
Expand Up @@ -11,6 +11,16 @@ import type { MoveDirectionAlt } from "../Enums/Directions/MoveDirection";
import type { RangeValue } from "../Types/RangeValue";
import { Vector } from "../Core/Utils/Vector";

export let tspRandom = Math.random;

/**
* Replaces the library random function with a custom one.
* @param rnd A random function that returns a number between 0 and 1.
*/
export function setRandom(rnd: () => number = Math.random): void {
tspRandom = rnd;
}

/**
* Clamps a number between a minimum and maximum value
* @param num the source number
Expand Down Expand Up @@ -40,7 +50,7 @@ export function randomInRange(r: RangeValue): number {
min = 0;
}

return Math.random() * (max - min) + min;
return tspRandom() * (max - min) + min;
}

export function getRangeValue(value: RangeValue): number {
Expand Down Expand Up @@ -136,7 +146,7 @@ export function getParticleDirectionAngle(
return Math.atan2(position.y - center.y, position.x - center.x);
case MoveDirection.none:
default:
return Math.random() * Math.PI * 2;
return tspRandom() * Math.PI * 2;
}
}
}
Expand Down Expand Up @@ -206,8 +216,8 @@ export function calcPositionFromSize(data: IPositionFromSizeParams): ICoordinate
*/
export function calcPositionOrRandomFromSize(data: IPositionFromSizeParams): ICoordinates {
return {
x: ((data.position?.x ?? Math.random() * 100) * data.size.width) / 100,
y: ((data.position?.y ?? Math.random() * 100) * data.size.height) / 100,
x: ((data.position?.x ?? tspRandom() * 100) * data.size.width) / 100,
y: ((data.position?.y ?? tspRandom() * 100) * data.size.height) / 100,
};
}

Expand All @@ -232,8 +242,8 @@ export function calcPositionOrRandomFromSizeRanged(data: IRangedPositionFromSize
*/
export function calcExactPositionOrRandomFromSize(data: IPositionFromSizeParams): ICoordinates {
return {
x: data.position?.x ?? Math.random() * data.size.width,
y: data.position?.y ?? Math.random() * data.size.height,
x: data.position?.x ?? tspRandom() * data.size.width,
y: data.position?.y ?? tspRandom() * data.size.height,
};
}

Expand Down
4 changes: 2 additions & 2 deletions engine/src/Utils/Utils.ts
@@ -1,4 +1,4 @@
import { collisionVelocity, getDistances, getValue } from "./NumberUtils";
import { collisionVelocity, getDistances, getValue, tspRandom } from "./NumberUtils";
import type { DivEvent } from "../Options/Classes/Interactivity/Events/DivEvent";
import type { DivMode } from "../Enums/Modes/DivMode";
import type { IBounds } from "../Core/Interfaces/IBounds";
Expand Down Expand Up @@ -158,7 +158,7 @@ export async function loadFont(font?: string, weight?: string): Promise<void> {
* @returns a random array index
*/
export function arrayRandomIndex<T>(array: T[]): number {
return Math.floor(Math.random() * array.length);
return Math.floor(tspRandom() * array.length);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions engine/tests/Fixture/TestParticle.ts
@@ -1,4 +1,4 @@
import type { ICoordinates, ICoordinates3d } from "../../src";
import { ICoordinates, ICoordinates3d, tspRandom } from "../../src";
import { Container } from "../../src";
import { Particle } from "../../src";
import { getRangeValue } from "../../src";
Expand Down Expand Up @@ -31,9 +31,9 @@ export class TestParticle {
const sizeValue = getRangeValue(container.actualOptions.particles.size.value) * container.retina.pixelRatio;
const width = container.canvas.size.width;
const height = container.canvas.size.height;
let x = width * Math.random();
let x = width * tspRandom();
x = Math.min(Math.max(x, sizeValue * 2), width - sizeValue * 2);
let y = height * Math.random();
let y = height * tspRandom();
y = Math.min(Math.max(y, sizeValue * 2), height - sizeValue * 2);
return { x, y, z: 0 };
}
Expand Down
12 changes: 6 additions & 6 deletions engine/tests/Particles.ts
@@ -1,5 +1,5 @@
import { describe, it } from "mocha";
import type { ICoordinates3d } from "../src";
import { ICoordinates3d, tspRandom } from "../src";
import { TestCanvas } from "./Fixture/TestCanvas";
import { TestContainer } from "./Fixture/TestContainer";
import { TestParticles } from "./Fixture/TestParticles";
Expand Down Expand Up @@ -178,7 +178,7 @@ describe("Particles", () => {
testParticles.particles.push(numParticles, { position, clicking: false, inside: false });
expect(testParticles.particles.count).to.equal(5);

let ts = Math.random() * 16.66667;
let ts = tspRandom() * 16.66667;
const logP = testParticles.particles.array[0];

console.log(logP.id);
Expand All @@ -188,28 +188,28 @@ describe("Particles", () => {
factor: (60 * ts) / 1000,
});

ts = Math.random() * 16.66667;
ts = tspRandom() * 16.66667;

testParticles.particles.update({
value: ts,
factor: (60 * ts) / 1000,
});

ts = Math.random() * 16.66667;
ts = tspRandom() * 16.66667;

testParticles.particles.update({
value: ts,
factor: (60 * ts) / 1000,
});

ts = Math.random() * 16.66667;
ts = tspRandom() * 16.66667;

testParticles.particles.update({
value: ts,
factor: (60 * ts) / 1000,
});

ts = Math.random() * 16.66667;
ts = tspRandom() * 16.66667;

testParticles.particles.update({
value: ts,
Expand Down
26 changes: 13 additions & 13 deletions engine/tests/Utils.ts
@@ -1,6 +1,6 @@
import * as NumberUtils from "../src/Utils/NumberUtils";
import * as Utils from "../src/Utils/Utils";
import { MoveDirection, OutModeDirection, Vector, tsParticles } from "../src";
import { MoveDirection, OutModeDirection, Vector, tsParticles, tspRandom } from "../src";
import type { ICoordinates, IParticle } from "../src";
import { describe, it } from "mocha";
import { Container } from "../src/Core/Container";
Expand Down Expand Up @@ -115,15 +115,15 @@ describe("Utils", () => {
const size = 10;

it("should return the average when weights are identical", () => {
const weight1 = Math.floor(Math.random() * (size - 1) + 1);
const weight1 = Math.floor(tspRandom() * (size - 1) + 1);
const weight2 = weight1;
const mean = Math.floor((comp1 + comp2) / 2);

expect(NumberUtils.mix(comp1, comp2, weight1, weight2)).to.be.equal(mean);
});

it("should return comp1 when weight2 is 0 (and weight1 > 0)", () => {
const weight1 = Math.floor(Math.random() * (size - 1) + 1);
const weight1 = Math.floor(tspRandom() * (size - 1) + 1);
const weight2 = 0;

expect(NumberUtils.mix(comp1, comp2, weight1, weight2), `weight 1: ${weight1}`).to.be.equal(
Expand All @@ -133,7 +133,7 @@ describe("Utils", () => {

it("should return comp2 when weight1 is 0 (and weight2 > 0)", () => {
const weight1 = 0;
const weight2 = Math.floor(Math.random() * (size - 1) + 1);
const weight2 = Math.floor(tspRandom() * (size - 1) + 1);

expect(NumberUtils.mix(comp1, comp2, weight1, weight2)).to.be.equal(Math.floor(comp2));
});
Expand Down Expand Up @@ -540,31 +540,31 @@ describe("Utils", () => {
});

it("should return true when point lies on top boundary of screen with non-zero radius", () => {
expect(Utils.isPointInside(topPoint, dimension, Vector.origin, Math.random())).to.be.true;
expect(Utils.isPointInside(topPoint, dimension, Vector.origin, tspRandom())).to.be.true;
});

it("should return false when point lies on bottom boundary of screen with no radius", () => {
expect(Utils.isPointInside(bottomPoint, dimension, Vector.origin)).to.be.false;
});

it("should return true when point lies on bottom boundary of screen with non-zero radius", () => {
expect(Utils.isPointInside(bottomPoint, dimension, Vector.origin, Math.random())).to.be.true;
expect(Utils.isPointInside(bottomPoint, dimension, Vector.origin, tspRandom())).to.be.true;
});

it("should return false when point lies on left boundary of screen with no radius", () => {
expect(Utils.isPointInside(leftPoint, dimension, Vector.origin)).to.be.false;
});

it("should return true when point lies on left boundary of screen with non-zero radius", () => {
expect(Utils.isPointInside(leftPoint, dimension, Vector.origin, Math.random())).to.be.true;
expect(Utils.isPointInside(leftPoint, dimension, Vector.origin, tspRandom())).to.be.true;
});

it("should return false when point lies on right boundary of screen with no radius", () => {
expect(Utils.isPointInside(rightPoint, dimension, Vector.origin)).to.be.false;
});

it("should return true when point lies on right boundary of screen with non-zero radius", () => {
expect(Utils.isPointInside(rightPoint, dimension, Vector.origin, Math.random())).to.be.true;
expect(Utils.isPointInside(rightPoint, dimension, Vector.origin, tspRandom())).to.be.true;
});
});

Expand Down Expand Up @@ -612,14 +612,14 @@ describe("Utils", () => {

describe("segmentBounce", () => {
const start = {
x: 29, //Math.floor(Math.random() * 100),
y: 82, //Math.floor(Math.random() * 100)
x: 29, //Math.floor(tspRandom() * 100),
y: 82, //Math.floor(tspRandom() * 100)
},
stop = {
x: 53, //Math.floor(Math.random() * 100),
y: 82, //Math.floor(Math.random() * 100)
x: 53, //Math.floor(tspRandom() * 100),
y: 82, //Math.floor(tspRandom() * 100)
},
velocity = Vector.origin; // angle = 238.91568442036498 * Math.PI / 180;//Math.random() * Math.PI * 2;
velocity = Vector.origin; // angle = 238.91568442036498 * Math.PI / 180;//tspRandom() * Math.PI * 2;

velocity.length = 1;
velocity.angle = (238.91568442036498 * Math.PI) / 180;
Expand Down
4 changes: 2 additions & 2 deletions interactions/particles/links/src/LinkInstance.ts
@@ -1,6 +1,6 @@
import type { IContainerPlugin, IRangeColor, IRgb, Particle, RangeValue } from "tsparticles-engine";
import { drawLinkLine, drawLinkTriangle } from "./Utils";
import { getDistance, getLinkColor, getRangeValue, rangeColorToRgb } from "tsparticles-engine";
import { getDistance, getLinkColor, getRangeValue, rangeColorToRgb, tspRandom } from "tsparticles-engine";
import type { ILink } from "./ILink";
import type { LinkContainer } from "./LinkContainer";
import type { LinkParticle } from "./LinkParticle";
Expand Down Expand Up @@ -105,7 +105,7 @@ export class LinkInstance implements IContainerPlugin {
if (twinkle?.enable) {
const twinkleFreq = twinkle.frequency,
twinkleRgb = rangeColorToRgb(twinkle.color),
twinkling = Math.random() < twinkleFreq;
twinkling = tspRandom() < twinkleFreq;

if (twinkling && twinkleRgb) {
colorLine = twinkleRgb;
Expand Down

0 comments on commit bd83a57

Please sign in to comment.