@tsparticles/plugin-polygon-mask
Version:
tsParticles polygon mask plugin
118 lines (117 loc) • 4.54 kB
JavaScript
import { Vector, getDistances, getStyleFromRgb, rangeColorToRgb, } from "@tsparticles/engine";
const squareExp = 2, inSegmentRange = {
min: 0,
max: 1,
}, double = 2;
export function drawPolygonMask(engine, context, rawData, stroke) {
const color = rangeColorToRgb(engine, stroke.color);
if (!color) {
return;
}
const firstIndex = 0, firstItem = rawData[firstIndex];
context.beginPath();
context.moveTo(firstItem.x, firstItem.y);
for (const item of rawData) {
context.lineTo(item.x, item.y);
}
context.closePath();
context.strokeStyle = getStyleFromRgb(color);
context.lineWidth = stroke.width;
context.stroke();
}
export function drawPolygonMaskPath(engine, context, path, stroke, position) {
const defaultTransform = {
a: 1,
b: 0,
c: 0,
d: 1,
};
context.setTransform(defaultTransform.a, defaultTransform.b, defaultTransform.c, defaultTransform.d, position.x, position.y);
const color = rangeColorToRgb(engine, stroke.color);
if (!color) {
return;
}
context.strokeStyle = getStyleFromRgb(color, stroke.opacity);
context.lineWidth = stroke.width;
context.stroke(path);
context.resetTransform();
}
export function parsePaths(paths, scale, offset) {
const res = [], defaultCount = 0;
for (const path of paths) {
const segments = path.element.pathSegList, len = segments?.numberOfItems ?? defaultCount, p = {
x: 0,
y: 0,
};
for (let i = 0; i < len; i++) {
const segment = segments?.getItem(i), svgPathSeg = window.SVGPathSeg;
switch (segment?.pathSegType) {
case svgPathSeg.PATHSEG_MOVETO_ABS:
case svgPathSeg.PATHSEG_LINETO_ABS:
case svgPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
case svgPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
case svgPathSeg.PATHSEG_ARC_ABS:
case svgPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
case svgPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: {
const absSeg = segment;
p.x = absSeg.x;
p.y = absSeg.y;
break;
}
case svgPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
p.x = segment.x;
break;
case svgPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
p.y = segment.y;
break;
case svgPathSeg.PATHSEG_LINETO_REL:
case svgPathSeg.PATHSEG_MOVETO_REL:
case svgPathSeg.PATHSEG_CURVETO_CUBIC_REL:
case svgPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
case svgPathSeg.PATHSEG_ARC_REL:
case svgPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
case svgPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: {
const relSeg = segment;
p.x += relSeg.x;
p.y += relSeg.y;
break;
}
case svgPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
p.x += segment.x;
break;
case svgPathSeg.PATHSEG_LINETO_VERTICAL_REL:
p.y += segment.y;
break;
case svgPathSeg.PATHSEG_UNKNOWN:
case svgPathSeg.PATHSEG_CLOSEPATH:
continue;
}
res.push({
x: p.x * scale + offset.x,
y: p.y * scale + offset.y,
});
}
}
return res;
}
export function calcClosestPointOnSegment(s1, s2, pos) {
const { dx: dx1, dy: dy1 } = getDistances(pos, s1), { dx: dx2, dy: dy2 } = getDistances(s2, s1), t = (dx1 * dx2 + dy1 * dy2) / (dx2 ** squareExp + dy2 ** squareExp), res = {
x: s1.x + dx2 * t,
y: s1.y + dy2 * t,
isOnSegment: t >= inSegmentRange.min && t <= inSegmentRange.max,
};
if (t < inSegmentRange.min) {
res.x = s1.x;
res.y = s1.y;
}
else if (t > inSegmentRange.max) {
res.x = s2.x;
res.y = s2.y;
}
return res;
}
export function segmentBounce(start, stop, velocity) {
const { dx, dy } = getDistances(start, stop), wallAngle = Math.atan2(dy, dx), wallNormal = Vector.create(Math.sin(wallAngle), -Math.cos(wallAngle)), d = double * (velocity.x * wallNormal.x + velocity.y * wallNormal.y);
wallNormal.multTo(d);
velocity.subFrom(wallNormal);
}