@tsparticles/path-svg
Version:
tsParticles svg path
146 lines (145 loc) • 6.55 kB
JavaScript
import { PixelMode, Vector, getPosition, getRandom, half, randomInRange, } from "@tsparticles/engine";
var SVGPathDirection;
(function (SVGPathDirection) {
SVGPathDirection[SVGPathDirection["normal"] = 0] = "normal";
SVGPathDirection[SVGPathDirection["reverse"] = 1] = "reverse";
})(SVGPathDirection || (SVGPathDirection = {}));
const defaultSpeed = 1, minStep = 0, minIndex = 0, minWidth = 0, minScale = 1;
export class SVGPathGenerator {
constructor() {
this._paths = [];
this._reverse = false;
this._size = { width: 0, height: 0 };
this._scale = 1;
this._offset = { x: 0, y: 0, mode: PixelMode.percent };
this._width = 0;
}
generate(particle, delta) {
const container = particle.container, pxRatio = container.retina.pixelRatio;
if (particle.svgDirection === undefined) {
particle.svgDirection = getRandom() > half ? SVGPathDirection.normal : SVGPathDirection.reverse;
}
if (particle.svgPathIndex === undefined) {
particle.svgPathIndex = Math.floor(getRandom() * this._paths.length);
}
if (particle.svgSpeed === undefined) {
particle.svgSpeed = particle.velocity.mult((particle.retina.moveSpeed ?? defaultSpeed) * half).length;
}
if (particle.svgStep === undefined) {
particle.svgStep = randomInRange({ min: 0, max: this._paths[particle.svgPathIndex].length }) * pxRatio;
}
if (particle.svgOffset === undefined) {
particle.svgOffset = {
width: randomInRange({ min: -this._width * half, max: this._width * half }) * pxRatio,
height: randomInRange({ min: -this._width * half, max: this._width * half }) * pxRatio,
};
}
if (particle.svgInitialPosition === undefined) {
particle.svgInitialPosition = { ...particle.position };
}
particle.velocity.x = 0;
particle.velocity.y = 0;
if (particle.svgDirection === SVGPathDirection.normal) {
particle.svgStep += particle.svgSpeed * delta.factor;
}
else {
particle.svgStep -= particle.svgSpeed * delta.factor;
}
let path = this._paths[particle.svgPathIndex];
if (path) {
const pathLength = path.length, indexOffset = 1;
if (particle.svgStep >= pathLength) {
particle.svgPathIndex = particle.svgPathIndex + indexOffset;
if (particle.svgPathIndex >= this._paths.length) {
if (this._reverse) {
particle.svgPathIndex = this._paths.length - indexOffset;
particle.svgDirection = SVGPathDirection.reverse;
}
else {
particle.svgPathIndex = 0;
particle.svgStep = 0;
}
}
}
else if (particle.svgStep <= minStep) {
particle.svgPathIndex = particle.svgPathIndex - indexOffset;
if (particle.svgPathIndex < minIndex) {
if (this._reverse) {
particle.svgPathIndex = 0;
particle.svgDirection = SVGPathDirection.normal;
}
else {
particle.svgPathIndex = this._paths.length - indexOffset;
path = this._paths[particle.svgPathIndex];
particle.svgStep = path.length;
}
}
}
path = this._paths[particle.svgPathIndex];
}
if (path) {
const pathElement = path.element, pos = pathElement.getPointAtLength(particle.svgStep), canvasSize = particle.container.canvas.size, offset = getPosition(this._offset, canvasSize), scale = this._scale * pxRatio;
particle.position.x =
(pos.x - this._size.width * half) * scale +
particle.svgInitialPosition.x +
offset.x +
particle.svgOffset.width;
particle.position.y =
(pos.y - this._size.height * half) * scale +
particle.svgInitialPosition.y +
offset.y +
particle.svgOffset.height;
}
return Vector.origin;
}
init(container) {
const options = container.actualOptions.particles.move.path.options, position = options.position ?? this._offset;
this._reverse = options.reverse ?? this._reverse;
this._scale = options.scale ?? minScale;
this._offset.x = position.x;
this._offset.y = position.y;
this._offset.mode = position.mode;
this._width = options.width ?? minWidth;
if (options.url && !options.path) {
const url = options.url;
void (async () => {
const response = await fetch(url), data = await response.text();
const parser = new DOMParser(), doc = parser.parseFromString(data, "image/svg+xml"), firstIndex = 0, svg = doc.getElementsByTagName("svg")[firstIndex];
let svgPaths = svg.getElementsByTagName("path");
if (!svgPaths.length) {
svgPaths = doc.getElementsByTagName("path");
}
this._paths = [];
for (let i = 0; i < svgPaths.length; i++) {
const path = svgPaths.item(i);
if (path) {
this._paths.push({
element: path,
length: path.getTotalLength(),
});
}
}
this._size.height = parseFloat(svg.getAttribute("height") ?? "0");
this._size.width = parseFloat(svg.getAttribute("width") ?? "0");
})();
}
else if (options.path) {
const path = options.path;
this._paths = [];
for (const item of path.data) {
const element = document.createElementNS("http://www.w3.org/2000/svg", "path");
element.setAttribute("d", item);
this._paths.push({
element,
length: element.getTotalLength(),
});
}
this._size.height = path.size.height;
this._size.width = path.size.width;
}
}
reset() {
}
update() {
}
}