UNPKG

@tsparticles/effect-trail

Version:
76 lines (75 loc) 3.79 kB
import { defaultAlpha, double, getRangeValue, half, none, originPoint, } from "@tsparticles/engine"; const minTrailLength = 2, trailLengthOffset = 1, minWidth = -1, defaultLength = 10; const defaultTransform = { a: 1, b: 0, c: 0, d: 1, }; export class TrailDrawer { draw(data) { const { context, radius, particle, transformData } = data, diameter = radius * double, pxRatio = particle.container.retina.pixelRatio, currentPos = particle.getPosition(), trail = particle.trail; if (!trail || !particle.trailLength) { return; } const pathLength = particle.trailLength + radius; trail.push({ color: context.fillStyle ?? context.strokeStyle, position: { x: currentPos.x, y: currentPos.y, }, transformData: { ...data.transformData }, }); if (trail.length < minTrailLength) { return; } while (trail.length > pathLength) { trail.shift(); } const trailLength = Math.min(trail.length, pathLength), canvasSize = { width: particle.container.canvas.size.width + diameter, height: particle.container.canvas.size.height + diameter, }; let lastPos = trail[trailLength - trailLengthOffset].position; for (let i = trailLength; i > none; i--) { const step = trail[i - trailLengthOffset], position = step.position, stepTransformData = particle.trailTransform ? (step.transformData ?? defaultTransform) : defaultTransform; context.setTransform(stepTransformData.a, stepTransformData.b, stepTransformData.c, stepTransformData.d, position.x, position.y); context.beginPath(); context.moveTo(lastPos.x - position.x, lastPos.y - position.y); const warp = { x: (lastPos.x + canvasSize.width) % canvasSize.width, y: (lastPos.y + canvasSize.height) % canvasSize.height, }; if (Math.abs(lastPos.x - position.x) > canvasSize.width * half || Math.abs(lastPos.y - position.y) > canvasSize.height * half) { lastPos = position; continue; } context.lineTo(Math.abs(lastPos.x - position.x) > canvasSize.width * half ? warp.x : originPoint.x, Math.abs(lastPos.y - position.y) > canvasSize.height * half ? warp.y : originPoint.y); const width = Math.max((i / trailLength) * diameter, pxRatio, particle.trailMinWidth ?? minWidth), oldAlpha = context.globalAlpha; context.globalAlpha = particle.trailFade ? i / trailLength : defaultAlpha; context.lineWidth = particle.trailMaxWidth ? Math.min(width, particle.trailMaxWidth) : width; context.strokeStyle = step.color; context.stroke(); context.globalAlpha = oldAlpha; lastPos = position; } context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, currentPos.x, currentPos.y); } particleInit(container, particle) { particle.trail = []; const effectData = particle.effectData; particle.trailFade = effectData?.fade ?? true; particle.trailLength = getRangeValue(effectData?.length ?? defaultLength) * container.retina.pixelRatio; particle.trailMaxWidth = effectData?.maxWidth ? getRangeValue(effectData.maxWidth) * container.retina.pixelRatio : undefined; particle.trailMinWidth = effectData?.minWidth ? getRangeValue(effectData.minWidth) * container.retina.pixelRatio : undefined; particle.trailTransform = effectData?.transform ?? false; } }