"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { Path2D: () => Path2D, applyPath2DToCanvasRenderingContext: () => applyPath2DToCanvasRenderingContext, applyRoundRectToCanvasRenderingContext2D: () => applyRoundRectToCanvasRenderingContext2D, applyRoundRectToPath2D: () => applyRoundRectToPath2D, buildPath: () => buildPath, parsePath: () => parsePath, roundRect: () => roundRect }); module.exports = __toCommonJS(src_exports); // src/parse-path.ts var ARG_LENGTH = { a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0 }; var SEGMENT_PATTERN = /([astvzqmhlc])([^astvzqmhlc]*)/gi; var NUMBER = /-?[0-9]*\.?[0-9]+(?:e[-+]?\d+)?/gi; function parseValues(args) { const numbers = args.match(NUMBER); return numbers ? numbers.map(Number) : []; } function parsePath(path) { const data = []; const p = String(path).trim(); if (p[0] !== "M" && p[0] !== "m") { return data; } p.replace(SEGMENT_PATTERN, (_, command, args) => { const theArgs = parseValues(args); let type = command.toLowerCase(); let theCommand = command; if (type === "m" && theArgs.length > 2) { data.push([theCommand, ...theArgs.splice(0, 2)]); type = "l"; theCommand = theCommand === "m" ? "l" : "L"; } if (theArgs.length < ARG_LENGTH[type]) { return ""; } data.push([theCommand, ...theArgs.splice(0, ARG_LENGTH[type])]); while (theArgs.length >= ARG_LENGTH[type] && theArgs.length && ARG_LENGTH[type]) { data.push([theCommand, ...theArgs.splice(0, ARG_LENGTH[type])]); } return ""; }); return data; } // src/path2d.ts function rotatePoint(point, angle) { const nx = point.x * Math.cos(angle) - point.y * Math.sin(angle); const ny = point.y * Math.cos(angle) + point.x * Math.sin(angle); point.x = nx; point.y = ny; } function translatePoint(point, dx, dy) { point.x += dx; point.y += dy; } function scalePoint(point, s) { point.x *= s; point.y *= s; } var Path2D = class _Path2D { constructor(path) { this.commands = []; if (path && path instanceof _Path2D) { this.commands.push(...path.commands); } else if (path) { this.commands = parsePath(path); } } addPath(path) { if (path && path instanceof _Path2D) { this.commands.push(...path.commands); } } moveTo(x, y) { this.commands.push(["M", x, y]); } lineTo(x, y) { this.commands.push(["L", x, y]); } arc(x, y, r, start, end, ccw) { this.commands.push(["AC", x, y, r, start, end, !!ccw]); } arcTo(x1, y1, x2, y2, r) { this.commands.push(["AT", x1, y1, x2, y2, r]); } ellipse(x, y, rx, ry, angle, start, end, ccw) { this.commands.push(["E", x, y, rx, ry, angle, start, end, !!ccw]); } closePath() { this.commands.push(["Z"]); } bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) { this.commands.push(["C", cp1x, cp1y, cp2x, cp2y, x, y]); } quadraticCurveTo(cpx, cpy, x, y) { this.commands.push(["Q", cpx, cpy, x, y]); } rect(x, y, width, height) { this.commands.push(["R", x, y, width, height]); } roundRect(x, y, width, height, radii) { if (typeof radii === "undefined") { this.commands.push(["RR", x, y, width, height, 0]); } else { this.commands.push(["RR", x, y, width, height, radii]); } } }; function buildPath(ctx, commands) { let x = 0; let y = 0; let endAngle; let startAngle; let largeArcFlag; let sweepFlag; let endPoint; let midPoint; let angle; let lambda; let t1; let t2; let x1; let y1; let r; let rx; let ry; let w; let h; let pathType; let centerPoint; let ccw; let radii; let cpx = null; let cpy = null; let qcpx = null; let qcpy = null; let startPoint = null; let currentPoint = null; ctx.beginPath(); for (let i = 0; i < commands.length; ++i) { pathType = commands[i][0]; if (pathType !== "S" && pathType !== "s" && pathType !== "C" && pathType !== "c") { cpx = null; cpy = null; } if (pathType !== "T" && pathType !== "t" && pathType !== "Q" && pathType !== "q") { qcpx = null; qcpy = null; } let c; switch (pathType) { case "m": case "M": c = commands[i]; if (pathType === "m") { x += c[1]; y += c[2]; } else { x = c[1]; y = c[2]; } if (pathType === "M" || !startPoint) { startPoint = { x, y }; } ctx.moveTo(x, y); break; case "l": c = commands[i]; x += c[1]; y += c[2]; ctx.lineTo(x, y); break; case "L": c = commands[i]; x = c[1]; y = c[2]; ctx.lineTo(x, y); break; case "H": c = commands[i]; x = c[1]; ctx.lineTo(x, y); break; case "h": c = commands[i]; x += c[1]; ctx.lineTo(x, y); break; case "V": c = commands[i]; y = c[1]; ctx.lineTo(x, y); break; case "v": c = commands[i]; y += c[1]; ctx.lineTo(x, y); break; case "a": case "A": c = commands[i]; if (currentPoint === null) { throw new Error("This should never happen"); } if (pathType === "a") { x += c[6]; y += c[7]; } else { x = c[6]; y = c[7]; } rx = c[1]; ry = c[2]; angle = c[3] * Math.PI / 180; largeArcFlag = !!c[4]; sweepFlag = !!c[5]; endPoint = { x, y }; midPoint = { x: (currentPoint.x - endPoint.x) / 2, y: (currentPoint.y - endPoint.y) / 2 }; rotatePoint(midPoint, -angle); lambda = midPoint.x * midPoint.x / (rx * rx) + midPoint.y * midPoint.y / (ry * ry); if (lambda > 1) { lambda = Math.sqrt(lambda); rx *= lambda; ry *= lambda; } centerPoint = { x: rx * midPoint.y / ry, y: -(ry * midPoint.x) / rx }; t1 = rx * rx * ry * ry; t2 = rx * rx * midPoint.y * midPoint.y + ry * ry * midPoint.x * midPoint.x; if (sweepFlag !== largeArcFlag) { scalePoint(centerPoint, Math.sqrt((t1 - t2) / t2) || 0); } else { scalePoint(centerPoint, -Math.sqrt((t1 - t2) / t2) || 0); } startAngle = Math.atan2((midPoint.y - centerPoint.y) / ry, (midPoint.x - centerPoint.x) / rx); endAngle = Math.atan2(-(midPoint.y + centerPoint.y) / ry, -(midPoint.x + centerPoint.x) / rx); rotatePoint(centerPoint, angle); translatePoint(centerPoint, (endPoint.x + currentPoint.x) / 2, (endPoint.y + currentPoint.y) / 2); ctx.save(); ctx.translate(centerPoint.x, centerPoint.y); ctx.rotate(angle); ctx.scale(rx, ry); ctx.arc(0, 0, 1, startAngle, endAngle, !sweepFlag); ctx.restore(); break; case "C": c = commands[i]; cpx = c[3]; cpy = c[4]; x = c[5]; y = c[6]; ctx.bezierCurveTo(c[1], c[2], cpx, cpy, x, y); break; case "c": c = commands[i]; ctx.bezierCurveTo(c[1] + x, c[2] + y, c[3] + x, c[4] + y, c[5] + x, c[6] + y); cpx = c[3] + x; cpy = c[4] + y; x += c[5]; y += c[6]; break; case "S": c = commands[i]; if (cpx === null || cpy === null) { cpx = x; cpy = y; } ctx.bezierCurveTo(2 * x - cpx, 2 * y - cpy, c[1], c[2], c[3], c[4]); cpx = c[1]; cpy = c[2]; x = c[3]; y = c[4]; break; case "s": c = commands[i]; if (cpx === null || cpy === null) { cpx = x; cpy = y; } ctx.bezierCurveTo(2 * x - cpx, 2 * y - cpy, c[1] + x, c[2] + y, c[3] + x, c[4] + y); cpx = c[1] + x; cpy = c[2] + y; x += c[3]; y += c[4]; break; case "Q": c = commands[i]; qcpx = c[1]; qcpy = c[2]; x = c[3]; y = c[4]; ctx.quadraticCurveTo(qcpx, qcpy, x, y); break; case "q": c = commands[i]; qcpx = c[1] + x; qcpy = c[2] + y; x += c[3]; y += c[4]; ctx.quadraticCurveTo(qcpx, qcpy, x, y); break; case "T": c = commands[i]; if (qcpx === null || qcpy === null) { qcpx = x; qcpy = y; } qcpx = 2 * x - qcpx; qcpy = 2 * y - qcpy; x = c[1]; y = c[2]; ctx.quadraticCurveTo(qcpx, qcpy, x, y); break; case "t": c = commands[i]; if (qcpx === null || qcpy === null) { qcpx = x; qcpy = y; } qcpx = 2 * x - qcpx; qcpy = 2 * y - qcpy; x += c[1]; y += c[2]; ctx.quadraticCurveTo(qcpx, qcpy, x, y); break; case "z": case "Z": if (startPoint) { x = startPoint.x; y = startPoint.y; } startPoint = null; ctx.closePath(); break; case "AC": c = commands[i]; x = c[1]; y = c[2]; r = c[3]; startAngle = c[4]; endAngle = c[5]; ccw = c[6]; ctx.arc(x, y, r, startAngle, endAngle, ccw); break; case "AT": c = commands[i]; x1 = c[1]; y1 = c[2]; x = c[3]; y = c[4]; r = c[5]; ctx.arcTo(x1, y1, x, y, r); break; case "E": c = commands[i]; x = c[1]; y = c[2]; rx = c[3]; ry = c[4]; angle = c[5]; startAngle = c[6]; endAngle = c[7]; ccw = c[8]; ctx.save(); ctx.translate(x, y); ctx.rotate(angle); ctx.scale(rx, ry); ctx.arc(0, 0, 1, startAngle, endAngle, ccw); ctx.restore(); break; case "R": c = commands[i]; x = c[1]; y = c[2]; w = c[3]; h = c[4]; startPoint = { x, y }; ctx.rect(x, y, w, h); break; case "RR": c = commands[i]; x = c[1]; y = c[2]; w = c[3]; h = c[4]; radii = c[5]; startPoint = { x, y }; ctx.roundRect(x, y, w, h, radii); break; default: throw new Error(`Invalid path command: ${pathType}`); } if (!currentPoint) { currentPoint = { x, y }; } else { currentPoint.x = x; currentPoint.y = y; } } } // src/round-rect.ts function roundRect(x, y, width, height, radii = 0) { if (typeof radii === "number") { radii = [radii]; } if (Array.isArray(radii)) { if (radii.length === 0 || radii.length > 4) { throw new RangeError( `Failed to execute 'roundRect' on '${this.constructor.name}': ${radii.length} radii provided. Between one and four radii are necessary.` ); } radii.forEach((v) => { if (v < 0) { throw new RangeError( `Failed to execute 'roundRect' on '${this.constructor.name}': Radius value ${v} is negative.` ); } }); } else { return; } if (radii.length === 1 && radii[0] === 0) { this.rect(x, y, width, height); return; } const minRadius = Math.min(width, height) / 2; const tl = Math.min(minRadius, radii[0]); let tr = tl; let br = tl; let bl = tl; if (radii.length === 2) { tr = Math.min(minRadius, radii[1]); bl = tr; } if (radii.length === 3) { tr = Math.min(minRadius, radii[1]); bl = tr; br = Math.min(minRadius, radii[2]); } if (radii.length === 4) { tr = Math.min(minRadius, radii[1]); br = Math.min(minRadius, radii[2]); bl = Math.min(minRadius, radii[3]); } this.moveTo(x, y + height - bl); this.arcTo(x, y, x + tl, y, tl); this.arcTo(x + width, y, x + width, y + tr, tr); this.arcTo(x + width, y + height, x + width - br, y + height, br); this.arcTo(x, y + height, x, y + height - bl, bl); this.closePath(); } // src/apply.ts function applyPath2DToCanvasRenderingContext(CanvasRenderingContext2D) { if (!CanvasRenderingContext2D) return; const cClip = CanvasRenderingContext2D.prototype.clip; const cFill = CanvasRenderingContext2D.prototype.fill; const cStroke = CanvasRenderingContext2D.prototype.stroke; const cIsPointInPath = CanvasRenderingContext2D.prototype.isPointInPath; CanvasRenderingContext2D.prototype.clip = function clip(...args) { if (args[0] instanceof Path2D) { const path = args[0]; const fillRule2 = args[1] || "nonzero"; buildPath(this, path.commands); return cClip.apply(this, [fillRule2]); } const fillRule = args[0] || "nonzero"; return cClip.apply(this, [fillRule]); }; CanvasRenderingContext2D.prototype.fill = function fill(...args) { if (args[0] instanceof Path2D) { const path = args[0]; const fillRule2 = args[1] || "nonzero"; buildPath(this, path.commands); return cFill.apply(this, [fillRule2]); } const fillRule = args[0] || "nonzero"; return cFill.apply(this, [fillRule]); }; CanvasRenderingContext2D.prototype.stroke = function stroke(path) { if (path) { buildPath(this, path.commands); } cStroke.apply(this); }; CanvasRenderingContext2D.prototype.isPointInPath = function isPointInPath(...args) { if (args[0] instanceof Path2D) { const path = args[0]; const x = args[1]; const y = args[2]; const fillRule = args[3] || "nonzero"; buildPath(this, path.commands); return cIsPointInPath.apply(this, [x, y, fillRule]); } return cIsPointInPath.apply(this, args); }; } function applyRoundRectToCanvasRenderingContext2D(CanvasRenderingContext2D) { if (CanvasRenderingContext2D && !CanvasRenderingContext2D.prototype.roundRect) { CanvasRenderingContext2D.prototype.roundRect = roundRect; } } function applyRoundRectToPath2D(P2D) { if (P2D && !P2D.prototype.roundRect) { P2D.prototype.roundRect = roundRect; } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Path2D, applyPath2DToCanvasRenderingContext, applyRoundRectToCanvasRenderingContext2D, applyRoundRectToPath2D, buildPath, parsePath, roundRect });