125 lines
3.2 KiB
JavaScript
125 lines
3.2 KiB
JavaScript
const { createCanvas } = require("canvas");
|
|
const Chart = require("chart.js/auto");
|
|
const logger = require("../utils/logger");
|
|
|
|
const { backgroundColors, borderColors } = require("./canvas-colors");
|
|
const { isObject, defaultsDeep, isNumber } = require("lodash");
|
|
|
|
let isProcessing = false;
|
|
const requestQueue = [];
|
|
|
|
const processCanvasRequest = async (req, res) => {
|
|
try {
|
|
const { w, h, values, keys, override } = req.body;
|
|
logger.log("inbound-canvas-creation", "debug", "jsr", null, { w, h, values, keys, override });
|
|
|
|
// Set dimensions with defaults
|
|
const width = isNumber(w) ? w : 500;
|
|
const height = isNumber(h) ? h : 275;
|
|
|
|
const configuration = {
|
|
type: "doughnut",
|
|
data: {
|
|
labels: keys,
|
|
datasets: [
|
|
{
|
|
data: values,
|
|
backgroundColor: backgroundColors,
|
|
borderColor: borderColors,
|
|
borderWidth: 1
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
animation: false,
|
|
devicePixelRatio: 4,
|
|
responsive: false,
|
|
maintainAspectRatio: true,
|
|
circumference: 180,
|
|
rotation: -90,
|
|
plugins: {
|
|
legend: {
|
|
labels: {
|
|
boxWidth: 20,
|
|
font: {
|
|
family: "'Montserrat'",
|
|
size: 10,
|
|
style: "normal",
|
|
weight: "normal"
|
|
}
|
|
},
|
|
position: "left"
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// If we have a valid override object, merge it with the default configuration object.
|
|
// This allows for you to override the default configuration with a custom one.
|
|
const defaults = () => {
|
|
if (!override || !isObject(override)) {
|
|
return configuration;
|
|
}
|
|
return defaultsDeep(override, configuration);
|
|
};
|
|
|
|
// Generate chart
|
|
let canvas = createCanvas(width, height);
|
|
let ctx = canvas.getContext("2d");
|
|
let chart = new Chart(ctx, defaults());
|
|
const result = canvas.toDataURL();
|
|
|
|
chart.destroy();
|
|
canvas.width = 0;
|
|
canvas.height = 0;
|
|
ctx = null;
|
|
canvas = null;
|
|
chart = null;
|
|
|
|
res.status(200).send(result);
|
|
} catch (error) {
|
|
if (chart) chart.destroy();
|
|
if (canvas) {
|
|
canvas.width = 0;
|
|
canvas.height = 0;
|
|
}
|
|
ctx = null;
|
|
canvas = null;
|
|
chart = null;
|
|
|
|
logger.log("inbound-canvas-creation", "error", "jsr", null, { error: error.message, stack: error.stack });
|
|
res.status(500).send("Error generating canvas");
|
|
}
|
|
};
|
|
|
|
const processNextInQueue = async () => {
|
|
if (requestQueue.length === 0) {
|
|
isProcessing = false;
|
|
return;
|
|
}
|
|
|
|
const { req, res } = requestQueue.shift();
|
|
await processCanvasRequest(req, res);
|
|
processNextInQueue();
|
|
};
|
|
|
|
exports.canvastest = function (req, res) {
|
|
res.status(200).send("OK");
|
|
};
|
|
|
|
exports.canvas = async function (req, res) {
|
|
if (isProcessing) {
|
|
if (requestQueue.length >= 100) {
|
|
// Set a maximum queue size
|
|
return res.status(503).send("Server is busy. Please try again later.");
|
|
}
|
|
requestQueue.push({ req, res });
|
|
logger.log("inbound-canvas-creation-queue", "debug", "jsr", null, { queue: requestQueue.length });
|
|
return;
|
|
}
|
|
|
|
isProcessing = true;
|
|
await processCanvasRequest(req, res);
|
|
processNextInQueue();
|
|
};
|