Files
purple-explorer/public/js/custom.js
T
davide f4c47a72ac Fix hashrate chart: auto-scale tooltip units, remove green block lines
- layout.pug: formatNetworkChartValue now calls scaleFromGH() for
  Hashrate labels instead of appending the fixed (GH/s) unit, so
  tooltip values match the Y-axis auto-scaled unit (MH/s…PH/s)
- custom.js: promote HASH_UNITS and scaleFromGH to global scope so
  layout.pug inline scripts can reuse them; fix unused 'mutations' param
- settings.json.tmpl: disable block_line on both charts (was green
  rgba(0,128,0)); color updated to purple rgba(120,60,220,0.25)
2026-04-29 22:21:07 +02:00

174 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ══════════════════════════════════════════════════════════════
// HASHRATE AUTO-SCALING (global scope — reused by layout.pug chart scripts)
// The server sends hashrate already divided by nethash_units ("G"),
// so values arrive in GH/s. We scale to keep the display 1999.
// ══════════════════════════════════════════════════════════════
var HASH_UNITS = [
{ div: 1e6, label: 'PH/s' },
{ div: 1e3, label: 'TH/s' },
{ div: 1, label: 'GH/s' },
{ div: 1e-3, label: 'MH/s' },
{ div: 1e-6, label: 'KH/s' },
{ div: 1e-9, label: 'H/s' }
];
// Returns {num, unit} where 1 ≤ |num| < 1000 (best fit)
function scaleFromGH(gh) {
var abs = Math.abs(gh);
for (var i = 0; i < HASH_UNITS.length; i++) {
if (abs >= HASH_UNITS[i].div) {
return { num: gh / HASH_UNITS[i].div, unit: HASH_UNITS[i].label };
}
}
return { num: gh, unit: 'GH/s' };
}
$(document).ready(function() {
// ── Panel: reformat #hashrate + update unit label ─────────────
function refreshHashratePanel() {
var $el = $('#hashrate');
if (!$el.length) return;
// Read raw text ("42,650.8351" or similar), strip formatting
var raw = $el.text().replace(/[,\s]/g, '');
var ghVal = parseFloat(raw);
if (!isFinite(ghVal) || ghVal <= 0) return;
var s = scaleFromGH(ghVal);
// Format to max 4 significant digits, always 2 decimals
var decimals = (s.num >= 100) ? 1 : (s.num >= 10) ? 2 : 3;
var formatted = s.num.toFixed(decimals);
var parts = formatted.split('.');
// Temporarily disconnect observer to avoid loop
_hashrateObserver.disconnect();
$el.html(parts[0] + '.<span class="decimal">' + parts[1] + '</span>');
_hashrateObserver.observe($el[0], { childList: true, subtree: true });
// Update the unit label "(GH/s)" → "(TH/s)" etc.
var $unitSpan = $el.closest('.card').find('.card-header span.small');
if ($unitSpan.length) $unitSpan.text('(' + s.unit + ')');
}
var _hashrateObserver = new MutationObserver(function() {
refreshHashratePanel();
});
// Start watching once #hashrate appears in the DOM
var _panelWatcher = new MutationObserver(function(_mutations, obs) {
var el = document.getElementById('hashrate');
if (el) {
obs.disconnect();
_hashrateObserver.observe(el, { childList: true, subtree: true });
}
});
_panelWatcher.observe(document.body, { childList: true, subtree: true });
// ══════════════════════════════════════════════════════════════
// CHART.JS IMPROVEMENTS
// ══════════════════════════════════════════════════════════════
if (typeof Chart === 'undefined') return;
var font = { family: 'Inter, system-ui, sans-serif', size: 11 };
// ── Y-axis tick formatters ────────────────────────────────────
// Generic large-number formatter (difficulty, etc.)
function fmtAxis(value) {
var abs = Math.abs(value);
if (abs >= 1e9) return (value / 1e9).toFixed(1).replace(/\.0$/, '') + 'B';
if (abs >= 1e6) return (value / 1e6).toFixed(1).replace(/\.0$/, '') + 'M';
if (abs >= 1e3) return (value / 1e3).toFixed(1).replace(/\.0$/, '') + 'K';
return value;
}
// Hashrate formatter for nethashChart Y-axis ticks
// Scales GH/s values to the 1-999 range with the right unit
function fmtHashAxis(gh) {
if (gh === 0) return '0';
var s = scaleFromGH(gh);
var decimals = (Math.abs(s.num) >= 100) ? 0 : (Math.abs(s.num) >= 10) ? 1 : 2;
return s.num.toFixed(decimals) + ' ' + s.unit;
}
// ── Linear scale defaults ─────────────────────────────────────
var lin = Chart.defaults.scales.linear;
if (lin) {
lin.ticks = Object.assign({}, lin.ticks, {
// 'this' inside callback is the scale; this.chart.canvas.id identifies the chart
callback: function(value) {
if (this.chart && this.chart.canvas &&
this.chart.canvas.id === 'nethashChart') {
return fmtHashAxis(value);
}
return fmtAxis(value);
},
font: font,
color: 'rgba(200,160,255,0.85)',
padding: 8,
maxTicksLimit: 6
});
lin.title = Object.assign({}, lin.title, {
font: Object.assign({}, font, { weight: '700', size: 11 }),
color: 'rgba(216,180,254,1)'
});
lin.grid = Object.assign({}, lin.grid, {
color: 'rgba(80,40,130,0.3)'
});
}
// ── Time scale (X-axis) ───────────────────────────────────────
['time', 'timeseries'].forEach(function(t) {
var s = Chart.defaults.scales[t];
if (!s) return;
s.ticks = Object.assign({}, s.ticks, {
font: font,
color: 'rgba(200,160,255,0.75)',
maxTicksLimit: 6,
maxRotation: 30,
minRotation: 0,
padding: 6
});
s.grid = Object.assign({}, s.grid, { color: 'rgba(80,40,130,0.3)' });
});
// ── Plugin: update nethashChart Y-axis title to match auto unit ──
Chart.register({
id: 'btcpHashrateUnit',
afterUpdate: function(chart) {
if (!chart.canvas || chart.canvas.id !== 'nethashChart') return;
var yScale = chart.scales && chart.scales.y;
if (!yScale || !yScale.max) return;
var s = scaleFromGH(yScale.max);
var newTitle = 'Hashrate (' + s.unit + ')';
var opts = yScale.options;
if (opts && opts.title && opts.title.text !== newTitle) {
opts.title.text = newTitle;
}
}
});
// ── Tooltip ───────────────────────────────────────────────────
Object.assign(Chart.defaults.plugins.tooltip, {
backgroundColor: 'rgba(10,0,28,0.96)',
borderColor: 'rgba(93,33,182,0.65)',
borderWidth: 1,
titleColor: 'rgba(216,180,254,1)',
titleFont: Object.assign({}, font, { weight: '700', size: 12 }),
bodyColor: 'rgba(240,230,255,0.9)',
bodyFont: Object.assign({}, font, { size: 12 }),
padding: 11,
cornerRadius: 7
});
// ── Legend ────────────────────────────────────────────────────
Chart.defaults.plugins.legend.labels.font = Object.assign({}, font, { size: 12 });
Chart.defaults.plugins.legend.labels.color = 'rgba(216,180,254,1)';
});