Revenue: $${resultsData.dailyRevenue.toFixed(2)}
Electricity Cost: $${resultsData.dailyElectricityCost.toFixed(2)}
Pool Fees: $${resultsData.dailyPoolFees.toFixed(2)}
Net Profit/Loss: $${resultsData.dailyNetProfit.toFixed(2)}
Projected Estimates
Period: ${periodName}
Coins Mined: ${projectedCoins.toFixed(8)}
Revenue: $${projectedRevenue.toFixed(2)}
Electricity Cost: $${projectedElectricityCost.toFixed(2)}
Pool Fees: $${projectedPoolFees.toFixed(2)}
Net Profit/Loss: $${projectedNetProfit.toFixed(2)}
Additional Metrics
Break-Even Electricity Price: $${resultsData.breakEvenElectricityPrice.toFixed(4)} / kWh
${resultsData.hardwareCost > 0 ?
`
Return on Investment (ROI): ${isFinite(resultsData.roiDays) ? resultsData.roiDays.toFixed(1) + ' days' : (resultsData.dailyNetProfit <=0 ? 'Never (at current rate)' : 'N/A')}
`
: '
Return on Investment (ROI): Enter hardware cost to calculate.
'}
`;
resultsMiningEl.style.display = 'block';
}
/**
* Handles the mining calculation process.
*/
function handleMiningCalculate() {
const inputs = getMiningInputs();
if (!inputs) return;
if (!validateMiningInputs(inputs)) {
if(resultsMiningEl) resultsMiningEl.style.display = 'none';
return;
}
const calculationResults = calculateMiningProfitability(inputs);
displayMiningResults(calculationResults);
}
/**
* Generates and downloads a PDF of the mining results.
*/
function generateMiningPdf() {
const inputs = getMiningInputs();
if (!inputs) {
alert('Could not retrieve input data for PDF generation. Please calculate first.');
return;
}
if (!validateMiningInputs(inputs)) {
alert('Invalid inputs. Please correct them before generating PDF.');
return;
}
const resultsData = calculateMiningProfitability(inputs);
if (!resultsData) {
alert('Could not calculate results for PDF generation. Please try again.');
return;
}
const doc = new jsPDF();
const today = new Date();
const formattedDate = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
const title = `Mining Profitability Report: ${resultsData.cryptoName}`;
const projectionPeriodEl = document.getElementById('projectionPeriodMining');
const projectionPeriodText = projectionPeriodEl ? projectionPeriodEl.options[projectionPeriodEl.selectedIndex].text : "Daily";
doc.setFontSize(18);
doc.text(title, 14, 22);
doc.setFontSize(11);
doc.setTextColor(100);
doc.text(`Report Generated: ${formattedDate}`, 14, 30);
const headStyle = { fillColor: [79, 70, 229] }; // Indigo for header
const bodyStyle = { minCellHeight: 9, fontSize: 10 };
const inputSummaryBody = [
['Cryptocurrency', resultsData.cryptoName],
['Your Hashrate', `${resultsData.hashrateValue} ${resultsData.hashrateUnit} (${resultsData.userHashrateHps.toExponential(2)} H/s)`],
['Power Consumption', `${resultsData.powerConsumption} Watts`],
['Electricity Cost', `$${resultsData.electricityCost.toFixed(4)} / kWh`],
['Pool Fee', `${(resultsData.poolFee * 100).toFixed(2)}%`],
['Block Reward', `${resultsData.blockReward} coins`],
['Network Difficulty', `${resultsData.networkDifficulty.toExponential(4)}`],
['Current Crypto Price', `$${resultsData.currentPrice.toFixed(2)}`],
['Hardware Cost', `$${resultsData.hardwareCost.toFixed(2)}`],
];
doc.autoTable({
startY: 40,
head: [['Input Parameters', 'Value']],
body: inputSummaryBody,
theme: 'striped',
headStyles: headStyle,
styles: bodyStyle,
columnStyles: { 0: { fontStyle: 'bold' } }
});
let multiplier = 1;
switch(projectionPeriodEl?.value || 'daily') {
case 'weekly': multiplier = 7; break;
case 'monthly': multiplier = 30.4375; break;
case 'annually': multiplier = 365.25; break;
}
const dailyResultsBody = [
['Coins Mined', `${resultsData.dailyCoinsMined.toFixed(8)}`],
['Revenue', `$${resultsData.dailyRevenue.toFixed(2)}`],
['Electricity Cost', `$${resultsData.dailyElectricityCost.toFixed(2)}`],
['Pool Fees', `$${resultsData.dailyPoolFees.toFixed(2)}`],
['Net Profit/Loss', `$${resultsData.dailyNetProfit.toFixed(2)}`],
];
doc.autoTable({
startY: doc.lastAutoTable.finalY + 10,
head: [['Daily Estimates', 'Value']],
body: dailyResultsBody,
theme: 'striped',
headStyles: headStyle,
styles: bodyStyle,
columnStyles: { 0: { fontStyle: 'bold'} },
didParseCell: function (data) {
if (data.row.index === 4 && data.column.index === 1) { // Net Profit/Loss value
data.cell.styles.textColor = resultsData.dailyNetProfit >= 0 ? [16, 185, 129] : [239, 68, 68];
}
}
});
const projectedResultsBody = [
['Coins Mined', `${(resultsData.dailyCoinsMined * multiplier).toFixed(8)}`],
['Revenue', `$${(resultsData.dailyRevenue * multiplier).toFixed(2)}`],
['Electricity Cost', `$${(resultsData.dailyElectricityCost * multiplier).toFixed(2)}`],
['Pool Fees', `$${(resultsData.dailyPoolFees * multiplier).toFixed(2)}`],
['Net Profit/Loss', `$${(resultsData.dailyNetProfit * multiplier).toFixed(2)}`],
];
doc.autoTable({
startY: doc.lastAutoTable.finalY + 10,
head: [[`${projectionPeriodText} Projected Estimates`, 'Value']],
body: projectedResultsBody,
theme: 'striped',
headStyles: headStyle,
styles: bodyStyle,
columnStyles: { 0: { fontStyle: 'bold'} },
didParseCell: function (data) {
if (data.row.index === 4 && data.column.index === 1) { // Net Profit/Loss value
data.cell.styles.textColor = (resultsData.dailyNetProfit * multiplier) >= 0 ? [16, 185, 129] : [239, 68, 68];
}
}
});
const additionalMetricsBody = [
['Break-Even Electricity Price', `$${resultsData.breakEvenElectricityPrice.toFixed(4)} / kWh`],
['Return on Investment (ROI)', resultsData.hardwareCost > 0 ? (isFinite(resultsData.roiDays) ? `${resultsData.roiDays.toFixed(1)} days` : (resultsData.dailyNetProfit <= 0 ? 'Never (at current rate)' : 'N/A')) : 'N/A (No hardware cost)'],
];
doc.autoTable({
startY: doc.lastAutoTable.finalY + 10,
head: [['Additional Metrics', 'Value']],
body: additionalMetricsBody,
theme: 'striped',
headStyles: headStyle,
styles: bodyStyle,
columnStyles: { 0: { fontStyle: 'bold'} }
});
doc.save(`mining_report_${resultsData.cryptoName.replace(/[^a-zA-Z0-9]/g, '_')}_${formattedDate}.pdf`);
}
// Event listener for DOMContentLoaded
document.addEventListener('DOMContentLoaded', function() {
// Assign DOM elements
cryptoNameMiningEl = document.getElementById('cryptoNameMining');
hashrateValueMiningEl = document.getElementById('hashrateValueMining');
hashrateUnitMiningEl = document.getElementById('hashrateUnitMining');
powerConsumptionMiningEl = document.getElementById('powerConsumptionMining');
hardwareCostMiningEl = document.getElementById('hardwareCostMining');
electricityCostMiningEl = document.getElementById('electricityCostMining');
poolFeeMiningEl = document.getElementById('poolFeeMining');
blockRewardMiningEl = document.getElementById('blockRewardMining');
networkDifficultyMiningEl = document.getElementById('networkDifficultyMining');
currentPriceMiningEl = document.getElementById('currentPriceMining');
errorMiningEl = document.getElementById('errorMining');
resultsMiningEl = document.getElementById('resultsMining');
const criticalElements = [
hashrateValueMiningEl, hashrateUnitMiningEl, powerConsumptionMiningEl, electricityCostMiningEl,
poolFeeMiningEl, blockRewardMiningEl, networkDifficultyMiningEl, currentPriceMiningEl,
errorMiningEl, resultsMiningEl
];
if (criticalElements.some(el => !el)) {
console.error("One or more critical elements are missing from the DOM for the Mining Calculator.");
const body = document.querySelector('body');
if (body && errorMiningEl && errorMiningEl.style.display === 'none') {
errorMiningEl.textContent = "Error: Calculator UI could not be fully initialized. Some fields may be missing. Please refresh.";
errorMiningEl.style.display = 'block';
} else if (body && !errorMiningEl) {
const errorDiv = document.createElement('div');
errorDiv.className = 'error-message';
errorDiv.textContent = "Critical Error: Calculator UI initialization failed. Please refresh.";
errorDiv.style.display = 'block';
const container = document.querySelector('.calculator-container');
if (container) container.prepend(errorDiv); else body.prepend(errorDiv);
}
}
});