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.

338 lines (337 loc) 12.5 kB
import { clear, colorToHsl, colorToRgb, deepExtend, drawConnectLine, drawGrabLine, drawParticle, drawParticlePlugin, drawPlugin, getRangeValue, getStyleFromHsl, getStyleFromRgb, gradient, paintBase, } from "../Utils"; import { Constants } from "./Utils"; /** * Canvas manager * @category Core */ export class Canvas { /** * Constructor of canvas manager * @param container the parent container */ constructor(container) { this.container = container; this.size = { height: 0, width: 0, }; this.context = null; this.generatedCanvas = false; } /* ---------- tsParticles functions - canvas ------------ */ /** * Initializes the canvas element */ init() { this.resize(); this.initStyle(); this.initCover(); this.initTrail(); this.initBackground(); this.paint(); } loadCanvas(canvas) { var _a; if (this.generatedCanvas) { (_a = this.element) === null || _a === void 0 ? void 0 : _a.remove(); } this.generatedCanvas = canvas.dataset && Constants.generatedAttribute in canvas.dataset ? canvas.dataset[Constants.generatedAttribute] === "true" : this.generatedCanvas; this.element = canvas; this.originalStyle = deepExtend({}, this.element.style); this.size.height = canvas.offsetHeight; this.size.width = canvas.offsetWidth; this.context = this.element.getContext("2d"); this.container.retina.init(); this.initBackground(); } destroy() { var _a; if (this.generatedCanvas) { (_a = this.element) === null || _a === void 0 ? void 0 : _a.remove(); } this.draw((ctx) => { clear(ctx, this.size); }); } /** * Paints the canvas background */ paint() { const options = this.container.actualOptions; this.draw((ctx) => { if (options.backgroundMask.enable && options.backgroundMask.cover) { clear(ctx, this.size); this.paintBase(this.coverColorStyle); } else { this.paintBase(); } }); } /** * Clears the canvas content */ clear() { const options = this.container.actualOptions; const trail = options.particles.move.trail; if (options.backgroundMask.enable) { this.paint(); } else if (trail.enable && trail.length > 0 && this.trailFillColor) { this.paintBase(getStyleFromRgb(this.trailFillColor, 1 / trail.length)); } else { this.draw((ctx) => { clear(ctx, this.size); }); } } async windowResize() { if (!this.element) { return; } const container = this.container; this.resize(); const needsRefresh = container.updateActualOptions(); /* density particles enabled */ container.particles.setDensity(); for (const [, plugin] of container.plugins) { if (plugin.resize !== undefined) { plugin.resize(); } } if (needsRefresh) { await container.refresh(); } } /** * Calculates the size of the canvas */ resize() { if (!this.element) { return; } const container = this.container; const pxRatio = container.retina.pixelRatio; const size = container.canvas.size; const oldSize = Object.assign({}, size); size.width = this.element.offsetWidth * pxRatio; size.height = this.element.offsetHeight * pxRatio; this.element.width = size.width; this.element.height = size.height; if (this.container.started) { this.resizeFactor = { width: size.width / oldSize.width, height: size.height / oldSize.height, }; } } drawConnectLine(p1, p2) { this.draw((ctx) => { var _a; const lineStyle = this.lineStyle(p1, p2); if (!lineStyle) { return; } const pos1 = p1.getPosition(); const pos2 = p2.getPosition(); drawConnectLine(ctx, (_a = p1.retina.linksWidth) !== null && _a !== void 0 ? _a : this.container.retina.linksWidth, lineStyle, pos1, pos2); }); } drawGrabLine(particle, lineColor, opacity, mousePos) { const container = this.container; this.draw((ctx) => { var _a; const beginPos = particle.getPosition(); drawGrabLine(ctx, (_a = particle.retina.linksWidth) !== null && _a !== void 0 ? _a : container.retina.linksWidth, beginPos, mousePos, lineColor, opacity); }); } drawParticle(particle, delta) { var _a, _b, _c, _d, _e, _f; if (particle.spawning || particle.destroyed) { return; } const pfColor = particle.getFillColor(); const psColor = (_a = particle.getStrokeColor()) !== null && _a !== void 0 ? _a : pfColor; if (!pfColor && !psColor) { return; } let [fColor, sColor] = this.getPluginParticleColors(particle); const pOptions = particle.options; const twinkle = pOptions.twinkle.particles; const twinkling = twinkle.enable && Math.random() < twinkle.frequency; if (!fColor || !sColor) { const twinkleRgb = colorToHsl(twinkle.color); if (!fColor) { fColor = twinkling && twinkleRgb !== undefined ? twinkleRgb : pfColor ? pfColor : undefined; } if (!sColor) { sColor = twinkling && twinkleRgb !== undefined ? twinkleRgb : psColor ? psColor : undefined; } } const options = this.container.actualOptions; const zIndexOptions = particle.options.zIndex; const zOpacityFactor = (1 - particle.zIndexFactor) ** zIndexOptions.opacityRate; const radius = particle.getRadius(); const opacity = twinkling ? getRangeValue(twinkle.opacity) : (_d = (_b = particle.bubble.opacity) !== null && _b !== void 0 ? _b : (_c = particle.opacity) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : 1; const strokeOpacity = (_f = (_e = particle.stroke) === null || _e === void 0 ? void 0 : _e.opacity) !== null && _f !== void 0 ? _f : opacity; const zOpacity = opacity * zOpacityFactor; const fillColorValue = fColor ? getStyleFromHsl(fColor, zOpacity) : undefined; if (!fillColorValue && !sColor) { return; } this.draw((ctx) => { const zSizeFactor = (1 - particle.zIndexFactor) ** zIndexOptions.sizeRate; const zStrokeOpacity = strokeOpacity * zOpacityFactor; const strokeColorValue = sColor ? getStyleFromHsl(sColor, zStrokeOpacity) : fillColorValue; if (radius <= 0) { return; } const container = this.container; for (const updater of container.particles.updaters) { if (updater.beforeDraw) { updater.beforeDraw(particle); } } drawParticle(this.container, ctx, particle, delta, fillColorValue, strokeColorValue, options.backgroundMask.enable, options.backgroundMask.composite, radius * zSizeFactor, zOpacity, particle.options.shadow, particle.gradient); for (const updater of container.particles.updaters) { if (updater.afterDraw) { updater.afterDraw(particle); } } }); } drawPlugin(plugin, delta) { this.draw((ctx) => { drawPlugin(ctx, plugin, delta); }); } drawParticlePlugin(plugin, particle, delta) { this.draw((ctx) => { drawParticlePlugin(ctx, plugin, particle, delta); }); } initBackground() { const options = this.container.actualOptions; const background = options.background; const element = this.element; const elementStyle = element === null || element === void 0 ? void 0 : element.style; if (!elementStyle) { return; } if (background.color) { const color = colorToRgb(background.color); elementStyle.backgroundColor = color ? getStyleFromRgb(color, background.opacity) : ""; } else { elementStyle.backgroundColor = ""; } elementStyle.backgroundImage = background.image || ""; elementStyle.backgroundPosition = background.position || ""; elementStyle.backgroundRepeat = background.repeat || ""; elementStyle.backgroundSize = background.size || ""; } draw(cb) { if (!this.context) { return; } return cb(this.context); } initCover() { const options = this.container.actualOptions; const cover = options.backgroundMask.cover; const color = cover.color; const coverRgb = colorToRgb(color); if (coverRgb) { const coverColor = { r: coverRgb.r, g: coverRgb.g, b: coverRgb.b, a: cover.opacity, }; this.coverColorStyle = getStyleFromRgb(coverColor, coverColor.a); console.log(this.coverColorStyle); } } initTrail() { const options = this.container.actualOptions; const trail = options.particles.move.trail; const fillColor = colorToRgb(trail.fillColor); if (fillColor) { const trail = options.particles.move.trail; this.trailFillColor = { r: fillColor.r, g: fillColor.g, b: fillColor.b, a: 1 / trail.length, }; } } getPluginParticleColors(particle) { let fColor; let sColor; for (const [, plugin] of this.container.plugins) { if (!fColor && plugin.particleFillColor) { fColor = colorToHsl(plugin.particleFillColor(particle)); } if (!sColor && plugin.particleStrokeColor) { sColor = colorToHsl(plugin.particleStrokeColor(particle)); } if (fColor && sColor) { break; } } return [fColor, sColor]; } initStyle() { const element = this.element, options = this.container.actualOptions; if (!element) { return; } const originalStyle = this.originalStyle; if (options.fullScreen.enable) { this.originalStyle = deepExtend({}, element.style); element.style.setProperty("position", "fixed", "important"); element.style.setProperty("z-index", options.fullScreen.zIndex.toString(10), "important"); element.style.setProperty("top", "0", "important"); element.style.setProperty("left", "0", "important"); element.style.setProperty("width", "100%", "important"); element.style.setProperty("height", "100%", "important"); } else if (originalStyle) { element.style.position = originalStyle.position; element.style.zIndex = originalStyle.zIndex; element.style.top = originalStyle.top; element.style.left = originalStyle.left; element.style.width = originalStyle.width; element.style.height = originalStyle.height; } for (const key in options.style) { if (!key || !options.style) { continue; } const value = options.style[key]; if (!value) { continue; } element.style.setProperty(key, value, "important"); } } paintBase(baseColor) { this.draw((ctx) => { paintBase(ctx, this.size, baseColor); }); } lineStyle(p1, p2) { return this.draw((ctx) => { const options = this.container.actualOptions; const connectOptions = options.interactivity.modes.connect; return gradient(ctx, p1, p2, connectOptions.links.opacity); }); } }