UNPKG

tsparticles

Version:

Easily create highly customizable particle, confetti and fireworks 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.

387 lines (386 loc) 17.7 kB
"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _Particle_engine; Object.defineProperty(exports, "__esModule", { value: true }); exports.Particle = void 0; const Utils_1 = require("./Utils"); const Utils_2 = require("../Utils"); const ParticlesOptions_1 = require("../Options/Classes/Particles/ParticlesOptions"); const Shape_1 = require("../Options/Classes/Particles/Shape/Shape"); const fixOutMode = (data) => { if ((0, Utils_2.isInArray)(data.outMode, data.checkModes) || (0, Utils_2.isInArray)(data.outMode, data.checkModes)) { 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) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; this.id = id; this.container = container; this.group = group; _Particle_engine.set(this, void 0); __classPrivateFieldSet(this, _Particle_engine, engine, "f"); this.fill = true; this.close = true; this.lastPathTime = 0; this.destroyed = false; this.unbreakable = false; this.splitCount = 0; this.misplaced = false; this.retina = { maxDistance: {}, }; this.ignoresResizeRatio = true; const pxRatio = container.retina.pixelRatio; const mainOptions = container.actualOptions; const particlesOptions = new ParticlesOptions_1.ParticlesOptions(); particlesOptions.load(mainOptions.particles); const shapeType = particlesOptions.shape.type; const reduceDuplicates = particlesOptions.reduceDuplicates; this.shape = shapeType instanceof Array ? (0, Utils_2.itemFromArray)(shapeType, this.id, reduceDuplicates) : shapeType; if (overrideOptions === null || overrideOptions === void 0 ? void 0 : overrideOptions.shape) { if (overrideOptions.shape.type) { const overrideShapeType = overrideOptions.shape.type; this.shape = overrideShapeType instanceof Array ? (0, Utils_2.itemFromArray)(overrideShapeType, this.id, reduceDuplicates) : overrideShapeType; } const shapeOptions = new Shape_1.Shape(); shapeOptions.load(overrideOptions.shape); if (this.shape) { this.shapeData = this.loadShapeData(shapeOptions, reduceDuplicates); } } else { this.shapeData = this.loadShapeData(particlesOptions.shape, reduceDuplicates); } if (overrideOptions !== undefined) { particlesOptions.load(overrideOptions); } if (((_a = this.shapeData) === null || _a === void 0 ? void 0 : _a.particles) !== undefined) { particlesOptions.load((_b = this.shapeData) === null || _b === void 0 ? void 0 : _b.particles); } this.fill = (_d = (_c = this.shapeData) === null || _c === void 0 ? void 0 : _c.fill) !== null && _d !== void 0 ? _d : this.fill; this.close = (_f = (_e = this.shapeData) === null || _e === void 0 ? void 0 : _e.close) !== null && _f !== void 0 ? _f : this.close; this.options = particlesOptions; this.pathDelay = (0, Utils_2.getValue)(this.options.move.path.delay) * 1000; const zIndexValue = (0, Utils_2.getRangeValue)(this.options.zIndex.value); container.retina.initParticle(this); const sizeOptions = this.options.size, sizeRange = sizeOptions.value; this.size = { enable: sizeOptions.animation.enable, value: (0, Utils_2.getValue)(sizeOptions) * container.retina.pixelRatio, max: (0, Utils_2.getRangeMax)(sizeRange) * pxRatio, min: (0, Utils_2.getRangeMin)(sizeRange) * pxRatio, loops: 0, maxLoops: (0, Utils_2.getRangeValue)(sizeOptions.animation.count), }; const sizeAnimation = sizeOptions.animation; if (sizeAnimation.enable) { this.size.status = 0; switch (sizeAnimation.startValue) { case "min": this.size.value = this.size.min; this.size.status = 0; break; case "random": this.size.value = (0, Utils_2.randomInRange)(this.size) * pxRatio; this.size.status = Math.random() >= 0.5 ? 0 : 1; break; case "max": default: this.size.value = this.size.max; this.size.status = 1; break; } this.size.velocity = (((_g = this.retina.sizeAnimationSpeed) !== null && _g !== void 0 ? _g : container.retina.sizeAnimationSpeed) / 100) * container.retina.reduceFactor; if (!sizeAnimation.sync) { this.size.velocity *= Math.random(); } } this.direction = (0, Utils_2.getParticleDirectionAngle)(this.options.move.direction); this.bubble = { inRange: false, }; this.initialVelocity = this.calculateVelocity(); this.velocity = this.initialVelocity.copy(); this.moveDecay = 1 - (0, Utils_2.getRangeValue)(this.options.move.decay); const gravityOptions = this.options.move.gravity; this.gravity = { enable: gravityOptions.enable, acceleration: (0, Utils_2.getRangeValue)(gravityOptions.acceleration), inverse: gravityOptions.inverse, }; this.position = this.calcPosition(container, position, (0, Utils_2.clamp)(zIndexValue, 0, container.zLayers)); this.initialPosition = this.position.copy(); this.offset = Utils_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 = __classPrivateFieldGet(this, _Particle_engine, "f").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.life = this.loadLife(); this.spawning = this.life.delay > 0; if (this.options.move.spin.enable) { const spinPos = (_h = this.options.move.spin.position) !== null && _h !== void 0 ? _h : { x: 50, y: 50 }; const spinCenter = { x: (spinPos.x / 100) * container.canvas.size.width, y: (spinPos.y / 100) * container.canvas.size.height, }; const pos = this.getPosition(); const distance = (0, Utils_2.getDistance)(pos, spinCenter); this.spin = { center: spinCenter, direction: this.velocity.x >= 0 ? "clockwise" : "counter-clockwise", angle: this.velocity.angle, radius: distance, acceleration: (_j = this.retina.spinAcceleration) !== null && _j !== void 0 ? _j : (0, Utils_2.getRangeValue)(this.options.move.spin.acceleration), }; } this.shadowColor = (0, Utils_2.colorToRgb)(this.options.shadow.color); for (const updater of container.particles.updaters) { if (updater.init) { updater.init(this); } } if (drawer && drawer.particleInit) { drawer.particleInit(container, this); } for (const [, plugin] of container.plugins) { if (plugin.particleCreated) { plugin.particleCreated(this); } } } isVisible() { return !this.destroyed && !this.spawning && this.isInsideCanvas(); } isInsideCanvas() { const radius = this.getRadius(); const 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); } draw(delta) { const container = this.container; for (const [, plugin] of container.plugins) { container.canvas.drawParticlePlugin(plugin, this, delta); } container.canvas.drawParticle(this, delta); } 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; } getMass() { return (this.getRadius() ** 2 * Math.PI) / 2; } getFillColor() { var _a, _b; const color = (_a = this.bubble.color) !== null && _a !== void 0 ? _a : (0, Utils_2.getHslFromAnimation)(this.color); if (color && this.roll && (this.backColor || this.roll.alter)) { const backFactor = this.options.roll.mode === "both" ? 2 : 1, backSum = this.options.roll.mode === "horizontal" ? Math.PI / 2 : 0, rolled = Math.floor((((_b = this.roll.angle) !== null && _b !== void 0 ? _b : 0) + backSum) / (Math.PI / backFactor)) % 2; if (rolled) { if (this.backColor) { return this.backColor; } if (this.roll.alter) { return (0, Utils_2.alterHsl)(color, this.roll.alter.type, this.roll.alter.value); } } } return color; } getStrokeColor() { var _a, _b; return (_b = (_a = this.bubble.color) !== null && _a !== void 0 ? _a : (0, Utils_2.getHslFromAnimation)(this.strokeColor)) !== null && _b !== void 0 ? _b : this.getFillColor(); } destroy(override) { this.destroyed = true; this.bubble.inRange = false; if (this.unbreakable) { return; } this.destroyed = true; this.bubble.inRange = false; for (const [, plugin] of this.container.plugins) { if (plugin.particleDestroyed) { plugin.particleDestroyed(this, override); } } if (override) { return; } const destroyOptions = this.options.destroy; if (destroyOptions.mode === "split") { this.split(); } } reset() { if (this.opacity) { this.opacity.loops = 0; } this.size.loops = 0; } split() { const splitOptions = this.options.destroy.split; if (splitOptions.count >= 0 && this.splitCount++ > splitOptions.count) { return; } const rate = (0, Utils_2.getRangeValue)(splitOptions.rate.value); for (let i = 0; i < rate; i++) { this.container.particles.addSplitParticle(this); } } calcPosition(container, position, zIndex, tryCount = 0) { var _a, _b, _c, _d, _e, _f; for (const [, plugin] of container.plugins) { const pluginPos = plugin.particlePosition !== undefined ? plugin.particlePosition(position, this) : undefined; if (pluginPos !== undefined) { return Utils_1.Vector3d.create(pluginPos.x, pluginPos.y, zIndex); } } const canvasSize = container.canvas.size; const pos = Utils_1.Vector3d.create((_a = position === null || position === void 0 ? void 0 : position.x) !== null && _a !== void 0 ? _a : Math.random() * canvasSize.width, (_b = position === null || position === void 0 ? void 0 : position.y) !== null && _b !== void 0 ? _b : Math.random() * canvasSize.height, zIndex); const radius = this.getRadius(); const 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((_c = outModes.left) !== null && _c !== void 0 ? _c : outModes.default); fixHorizontal((_d = outModes.right) !== null && _d !== void 0 ? _d : outModes.default); fixVertical((_e = outModes.top) !== null && _e !== void 0 ? _e : outModes.default); fixVertical((_f = outModes.bottom) !== null && _f !== void 0 ? _f : outModes.default); if (this.checkOverlap(pos, tryCount)) { return this.calcPosition(container, undefined, zIndex, tryCount + 1); } return pos; } checkOverlap(pos, tryCount = 0) { const collisionsOptions = this.options.collisions; const 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, Utils_2.getDistance)(pos, particle.position) < radius + particle.getRadius()) { overlaps = true; break; } } return overlaps; } calculateVelocity() { const baseVelocity = (0, Utils_2.getParticleBaseVelocity)(this.direction), res = baseVelocity.copy(), moveOptions = this.options.move, rad = (Math.PI / 180) * (0, Utils_2.getRangeValue)(moveOptions.angle.value), radOffset = (Math.PI / 180) * (0, Utils_2.getRangeValue)(moveOptions.angle.offset), range = { left: radOffset - rad / 2, right: radOffset + rad / 2, }; if (!moveOptions.straight) { res.angle += (0, Utils_2.randomInRange)((0, Utils_2.setRangeValue)(range.left, range.right)); } if (moveOptions.random && typeof moveOptions.speed === "number") { res.length *= Math.random(); } return res; } loadShapeData(shapeOptions, reduceDuplicates) { const shapeData = shapeOptions.options[this.shape]; if (shapeData) { return (0, Utils_2.deepExtend)({}, shapeData instanceof Array ? (0, Utils_2.itemFromArray)(shapeData, this.id, reduceDuplicates) : shapeData); } } loadLife() { const container = this.container; const particlesOptions = this.options; const lifeOptions = particlesOptions.life; const life = { delay: container.retina.reduceFactor ? (((0, Utils_2.getRangeValue)(lifeOptions.delay.value) * (lifeOptions.delay.sync ? 1 : Math.random())) / container.retina.reduceFactor) * 1000 : 0, delayTime: 0, duration: container.retina.reduceFactor ? (((0, Utils_2.getRangeValue)(lifeOptions.duration.value) * (lifeOptions.duration.sync ? 1 : Math.random())) / container.retina.reduceFactor) * 1000 : 0, time: 0, count: particlesOptions.life.count, }; if (life.duration <= 0) { life.duration = -1; } if (life.count <= 0) { life.count = -1; } return life; } } exports.Particle = Particle; _Particle_engine = new WeakMap();