UNPKG

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.

371 lines (370 loc) 16 kB
import { CanvasUtils, ColorUtils, Constants, NumberUtils, Utils } from "../Utils"; export class Canvas { constructor(container) { this.container = container; this.size = { height: 0, width: 0, }; this.context = null; this.generatedCanvas = false; } init() { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m; this.resize(); const options = this.container.actualOptions; const element = this.element; if (element) { if (options.fullScreen.enable) { this.originalStyle = Utils.deepExtend({}, element.style); element.style.position = "fixed"; element.style.zIndex = options.fullScreen.zIndex.toString(10); element.style.top = "0"; element.style.left = "0"; element.style.width = "100%"; element.style.height = "100%"; } else { element.style.position = (_b = (_a = this.originalStyle) === null || _a === void 0 ? void 0 : _a.position) !== null && _b !== void 0 ? _b : ""; element.style.zIndex = (_d = (_c = this.originalStyle) === null || _c === void 0 ? void 0 : _c.zIndex) !== null && _d !== void 0 ? _d : ""; element.style.top = (_f = (_e = this.originalStyle) === null || _e === void 0 ? void 0 : _e.top) !== null && _f !== void 0 ? _f : ""; element.style.left = (_h = (_g = this.originalStyle) === null || _g === void 0 ? void 0 : _g.left) !== null && _h !== void 0 ? _h : ""; element.style.width = (_k = (_j = this.originalStyle) === null || _j === void 0 ? void 0 : _j.width) !== null && _k !== void 0 ? _k : ""; element.style.height = (_m = (_l = this.originalStyle) === null || _l === void 0 ? void 0 : _l.height) !== null && _m !== void 0 ? _m : ""; } } const cover = options.backgroundMask.cover; const color = cover.color; const trail = options.particles.move.trail; const coverRgb = ColorUtils.colorToRgb(color); this.coverColor = coverRgb !== undefined ? { r: coverRgb.r, g: coverRgb.g, b: coverRgb.b, a: cover.opacity, } : undefined; this.trailFillColor = ColorUtils.colorToRgb(trail.fillColor); this.initBackground(); this.paint(); } loadCanvas(canvas, generatedCanvas) { var _a; if (!canvas.className) { canvas.className = Constants.canvasClass; } if (this.generatedCanvas) { (_a = this.element) === null || _a === void 0 ? void 0 : _a.remove(); } this.generatedCanvas = generatedCanvas !== null && generatedCanvas !== void 0 ? generatedCanvas : this.generatedCanvas; this.element = canvas; this.originalStyle = Utils.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(); } if (this.context) { CanvasUtils.clear(this.context, this.size); } } paint() { const options = this.container.actualOptions; if (!this.context) { return; } if (options.backgroundMask.enable && options.backgroundMask.cover && this.coverColor) { CanvasUtils.clear(this.context, this.size); this.paintBase(ColorUtils.getStyleFromRgb(this.coverColor, this.coverColor.a)); } else { this.paintBase(); } } 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(ColorUtils.getStyleFromRgb(this.trailFillColor, 1 / trail.length)); } else if (this.context) { CanvasUtils.clear(this.context, this.size); } } windowResize() { if (!this.element) { return; } const container = this.container; this.resize(); container.actualOptions.setResponsive(this.size.width, container.retina.pixelRatio, container.options); container.particles.setDensity(); for (const [, plugin] of container.plugins) { if (plugin.resize !== undefined) { plugin.resize(); } } } resize() { if (!this.element) { return; } const container = this.container; const pxRatio = container.retina.pixelRatio; const size = container.canvas.size; const oldSize = { width: size.width, height: size.height, }; 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) { var _a; const ctx = this.context; if (!ctx) { return; } const lineStyle = this.lineStyle(p1, p2); if (!lineStyle) { return; } const pos1 = p1.getPosition(); const pos2 = p2.getPosition(); CanvasUtils.drawConnectLine(ctx, (_a = p1.linksWidth) !== null && _a !== void 0 ? _a : this.container.retina.linksWidth, lineStyle, pos1, pos2); } drawGrabLine(particle, lineColor, opacity, mousePos) { var _a; const container = this.container; const ctx = container.canvas.context; if (!ctx) { return; } const beginPos = particle.getPosition(); CanvasUtils.drawGrabLine(ctx, (_a = particle.linksWidth) !== null && _a !== void 0 ? _a : container.retina.linksWidth, beginPos, mousePos, lineColor, opacity); } drawParticleShadow(particle, mousePos) { if (!this.context) { return; } CanvasUtils.drawParticleShadow(this.container, this.context, particle, mousePos); } drawLinkTriangle(p1, link1, link2) { var _a; const container = this.container; const options = container.actualOptions; const p2 = link1.destination; const p3 = link2.destination; const triangleOptions = p1.options.links.triangles; const opacityTriangle = (_a = triangleOptions.opacity) !== null && _a !== void 0 ? _a : (link1.opacity + link2.opacity) / 2; if (opacityTriangle <= 0) { return; } const pos1 = p1.getPosition(); const pos2 = p2.getPosition(); const pos3 = p3.getPosition(); const ctx = this.context; if (!ctx) { return; } if (NumberUtils.getDistance(pos1, pos2) > container.retina.linksDistance || NumberUtils.getDistance(pos3, pos2) > container.retina.linksDistance || NumberUtils.getDistance(pos3, pos1) > container.retina.linksDistance) { return; } let colorTriangle = ColorUtils.colorToRgb(triangleOptions.color); if (!colorTriangle) { const linksOptions = p1.options.links; const linkColor = linksOptions.id !== undefined ? container.particles.linksColors.get(linksOptions.id) : container.particles.linksColor; colorTriangle = ColorUtils.getLinkColor(p1, p2, linkColor); } if (!colorTriangle) { return; } CanvasUtils.drawLinkTriangle(ctx, pos1, pos2, pos3, options.backgroundMask.enable, options.backgroundMask.composite, colorTriangle, opacityTriangle); } drawLinkLine(p1, link) { var _a, _b; const container = this.container; const options = container.actualOptions; const p2 = link.destination; let opacity = link.opacity; const pos1 = p1.getPosition(); const pos2 = p2.getPosition(); const ctx = this.context; if (!ctx) { return; } let colorLine; const twinkle = p1.options.twinkle.lines; if (twinkle.enable) { const twinkleFreq = twinkle.frequency; const twinkleRgb = ColorUtils.colorToRgb(twinkle.color); const twinkling = Math.random() < twinkleFreq; if (twinkling && twinkleRgb !== undefined) { colorLine = twinkleRgb; opacity = twinkle.opacity; } } if (!colorLine) { const linksOptions = p1.options.links; const linkColor = linksOptions.id !== undefined ? container.particles.linksColors.get(linksOptions.id) : container.particles.linksColor; colorLine = ColorUtils.getLinkColor(p1, p2, linkColor); } if (!colorLine) { return; } const width = (_a = p1.linksWidth) !== null && _a !== void 0 ? _a : container.retina.linksWidth; const maxDistance = (_b = p1.linksDistance) !== null && _b !== void 0 ? _b : container.retina.linksDistance; CanvasUtils.drawLinkLine(ctx, width, pos1, pos2, maxDistance, container.canvas.size, p1.options.links.warp, options.backgroundMask.enable, options.backgroundMask.composite, colorLine, opacity, p1.options.links.shadow); } drawParticle(particle, delta) { var _a, _b, _c, _d; if (((_a = particle.image) === null || _a === void 0 ? void 0 : _a.loaded) === false || particle.spawning || particle.destroyed) { return; } const pfColor = particle.getFillColor(); const psColor = (_b = particle.getStrokeColor()) !== null && _b !== void 0 ? _b : pfColor; if (!pfColor && !psColor) { return; } const options = this.container.actualOptions; const pOptions = particle.options; const twinkle = pOptions.twinkle.particles; const twinkleFreq = twinkle.frequency; const twinkleRgb = ColorUtils.colorToRgb(twinkle.color); const twinkling = twinkle.enable && Math.random() < twinkleFreq; const radius = particle.getRadius(); const opacity = twinkling ? twinkle.opacity : (_c = particle.bubble.opacity) !== null && _c !== void 0 ? _c : particle.opacity.value; const infectionStage = particle.infecter.infectionStage; const infection = options.infection; const infectionStages = infection.stages; const infectionColor = infectionStage !== undefined ? infectionStages[infectionStage].color : undefined; const infectionRgb = ColorUtils.colorToRgb(infectionColor); const fColor = twinkling && twinkleRgb !== undefined ? twinkleRgb : infectionRgb !== null && infectionRgb !== void 0 ? infectionRgb : (pfColor ? ColorUtils.hslToRgb(pfColor) : undefined); const sColor = twinkling && twinkleRgb !== undefined ? twinkleRgb : infectionRgb !== null && infectionRgb !== void 0 ? infectionRgb : (psColor ? ColorUtils.hslToRgb(psColor) : undefined); const fillColorValue = fColor !== undefined ? ColorUtils.getStyleFromRgb(fColor, opacity) : undefined; if (!this.context || (!fillColorValue && !sColor)) { return; } const strokeColorValue = sColor !== undefined ? ColorUtils.getStyleFromRgb(sColor, (_d = particle.stroke.opacity) !== null && _d !== void 0 ? _d : opacity) : fillColorValue; this.drawParticleLinks(particle); if (radius > 0) { CanvasUtils.drawParticle(this.container, this.context, particle, delta, fillColorValue, strokeColorValue, options.backgroundMask.enable, options.backgroundMask.composite, radius, opacity, particle.options.shadow); } } drawParticleLinks(particle) { if (!this.context) { return; } const container = this.container; const particles = container.particles; const pOptions = particle.options; if (particle.links.length > 0) { this.context.save(); const p1Links = particle.links.filter((l) => { const linkFreq = container.particles.getLinkFrequency(particle, l.destination); return linkFreq <= pOptions.links.frequency; }); for (const link of p1Links) { const p2 = link.destination; if (pOptions.links.triangles.enable) { const links = p1Links.map((l) => l.destination); const vertices = p2.links.filter((t) => { const linkFreq = container.particles.getLinkFrequency(p2, t.destination); return linkFreq <= p2.options.links.frequency && links.indexOf(t.destination) >= 0; }); if (vertices.length) { for (const vertex of vertices) { const p3 = vertex.destination; const triangleFreq = particles.getTriangleFrequency(particle, p2, p3); if (triangleFreq > pOptions.links.triangles.frequency) { continue; } this.drawLinkTriangle(particle, link, vertex); } } } if (link.opacity > 0 && container.retina.linksWidth > 0) { this.drawLinkLine(particle, link); } } this.context.restore(); } } drawPlugin(plugin, delta) { if (!this.context) { return; } CanvasUtils.drawPlugin(this.context, plugin, delta); } drawLight(mousePos) { if (!this.context) { return; } CanvasUtils.drawLight(this.container, this.context, mousePos); } paintBase(baseColor) { if (!this.context) { return; } CanvasUtils.paintBase(this.context, this.size, baseColor); } lineStyle(p1, p2) { if (!this.context) { return; } const options = this.container.actualOptions; const connectOptions = options.interactivity.modes.connect; return CanvasUtils.gradient(this.context, p1, p2, connectOptions.links.opacity); } 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 = ColorUtils.colorToRgb(background.color); elementStyle.backgroundColor = color ? ColorUtils.getStyleFromRgb(color, background.opacity) : ""; } else { elementStyle.backgroundColor = ""; } elementStyle.backgroundImage = background.image || ""; elementStyle.backgroundPosition = background.position || ""; elementStyle.backgroundRepeat = background.repeat || ""; elementStyle.backgroundSize = background.size || ""; } }