|
- (function () {
- 'use strict';
- const asset = 'modules/servers/vpsmanager/assets/chart-4.4.8.scoped.js';
- const unavailable = 'Las métricas no están disponibles temporalmente.';
- const colors = ['#176aa3', '#bd5623', '#338345'];
- function scaled(value, base, units) {
- if (value === null || !Number.isFinite(value)) return 'Sin datos';
- let i = 0;
- while (Math.abs(value) >= base && i < units.length - 1) { value /= base; i++; }
- return value.toLocaleString('es-ES', { maximumFractionDigits: 2 }) + ' ' + units[i];
- }
- function format(kind, value) {
- if (kind === 'memory') return scaled(value, 1024, ['B', 'KiB', 'MiB', 'GiB', 'TiB']);
- if (kind === 'network') return scaled(value, 1000, ['bit/s', 'Kbit/s', 'Mbit/s', 'Gbit/s']);
- return value === null ? 'Sin datos' : value.toLocaleString('es-ES', { maximumFractionDigits: 2 });
- }
- function datasets(kind, series) {
- return Object.entries(series).map(([label, points], i) => ({
- label,
- // The server keeps rates in bytes/s. Conversion happens exactly here.
- data: points.map(p => ({ x: p.x, y: p.y === null ? null : (kind === 'network' ? p.y * 8 : p.y) })),
- borderColor: colors[i % colors.length], backgroundColor: colors[i % colors.length],
- borderWidth: 2, pointRadius: 0, pointHitRadius: 8, spanGaps: false, tension: 0
- }));
- }
- function summary(kind, data, metrics) {
- const times = data.flatMap(d => d.data.map(p => p.x));
- if (!times.length) return unavailable;
- const lastTime = times.reduce((a, b) => Math.max(a, b), 0);
- const values = data.map(d => {
- const point = d.data.find(p => p.x === lastTime);
- return d.label + ': ' + format(kind, point ? point.y : null);
- });
- if (kind === 'memory') {
- const percentage = metrics.memoryPercent.find(p => p.x === lastTime);
- values.push('Uso: ' + (percentage && percentage.y !== null ? percentage.y.toFixed(1) + ' %' : 'Sin datos'));
- }
- return values.join(' · ') + ' · ' + new Date(lastTime).toLocaleString('es-ES');
- }
- function start(ChartClass) {
- document.querySelectorAll('.vpsmanager-metrics[data-metrics]').forEach(root => {
- if (root.dataset.initialized || !root.dataset.metrics) return;
- root.dataset.initialized = 'true';
- let metrics;
- try { metrics = JSON.parse(root.dataset.metrics); } catch (_) { return; }
- root.querySelectorAll('[data-chart]').forEach(card => {
- const kind = card.dataset.chart;
- const data = datasets(kind, metrics[kind]);
- const text = card.querySelector('[data-summary]');
- const canvas = card.querySelector('canvas');
- if (!ChartClass || !data.some(d => d.data.some(p => p.y !== null))) {
- text.textContent = unavailable;
- canvas.parentElement.hidden = true;
- return;
- }
- text.textContent = summary(kind, data, metrics);
- try {
- new ChartClass(canvas, {
- type: 'line', data: { datasets: data },
- options: {
- responsive: true, maintainAspectRatio: false, animation: false, parsing: false,
- interaction: { mode: 'nearest', intersect: false },
- scales: {
- x: { type: 'linear', ticks: { maxTicksLimit: 6, callback: v => new Date(v).toLocaleString('es-ES', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }) } },
- y: { beginAtZero: true, ticks: { callback: v => format(kind, v) } }
- },
- plugins: { tooltip: { callbacks: {
- title: items => items.length ? new Date(items[0].parsed.x).toLocaleString('es-ES') : '',
- label: ctx => ctx.dataset.label + ': ' + format(kind, ctx.parsed.y)
- } } }
- }
- });
- } catch (_) {
- text.textContent = unavailable;
- canvas.parentElement.hidden = true;
- }
- });
- });
- }
- function boot() {
- // Reuse an installed compatible Chart.js; otherwise use the local isolated build.
- if (window.Chart && /^4\./.test(window.Chart.version || '')) { start(window.Chart); return; }
- if (window.O6HVpsChart) { start(window.O6HVpsChart); return; }
- const script = document.createElement('script');
- script.src = asset;
- script.onload = () => start(window.O6HVpsChart);
- script.onerror = () => start(null);
- document.head.appendChild(script);
- }
- if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot, { once: true });
- else boot();
- }());
|