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.

271 lines (270 loc) 10.4 kB
import { colorMix, colorToRgb, getStyleFromHsl, getStyleFromRgb } from "./ColorUtils"; import { getDistance, getDistances } from "./NumberUtils"; function drawLine(context, begin, end) { context.beginPath(); context.moveTo(begin.x, begin.y); context.lineTo(end.x, end.y); context.closePath(); } function drawTriangle(context, p1, p2, p3) { context.beginPath(); context.moveTo(p1.x, p1.y); context.lineTo(p2.x, p2.y); context.lineTo(p3.x, p3.y); context.closePath(); } export function paintBase(context, dimension, baseColor) { context.save(); context.fillStyle = baseColor !== null && baseColor !== void 0 ? baseColor : "rgba(0,0,0,0)"; context.fillRect(0, 0, dimension.width, dimension.height); context.restore(); } export function clear(context, dimension) { context.clearRect(0, 0, dimension.width, dimension.height); } export function drawLinkLine(context, width, begin, end, maxDistance, canvasSize, warp, backgroundMask, composite, colorLine, opacity, shadow) { let drawn = false; if (getDistance(begin, end) <= maxDistance) { drawLine(context, begin, end); drawn = true; } else if (warp) { let pi1; let pi2; const endNE = { x: end.x - canvasSize.width, y: end.y, }; const d1 = getDistances(begin, endNE); if (d1.distance <= maxDistance) { const yi = begin.y - (d1.dy / d1.dx) * begin.x; pi1 = { x: 0, y: yi }; pi2 = { x: canvasSize.width, y: yi }; } else { const endSW = { x: end.x, y: end.y - canvasSize.height, }; const d2 = getDistances(begin, endSW); if (d2.distance <= maxDistance) { const yi = begin.y - (d2.dy / d2.dx) * begin.x; const xi = -yi / (d2.dy / d2.dx); pi1 = { x: xi, y: 0 }; pi2 = { x: xi, y: canvasSize.height }; } else { const endSE = { x: end.x - canvasSize.width, y: end.y - canvasSize.height, }; const d3 = getDistances(begin, endSE); if (d3.distance <= maxDistance) { const yi = begin.y - (d3.dy / d3.dx) * begin.x; const xi = -yi / (d3.dy / d3.dx); pi1 = { x: xi, y: yi }; pi2 = { x: pi1.x + canvasSize.width, y: pi1.y + canvasSize.height }; } } } if (pi1 && pi2) { drawLine(context, begin, pi1); drawLine(context, end, pi2); drawn = true; } } if (!drawn) { return; } context.lineWidth = width; if (backgroundMask) { context.globalCompositeOperation = composite; } context.strokeStyle = getStyleFromRgb(colorLine, opacity); if (shadow.enable) { const shadowColor = colorToRgb(shadow.color); if (shadowColor) { context.shadowBlur = shadow.blur; context.shadowColor = getStyleFromRgb(shadowColor); } } context.stroke(); } export function drawLinkTriangle(context, pos1, pos2, pos3, backgroundMask, composite, colorTriangle, opacityTriangle) { drawTriangle(context, pos1, pos2, pos3); if (backgroundMask) { context.globalCompositeOperation = composite; } context.fillStyle = getStyleFromRgb(colorTriangle, opacityTriangle); context.fill(); } export function drawConnectLine(context, width, lineStyle, begin, end) { context.save(); drawLine(context, begin, end); context.lineWidth = width; context.strokeStyle = lineStyle; context.stroke(); context.restore(); } export function gradient(context, p1, p2, opacity) { const gradStop = Math.floor(p2.getRadius() / p1.getRadius()); const color1 = p1.getFillColor(); const color2 = p2.getFillColor(); if (!color1 || !color2) { return; } const sourcePos = p1.getPosition(); const destPos = p2.getPosition(); const midRgb = colorMix(color1, color2, p1.getRadius(), p2.getRadius()); const grad = context.createLinearGradient(sourcePos.x, sourcePos.y, destPos.x, destPos.y); grad.addColorStop(0, getStyleFromHsl(color1, opacity)); grad.addColorStop(gradStop > 1 ? 1 : gradStop, getStyleFromRgb(midRgb, opacity)); grad.addColorStop(1, getStyleFromHsl(color2, opacity)); return grad; } export function drawGrabLine(context, width, begin, end, colorLine, opacity) { context.save(); drawLine(context, begin, end); context.strokeStyle = getStyleFromRgb(colorLine, opacity); context.lineWidth = width; context.stroke(); context.restore(); } export function drawParticle(container, context, particle, delta, fillColorValue, strokeColorValue, backgroundMask, composite, radius, opacity, shadow, gradient) { var _a, _b, _c, _d, _e, _f; const pos = particle.getPosition(); const tiltOptions = particle.options.tilt; const rollOptions = particle.options.roll; context.save(); if (tiltOptions.enable || rollOptions.enable) { const roll = rollOptions.enable && particle.roll; const tilt = tiltOptions.enable && particle.tilt; const rollHorizontal = roll && (rollOptions.mode === "horizontal" || rollOptions.mode === "both"); const rollVertical = roll && (rollOptions.mode === "vertical" || rollOptions.mode === "both"); context.setTransform(rollHorizontal ? Math.cos(particle.roll.angle) : 1, tilt ? Math.cos(particle.tilt.value) * particle.tilt.cosDirection : 0, tilt ? Math.sin(particle.tilt.value) * particle.tilt.sinDirection : 0, rollVertical ? Math.sin(particle.roll.angle) : 1, pos.x, pos.y); } else { context.translate(pos.x, pos.y); } context.beginPath(); const angle = ((_b = (_a = particle.rotate) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : 0) + (particle.options.rotate.path ? particle.velocity.angle : 0); if (angle !== 0) { context.rotate(angle); } if (backgroundMask) { context.globalCompositeOperation = composite; } const shadowColor = particle.shadowColor; if (shadow.enable && shadowColor) { context.shadowBlur = shadow.blur; context.shadowColor = getStyleFromRgb(shadowColor); context.shadowOffsetX = shadow.offset.x; context.shadowOffsetY = shadow.offset.y; } if (gradient) { const gradientAngle = gradient.angle.value; const fillGradient = gradient.type === "radial" ? context.createRadialGradient(0, 0, 0, 0, 0, radius) : context.createLinearGradient(Math.cos(gradientAngle) * -radius, Math.sin(gradientAngle) * -radius, Math.cos(gradientAngle) * radius, Math.sin(gradientAngle) * radius); for (const color of gradient.colors) { fillGradient.addColorStop(color.stop, getStyleFromHsl({ h: color.value.h.value, s: color.value.s.value, l: color.value.l.value, }, (_d = (_c = color.opacity) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : opacity)); } context.fillStyle = fillGradient; } else { if (fillColorValue) { context.fillStyle = fillColorValue; } } const stroke = particle.stroke; context.lineWidth = (_e = particle.strokeWidth) !== null && _e !== void 0 ? _e : 0; if (strokeColorValue) { context.strokeStyle = strokeColorValue; } drawShape(container, context, particle, radius, opacity, delta); if (((_f = stroke === null || stroke === void 0 ? void 0 : stroke.width) !== null && _f !== void 0 ? _f : 0) > 0) { context.stroke(); } if (particle.close) { context.closePath(); } if (particle.fill) { context.fill(); } context.restore(); context.save(); if (tiltOptions.enable && particle.tilt) { context.setTransform(1, Math.cos(particle.tilt.value) * particle.tilt.cosDirection, Math.sin(particle.tilt.value) * particle.tilt.sinDirection, 1, pos.x, pos.y); } else { context.translate(pos.x, pos.y); } if (angle !== 0) { context.rotate(angle); } if (backgroundMask) { context.globalCompositeOperation = composite; } drawShapeAfterEffect(container, context, particle, radius, opacity, delta); context.restore(); } export function drawShape(container, context, particle, radius, opacity, delta) { if (!particle.shape) { return; } const drawer = container.drawers.get(particle.shape); if (!drawer) { return; } drawer.draw(context, particle, radius, opacity, delta, container.retina.pixelRatio); } export function drawShapeAfterEffect(container, context, particle, radius, opacity, delta) { if (!particle.shape) { return; } const drawer = container.drawers.get(particle.shape); if (!(drawer === null || drawer === void 0 ? void 0 : drawer.afterEffect)) { return; } drawer.afterEffect(context, particle, radius, opacity, delta, container.retina.pixelRatio); } export function drawPlugin(context, plugin, delta) { if (!plugin.draw) { return; } context.save(); plugin.draw(context, delta); context.restore(); } export function drawParticlePlugin(context, plugin, particle, delta) { if (plugin.drawParticle !== undefined) { context.save(); plugin.drawParticle(context, particle, delta); context.restore(); } } export function drawEllipse(context, particle, fillColorValue, radius, opacity, width, rotation, start, end) { const pos = particle.getPosition(); if (fillColorValue) { context.strokeStyle = getStyleFromHsl(fillColorValue, opacity); } if (width === 0) { return; } context.lineWidth = width; const rotationRadian = (rotation * Math.PI) / 180; context.beginPath(); context.ellipse(pos.x, pos.y, radius / 2, radius * 2, rotationRadian, start, end); context.stroke(); } export function alterHsl(color, type, value) { return { h: color.h, s: color.s, l: color.l + (type === "darken" ? -1 : 1) * value, }; }