UNPKG

@nmmty/lazycanvas

Version:

A simple way to interact with @napi-rs/canvas in an advanced way!

242 lines (241 loc) 9.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Gradient = void 0; const types_1 = require("../../types"); const LazyUtil_1 = require("../../utils/LazyUtil"); const utils_1 = require("../../utils/utils"); /** * Class representing a gradient with properties and methods to manipulate it. */ class Gradient { /** * The type of fill, which is always `Gradient`. */ fillType = types_1.FillType.Gradient; /** * The type of gradient (e.g., linear, radial, conic). */ type; /** * The points defining the gradient. */ points; /** * The color stops for the gradient. */ stops; /** * The angle of the gradient (optional, used for linear gradients). */ angle; /** * Constructs a new Gradient instance. * @param {Object} [opts] - Optional properties for the gradient. * @param {IGradient} [opts.props] - The gradient properties. */ constructor(opts) { this.type = opts?.props?.type || types_1.GradientType.Linear; this.points = opts?.props?.points || []; this.stops = opts?.props?.stops || []; this.angle = opts?.props?.angle || 0; } /** * Sets the type of the gradient. * @param {AnyGradientType} [type] - The type of the gradient (e.g., linear, radial, conic). * @returns {this} The current instance for chaining. */ setType(type) { this.type = type; return this; } /** * Adds points to the gradient. * @param {GradientPoint[]} [points] - The points to add to the gradient. * @returns {this} The current instance for chaining. */ addPoints(...points) { this.points.push(...points); return this; } /** * Sets the points of the gradient. * @param {GradientPoint[]} [points] - The points to set for the gradient. * @returns {this} The current instance for chaining. */ setPoints(...points) { this.points = points; return this; } /** * Removes points from the gradient by their indexes. * @param {number[]} [indexes] - The indexes of the points to remove. * @returns {this} The current instance for chaining. */ removePoints(...indexes) { this.points = this.points.filter((_, index) => !indexes.includes(index)); return this; } /** * Adds color stops to the gradient. * @param {GradientColorStop[]} [stops] - The color stops to add to the gradient. * @returns {this} The current instance for chaining. */ addStops(...stops) { this.stops.push(...stops); return this; } /** * Sets the color stops of the gradient. * @param {GradientColorStop[]} [stops] - The color stops to set for the gradient. * @returns {this} The current instance for chaining. */ setStops(...stops) { this.stops = stops; return this; } /** * Removes color stops from the gradient by their indexes. * @param {number[]} [indexes] - The indexes of the color stops to remove. * @returns {this} The current instance for chaining. */ removeStops(...indexes) { this.stops = this.stops.filter((_, index) => !indexes.includes(index)); return this; } /** * Sets the angle of the gradient (used for linear gradients). * @param {number} [angle] - The angle in degrees. * @returns {this} The current instance for chaining. */ setAngle(angle) { this.angle = angle; return this; } draw(ctx, opts = { debug: false }) { let gradientData = this.toJSON(); let gradient; if (opts.debug) LazyUtil_1.LazyLog.log('none', `Gradient:`, gradientData); const parse = (0, utils_1.parser)(ctx, ctx.canvas, opts.manager); const { x0, y0, x1, y1 } = parse.parseBatch({ x0: { v: gradientData.points[0]?.x || 0 }, y0: { v: gradientData.points[0]?.y || 0, options: LazyUtil_1.defaultArg.vl(true) }, x1: { v: gradientData.points[1]?.x || 0 }, y1: { v: gradientData.points[1]?.y || 0, options: LazyUtil_1.defaultArg.vl(true) } }); if (opts.debug) LazyUtil_1.LazyLog.log('none', `Gradient points:`, { x0, y0, x1, y1 }); switch (gradientData.type) { case types_1.GradientType.Linear: case "linear": if (gradientData.type === "linear" && (gradientData.angle || gradientData.angle === 0) && opts.layer && gradientData.points.length < 2) { const { width, height, x, y, align } = opts.layer; const cx = this.getPosition(x, width, align, 'x'); const cy = this.getPosition(y, height, align, 'y'); if (opts.debug) LazyUtil_1.LazyLog.log('none', `Center for angle calculation:`, { cx, cy }); const [p1, p2] = this.getLinearGradientPoints(cx, cy, width, height, gradientData.angle); if (opts.debug) LazyUtil_1.LazyLog.log('none', `Linear Gradient Points from angle:`, { p1, p2 }); gradient = ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y); } else { if (opts.debug) LazyUtil_1.LazyLog.log('none', `Linear Gradient created from points.`); gradient = ctx.createLinearGradient(x0, y0, x1 || x0, y1 || y0); } break; case types_1.GradientType.Radial: case "radial": gradient = ctx.createRadialGradient(x0, y0, gradientData.points[0].r || 0, x1 || x0, y1 || y0, gradientData.points[1].r || 0); break; case types_1.GradientType.Conic: case "conic": gradient = ctx.createConicGradient((gradientData.angle || 0) * (Math.PI / 180), x0, y0); break; default: if ((gradientData.angle || gradientData.angle === 0) && opts.layer) { const { width, height, x, y, align } = opts.layer; const cx = this.getPosition(x, width, align, 'x'); const cy = this.getPosition(y, height, align, 'y'); const [p1, p2] = this.getLinearGradientPoints(cx, cy, width, height, gradientData.angle); gradient = ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y); } else { gradient = ctx.createLinearGradient(x0, y0, x1 || x0, y1 || y0); } break; } for (let stop of gradientData.stops) { gradient.addColorStop(stop.offset, stop.color); } return gradient; } /** * Converts the gradient to a JSON representation. * @returns {IGradient} The JSON representation of the gradient. */ toJSON() { return { fillType: this.fillType, type: this.type, points: this.points, stops: this.stops, angle: this.angle }; } getLinearGradientPoints(cx, cy, w, h, angleInDegrees) { const angle = angleInDegrees * (Math.PI / 180); const x1 = cx; const y1 = cy - h / 2; const x2 = cx; const y2 = cy + h / 2; const cos = Math.cos(angle); const sin = Math.sin(angle); const x1r = cx + (x1 - cx) * cos - (y1 - cy) * sin; const y1r = cy + (x1 - cx) * sin + (y1 - cy) * cos; const x2r = cx + (x2 - cx) * cos - (y2 - cy) * sin; const y2r = cy + (x2 - cx) * sin + (y2 - cy) * cos; return [ { x: x1r, y: y1r }, { x: x2r, y: y2r } ]; } getPosition(pos, side, align, type = 'x') { switch (align) { case types_1.Centring.StartTop: case "start-top": return type === 'x' ? pos + (side / 2) : pos + (side / 2); case types_1.Centring.Start: case "start": return type === 'x' ? pos + (side / 2) : pos; case types_1.Centring.StartBottom: case "start-bottom": return type === 'x' ? pos + (side / 2) : pos - (side / 2); case types_1.Centring.CenterTop: case "center-top": return type === 'x' ? pos : pos - (side / 2); case types_1.Centring.Center: case "center": return type === 'x' ? pos : pos; case types_1.Centring.CenterBottom: case "center-bottom": return type === 'x' ? pos : pos - (side / 2); case types_1.Centring.EndTop: case "end-top": return type === 'x' ? pos - (side / 2) : pos + (side / 2); case types_1.Centring.End: case "end": return type === 'x' ? pos - (side / 2) : pos; case types_1.Centring.EndBottom: case "end-bottom": return type === 'x' ? pos - (side / 2) : pos - (side / 2); case types_1.Centring.None: case "none": return type === 'x' ? pos + (side / 2) : pos + (side / 2); default: throw new LazyUtil_1.LazyError(`Invalid centring type: ${align}`); } } } exports.Gradient = Gradient;