UNPKG

@tsparticles/plugin-polygon-mask

Version:

tsParticles polygon mask plugin

118 lines (117 loc) 4.54 kB
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); }