canvafy
Version:
Make configurable canvas easily with Canvafy
343 lines (306 loc) • 11 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const { createCanvas, loadImage, GlobalFonts } = require('@napi-rs/canvas');
/**
* @typedef {object} LevelUp
* @see {LevelUp}
* @example const levelUpCard = await new canvafy.LevelUp()
* @type {Class}
*/
module.exports = class LevelUp {
constructor(options) {
this.font = { name: options?.font?.name ?? "Poppins", path: options?.font?.path };
this.avatar = "https://cdn.discordapp.com/embed/avatars/0.png";
this.background = {
type: "color",
background: "#23272a"
};
this.title = {
data: "Welcome",
color: "#fff",
size: 36
};
this.description = {
data: "Welcome to this server, go read the rules please!",
color: "#a7b9c5",
size: 26
};
this.overlay_opacity = 0;
this.levels = {
oldLevel: 0,
newLevel: 1
}
this.border;
this.avatar_border = "#2a2e35";
}
/**
* .setAvatar
* @param {string} image Set User Avatar URL
* @returns {LevelUp}
* @example setAvatar("https://someone-image.png")
*/
setAvatar(image) {
this.avatar = image;
return this;
}
/**
* .setAvatarBorder
* @param {string} color Set Avatar Avatar Border Color
* @returns {LevelUp}
* @example setAvatarBorder("#fff")
*/
setAvatarBorder(color) {
if (color) {
if (/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(color)) {
this.avatar_border = color;
return this;
} else {
throw new Error("Invalid color for the argument in the setBorder method. You must give a hexadecimal color.")
}
} else {
throw new Error("You must give a hexadecimal color as the argument of setBorder method.");
}
}
/**
* .setBackground
* @param {string} type "image" or "color"
* @param {string|Buffer|Image} value "url" or "hexcolor"
* @returns {LevelUp}
* @example setBackground("image","https://someone-image.png")
* @example setBackground("color","#000")
*/
setBackground(type, value) {
if (type === 'color') {
if (value) {
if (/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(value)) {
this.background.type = "color";
this.background.background = value;
return this;
} else {
throw new Error("Invalid color for the second argument in setForeground method. You must give a hexadecimal color.");
}
} else {
throw new Error("You must give a hexadecimal color as a second argument of setBackground method.");
}
} else if (type === 'image') {
if (value) {
this.background.type = "image";
this.background.background = value;
return this;
} else {
throw new Error("You must give a background URL as a second argument.");
}
} else {
throw new Error("The first argument of setBackground must be 'color' or 'image'.");
}
}
/**
* .setBorder
* @param {string} color "hexcolor"
* @returns {LevelUp}
* @example setBorder("#fff")
*/
setBorder(color) {
if (color) {
if (/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(color)) {
this.border = color;
return this;
} else {
throw new Error("Invalid color for the argument in the setBorder method. You must give a hexadecimal color.")
}
} else {
throw new Error("You must give a hexadecimal color as the argument of setBorder method.");
}
}
/**
* .setRank
* @param {number} oldLevel Old Level Number
* @param {number} newLevel New Level Number
* @returns {LevelUp}
* @example setLevels(5,6)
*/
setLevels(oldLevel, newLevel) {
if (typeof oldLevel !== "number") throw new Error("The first argument of setLevels method is not a number.");
this.levels.oldLevel = oldLevel;
if (typeof newLevel !== "number") throw new Error("The second argument of setLevels method is not a number.");
this.levels.newLevel = newLevel;
return this;
}
/**
* .setOverlayOpacity
* @param {number} opacity must be between 0 and 1
* @returns {LevelUp}
* @example setOverlayOpacity(0.7)
*/
setOverlayOpacity(opacity = 0) {
if (opacity) {
if (opacity >= 0 && opacity <= 1) {
this.overlay_opacity = opacity;
return this;
} else {
throw new Error("The value of the opacity of setOverlayOpacity method must be between 0 and 1 (0 and 1 included).");
}
}
}
/**
* .setUsername
* @param {string} text Username
* @param {string} color "hexcolor"
* @returns {LevelUp}
* @example setUsername("fivesobes")
* @example setUsername("fivesobes","#ff0000")
*/
setUsername(text, color = "#fff") {
if (text) {
this.title.data = text;
if (color) {
if (/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/.test(color)) {
this.title.color = color;
}
}
} else {
throw new Error("You must give a text as the first argument of setUsername method.");
}
return this;
}
async build() {
if (this.font.path) GlobalFonts.registerFromPath(this.font.path, this.font.name);
const canvas = createCanvas(600, 150);
const ctx = canvas.getContext("2d");
const abbreviateNumber = (value) => {
var newValue = value;
if (value >= 1000) {
var suffixes = ["", "K", "M", "B","T"];
var suffixNum = Math.floor( (""+value).length/3 );
var shortValue = '';
for (var precision = 2; precision >= 1; precision--) {
shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
if (dotLessShortValue.length <= 2) { break; }
}
if (shortValue % 1 != 0) shortValue = shortValue.toFixed(1);
newValue = shortValue+suffixes[suffixNum];
}
return newValue;
}
if(this.border){
ctx.beginPath();
ctx.lineWidth = 8;
ctx.strokeStyle = this.border;
ctx.moveTo(55, 15);
ctx.lineTo(canvas.width - 55, 15);
ctx.quadraticCurveTo(canvas.width - 20, 20, canvas.width - 15, 55);
ctx.lineTo(canvas.width - 15, canvas.height - 55);
ctx.quadraticCurveTo(canvas.width - 20, canvas.height - 20, canvas.width - 55, canvas.height - 15);
ctx.lineTo(55, canvas.height - 15);
ctx.quadraticCurveTo(20, canvas.height - 20, 15, canvas.height - 55);
ctx.lineTo(15, 55);
ctx.quadraticCurveTo(20, 20, 55, 15);
ctx.lineTo(56, 15);
ctx.stroke();
ctx.closePath();
}
ctx.beginPath();
ctx.moveTo(65, 25);
ctx.lineTo(canvas.width - 65, 25);
ctx.quadraticCurveTo(canvas.width - 25, 25, canvas.width - 25, 65);
ctx.lineTo(canvas.width - 25, canvas.height - 65);
ctx.quadraticCurveTo(canvas.width - 25, canvas.height - 25, canvas.width - 65, canvas.height - 25);
ctx.lineTo(65, canvas.height - 25);
ctx.quadraticCurveTo(25, canvas.height - 25, 25, canvas.height - 65);
ctx.lineTo(25, 65);
ctx.quadraticCurveTo(25, 25, 65, 25);
ctx.lineTo(66, 25);
ctx.closePath();
ctx.clip();
ctx.globalAlpha = 1;
if (this.background.type === "color") {
ctx.beginPath();
ctx.fillStyle = this.background.background;
ctx.fillRect(10, 10, canvas.width - 20, canvas.height - 20)
} else if (this.background.type === "image") {
try {
ctx.drawImage(await loadImage(this.background.background), 10, 10, canvas.width - 20, canvas.height - 20);
} catch {
throw new Error("The image given in the second parameter of the setBackground method is not valid or you are not connected to the internet.");
}
}
ctx.beginPath();
ctx.globalAlpha = this.overlay_opacity;
ctx.fillStyle = "#000";
ctx.moveTo(65, 35);
ctx.lineTo(canvas.width - 65, 35);
ctx.quadraticCurveTo(canvas.width - 35, 35, canvas.width - 35, 65);
ctx.lineTo(canvas.width - 35, canvas.height - 65);
ctx.quadraticCurveTo(canvas.width - 35, canvas.height - 35, canvas.width - 65, canvas.height - 35);
ctx.lineTo(65, canvas.height - 35);
ctx.quadraticCurveTo(35, canvas.height - 35, 35, canvas.height - 65);
ctx.lineTo(35, 65);
ctx.quadraticCurveTo(35, 35, 65, 35);
ctx.fill();
ctx.closePath();
ctx.font = `${this.title.size}px ${this.font.name} Bold`;
ctx.globalAlpha = 1;
ctx.fillStyle = this.title.color;
ctx.textAlign = "left";
ctx.fillText(this.title.data.length > 10 ? this.title.data.substring(0,10)+".." : this.title.data, 133, 85);
ctx.beginPath();
ctx.globalAlpha = 1;
ctx.lineWidth = 5;
ctx.strokeStyle = this.avatar_border;
ctx.arc(80, 75, 46, 0, Math.PI * 2);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.globalAlpha = 1;
ctx.lineWidth = 5;
ctx.shadowBlur = 9;
ctx.shadowColor = this.avatar_border;
ctx.shadowOffsetY = 0;
ctx.shadowOffsetX = 0;
ctx.strokeStyle = this.avatar_border;
ctx.arc(410, 75, 30, 0, Math.PI * 2);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.globalAlpha = 1;
ctx.lineWidth = 5;
ctx.shadowBlur = 9;
ctx.shadowColor = this.avatar_border;
ctx.shadowOffsetY = 0;
ctx.shadowOffsetX = 0;
ctx.strokeStyle = this.avatar_border;
ctx.arc(520, 75, 30, 0, Math.PI * 2);
ctx.stroke();
ctx.closePath();
ctx.font = `60px ${this.font.name} Bold`;
ctx.globalAlpha = 1;
ctx.fillStyle = this.avatar_border;
ctx.shadowBlur = 9;
ctx.shadowColor = this.avatar_border;
ctx.shadowOffsetY = 0;
ctx.shadowOffsetX = 0;
ctx.textAlign = "center";
ctx.fillText(">", 465, 95);
ctx.font = `30px ${this.font.name} Bold`;
ctx.globalAlpha = 1;
ctx.fillStyle = "#f0f0f0";
ctx.textAlign = "center";
ctx.fillText(`${abbreviateNumber(this.levels.oldLevel)}`, 410, 85);
ctx.font = `30px ${this.font.name} Bold`;
ctx.globalAlpha = 1;
ctx.fillStyle = "#f0f0f0";
ctx.textAlign = "center";
ctx.fillText(`${abbreviateNumber(this.levels.newLevel)}`, 520, 85);
ctx.beginPath();
ctx.arc(80, 75, 40, 0, Math.PI * 2);
ctx.closePath();
ctx.clip();
try {
ctx.drawImage(await loadImage(this.avatar), 93 - 60, 32, 90, 90);
} catch {
throw new Error("The image given in the argument of the setAvatar method is not valid or you are not connected to the internet.");
}
return canvas.toBuffer('image/png');
}
};