@nmmty/lazycanvas
Version:
A simple way to interact with @napi-rs/canvas in an advanced way!
242 lines (241 loc) • 9.47 kB
JavaScript
"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;