Files
purple-explorer/public/js/custom.js
T
davide a91e5aceee Auto-scale hashrate display to 1-999 range with correct unit
Panel: MutationObserver intercepts the #hashrate DOM update and
rescales the GH/s value from the API to the appropriate unit
(MH/s, GH/s, TH/s, PH/s), also updating the unit label in the
card header.

Chart: nethashChart Y-axis tick callback detects the canvas ID
and applies the same scaling logic per tick; a btcpHashrateUnit
plugin updates the Y-axis title (e.g. "Hashrate (TH/s)") after
each chart update to stay in sync with the data range
2026-04-28 14:56:39 +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.
$(document).ready(function() {
// ══════════════════════════════════════════════════════════════
// HASHRATE AUTO-SCALING
// 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' };
}
// ── 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)';
});