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
This commit is contained in:
+119
-15
@@ -1,23 +1,113 @@
|
||||
$(document).ready(function() {
|
||||
if (typeof Chart === 'undefined') return;
|
||||
|
||||
// ── Y-axis: abbreviate large numbers ─────────────────────────
|
||||
// 1400000 → "1.4M", 45000 → "45K", 999 → "999"
|
||||
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 AUTO-SCALING
|
||||
// The server sends hashrate already divided by nethash_units ("G"),
|
||||
// so values arrive in GH/s. We scale to keep the display 1–999.
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
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 };
|
||||
|
||||
// ── Linear scale (Y-axis on both charts) ─────────────────────
|
||||
// ── 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, {
|
||||
callback: fmtAxis,
|
||||
// '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,
|
||||
@@ -33,7 +123,6 @@ $(document).ready(function() {
|
||||
}
|
||||
|
||||
// ── Time scale (X-axis) ───────────────────────────────────────
|
||||
// Reduce label density and avoid 90° rotation
|
||||
['time', 'timeseries'].forEach(function(t) {
|
||||
var s = Chart.defaults.scales[t];
|
||||
if (!s) return;
|
||||
@@ -45,9 +134,24 @@ $(document).ready(function() {
|
||||
minRotation: 0,
|
||||
padding: 6
|
||||
});
|
||||
s.grid = Object.assign({}, s.grid, {
|
||||
color: 'rgba(80,40,130,0.3)'
|
||||
});
|
||||
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 ───────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user