const { createCanvas } = require('canvas'); const Chart = require('chart.js/auto'); const { testData } = require("./trash/testData"); const { formatSeconds } = require("./utils"); const moment = require('moment'); function prepareData(data) { const result = []; const grabFirstValue = (container) => { if (!container) return 0; for (const mapName of Object.keys(container)) { return container[mapName]; } return 0; }; const grabMapName = (container) => { if (!container) return ""; for (const mapName of Object.keys(container)) { return mapName; } return ""; }; for (const srvId of Object.keys(data.lastplay)) { const obj = {}; obj.srv_id = srvId; obj.server_name = data.servers[srvId].name; obj.lastplay = grabFirstValue(data.lastplay[srvId]); obj.lastplay_moment = moment.unix(obj.lastplay).format("DD-MM-YYYY HH:mm"); obj.gametime = grabFirstValue(data.gametime[srvId]); obj.map_name = grabMapName(data.lastplay[srvId]); result.push(obj); } return result; } function getTextAlignByPoint(p, r) { const dx = p.x - r.xCenter; const dy = p.y - r.yCenter; if (Math.abs(dx) < Math.abs(dy) * 0.1) { return 'center'; } if (dx > 0) { return 'left'; } return 'right'; } function getAlignedRectX(textAlign, x, width, padX) { if (textAlign === 'left') { return x - padX; } if (textAlign === 'right') { return x - width - padX; } return x - width / 2 - padX; } const customLabelsPlugin = { id: 'customLabelsPlugin', afterDraw(chart) { const { ctx, scales: { r } } = chart; const labels = chart.data.labels; ctx.save(); labels.forEach((label, i) => { const p = r.getPointPosition(i, r.drawingArea + 40); const align = getTextAlignByPoint(p, r); const lines = Array.isArray(label) ? label : [label]; const [mapName, serverName, playTime] = lines; ctx.textAlign = align; ctx.textBaseline = 'middle'; // 1 строка ctx.font = 'bold 16px Arial'; let w = ctx.measureText(mapName).width; let rx = getAlignedRectX(align, p.x, w, 6); ctx.fillStyle = '#395c78'; ctx.fillRect(rx, p.y - 28, w + 12, 22); ctx.fillStyle = '#ffffff'; ctx.fillText(mapName, p.x, p.y - 17); // 2 строка ctx.font = '14px Arial'; w = ctx.measureText(serverName).width; rx = getAlignedRectX(align, p.x, w, 6); ctx.fillStyle = '#0e0d0d'; ctx.fillText(serverName, p.x, p.y + 4); // 3 строка ctx.font = '14px Arial'; ctx.fillStyle = '#0e0d0d'; ctx.fillText(playTime, p.x, p.y + 24); }); ctx.restore(); } }; function generateChartData(d) { const chartData = { labels: [], datasets: [] }; const data = []; d .sort((a, b) => a.server_name.localeCompare(b.server_name, 'ru')) .forEach((val) => { chartData.labels.push( [ `${val.server_name}`, `${val.lastplay_moment}`, `Наиграно: ${formatSeconds(val.gametime)}` ] ); data.push(Math.pow(val.gametime || 0, 0.3)); }); chartData.datasets.push({ label: "Наиграно времени", data, borderColor: '#ff853e', backgroundColor: '#ff853e94', pointBackgroundColor: '#ff853e', pointBorderColor: '#ff853e' }); return { type: 'radar', data: chartData, plugins: [ { id: 'customCanvasBackgroundColor', beforeDraw: (chart) => { const { ctx, width, height } = chart; ctx.save(); ctx.globalCompositeOperation = 'destination-over'; ctx.fillStyle = '#f7f3f1'; ctx.fillRect(0, 0, width, height); ctx.restore(); } }, customLabelsPlugin ], options: { responsive: false, maintainAspectRatio: false, layout: { padding: 130 }, plugins: { legend: { display: false }, title: { display: false } }, scales: { r: { beginAtZero: true, grid: { color: '#6d6d6d' }, angleLines: { color: '#6d6d6d' }, ticks: { display: false }, pointLabels: { display: false, } } } } }; } function createChartOnData(testData) { const width = Number(process.env.W) || 900; const height = Number(process.env.H) || 700; const canvas = createCanvas(width, height); const ctx = canvas.getContext('2d'); const d = prepareData(testData); const chartConfig = generateChartData(d); new Chart(ctx, chartConfig); return canvas.createPNGStream(); } module.exports = { createChartOnData }; function test() { const stream = createChartOnData(testData); // Save the chart image as a file const fs = require('fs'); const out = fs.createWriteStream('chart.png'); stream.pipe(out); out.on('finish', () => console.log('The chart image was saved.')); } if (process.env.TEST) test()