tsparticles
Version:
Easily create highly customizable particle animations and use them as animated backgrounds for your website. Ready to use components available also for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.
425 lines (424 loc) • 19.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Updater = void 0;
const Utils_1 = require("../../Utils");
const Enums_1 = require("../../Enums");
const OutModeDirection_1 = require("../../Enums/Directions/OutModeDirection");
function bounceHorizontal(data) {
if (data.outMode === Enums_1.OutMode.bounce ||
data.outMode === Enums_1.OutMode.bounceHorizontal ||
data.outMode === "bounceHorizontal" ||
data.outMode === Enums_1.OutMode.split) {
const velocity = data.particle.velocity.x;
let bounced = false;
if ((data.direction === OutModeDirection_1.OutModeDirection.right && data.bounds.right >= data.canvasSize.width && velocity > 0) ||
(data.direction === OutModeDirection_1.OutModeDirection.left && data.bounds.left <= 0 && velocity < 0)) {
const newVelocity = Utils_1.NumberUtils.getValue(data.particle.options.bounce.horizontal);
data.particle.velocity.x *= -newVelocity;
bounced = true;
}
if (!bounced) {
return;
}
const minPos = data.offset.x + data.size;
if (data.bounds.right >= data.canvasSize.width) {
data.particle.position.x = data.canvasSize.width - minPos;
}
else if (data.bounds.left <= 0) {
data.particle.position.x = minPos;
}
if (data.outMode === Enums_1.OutMode.split) {
data.particle.destroy();
}
}
}
function bounceVertical(data) {
if (data.outMode === Enums_1.OutMode.bounce ||
data.outMode === Enums_1.OutMode.bounceVertical ||
data.outMode === "bounceVertical" ||
data.outMode === Enums_1.OutMode.split) {
const velocity = data.particle.velocity.y;
let bounced = false;
if ((data.direction === OutModeDirection_1.OutModeDirection.bottom &&
data.bounds.bottom >= data.canvasSize.height &&
velocity > 0) ||
(data.direction === OutModeDirection_1.OutModeDirection.top && data.bounds.top <= 0 && velocity < 0)) {
const newVelocity = Utils_1.NumberUtils.getValue(data.particle.options.bounce.vertical);
data.particle.velocity.y *= -newVelocity;
bounced = true;
}
if (!bounced) {
return;
}
const minPos = data.offset.y + data.size;
if (data.bounds.bottom >= data.canvasSize.height) {
data.particle.position.y = data.canvasSize.height - minPos;
}
else if (data.bounds.top <= 0) {
data.particle.position.y = minPos;
}
if (data.outMode === Enums_1.OutMode.split) {
data.particle.destroy();
}
}
}
function checkDestroy(particle, destroy, value, minValue, maxValue) {
switch (destroy) {
case Enums_1.DestroyType.max:
if (value >= maxValue) {
particle.destroy();
}
break;
case Enums_1.DestroyType.min:
if (value <= minValue) {
particle.destroy();
}
break;
}
}
class Updater {
constructor(container, particle) {
this.container = container;
this.particle = particle;
}
update(delta) {
if (this.particle.destroyed) {
return;
}
this.updateLife(delta);
if (this.particle.destroyed || this.particle.spawning) {
return;
}
this.updateOpacity(delta);
this.updateSize(delta);
this.updateAngle(delta);
this.updateColor(delta);
this.updateStrokeColor(delta);
this.updateOutModes(delta);
}
updateLife(delta) {
const particle = this.particle;
let justSpawned = false;
if (particle.spawning) {
particle.lifeDelayTime += delta.value;
if (particle.lifeDelayTime >= particle.lifeDelay) {
justSpawned = true;
particle.spawning = false;
particle.lifeDelayTime = 0;
particle.lifeTime = 0;
}
}
if (particle.lifeDuration === -1) {
return;
}
if (!particle.spawning) {
if (justSpawned) {
particle.lifeTime = 0;
}
else {
particle.lifeTime += delta.value;
}
if (particle.lifeTime >= particle.lifeDuration) {
particle.lifeTime = 0;
if (particle.livesRemaining > 0) {
particle.livesRemaining--;
}
if (particle.livesRemaining === 0) {
particle.destroy();
return;
}
const canvasSize = this.container.canvas.size;
particle.position.x = Utils_1.NumberUtils.randomInRange(Utils_1.NumberUtils.setRangeValue(0, canvasSize.width));
particle.position.y = Utils_1.NumberUtils.randomInRange(Utils_1.NumberUtils.setRangeValue(0, canvasSize.height));
particle.spawning = true;
particle.lifeDelayTime = 0;
particle.lifeTime = 0;
particle.reset();
const lifeOptions = particle.options.life;
particle.lifeDelay = Utils_1.NumberUtils.getValue(lifeOptions.delay) * 1000;
particle.lifeDuration = Utils_1.NumberUtils.getValue(lifeOptions.duration) * 1000;
}
}
}
updateOpacity(delta) {
var _a, _b;
const particle = this.particle;
const opacityOpt = particle.options.opacity;
const opacityAnim = opacityOpt.animation;
const minValue = Utils_1.NumberUtils.getRangeMin(opacityOpt.value);
const maxValue = Utils_1.NumberUtils.getRangeMax(opacityOpt.value);
if (!particle.destroyed &&
opacityAnim.enable &&
(opacityAnim.count <= 0 || particle.loops.size < opacityAnim.count)) {
switch (particle.opacity.status) {
case Enums_1.AnimationStatus.increasing:
if (particle.opacity.value >= maxValue) {
particle.opacity.status = Enums_1.AnimationStatus.decreasing;
particle.loops.opacity++;
}
else {
particle.opacity.value += ((_a = particle.opacity.velocity) !== null && _a !== void 0 ? _a : 0) * delta.factor;
}
break;
case Enums_1.AnimationStatus.decreasing:
if (particle.opacity.value <= minValue) {
particle.opacity.status = Enums_1.AnimationStatus.increasing;
particle.loops.opacity++;
}
else {
particle.opacity.value -= ((_b = particle.opacity.velocity) !== null && _b !== void 0 ? _b : 0) * delta.factor;
}
break;
}
checkDestroy(particle, opacityAnim.destroy, particle.opacity.value, minValue, maxValue);
if (!particle.destroyed) {
particle.opacity.value = Utils_1.NumberUtils.clamp(particle.opacity.value, minValue, maxValue);
}
}
}
updateSize(delta) {
var _a;
const container = this.container;
const particle = this.particle;
const sizeOpt = particle.options.size;
const sizeAnim = sizeOpt.animation;
const sizeVelocity = ((_a = particle.size.velocity) !== null && _a !== void 0 ? _a : 0) * delta.factor;
const minValue = Utils_1.NumberUtils.getRangeMin(sizeOpt.value) * container.retina.pixelRatio;
const maxValue = Utils_1.NumberUtils.getRangeMax(sizeOpt.value) * container.retina.pixelRatio;
if (!particle.destroyed && sizeAnim.enable && (sizeAnim.count <= 0 || particle.loops.size < sizeAnim.count)) {
switch (particle.size.status) {
case Enums_1.AnimationStatus.increasing:
if (particle.size.value >= maxValue) {
particle.size.status = Enums_1.AnimationStatus.decreasing;
particle.loops.size++;
}
else {
particle.size.value += sizeVelocity;
}
break;
case Enums_1.AnimationStatus.decreasing:
if (particle.size.value <= minValue) {
particle.size.status = Enums_1.AnimationStatus.increasing;
particle.loops.size++;
}
else {
particle.size.value -= sizeVelocity;
}
}
checkDestroy(particle, sizeAnim.destroy, particle.size.value, minValue, maxValue);
if (!particle.destroyed) {
particle.size.value = Utils_1.NumberUtils.clamp(particle.size.value, minValue, maxValue);
}
}
}
updateAngle(delta) {
var _a;
const particle = this.particle;
const rotate = particle.options.rotate;
const rotateAnimation = rotate.animation;
const speed = ((_a = particle.rotate.velocity) !== null && _a !== void 0 ? _a : 0) * delta.factor;
const max = 2 * Math.PI;
if (rotateAnimation.enable) {
switch (particle.rotate.status) {
case Enums_1.AnimationStatus.increasing:
particle.rotate.value += speed;
if (particle.rotate.value > max) {
particle.rotate.value -= max;
}
break;
case Enums_1.AnimationStatus.decreasing:
default:
particle.rotate.value -= speed;
if (particle.rotate.value < 0) {
particle.rotate.value += max;
}
break;
}
}
}
updateColor(delta) {
var _a, _b, _c;
const particle = this.particle;
const animationOptions = particle.options.color.animation;
if (((_a = particle.color) === null || _a === void 0 ? void 0 : _a.h) !== undefined) {
this.updateColorValue(particle, delta, particle.color.h, animationOptions.h, 360, false);
}
if (((_b = particle.color) === null || _b === void 0 ? void 0 : _b.s) !== undefined) {
this.updateColorValue(particle, delta, particle.color.s, animationOptions.s, 100, true);
}
if (((_c = particle.color) === null || _c === void 0 ? void 0 : _c.l) !== undefined) {
this.updateColorValue(particle, delta, particle.color.l, animationOptions.l, 100, true);
}
}
updateStrokeColor(delta) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
const particle = this.particle;
if (!particle.stroke.color) {
return;
}
const animationOptions = particle.stroke.color.animation;
const valueAnimations = animationOptions;
if (valueAnimations.enable !== undefined) {
const hue = (_b = (_a = particle.strokeColor) === null || _a === void 0 ? void 0 : _a.h) !== null && _b !== void 0 ? _b : (_c = particle.color) === null || _c === void 0 ? void 0 : _c.h;
if (hue) {
this.updateColorValue(particle, delta, hue, valueAnimations, 360, false);
}
}
else {
const hslAnimations = animationOptions;
const h = (_e = (_d = particle.strokeColor) === null || _d === void 0 ? void 0 : _d.h) !== null && _e !== void 0 ? _e : (_f = particle.color) === null || _f === void 0 ? void 0 : _f.h;
if (h) {
this.updateColorValue(particle, delta, h, hslAnimations.h, 360, false);
}
const s = (_h = (_g = particle.strokeColor) === null || _g === void 0 ? void 0 : _g.s) !== null && _h !== void 0 ? _h : (_j = particle.color) === null || _j === void 0 ? void 0 : _j.s;
if (s) {
this.updateColorValue(particle, delta, s, hslAnimations.s, 100, true);
}
const l = (_l = (_k = particle.strokeColor) === null || _k === void 0 ? void 0 : _k.l) !== null && _l !== void 0 ? _l : (_m = particle.color) === null || _m === void 0 ? void 0 : _m.l;
if (l) {
this.updateColorValue(particle, delta, l, hslAnimations.l, 100, true);
}
}
}
updateColorValue(particle, delta, value, valueAnimation, max, decrease) {
var _a;
const colorValue = value;
if (!colorValue || !valueAnimation.enable) {
return;
}
const offset = Utils_1.NumberUtils.randomInRange(valueAnimation.offset);
const velocity = ((_a = value.velocity) !== null && _a !== void 0 ? _a : 0) * delta.factor + offset * 3.6;
if (!decrease || colorValue.status === Enums_1.AnimationStatus.increasing) {
colorValue.value += velocity;
if (decrease && colorValue.value > max) {
colorValue.status = Enums_1.AnimationStatus.decreasing;
colorValue.value -= colorValue.value % max;
}
}
else {
colorValue.value -= velocity;
if (colorValue.value < 0) {
colorValue.status = Enums_1.AnimationStatus.increasing;
colorValue.value += colorValue.value;
}
}
if (colorValue.value > max) {
colorValue.value %= max;
}
}
updateOutModes(delta) {
var _a, _b, _c, _d;
const outModes = this.particle.options.move.outModes;
this.updateOutMode(delta, (_a = outModes.bottom) !== null && _a !== void 0 ? _a : outModes.default, OutModeDirection_1.OutModeDirection.bottom);
this.updateOutMode(delta, (_b = outModes.left) !== null && _b !== void 0 ? _b : outModes.default, OutModeDirection_1.OutModeDirection.left);
this.updateOutMode(delta, (_c = outModes.right) !== null && _c !== void 0 ? _c : outModes.default, OutModeDirection_1.OutModeDirection.right);
this.updateOutMode(delta, (_d = outModes.top) !== null && _d !== void 0 ? _d : outModes.default, OutModeDirection_1.OutModeDirection.top);
}
updateOutMode(delta, outMode, direction) {
const container = this.container;
const particle = this.particle;
switch (outMode) {
case Enums_1.OutMode.bounce:
case Enums_1.OutMode.bounceVertical:
case Enums_1.OutMode.bounceHorizontal:
case "bounceVertical":
case "bounceHorizontal":
case Enums_1.OutMode.split:
this.updateBounce(delta, direction, outMode);
break;
case Enums_1.OutMode.destroy:
if (!Utils_1.Utils.isPointInside(particle.position, container.canvas.size, particle.getRadius(), direction)) {
container.particles.remove(particle, true);
}
break;
case Enums_1.OutMode.out:
if (!Utils_1.Utils.isPointInside(particle.position, container.canvas.size, particle.getRadius(), direction)) {
this.fixOutOfCanvasPosition(direction);
}
break;
case Enums_1.OutMode.none:
this.bounceNone(direction);
break;
}
}
fixOutOfCanvasPosition(direction) {
const container = this.container;
const particle = this.particle;
const wrap = particle.options.move.warp;
const canvasSize = container.canvas.size;
const newPos = {
bottom: canvasSize.height + particle.getRadius() - particle.offset.y,
left: -particle.getRadius() - particle.offset.x,
right: canvasSize.width + particle.getRadius() + particle.offset.x,
top: -particle.getRadius() - particle.offset.y,
};
const sizeValue = particle.getRadius();
const nextBounds = Utils_1.Utils.calculateBounds(particle.position, sizeValue);
if (direction === OutModeDirection_1.OutModeDirection.right && nextBounds.left > canvasSize.width - particle.offset.x) {
particle.position.x = newPos.left;
if (!wrap) {
particle.position.y = Math.random() * canvasSize.height;
}
}
else if (direction === OutModeDirection_1.OutModeDirection.left && nextBounds.right < -particle.offset.x) {
particle.position.x = newPos.right;
if (!wrap) {
particle.position.y = Math.random() * canvasSize.height;
}
}
if (direction === OutModeDirection_1.OutModeDirection.bottom && nextBounds.top > canvasSize.height - particle.offset.y) {
if (!wrap) {
particle.position.x = Math.random() * canvasSize.width;
}
particle.position.y = newPos.top;
}
else if (direction === OutModeDirection_1.OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
if (!wrap) {
particle.position.x = Math.random() * canvasSize.width;
}
particle.position.y = newPos.bottom;
}
}
updateBounce(delta, direction, outMode) {
const container = this.container;
const particle = this.particle;
let handled = false;
for (const [, plugin] of container.plugins) {
if (plugin.particleBounce !== undefined) {
handled = plugin.particleBounce(particle, delta, direction);
}
if (handled) {
break;
}
}
if (handled) {
return;
}
const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = Utils_1.Utils.calculateBounds(pos, size), canvasSize = container.canvas.size;
bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, size });
bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, size });
}
bounceNone(direction) {
const particle = this.particle;
if (particle.options.move.distance) {
return;
}
const gravityOptions = particle.options.move.gravity;
const container = this.container;
if (!gravityOptions.enable) {
if (!Utils_1.Utils.isPointInside(particle.position, container.canvas.size, particle.getRadius(), direction)) {
container.particles.remove(particle);
}
}
else {
const position = particle.position;
if ((gravityOptions.acceleration >= 0 &&
position.y > container.canvas.size.height &&
direction === OutModeDirection_1.OutModeDirection.bottom) ||
(gravityOptions.acceleration < 0 && position.y < 0 && direction === OutModeDirection_1.OutModeDirection.top)) {
container.particles.remove(particle);
}
}
}
}
exports.Updater = Updater;