|
|
|
@ -1,10 +1,9 @@ |
|
|
|
const { createCanvas, registerFont } = require('canvas'); |
|
|
|
const { createCanvas } = require('canvas'); |
|
|
|
const Chart = require('chart.js/auto'); |
|
|
|
|
|
|
|
const {testData} = require("./trash/testData"); |
|
|
|
const {formatSeconds} = require("./utils"); |
|
|
|
const { testData } = require("./trash/testData"); |
|
|
|
const { formatSeconds } = require("./utils"); |
|
|
|
const moment = require('moment'); |
|
|
|
const fs = require("fs"); |
|
|
|
|
|
|
|
function prepareData(data) { |
|
|
|
const result = []; |
|
|
|
@ -15,7 +14,7 @@ function prepareData(data) { |
|
|
|
return container[mapName]; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
const grabMapName = (container) => { |
|
|
|
if (!container) return ""; |
|
|
|
@ -23,103 +22,178 @@ function prepareData(data) { |
|
|
|
return mapName; |
|
|
|
} |
|
|
|
return ""; |
|
|
|
} |
|
|
|
//console.log(data)
|
|
|
|
}; |
|
|
|
|
|
|
|
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]) |
|
|
|
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 generateChartData(d) { |
|
|
|
const maxGametime = d.sort((a, b) => a.gametime - b.gametime).at(d.length - 1)["gametime"] |
|
|
|
console.log(maxGametime) |
|
|
|
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'; |
|
|
|
} |
|
|
|
|
|
|
|
let gametimeDelimiter = 1; |
|
|
|
for (const delimiter of [60, 3600, 3600 * 24]) { |
|
|
|
if (maxGametime > delimiter) |
|
|
|
gametimeDelimiter = delimiter; |
|
|
|
if (dx > 0) { |
|
|
|
return 'left'; |
|
|
|
} |
|
|
|
console.log(gametimeDelimiter) |
|
|
|
|
|
|
|
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 + 50); |
|
|
|
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) => b.gametime - a.gametime).forEach( |
|
|
|
(val) => { |
|
|
|
chartData.labels.push(`${val['server_name']}\n${val['lastplay_moment']}\nНаиграно: ${formatSeconds(val['gametime'])}`) |
|
|
|
data.push(val['gametime'] / gametimeDelimiter) |
|
|
|
} |
|
|
|
) |
|
|
|
}; |
|
|
|
|
|
|
|
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: data, |
|
|
|
}) |
|
|
|
|
|
|
|
const chartConfig = { |
|
|
|
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, |
|
|
|
|
|
|
|
borderColor: '#bd3b3b', |
|
|
|
//backgroundColor: '#FFFFFF',
|
|
|
|
layout: { |
|
|
|
padding: 20 |
|
|
|
padding: 110 |
|
|
|
}, |
|
|
|
|
|
|
|
plugins: { |
|
|
|
legend: { |
|
|
|
position: 'top', |
|
|
|
display: false |
|
|
|
}, |
|
|
|
title: { |
|
|
|
display: false, |
|
|
|
text: 'Chart.js Polar Area Chart With Centered Point Labels' |
|
|
|
display: false |
|
|
|
} |
|
|
|
}, |
|
|
|
scales: { |
|
|
|
r: { |
|
|
|
beginAtZero: true, |
|
|
|
grid: { |
|
|
|
color: '#ef9849' |
|
|
|
color: '#6d6d6d' |
|
|
|
}, |
|
|
|
angleLines: { |
|
|
|
color: '#f08149' |
|
|
|
color: '#6d6d6d' |
|
|
|
}, |
|
|
|
pointLabels: { |
|
|
|
display: true, |
|
|
|
//centerPointLabels: true,
|
|
|
|
padding: 44, |
|
|
|
font: { |
|
|
|
size: 16 |
|
|
|
}, |
|
|
|
backdropColor: "#395c78", |
|
|
|
backdropPadding: "1", |
|
|
|
color: "#f5e7de" |
|
|
|
ticks: { |
|
|
|
display: false |
|
|
|
}, |
|
|
|
|
|
|
|
pointLabels: { |
|
|
|
display: false, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
}; |
|
|
|
return chartConfig; |
|
|
|
} |
|
|
|
|
|
|
|
function createChartOnData(testData) { |
|
|
|
|
|
|
|
// Create a canvas and chart
|
|
|
|
const width = process.env.W || 900; |
|
|
|
const height = process.env.H || 700; |
|
|
|
const width = Number(process.env.W) || 900; |
|
|
|
const height = Number(process.env.H) || 700; |
|
|
|
|
|
|
|
const canvas = createCanvas(width, height); |
|
|
|
const ctx = canvas.getContext('2d'); |
|
|
|
@ -129,10 +203,10 @@ function createChartOnData(testData) { |
|
|
|
|
|
|
|
new Chart(ctx, chartConfig); |
|
|
|
|
|
|
|
return canvas.createPNGStream(); |
|
|
|
return canvas.createPNGStream(); |
|
|
|
} |
|
|
|
|
|
|
|
module.exports = {createChartOnData} |
|
|
|
module.exports = { createChartOnData }; |
|
|
|
|
|
|
|
function test() { |
|
|
|
const stream = createChartOnData(testData); |
|
|
|
@ -143,5 +217,4 @@ function test() { |
|
|
|
out.on('finish', () => console.log('The chart image was saved.')); |
|
|
|
} |
|
|
|
|
|
|
|
//test()
|
|
|
|
|
|
|
|
test() |
|
|
|
|