336 lines
15 KiB
JavaScript
336 lines
15 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.Particle = void 0;
|
|
const NumberUtils_1 = require("../Utils/NumberUtils");
|
|
const Utils_1 = require("../Utils/Utils");
|
|
const ColorUtils_1 = require("../Utils/ColorUtils");
|
|
const Interactivity_1 = require("../Options/Classes/Interactivity/Interactivity");
|
|
const Vector_1 = require("./Utils/Vector");
|
|
const Vector3d_1 = require("./Utils/Vector3d");
|
|
const CanvasUtils_1 = require("../Utils/CanvasUtils");
|
|
const OptionsUtils_1 = require("../Utils/OptionsUtils");
|
|
const fixOutMode = (data) => {
|
|
if (!(0, Utils_1.isInArray)(data.outMode, data.checkModes)) {
|
|
return;
|
|
}
|
|
if (data.coord > data.maxCoord - data.radius * 2) {
|
|
data.setCb(-data.radius);
|
|
}
|
|
else if (data.coord < data.radius * 2) {
|
|
data.setCb(data.radius);
|
|
}
|
|
};
|
|
class Particle {
|
|
constructor(engine, id, container, position, overrideOptions, group) {
|
|
this.container = container;
|
|
this._engine = engine;
|
|
this.init(id, position, overrideOptions, group);
|
|
}
|
|
destroy(override) {
|
|
var _a;
|
|
if (this.unbreakable || this.destroyed) {
|
|
return;
|
|
}
|
|
this.destroyed = true;
|
|
this.bubble.inRange = false;
|
|
this.slow.inRange = false;
|
|
for (const [, plugin] of this.container.plugins) {
|
|
if (plugin.particleDestroyed) {
|
|
plugin.particleDestroyed(this, override);
|
|
}
|
|
}
|
|
for (const updater of this.container.particles.updaters) {
|
|
if (updater.particleDestroyed) {
|
|
updater.particleDestroyed(this, override);
|
|
}
|
|
}
|
|
(_a = this.pathGenerator) === null || _a === void 0 ? void 0 : _a.reset(this);
|
|
}
|
|
draw(delta) {
|
|
const container = this.container;
|
|
for (const [, plugin] of container.plugins) {
|
|
container.canvas.drawParticlePlugin(plugin, this, delta);
|
|
}
|
|
container.canvas.drawParticle(this, delta);
|
|
}
|
|
getFillColor() {
|
|
var _a;
|
|
return this._getRollColor((_a = this.bubble.color) !== null && _a !== void 0 ? _a : (0, ColorUtils_1.getHslFromAnimation)(this.color));
|
|
}
|
|
getMass() {
|
|
return (this.getRadius() ** 2 * Math.PI) / 2;
|
|
}
|
|
getPosition() {
|
|
return {
|
|
x: this.position.x + this.offset.x,
|
|
y: this.position.y + this.offset.y,
|
|
z: this.position.z,
|
|
};
|
|
}
|
|
getRadius() {
|
|
var _a;
|
|
return (_a = this.bubble.radius) !== null && _a !== void 0 ? _a : this.size.value;
|
|
}
|
|
getStrokeColor() {
|
|
var _a;
|
|
return this._getRollColor((_a = this.bubble.color) !== null && _a !== void 0 ? _a : (0, ColorUtils_1.getHslFromAnimation)(this.strokeColor));
|
|
}
|
|
init(id, position, overrideOptions, group) {
|
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
const container = this.container, engine = this._engine;
|
|
this.id = id;
|
|
this.group = group;
|
|
this.fill = true;
|
|
this.pathRotation = false;
|
|
this.close = true;
|
|
this.lastPathTime = 0;
|
|
this.destroyed = false;
|
|
this.unbreakable = false;
|
|
this.rotation = 0;
|
|
this.misplaced = false;
|
|
this.retina = {
|
|
maxDistance: {},
|
|
};
|
|
this.outType = "normal";
|
|
this.ignoresResizeRatio = true;
|
|
const pxRatio = container.retina.pixelRatio, mainOptions = container.actualOptions, particlesOptions = (0, OptionsUtils_1.loadParticlesOptions)(this._engine, container, mainOptions.particles), shapeType = particlesOptions.shape.type, { reduceDuplicates } = particlesOptions;
|
|
this.shape = (0, Utils_1.itemFromSingleOrMultiple)(shapeType, this.id, reduceDuplicates);
|
|
const shapeOptions = particlesOptions.shape;
|
|
if (overrideOptions && overrideOptions.shape && overrideOptions.shape.type) {
|
|
const overrideShapeType = overrideOptions.shape.type, shape = (0, Utils_1.itemFromSingleOrMultiple)(overrideShapeType, this.id, reduceDuplicates);
|
|
if (shape) {
|
|
this.shape = shape;
|
|
shapeOptions.load(overrideOptions.shape);
|
|
}
|
|
}
|
|
this.shapeData = this._loadShapeData(shapeOptions, reduceDuplicates);
|
|
particlesOptions.load(overrideOptions);
|
|
particlesOptions.load((_a = this.shapeData) === null || _a === void 0 ? void 0 : _a.particles);
|
|
this.interactivity = new Interactivity_1.Interactivity(engine, container);
|
|
this.interactivity.load(container.actualOptions.interactivity);
|
|
this.interactivity.load(particlesOptions.interactivity);
|
|
this.fill = (_c = (_b = this.shapeData) === null || _b === void 0 ? void 0 : _b.fill) !== null && _c !== void 0 ? _c : this.fill;
|
|
this.close = (_e = (_d = this.shapeData) === null || _d === void 0 ? void 0 : _d.close) !== null && _e !== void 0 ? _e : this.close;
|
|
this.options = particlesOptions;
|
|
const pathOptions = this.options.move.path;
|
|
this.pathDelay = (0, NumberUtils_1.getValue)(pathOptions.delay) * 1000;
|
|
if (pathOptions.generator) {
|
|
this.pathGenerator = this._engine.plugins.getPathGenerator(pathOptions.generator);
|
|
if (this.pathGenerator && container.addPath(pathOptions.generator, this.pathGenerator)) {
|
|
this.pathGenerator.init(container);
|
|
}
|
|
}
|
|
const zIndexValue = (0, NumberUtils_1.getRangeValue)(this.options.zIndex.value);
|
|
container.retina.initParticle(this);
|
|
const sizeOptions = this.options.size, sizeRange = sizeOptions.value, sizeAnimation = sizeOptions.animation;
|
|
this.size = {
|
|
enable: sizeOptions.animation.enable,
|
|
value: (0, NumberUtils_1.getRangeValue)(sizeOptions.value) * container.retina.pixelRatio,
|
|
max: (0, NumberUtils_1.getRangeMax)(sizeRange) * pxRatio,
|
|
min: (0, NumberUtils_1.getRangeMin)(sizeRange) * pxRatio,
|
|
loops: 0,
|
|
maxLoops: (0, NumberUtils_1.getRangeValue)(sizeOptions.animation.count),
|
|
};
|
|
if (sizeAnimation.enable) {
|
|
this.size.status = "increasing";
|
|
this.size.decay = 1 - (0, NumberUtils_1.getRangeValue)(sizeAnimation.decay);
|
|
switch (sizeAnimation.startValue) {
|
|
case "min":
|
|
this.size.value = this.size.min;
|
|
this.size.status = "increasing";
|
|
break;
|
|
case "random":
|
|
this.size.value = (0, NumberUtils_1.randomInRange)(this.size);
|
|
this.size.status = (0, NumberUtils_1.getRandom)() >= 0.5 ? "increasing" : "decreasing";
|
|
break;
|
|
case "max":
|
|
default:
|
|
this.size.value = this.size.max;
|
|
this.size.status = "decreasing";
|
|
break;
|
|
}
|
|
}
|
|
this.size.initialValue = this.size.value;
|
|
this.bubble = {
|
|
inRange: false,
|
|
};
|
|
this.slow = {
|
|
inRange: false,
|
|
factor: 1,
|
|
};
|
|
this.position = this._calcPosition(container, position, (0, NumberUtils_1.clamp)(zIndexValue, 0, container.zLayers));
|
|
this.initialPosition = this.position.copy();
|
|
const canvasSize = container.canvas.size, moveCenter = Object.assign({}, this.options.move.center), isCenterPercent = moveCenter.mode === "percent";
|
|
this.moveCenter = {
|
|
x: moveCenter.x * (isCenterPercent ? canvasSize.width / 100 : 1),
|
|
y: moveCenter.y * (isCenterPercent ? canvasSize.height / 100 : 1),
|
|
radius: (_f = this.options.move.center.radius) !== null && _f !== void 0 ? _f : 0,
|
|
mode: (_g = this.options.move.center.mode) !== null && _g !== void 0 ? _g : "percent",
|
|
};
|
|
this.direction = (0, NumberUtils_1.getParticleDirectionAngle)(this.options.move.direction, this.position, this.moveCenter);
|
|
switch (this.options.move.direction) {
|
|
case "inside":
|
|
this.outType = "inside";
|
|
break;
|
|
case "outside":
|
|
this.outType = "outside";
|
|
break;
|
|
}
|
|
this.initialVelocity = this._calculateVelocity();
|
|
this.velocity = this.initialVelocity.copy();
|
|
this.moveDecay = 1 - (0, NumberUtils_1.getRangeValue)(this.options.move.decay);
|
|
this.offset = Vector_1.Vector.origin;
|
|
const particles = container.particles;
|
|
particles.needsSort = particles.needsSort || particles.lastZIndex < this.position.z;
|
|
particles.lastZIndex = this.position.z;
|
|
this.zIndexFactor = this.position.z / container.zLayers;
|
|
this.sides = 24;
|
|
let drawer = container.drawers.get(this.shape);
|
|
if (!drawer) {
|
|
drawer = this._engine.plugins.getShapeDrawer(this.shape);
|
|
if (drawer) {
|
|
container.drawers.set(this.shape, drawer);
|
|
}
|
|
}
|
|
if (drawer === null || drawer === void 0 ? void 0 : drawer.loadShape) {
|
|
drawer === null || drawer === void 0 ? void 0 : drawer.loadShape(this);
|
|
}
|
|
const sideCountFunc = drawer === null || drawer === void 0 ? void 0 : drawer.getSidesCount;
|
|
if (sideCountFunc) {
|
|
this.sides = sideCountFunc(this);
|
|
}
|
|
this.spawning = false;
|
|
this.shadowColor = (0, ColorUtils_1.rangeColorToRgb)(this.options.shadow.color);
|
|
for (const updater of container.particles.updaters) {
|
|
updater.init(this);
|
|
}
|
|
for (const mover of container.particles.movers) {
|
|
(_h = mover.init) === null || _h === void 0 ? void 0 : _h.call(mover, this);
|
|
}
|
|
if (drawer === null || drawer === void 0 ? void 0 : drawer.particleInit) {
|
|
drawer.particleInit(container, this);
|
|
}
|
|
for (const [, plugin] of container.plugins) {
|
|
(_j = plugin.particleCreated) === null || _j === void 0 ? void 0 : _j.call(plugin, this);
|
|
}
|
|
}
|
|
isInsideCanvas() {
|
|
const radius = this.getRadius(), canvasSize = this.container.canvas.size;
|
|
return (this.position.x >= -radius &&
|
|
this.position.y >= -radius &&
|
|
this.position.y <= canvasSize.height + radius &&
|
|
this.position.x <= canvasSize.width + radius);
|
|
}
|
|
isVisible() {
|
|
return !this.destroyed && !this.spawning && this.isInsideCanvas();
|
|
}
|
|
reset() {
|
|
var _a;
|
|
for (const updater of this.container.particles.updaters) {
|
|
(_a = updater.reset) === null || _a === void 0 ? void 0 : _a.call(updater, this);
|
|
}
|
|
}
|
|
_calcPosition(container, position, zIndex, tryCount = 0) {
|
|
var _a, _b, _c, _d;
|
|
for (const [, plugin] of container.plugins) {
|
|
const pluginPos = plugin.particlePosition !== undefined ? plugin.particlePosition(position, this) : undefined;
|
|
if (pluginPos !== undefined) {
|
|
return Vector3d_1.Vector3d.create(pluginPos.x, pluginPos.y, zIndex);
|
|
}
|
|
}
|
|
const canvasSize = container.canvas.size, exactPosition = (0, NumberUtils_1.calcExactPositionOrRandomFromSize)({
|
|
size: canvasSize,
|
|
position: position,
|
|
}), pos = Vector3d_1.Vector3d.create(exactPosition.x, exactPosition.y, zIndex), radius = this.getRadius(), outModes = this.options.move.outModes, fixHorizontal = (outMode) => {
|
|
fixOutMode({
|
|
outMode,
|
|
checkModes: ["bounce", "bounce-horizontal"],
|
|
coord: pos.x,
|
|
maxCoord: container.canvas.size.width,
|
|
setCb: (value) => (pos.x += value),
|
|
radius,
|
|
});
|
|
}, fixVertical = (outMode) => {
|
|
fixOutMode({
|
|
outMode,
|
|
checkModes: ["bounce", "bounce-vertical"],
|
|
coord: pos.y,
|
|
maxCoord: container.canvas.size.height,
|
|
setCb: (value) => (pos.y += value),
|
|
radius,
|
|
});
|
|
};
|
|
fixHorizontal((_a = outModes.left) !== null && _a !== void 0 ? _a : outModes.default);
|
|
fixHorizontal((_b = outModes.right) !== null && _b !== void 0 ? _b : outModes.default);
|
|
fixVertical((_c = outModes.top) !== null && _c !== void 0 ? _c : outModes.default);
|
|
fixVertical((_d = outModes.bottom) !== null && _d !== void 0 ? _d : outModes.default);
|
|
if (this._checkOverlap(pos, tryCount)) {
|
|
return this._calcPosition(container, undefined, zIndex, tryCount + 1);
|
|
}
|
|
return pos;
|
|
}
|
|
_calculateVelocity() {
|
|
const baseVelocity = (0, NumberUtils_1.getParticleBaseVelocity)(this.direction), res = baseVelocity.copy(), moveOptions = this.options.move;
|
|
if (moveOptions.direction === "inside" || moveOptions.direction === "outside") {
|
|
return res;
|
|
}
|
|
const rad = (Math.PI / 180) * (0, NumberUtils_1.getRangeValue)(moveOptions.angle.value), radOffset = (Math.PI / 180) * (0, NumberUtils_1.getRangeValue)(moveOptions.angle.offset), range = {
|
|
left: radOffset - rad / 2,
|
|
right: radOffset + rad / 2,
|
|
};
|
|
if (!moveOptions.straight) {
|
|
res.angle += (0, NumberUtils_1.randomInRange)((0, NumberUtils_1.setRangeValue)(range.left, range.right));
|
|
}
|
|
if (moveOptions.random && typeof moveOptions.speed === "number") {
|
|
res.length *= (0, NumberUtils_1.getRandom)();
|
|
}
|
|
return res;
|
|
}
|
|
_checkOverlap(pos, tryCount = 0) {
|
|
const collisionsOptions = this.options.collisions, radius = this.getRadius();
|
|
if (!collisionsOptions.enable) {
|
|
return false;
|
|
}
|
|
const overlapOptions = collisionsOptions.overlap;
|
|
if (overlapOptions.enable) {
|
|
return false;
|
|
}
|
|
const retries = overlapOptions.retries;
|
|
if (retries >= 0 && tryCount > retries) {
|
|
throw new Error("Particle is overlapping and can't be placed");
|
|
}
|
|
let overlaps = false;
|
|
for (const particle of this.container.particles.array) {
|
|
if ((0, NumberUtils_1.getDistance)(pos, particle.position) < radius + particle.getRadius()) {
|
|
overlaps = true;
|
|
break;
|
|
}
|
|
}
|
|
return overlaps;
|
|
}
|
|
_getRollColor(color) {
|
|
var _a;
|
|
if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
|
|
return color;
|
|
}
|
|
const backFactor = this.roll.horizontal && this.roll.vertical ? 2 : 1, backSum = this.roll.horizontal ? Math.PI / 2 : 0, rolled = Math.floor((((_a = this.roll.angle) !== null && _a !== void 0 ? _a : 0) + backSum) / (Math.PI / backFactor)) % 2;
|
|
if (!rolled) {
|
|
return color;
|
|
}
|
|
if (this.backColor) {
|
|
return this.backColor;
|
|
}
|
|
if (this.roll.alter) {
|
|
return (0, CanvasUtils_1.alterHsl)(color, this.roll.alter.type, this.roll.alter.value);
|
|
}
|
|
return color;
|
|
}
|
|
_loadShapeData(shapeOptions, reduceDuplicates) {
|
|
const shapeData = shapeOptions.options[this.shape];
|
|
if (shapeData) {
|
|
return (0, Utils_1.deepExtend)({}, (0, Utils_1.itemFromSingleOrMultiple)(shapeData, this.id, reduceDuplicates));
|
|
}
|
|
}
|
|
}
|
|
exports.Particle = Particle;
|