UNPKG

@tsparticles/plugin-emitters

Version:

tsParticles emitters plugin

318 lines (317 loc) 13.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EmitterInstance = void 0; const engine_1 = require("@tsparticles/engine"); const Emitter_js_1 = require("./Options/Classes/Emitter.js"); const EmitterSize_js_1 = require("./Options/Classes/EmitterSize.js"); const half = 0.5, defaultLifeDelay = 0, minLifeCount = 0, defaultSpawnDelay = 0, defaultEmitDelay = 0, defaultLifeCount = -1, defaultColorAnimationFactor = 1; function setParticlesOptionsColor(particlesOptions, color) { if (particlesOptions.color) { particlesOptions.color.value = color; } else { particlesOptions.color = { value: color, }; } } class EmitterInstance { constructor(engine, emitters, container, options, position) { this.emitters = emitters; this.container = container; this._destroy = () => { this._mutationObserver?.disconnect(); this._mutationObserver = undefined; this._resizeObserver?.disconnect(); this._resizeObserver = undefined; this.emitters.removeEmitter(this); this._engine.dispatchEvent("emitterDestroyed", { container: this.container, data: { emitter: this, }, }); }; this._prepareToDie = () => { if (this._paused) { return; } const duration = this.options.life?.duration !== undefined ? (0, engine_1.getRangeValue)(this.options.life.duration) : undefined, minDuration = 0, minLifeCount = 0; if ((this._lifeCount > minLifeCount || this._immortal) && duration !== undefined && duration > minDuration) { this._duration = duration * engine_1.millisecondsToSeconds; } }; this._setColorAnimation = (animation, initValue, maxValue, factor = defaultColorAnimationFactor) => { const container = this.container; if (!animation.enable) { return initValue; } const colorOffset = (0, engine_1.randomInRange)(animation.offset), delay = (0, engine_1.getRangeValue)(this.options.rate.delay), emitFactor = container.retina.reduceFactor ? (delay * engine_1.millisecondsToSeconds) / container.retina.reduceFactor : Infinity, defaultColorSpeed = 0, colorSpeed = (0, engine_1.getRangeValue)(animation.speed ?? defaultColorSpeed); return (initValue + (colorSpeed * container.fpsLimit) / emitFactor + colorOffset * factor) % maxValue; }; this._engine = engine; this._currentDuration = 0; this._currentEmitDelay = 0; this._currentSpawnDelay = 0; this._initialPosition = position; if (options instanceof Emitter_js_1.Emitter) { this.options = options; } else { this.options = new Emitter_js_1.Emitter(); this.options.load(options); } this._spawnDelay = container.retina.reduceFactor ? ((0, engine_1.getRangeValue)(this.options.life.delay ?? defaultLifeDelay) * engine_1.millisecondsToSeconds) / container.retina.reduceFactor : Infinity; this.position = this._initialPosition ?? this._calcPosition(); this.name = this.options.name; this.fill = this.options.fill; this._firstSpawn = !this.options.life.wait; this._startParticlesAdded = false; let particlesOptions = (0, engine_1.deepExtend)({}, this.options.particles); particlesOptions ??= {}; particlesOptions.move ??= {}; particlesOptions.move.direction ??= this.options.direction; if (this.options.spawnColor) { this.spawnColor = (0, engine_1.rangeColorToHsl)(this._engine, this.options.spawnColor); } this._paused = !this.options.autoPlay; this._particlesOptions = particlesOptions; this._size = this._calcSize(); this.size = (0, engine_1.getSize)(this._size, this.container.canvas.size); this._lifeCount = this.options.life.count ?? defaultLifeCount; this._immortal = this._lifeCount <= minLifeCount; if (this.options.domId) { const element = document.getElementById(this.options.domId); if (element) { this._mutationObserver = new MutationObserver(() => { this.resize(); }); this._resizeObserver = new ResizeObserver(() => { this.resize(); }); this._mutationObserver.observe(element, { attributes: true, attributeFilter: ["style", "width", "height"], }); this._resizeObserver.observe(element); } } const shapeOptions = this.options.shape, shapeGenerator = this._engine.emitterShapeManager?.getShapeGenerator(shapeOptions.type); if (shapeGenerator) { this._shape = shapeGenerator.generate(this.position, this.size, this.fill, shapeOptions.options); } this._engine.dispatchEvent("emitterCreated", { container, data: { emitter: this, }, }); this.play(); } externalPause() { this._paused = true; this.pause(); } externalPlay() { this._paused = false; this.play(); } async init() { await this._shape?.init(); } pause() { if (this._paused) { return; } delete this._emitDelay; } play() { if (this._paused) { return; } if (!((this._lifeCount > minLifeCount || this._immortal || !this.options.life.count) && (this._firstSpawn || this._currentSpawnDelay >= (this._spawnDelay ?? defaultSpawnDelay)))) { return; } const container = this.container; if (this._emitDelay === undefined) { const delay = (0, engine_1.getRangeValue)(this.options.rate.delay); this._emitDelay = container.retina.reduceFactor ? (delay * engine_1.millisecondsToSeconds) / container.retina.reduceFactor : Infinity; } if (this._lifeCount > minLifeCount || this._immortal) { this._prepareToDie(); } } resize() { const initialPosition = this._initialPosition, container = this.container; this.position = initialPosition && (0, engine_1.isPointInside)(initialPosition, container.canvas.size, engine_1.Vector.origin) ? initialPosition : this._calcPosition(); this._size = this._calcSize(); this.size = (0, engine_1.getSize)(this._size, container.canvas.size); this._shape?.resize(this.position, this.size); } update(delta) { if (this._paused) { return; } const container = this.container; if (this._firstSpawn) { this._firstSpawn = false; this._currentSpawnDelay = this._spawnDelay ?? defaultSpawnDelay; this._currentEmitDelay = this._emitDelay ?? defaultEmitDelay; } if (!this._startParticlesAdded) { this._startParticlesAdded = true; this._emitParticles(this.options.startCount); } if (this._duration !== undefined) { this._currentDuration += delta.value; if (this._currentDuration >= this._duration) { this.pause(); if (this._spawnDelay !== undefined) { delete this._spawnDelay; } if (!this._immortal) { this._lifeCount--; } if (this._lifeCount > minLifeCount || this._immortal) { this.position = this._calcPosition(); this._shape?.resize(this.position, this.size); this._spawnDelay = container.retina.reduceFactor ? ((0, engine_1.getRangeValue)(this.options.life.delay ?? defaultLifeDelay) * engine_1.millisecondsToSeconds) / container.retina.reduceFactor : Infinity; } else { this._destroy(); } this._currentDuration -= this._duration; delete this._duration; } } if (this._spawnDelay !== undefined) { this._currentSpawnDelay += delta.value; if (this._currentSpawnDelay >= this._spawnDelay) { this._engine.dispatchEvent("emitterPlay", { container: this.container, }); this.play(); this._currentSpawnDelay -= this._currentSpawnDelay; delete this._spawnDelay; } } if (this._emitDelay !== undefined) { this._currentEmitDelay += delta.value; if (this._currentEmitDelay >= this._emitDelay) { this._emit(); this._currentEmitDelay -= this._emitDelay; } } } _calcPosition() { const container = this.container; if (this.options.domId) { const element = document.getElementById(this.options.domId); if (element) { const elRect = element.getBoundingClientRect(), pxRatio = container.retina.pixelRatio; return { x: (elRect.x + elRect.width * half) * pxRatio, y: (elRect.y + elRect.height * half) * pxRatio, }; } } return (0, engine_1.calcPositionOrRandomFromSizeRanged)({ size: container.canvas.size, position: this.options.position, }); } _calcSize() { const container = this.container; if (this.options.domId) { const element = document.getElementById(this.options.domId); if (element) { const elRect = element.getBoundingClientRect(); return { width: elRect.width * container.retina.pixelRatio, height: elRect.height * container.retina.pixelRatio, mode: engine_1.PixelMode.precise, }; } } return (this.options.size ?? (() => { const size = new EmitterSize_js_1.EmitterSize(); size.load({ height: 0, mode: engine_1.PixelMode.percent, width: 0, }); return size; })()); } _emit() { if (this._paused) { return; } const quantity = (0, engine_1.getRangeValue)(this.options.rate.quantity); this._emitParticles(quantity); } _emitParticles(quantity) { const singleParticlesOptions = (0, engine_1.itemFromSingleOrMultiple)(this._particlesOptions), reduceFactor = this.container.retina.reduceFactor; for (let i = 0; i < quantity * reduceFactor; i++) { const particlesOptions = (0, engine_1.deepExtend)({}, singleParticlesOptions); if (this.spawnColor) { const hslAnimation = this.options.spawnColor?.animation; if (hslAnimation) { const maxValues = { h: 360, s: 100, l: 100, }, colorFactor = 3.6; this.spawnColor.h = this._setColorAnimation(hslAnimation.h, this.spawnColor.h, maxValues.h, colorFactor); this.spawnColor.s = this._setColorAnimation(hslAnimation.s, this.spawnColor.s, maxValues.s); this.spawnColor.l = this._setColorAnimation(hslAnimation.l, this.spawnColor.l, maxValues.l); } setParticlesOptionsColor(particlesOptions, this.spawnColor); } const shapeOptions = this.options.shape; let position = this.position; if (this._shape) { const shapePosData = this._shape.randomPosition(); if (shapePosData) { position = shapePosData.position; const replaceData = shapeOptions.replace; if (replaceData.color && shapePosData.color) { setParticlesOptionsColor(particlesOptions, shapePosData.color); } if (replaceData.opacity) { if (particlesOptions.opacity) { particlesOptions.opacity.value = shapePosData.opacity; } else { particlesOptions.opacity = { value: shapePosData.opacity, }; } } } else { position = null; } } if (position) { this.container.particles.addParticle(position, particlesOptions); } } } } exports.EmitterInstance = EmitterInstance;