' +
'
' +
'
' +
'
' + base + ' to ' + target + '
' +
'
' + price + '
' +
'
Source: ' + source + '
' +
'
' +
'
'
);
}
/**
* Market Charts
**/
// Create charts
function market_CreateCharts(stats) {
if (!stats || !stats.charts) return ;
let data = stats.charts;
let graphData = {
price: market_GetGraphData(data.price),
profit: market_GetGraphData(data.profit)
};
for(let graphType in graphData) {
if (graphData[graphType].values.length > 1) {
let $chart = $(`#chart${stats.config.coin}_${graphType}`);
let bgcolor = null, bordercolor = null, borderwidth = null;
let colorelem = $chart.siblings('a.chart-style');
if (colorelem.length == 1) {
bgcolor = colorelem.css('background-color');
bordercolor = colorelem.css('border-left-color');
borderwidth = parseFloat(colorelem.css('width'));
}
if (bgcolor === null) bgcolor = 'rgba(3, 169, 244, .4)';
if (bordercolor === null) bordercolor = '#03a9f4';
if (borderwidth === null || isNaN(borderwidth)) borderwidth = 1;
let chartObj = new Chart(document.getElementById(`chart${stats.config.coin}_${graphType}`), {
type: 'line',
data: {
labels: graphData[graphType].names,
datasets: [{
data: graphData[graphType].values,
dataType: graphType,
fill: true,
backgroundColor: bgcolor,
borderColor: bordercolor,
borderWidth: borderwidth
}]
},
options: {
animation: false,
responsive: true,
maintainAspectRatio: false,
legend: { display: false },
elements: { point: { radius: 0, hitRadius: 10, hoverRadius: 5 } },
scales: {
xAxes: [{
display: false,
ticks: { display: false },
gridLines: { display: false }
}],
yAxes: [{
display: false,
ticks: {
display: false,
beginAtZero: true,
userCallback: function(label, index, labels) {
if (Math.floor(label) === label) return label;
}
},
gridLines: { display: false }
}]
},
layout: {
padding: { top: 5, left: 10, right: 10, bottom: 10 }
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
let dataType = data.datasets[tooltipItem.datasetIndex].dataType || '';
let label = tooltipItem.yLabel;
if (dataType == 'price') label = parseFloat(tooltipItem.yLabel).toFixed(4);
else if (dataType == 'profit') label = parseFloat(tooltipItem.yLabel).toFixed(10);
return ' ' + label;
}
}
}
}
});
$chart.closest('.marketChart').show();
}
}
}
// Get chart data
function market_GetGraphData(rawData) {
let graphData = {
names: [],
values: []
};
if(rawData) {
for (let i = 0, xy; xy = rawData[i]; i++) {
graphData.names.push(new Date(xy[0]*1000).toLocaleString());
graphData.values.push(xy[1]);
}
}
return graphData;
}
// Calculate current estimation
function market_CalcEstimateProfit(marketPrices){
let rateUnit = Math.pow(1000,parseInt($('#calcHashUnit').data('mul')));
let hashRate = parseFloat($('#calcHashRate').val()) * rateUnit;
let coin = lastStats.config.coin
try {
if ($(`#calcHashAmount${coin}`).length == 0) {
let template = $(`#calcHashResultTemplate`).html()
Mustache.parse(template)
let rendered = Mustache.render(template, {coin:coin})
$(`#calcHashHolder`).append(rendered)
}
let profit = (hashRate * 86400 / lastStats.network.difficulty) * lastStats.lastblock.reward;
if (profit) {
updateText(`calcHashAmount${coin}1`, getReadableCoin(lastStats, profit));
updateText(`calcHashAmount${coin}2`, market_GetCurrencyPriceText(lastStats, profit, marketPrices));
//return;
} else {
updateText(`calcHashAmount${coin}1`, '');
updateText(`calcHashAmount${coin}2`, '');
}
}
catch (e){
updateText(`calcHashAmount${coin}1`, '');
updateText(`calcHashAmount${coin}2`, '');
}
Object.keys(mergedStats).forEach(key => {
try {
if ($(`#calcHashAmount${key}`).length == 0) {
let template = $(`#calcHashResultTemplate`).html()
Mustache.parse(template)
let rendered = Mustache.render(template, {coin:key})
$(`#calcHashHolder`).append(rendered)
}
let profit = (hashRate * 86400 / mergedStats[key].network.difficulty) * mergedStats[key].lastblock.reward;
if (profit) {
updateText(`calcHashAmount${key}1`, getReadableCoin(mergedStats[key], profit));
updateText(`calcHashAmount${key}2`, market_GetCurrencyPriceText(mergedStats[key], profit, marketPrices));
return;
} else {
updateText(`calcHashAmount${key}1`, '');
updateText(`calcHashAmount${key}2`, '');
}
}
catch(e)
{
updateText(`calcHashAmount${key}1`, '');
updateText(`calcHashAmount${key}2`, '');
}
})
}
// Get price in specified currency
function market_GetCurrencyPriceText(stats, coinsRaw, marketPrices) {
if (!priceCurrency || !marketPrices[stats.config.coin] || !marketPrices[stats.config.coin][priceCurrency]) return ;
let priceInCurrency = (Math.trunc(getReadableCoin(stats, coinsRaw, 2, true) * marketPrices[stats.config.coin][priceCurrency] * 100) / 100);
return priceInCurrency + ' ' + priceCurrency;
}
function market_InitTemplate(ranOnce, chartsInitialized, loadedData, marketPrices, intervalChartsUpdate, currencyPairs, xhrMarketGets) {
priceSource = lastStats.config.priceSource || 'cryptonator';
priceCurrency = lastStats.config.priceCurrency || 'USD';
let coin = lastStats.config.coin
if ($(`#blocksTabs li:contains(${coin})`).length == 0) {
chartsInitialized[coin] = false
loadedData[coin] = false
marketPrices[coin] = {}
let template = $('#siblingTabTemplate').html();
Mustache.parse(template)
let rendered = Mustache.render(template, {coin:lastStats.config.coin, symbol:`(${lastStats.config.symbol})`, active:'active'});
$('#blocksTabs').append(rendered)
let template1 = $('#siblingMarketTemplate').html()
Mustache.parse(template1)
let rendered1 = Mustache.render(template1, {coin:coin, active:'active'})
$(`#tab-content`).append(rendered1)
let template2 = $('#siblingCalculatorTemplate').html()
Mustache.parse(template2)
let rendered2 = Mustache.render(template2, {coin:coin})
$(`#calculator`).append(rendered2)
updateText(`priceChartCurrency${lastStats.config.coin}`, priceCurrency);
updateText(`profitChartProfit${lastStats.config.coin}`, priceCurrency);
if (lastStats.charts && !chartsInitialized[coin]) {
intervalChartsUpdate[coin] = setInterval(market_CreateCharts(lastStats), 60*1000);
market_CreateCharts(lastStats);
chartsInitialized[coin] = true;
}
}
market_LoadMarketData(api, lastStats, loadedData, currencyPairs, xhrMarketGets, marketPrices);
Object.keys(mergedStats).forEach(key => {
if ($(`#blocksTabs li:contains(${key})`).length === 0) {
chartsInitialized[key] = false;
loadedData[key] = false
marketPrices[key] = {}
let template1 = $('#siblingMarketTemplate').html()
Mustache.parse(template1)
let rendered1 = Mustache.render(template1, {coin:key})
$('#tab-content').append(rendered1)
let template = $('#siblingTabTemplate').html();
Mustache.parse(template)
let rendered = Mustache.render(template, {coin:key, symbol:`(${mergedStats[key].config.symbol})`});
$('#blocksTabs').append(rendered)
}
updateText(`priceChartCurrency${mergedStats[key].config.coin}`, priceCurrency);
updateText(`profitChartProfit${mergedStats[key].config.coin}`, priceCurrency);
market_LoadMarketData(mergedApis[key].api, mergedStats[key], loadedData, currencyPairs, xhrMarketGets, marketPrices);
if (mergedStats[key].charts && !chartsInitialized[key]) {
intervalChartsUpdate[key] = setInterval(market_CreateCharts(mergedStats[key]), 60*1000);
market_CreateCharts(mergedStats[key]);
chartsInitialized[key] = true;
}
})
market_CalcEstimateProfit(marketPrices);
sortElementList($(`#blocksTabs`), $(`#blocksTabs>li`), mergedStats)
if (!ranOnce)
ranOnce = RunOnce()
}
/*
***************************************************************
workerstats methods
***************************************************************
*/
function workerstats_Setup(stats, api, addressTimeout, xhrAddressPoll, xhrGetPayments ) {
// Enable time ago on last submitted share
$(`#yourLastShare${stats.config.coin}`).timeago();
$(`#lookUp${stats.config.coin}`).click(function(){
var address = $(`#yourStatsInput${stats.config.coin}`).val().trim();
if (getCurrentAddress(stats.config.coin) != address) {
docCookies.setItem(`mining_address_${stats.config.coin}`, address, Infinity);
var urlWalletAddress = location.search.split('walletMerged=')[1] || 0;
if (urlWalletAddress){
window.location.href = "/#worker_stats";
return ;
}
else {
docCookies.setItem(`mining_address_${stats.config.coin}`, address, Infinity);
loadLiveStats(true, mergedStats);
}
}
$(`#addressError${stats.config.coin}, .yourStats${stats.config.coin}, .yourWorkers${stats.config.coin}, .userChart${stats.config.coin}`).hide();
$(`#workersReport_rows_${stats.config.coin}`).empty();
$(`#paymentsReport_rows_${stats.config.coin}`).empty();
$(`#lookUp${stats.config.coin} > span:first-child`).hide();
$(`#lookUp${stats.config.coin} > span:last-child`).show();
if (addressTimeout[stats.config.coin]) clearTimeout(addressTimeout[stats.config.coin]);
if (xhrAddressPoll[stats.config.coin])
xhrAddressPoll[stats.config.coin].abort();
$(`#lookUp${stats.config.coin} > span:last-child`).hide();
$(`#lookUp${stats.config.coin} > span:first-child`).show();
if (!address){
$(`#yourStatsInput${stats.config.coin}`).focus();
return;
}
workerstats_FetchAddressStats(false, stats, api, xhrAddressPoll);
});
var address = getCurrentAddress(stats.config.coin);
if (address){
$(`#yourStatsInput${stats.config.coin}`).val(address);
$(`#lookUp${stats.config.coin}`).click();
}
else {
$(`#lookUp${stats.config.coin} > span:last-child`).hide();
$(`#lookUp${stats.config.coin} > span:first-child`).show();
$(`#addressError${stats.config.coin}, .yourStats${stats.config.coin}, .yourWorkers${stats.config.coin}, .userChart${stats.config.coin}`).hide();
}
$(`#yourStatsInput${stats.config.coin}`).keyup(function(e){
if(e.keyCode === 13)
$(`#lookUp${stats.config.coin}`).click();
});
// Handle sort on workers table
//$(`#workersReport${stats.config.coin} th.sort`).on('click', sortTable);
$(`.workerStats th.sort`).on('click', sortTable);
// Load more payments button
$(`#loadMorePayments${stats.config.coin}`).click(function(xhrGetPayments){
if (xhrGetPayments[stats.config.coin])
xhrGetPayments[stats.config.coin].abort();
xhrGetPayments[stats.config.coin] = $.ajax({
url: `${api}/get_payments`,
data: {
time: $(`#paymentsReport_rows_${stats.config.coin}`).children().last().data('time'),
address: address
},
dataType: 'json',
cache: 'false',
success: function(data){
workerstats_RenderPayments(data, stats);
}
});
});
}
/**
* Miner statistics
**/
// Load current miner statistics
function workerstats_FetchAddressStats(longpoll, stats, api, xhrAddressPoll){
let address = getCurrentAddress(stats.config.coin)
xhrAddressPoll[stats.config.coin] = $.ajax({
url: `${api}/stats_address`,
data: {
address: address,
longpoll: longpoll
},
dataType: 'json',
cache: 'false',
success: function(data){
if (!data.stats){
$(`.yourStats${stats.config.coin}, .yourWorkers${stats.config.coin}, .userChart${stats.config.coin}`).hide();
$(`#addressError${stats.config.coin}`).text(data.error).show();
docCookies.setItem(`mining_address_${stats.config.coin}`, '', Infinity);
loadLiveStats(true);
return;
}
$(`#addressError${stats.config.coin}`).hide();
if (data.stats.lastShare) {
$(`#yourLastShare${stats.config.coin}`).timeago('update', new Date(parseInt(data.stats.lastShare) * 1000).toISOString());
} // AQUĆ
else {
updateText(`yourLastShare${stats.config.coin}`, 'Never');
}
updateText(`yourHashrateHolder${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate) || '0 H') + '/sec');
if ('hashrate_1h' in data.stats) {
$(`#minerAvgHR${stats.config.coin}`).show();
updateText(`yourHR1h${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate_1h) || '0 H') + '/s');
updateText(`yourHR6h${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate_6h) || '0 H') + '/s');
updateText(`yourHR24h${stats.config.coin}`, (getReadableHashRateString(data.stats.hashrate_24h) || '0 H') + '/s');
} else {
$(`#minerAvgHR${stats.config.coin}`).hide();
}
let totalCoins = data.stats.paid;
let last24hCoins = 0;
let last7dCoins = 0;
for (let i = 0; i < data.payments.length; i += 2) {
let payment = workerstats_ParsePayment(data.payments[i + 1], data.payments[i]);
let paymentDate = new Date(parseInt(payment.time) * 1000);
let daysDiff = moment().diff(moment(paymentDate), 'days');
if (daysDiff < 1) {
last24hCoins = last24hCoins + parseInt(payment.amount);
}
if (daysDiff < 7) {
last7dCoins = last7dCoins + parseInt(payment.amount);
}
}
// $.getJSON(`https://api.coingecko.com/api/v3/coins/${stats.config.coin.toLowerCase()}?sparkline=true`, function() {})
// .done(data => {
// let paidTotalUSD = getReadableCoin(stats, totalCoins, 2, true) * data.market_data.current_price.usd;
// let paid24hUSD = getReadableCoin(stats, last24hCoins, 2, true) * data.market_data.current_price.usd;
// let paid7dUSD = getReadableCoin(stats, last7dCoins, 2, true) * data.market_data.current_price.usd;
// updateText(`yourPaid${stats.config.coin}`, `${getReadableCoin(stats, totalCoins)} - $${paidTotalUSD.toFixed(2)}`);
// updateText(`paid24h${stats.config.coin}`, `${getReadableCoin(stats, last24hCoins)} - $${paid24hUSD.toFixed(2)}`);
// updateText(`paid7d${stats.config.coin}`, `${getReadableCoin(stats, last7dCoins)} - $${paid7dUSD.toFixed(2)}`);
// })
// .fail(() => {
updateText(`yourPaid${stats.config.coin}`, getReadableCoin(stats, totalCoins));
updateText(`paid24h${stats.config.coin}`, getReadableCoin(stats, last24hCoins));
updateText(`paid7d${stats.config.coin}`, getReadableCoin(stats, last7dCoins));
// })
updateText(`yourHashes${stats.config.coin}`, (data.stats.hashes || 0).toString());
//updateText(`yourPaid${stats.config.coin}`, getReadableCoin(stats, data.stats.paid));
updateText(`yourPendingBalance${stats.config.coin}`, getReadableCoin(stats, data.stats.balance));
let userRoundHashes = parseInt(data.stats.roundHashes || 0);
let poolRoundHashes = parseInt(stats.pool.roundHashes || 0);
let userRoundScore = parseFloat(data.stats.roundScore || 0);
let poolRoundScore = parseFloat(stats.pool.roundScore || 0);
let lastReward = parseFloat(stats.lastblock.reward || 0);
let poolFee = stats.config.fee;
if (Object.keys((stats.config.donation)).length) {
let totalDonation = 0;
let ldon = stats.config.donation;
for(let i in ldon) {
totalDonation += ldon[i];
}
poolFee += totalDonation;
}
let transferFee = stats.config.transferFee;
let share_pct = userRoundHashes * 100 / poolRoundHashes;
let score_pct = userRoundScore * 100 / poolRoundScore;
updateText(`yourRoundShareProportion${stats.config.coin}`, Math.round(share_pct * 1000) / 1000);
updateText(`yourRoundScoreProportion${stats.config.coin}`, Math.round(score_pct * 1000) / 1000);
if (!lastStats.config.slushMiningEnabled) {
$(`#slush_round_info${stats.config.coin}`).hide();
}
let payoutEstimatePct = parseFloat(userRoundHashes * 100 / poolRoundHashes)
let payoutEstimate = Math.round(lastReward * (payoutEstimatePct / 100));
if (transferFee) payoutEstimate = payoutEstimate - transferFee;
if (payoutEstimate < 0)
payoutEstimate = 0;
updateText(`yourPayoutEstimate${stats.config.coin}`, getReadableCoin(stats, payoutEstimate));
workerstats_RenderPayments(data.payments, stats);
if (data.workers && data.workers.length > 0) {
workerstats_RenderWorkers(data.workers, stats);
$(`.yourWorkers${stats.config.coin}`).show();
}
$(`.yourStats${stats.config.coin}`).show();
workerstats_CreateCharts(data, stats);
},
error: function(e){
if (e.statusText === 'abort') return;
$(`#addressError${stats.config.coin}`).text('Connection error').show();
if (addressTimeout[stats.config.coin])
clearTimeout(addressTimeout[stats.config.coin]);
addressTimeout[stats.config.coin] = setTimeout(function(){
workerstats_FetchAddressStats(false, stats, mergedApis[stats.config.coin].api);
}, 2000);
}
});
}
/**
* Charts
**/
// Create charts
function workerstats_CreateCharts(data, stats) {
if (data.hasOwnProperty("charts")) {
var graphData = {
hashrate: workerstats_GetGraphData(stats, data.charts.hashrate),
payments: workerstats_GetGraphData(stats, data.charts.payments, true)
};
for(var graphType in graphData) {
if(graphData[graphType].values.length > 1) {
var settings = jQuery.extend({}, graphSettings);
settings.tooltipValueLookups = {names: graphData[graphType].names};
var $chart = $(`[data-chart=user_${graphType}_${stats.config.coin}]`).show().find('.chart');
$chart.sparkline(graphData[graphType].values, settings);
}
}
}
}
// Get chart data
function workerstats_GetGraphData(stats, rawData, fixValueToCoins) {
var graphData = {
names: [],
values: []
};
if(rawData) {
for (var i = 0, xy; xy = rawData[i]; i++) {
graphData.names.push(new Date(xy[0]*1000).toLocaleString());
graphData.values.push(fixValueToCoins ? getReadableCoin(stats, xy[1], null, true) : xy[1]);
}
}
return graphData;
}
/**
* Workers report
**/
// Get worker row id
function workerstats_GetWorkerRowId(workerName){
var id = btoa(workerName);
id = id.replace(/=/, '');
return id;
}
// Get worker row element
function workerstats_GetWorkerRowElement(worker, jsonString, stats){
var row = document.createElement('tr');
row.setAttribute('data-json', jsonString);
row.setAttribute('data-name', worker.name);
row.setAttribute('id', 'workerRow' + stats.config.coin + '_' + workerstats_GetWorkerRowId(worker.name));
row.innerHTML = workerstats_GetWorkerCells(worker);
return row;
}
// Get worker cells
function workerstats_GetWorkerCells(worker){
let hashrate = worker.hashrate ? worker.hashrate : 0;
let hashrate1h = worker.hashrate_1h || 0;
let hashrate6h = worker.hashrate_6h || 0;
let hashrate24h = worker.hashrate_24h || 0;
let lastShare = worker.lastShare ? worker.lastShare : 0;
let hashes = (worker.hashes || 0).toString();
let status = (hashrate <= 0) ? 'error' : 'ok';
return '
| ' +
'
' + (worker.name != 'undefined' ? worker.name : 'Undefined') + ' | ' +
'
' + getReadableHashRateString(hashrate) + '/s | ' +
'
' + getReadableHashRateString(hashrate1h) + '/s | ' +
'
' + getReadableHashRateString(hashrate6h) + '/s | ' +
'
' + getReadableHashRateString(hashrate24h) + '/s | ' +
'
' + (lastShare ? $.timeago(new Date(parseInt(lastShare) * 1000).toISOString()) : 'Never') + ' | ' +
'
' + hashes + ' | ';
}
// Sort workers
function workerstats_SortWorkers(a, b){
var aName = a.name.toLowerCase();
var bName = b.name.toLowerCase();
return ((aName < bName) ? -1 : ((aName > bName) ? 1 : 0));
}
// Render workers list
function workerstats_RenderWorkers(workersData, stats){
workersData = workersData.sort(workerstats_SortWorkers);
var $workersRows = $(`#workersReport_rows_${stats.config.coin}`);
for (var i = 0; i < workersData.length; i++){
var existingRow = document.getElementById(`workerRow${stats.config.coin}_${workerstats_GetWorkerRowId(workersData[i].name)}`);
if (!existingRow){
$workersRows.empty();
break;
}
}
let have_avg_hr = false;
for (var i = 0; i < workersData.length; i++){
var worker = workersData[i];
if (Date.now()/1000 - parseInt(worker.lastShare) > 2 * 86400) continue;
if (!have_avg_hr && 'hashrate_1h' in worker) have_avg_hr = true;
var workerJson = JSON.stringify(worker);
var existingRow = document.getElementById(`workerRow${stats.config.coin}_${workerstats_GetWorkerRowId(worker.name)}`);
if (existingRow && existingRow.getAttribute('data-json') !== workerJson){
$(existingRow).replaceWith(workerstats_GetWorkerRowElement(worker, workerJson, stats));
}
else if (!existingRow){
var workerElement = workerstats_GetWorkerRowElement(worker, workerJson, stats);
$workersRows.append(workerElement);
}
}
if (!have_avg_hr) $(`#workersReport${stats.config.coin} .avghr`).hide();
else $(`#workersReport${stats.config.coin} .avghr`).show();
}
/**
* Payments report
**/
// Parse payment data
function workerstats_ParsePayment(time, serializedPayment){
var parts = serializedPayment.split(':');
return {
time: parseInt(time),
hash: parts[0],
amount: parts[1],
fee: parts[2],
mixin: parts[3],
recipients: parts[4]
};
}
// Get payment row element
function workerstats_GetPaymentRowElement(payment, jsonString, stats){
var row = document.createElement('tr');
row.setAttribute('data-json', jsonString);
row.setAttribute('data-time', payment.time);
row.setAttribute('id', 'paymentRow' + stats.config.coin + payment.time);
row.innerHTML = workerstats_GetPaymentCells(payment, stats);
return row;
}
// Get payment cells
function workerstats_GetPaymentCells(payment, stats){
return '
' + formatDate(payment.time) + ' | ' +
'
' + formatPaymentLink(payment.hash, stats) + ' | ' +
'
' + getReadableCoin(stats, payment.amount) + ' | ' +
'
' + payment.mixin + ' | ';
}
// Get summary row element
function workerstats_GetSummaryRowElement(summary, jsonString, stats){
var row = document.createElement('tr');
row.setAttribute('data-json', jsonString);
row.setAttribute('data-date', summary.date);
row.setAttribute('id', 'summaryRow' + stats.config.coin + summary.date);
row.setAttribute('class', 'summary');
row.innerHTML = workerstats_GetSummaryCells(summary, stats);
return row;
}
// Get summary cells
function workerstats_GetSummaryCells(summary, stats){
var text = getTranslation('paymentSummaryMulti') ? getTranslation('paymentSummaryMulti') : 'On %DATE% you have received %AMOUNT% in %COUNT% payments';
if (summary.count <= 1) text = getTranslation('paymentSummarySingle') ? getTranslation('paymentSummarySingle') : 'On %DATE% you have received %AMOUNT%';
text = text.replace(/%DATE%/g, summary.date);
text = text.replace(/%COUNT%/g, summary.count);
text = text.replace(/%AMOUNT%/g, getReadableCoin(stats, summary.amount));
return '
' + text + ' | ';
}
// Render payments
function workerstats_RenderPayments(paymentsResults, stats){
var $paymentsRows = $(`#paymentsReport_rows_${stats.config.coin}`);
var lastPaymentDate = null;
var summaryData = { date: null, time: null, count: 0, amount: 0 };
for (var i = 0; i < paymentsResults.length; i += 2){
var payment = workerstats_ParsePayment(paymentsResults[i + 1], paymentsResults[i]);
var paymentJson = JSON.stringify(payment);
var paymentElement = workerstats_GetPaymentRowElement(payment, paymentJson, stats);
var paymentDate = new Date(parseInt(payment.time) * 1000).toLocaleDateString();
if (!lastPaymentDate || lastPaymentDate && paymentDate != lastPaymentDate) {
summaryData = { date: paymentDate, time: payment.time, count: 0, amount: 0 };
}
var existingRow = document.getElementById(`paymentRow${stats.config.coin}${payment.time}`);
if (existingRow && existingRow.getAttribute('data-json') !== paymentJson){
$(existingRow).replaceWith(workerstats_GetPaymentRowElement(payment, paymentJson, stats));
}
else if (!existingRow){
var inserted = false;
var rows = $paymentsRows.children().get();
for (var f = 0; f < rows.length; f++) {
var pTime = parseInt(rows[f].getAttribute('data-time'));
if (pTime && pTime < payment.time){
inserted = true;
$(rows[f]).before(paymentElement);
break;
}
}
if (!inserted) {
$paymentsRows.append(paymentElement);
}
}
summaryData.count ++;
summaryData.amount += parseInt(payment.amount);
var summaryJson = JSON.stringify(summaryData);
var summaryElement = workerstats_GetSummaryRowElement(summaryData, summaryJson, stats);
var existingSummary = document.getElementById(`summaryRow${stats.config.coin}${summaryData.date}`);
if (existingSummary && existingSummary.getAttribute('data-json') !== summaryJson){
$(existingSummary).replaceWith(summaryElement);
}
else if (!existingSummary){
var inserted = false;
var rows = $paymentsRows.children().get();
for (var f = 0; f < rows.length; f++) {
var pTime = parseInt(rows[f].getAttribute('data-time'));
if (pTime && pTime === summaryData.time){
inserted = true;
$(rows[f]).before(summaryElement);
break;
}
}
if (!inserted) {
$paymentsRows.append(summaryElement);
}
}
lastPaymentDate = paymentDate;
}
}
function workerstats_InitTemplate(ranOnce, addressTimeout, xhrAddressPoll, xhrGetPayments ) {
let coin = lastStats.config.coin
if ($(`#blocksTabs li:contains(${coin})`).length === 0) {
let template = $('#siblingTabTemplate').html();
Mustache.parse(template)
let rendered = Mustache.render(template, {coin:lastStats.config.coin, symbol:`(${lastStats.config.symbol})`, active: 'active'});
$('#blocksTabs').append(rendered)
template = $('#siblingTemplate').html()
Mustache.parse(template)
rendered = Mustache.render(template, {coin:coin, active: 'active'})
$('#tab-content').append(rendered)
workerstats_Setup(lastStats, api, addressTimeout, xhrAddressPoll, xhrGetPayments)
}
Object.keys(mergedStats).forEach(key => {
if ($(`#blocksTabs li:contains(${key})`).length === 0) {
coin = key
let template = $('#siblingTabTemplate').html();
Mustache.parse(template)
let rendered = Mustache.render(template, {coin:mergedStats[key].config.coin, symbol:`(${mergedStats[key].config.symbol})`});
$('#blocksTabs').append(rendered)
template = $('#siblingTemplate').html()
Mustache.parse(template)
rendered = Mustache.render(template, {coin:coin})
$('#tab-content').append(rendered)
workerstats_Setup(mergedStats[key], mergedApis[key].api, addressTimeout, xhrAddressPoll, xhrGetPayments)
}
})
sortElementList($(`#blocksTabs`), $(`#blocksTabs>li`), mergedStats)
if (!ranOnce)
ranOnce = RunOnce()
}
/*
***************************************************************
workerstats methods
***************************************************************
*/
let home_GraphSettings = {
type: 'line',
width: '100%',
height: '140',
lineColor: '#03a9f4',
fillColor: 'rgba(3, 169, 244, .4)',
spotColor: null,
minSpotColor: null,
maxSpotColor: null,
highlightLineColor: '#236d26',
spotRadius: 3,
chartRangeMin: 0,
drawNormalOnTop: false,
tooltipFormat: '
{{y}} – {{offset:names}}'
};
function home_CreateCharts(data) {
if (data.hasOwnProperty("charts")) {
var graphData = {
hashrate: home_GetGraphData(data.charts.hashrate),
diff: home_GetGraphData(data.charts.difficulty),
miners: home_GetGraphData(data.charts.miners),
workers: home_GetGraphData(data.charts.workers)
};
for(var graphType in graphData) {
if(graphData[graphType].values.length > 1) {
var settings = jQuery.extend({}, home_GraphSettings);
settings.tooltipValueLookups = {names: graphData[graphType].names};
var $chart = $('[data-chart=' + graphType + '] .chart');
$chart.closest('.poolChart').show();
$chart.sparkline(graphData[graphType].values, settings);
}
}
}
}
// Get chart data
function home_GetGraphData(rawData, fixValueToCoins) {
var graphData = {
names: [],
values: []
};
if(rawData) {
for (var i = 0, xy; xy = rawData[i]; i++) {
graphData.names.push(new Date(xy[0]*1000).toLocaleString());
graphData.values.push(fixValueToCoins ? getReadableCoin(lastStats, xy[1], null, true) : xy[1]);
}
}
return graphData;
}
function home_GenerateNetworkStats(key, symbol) {
if ($(`#networkStats${key}`).length == 0) {
let template = $('#siblingTemplate').html()
if (template) {
Mustache.parse(template)
let rendered = Mustache.render(template, {coin:key, symbol: symbol})
$(`#networkStats`).append(rendered)
}
}
}
function sortElementList(container, siblings, stats) {
let sorted = (a,b) => {
return ((a.id.toLowerCase() < b.id.toLowerCase()) ? -1 : ((a.id.toLowerCase() > b.id.toLowerCase()) ? 1 : 0))
}
if (stats && siblings.length -1 === Object.keys(stats).length) {
siblings.sort(sorted).appendTo(container)
}
}
function home_InitTemplate(parentStats, siblingStats) {
$('#networkLastBlockFound').timeago('update', new Date(parentStats.lastblock.timestamp * 1000).toISOString());
let coin = parentStats.config.coin
let minerInfo = []
let efforts = []
if ($(`#networkStats${coin}`).length == 0) {
minerInfo.push({blocks: parentStats.pool.totalBlocks.toString(),
blocksSolo: parentStats.pool.totalBlocksSolo.toString(),
coin: coin,
symbol: parentStats.config.symbol,
miners: parentStats.pool.miners.toString(),
minersSolo: parentStats.pool.minersSolo.toString()})
efforts.push({coin: coin, effort: `${(parentStats.pool.roundHashes / parentStats.network.difficulty * 100).toFixed(1)}%`,symbol: parentStats.config.symbol})
let template = $('#siblingTemplate').html()
Mustache.parse(template)
let rendered = Mustache.render(template, {coin: coin, symbol: parentStats.config.symbol})
$(`#networkStats`).append(rendered)
}
let lastBlockFound = null
if (parentStats.pool.lastBlockFound) {
lastBlockFound = parseInt(parentStats.pool.lastBlockFound);
}
updateText(`networkHashrate${coin}`, getReadableHashRateString(parentStats.network.difficulty / parentStats.config.coinDifficultyTarget) + '/sec');
updateText(`networkDifficulty${coin}`, formatNumber(parentStats.network.difficulty.toString(), ' '));
updateText(`blockchainHeight${coin}`, formatNumber(parentStats.network.height.toString(), ' '));
updateText(`networkLastReward${coin}`, getReadableCoin(parentStats, parentStats.lastblock.reward));
Object.keys(siblingStats).forEach(key => {
home_GenerateNetworkStats(key, siblingStats[key].config.symbol)
minerInfo.push({blocks: siblingStats[key].pool.totalBlocks.toString(),
blocksSolo: siblingStats[key].pool.totalBlocksSolo.toString(),
coin: key,
symbol: siblingStats[key].config.symbol,
miners: siblingStats[key].pool.miners.toString(),
minersSolo: siblingStats[key].pool.minersSolo.toString()})
efforts.push({coin: key, effort: `${(siblingStats[key].pool.roundHashes / siblingStats[key].network.difficulty * 100).toFixed(1)}%`, symbol: siblingStats[key].config.symbol});
if (siblingStats[key].pool.lastBlockFound) {
let lastChildBlockFound = parseInt(siblingStats[key].pool.lastBlockFound)
if (lastChildBlockFound > lastBlockFound)
lastBlockFound = lastChildBlockFound
}
updateText(`networkHashrate${key}`, getReadableHashRateString(siblingStats[key].network.difficulty / siblingStats[key].config.coinDifficultyTarget) + '/sec');
updateText(`networkDifficulty${key}`, formatNumber(siblingStats[key].network.difficulty.toString(), ' '));
updateText(`blockchainHeight${key}`, formatNumber(siblingStats[key].network.height.toString(), ' '));
updateText(`networkLastReward${key}`, getReadableCoin(siblingStats[key], siblingStats[key].lastblock.reward));
updateText(`poolMiners${key}`, `${siblingStats[key].pool.miners}/${siblingStats[key].pool.minersSolo}`);
updateText(`blocksTotal${key}`, `${siblingStats[key].pool.totalBlocks}/${siblingStats[key].pool.totalBlocksSolo}`);
updateText(`currentEffort${key}`, (siblingStats[key].pool.roundHashes / siblingStats[key].network.difficulty * 100).toFixed(1) + '%');
})
sortElementList($(`#networkStats`), $(`#networkStats>div`), siblingStats)
if ($(`#poolDetails > div`).length == 0) {
let template = $('#poolDetailTemplate').html()
Mustache.parse(template)
let rendered = Mustache.render(template, {coin:parentStats.config.coin, symbol: parentStats.config.symbol, blocks: minerInfo})
$(`#poolDetails`).append(rendered)
}
if ($(`#mainPoolStats > div`).length == 0) {
let template = $('#mainPoolTemplate').html()
Mustache.parse(template)
let rendered = Mustache.render(template, {coin:parentStats.config.coin, blocks: minerInfo, efforts: efforts})
$(`#mainPoolStats`).append(rendered)
}
if (lastBlockFound) {
$('#poolLastBlockFound').timeago('update', new Date(lastBlockFound).toISOString());
}
else {
$('#poolLastBlockFound').removeAttr('title').data('ts', '').update('Never');
}
let lastHash = updateText('lastHash', parentStats.lastblock.hash)
if (lastHash)
lastHash.setAttribute('href', getBlockchainUrl(parentStats.lastblock.hash, parentStats));
updateText('poolHashrate', `PROP: ${getReadableHashRateString(parentStats.pool.hashrate)}/sec`);
updateText('poolHashrateSolo', `SOLO: ${getReadableHashRateString(parentStats.pool.hashrateSolo)}/sec`);
var hashPowerSolo = parentStats.pool.hashrateSolo / (parentStats.network.difficulty / parentStats.config.coinDifficultyTarget) * 100;
updateText ('hashPowerSolo', hashPowerSolo.toFixed(2) + '%');
var hashPower = parentStats.pool.hashrate / (parentStats.network.difficulty / parentStats.config.coinDifficultyTarget) * 100;
updateText('hashPower', hashPower.toFixed(2) + '%');
updateText(`poolMiners${coin}`, `${parentStats.pool.miners}/${parentStats.pool.minersSolo}`);
updateText('blocksTotal', `${parentStats.pool.totalBlocks}/${parentStats.pool.totalBlocksSolo}`);
var totalFee = parentStats.config.fee;
var soloFee = parentStats.config.soloFee;
if (Object.keys(parentStats.config.donation).length) {
var totalDonation = 0;
for(var i in parentStats.config.donation) {
totalDonation += parentStats.config.donation[i];
}
totalFee += totalDonation;
soloFee += totalDonation;
}
updateText('poolFee', (totalFee > 0 && totalFee != 100 ? floatToString(totalFee) : (totalFee == 100 ? '100' : '0')) + '%/' + soloFee + '%');
updateText('finderReward', parentStats.config.finderReward + '%');
updateText('paymentsInterval', getReadableTime(parentStats.config.paymentsInterval));
updateText('paymentsMinimum', getReadableCoin(parentStats, parentStats.config.minPaymentThreshold));
updateText('blockSolvedTime', getReadableTime(parentStats.network.difficulty / parentStats.pool.hashrate));
updateText(`currentEffort${coin}`, (parentStats.pool.roundHashes / parentStats.network.difficulty * 100).toFixed(1) + '%');
}