UNPKG

@tsparticles/plugin-polygon-mask

Version:

tsParticles polygon mask plugin

123 lines (122 loc) 4.7 kB
import { Vector, double, getDistances, getStyleFromRgb, rangeColorToRgb, squareExp, } from "@tsparticles/engine"; const inSegmentRange = { min: 0, max: 1, }; export function drawPolygonMask(pluginManager, context, rawData, stroke, hdr = false) { const color = rangeColorToRgb(pluginManager, stroke.color); if (!color) { return; } const firstIndex = 0, firstItem = rawData[firstIndex]; if (!firstItem) { return; } 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, hdr); context.lineWidth = stroke.width; context.stroke(); } export function drawPolygonMaskPath(pluginManager, context, path, stroke, position, hdr = false) { 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(pluginManager, stroke.color); if (!color) { return; } context.strokeStyle = getStyleFromRgb(color, hdr, 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 = globalThis.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; default: 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); }