Upload or Enter Copper Market Data
Provide data with dates and prices. Prices are assumed to be in USD ($).
Or Enter Data Manually:
Current Data Preview:
No data loaded yet.
| Date | Price ($) |
|---|
Copper Market Analysis
Summary Statistics (USD $)
Date Range: -
Number of Data Points: -
Highest Price: - (on -)
Lowest Price: - (on -)
Average Price: -
Net Change: -
Percentage Change: -
Charting library (Chart.js) is missing or failed to load. Chart cannot be displayed.
"; return; } this.chartInstance = new Chart(ctx, { type: 'line', data: { labels: this.marketData.map(item => item.date.toLocaleDateString()), datasets: [{ label: 'Copper Price (USD $)', data: this.marketData.map(item => item.price), borderColor: '#007bff', backgroundColor: 'rgba(0, 123, 255, 0.1)', fill: true, tension: 0.1 }] }, options: { responsive: true, maintainAspectRatio: true, // Maintain aspect ratio scales: { x: { title: { display: true, text: 'Date' }, ticks: { autoSkip: true, maxTicksLimit: 15 } // Adjust for readability }, y: { title: { display: true, text: 'Price (USD $)' }, ticks: { callback: function(value) { return '$' + value.toFixed(2); } } } }, plugins: { tooltip: { callbacks: { label: function(context) { let label = context.dataset.label || ''; if (label) { label += ': '; } if (context.parsed.y !== null) { label += new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(context.parsed.y); } return label; } } } } } }); }, displaySummaryStatistics: function() { const summaryDateRangeEl = document.getElementById('cmtSummaryDateRange'); const summaryDataPointsEl = document.getElementById('cmtSummaryDataPoints'); const summaryHighestPriceEl = document.getElementById('cmtSummaryHighestPrice'); const summaryHighestPriceDateEl = document.getElementById('cmtSummaryHighestPriceDate'); const summaryLowestPriceEl = document.getElementById('cmtSummaryLowestPrice'); const summaryLowestPriceDateEl = document.getElementById('cmtSummaryLowestPriceDate'); const summaryAveragePriceEl = document.getElementById('cmtSummaryAveragePrice'); const summaryNetChangeEl = document.getElementById('cmtSummaryNetChange'); const summaryPercentageChangeEl = document.getElementById('cmtSummaryPercentageChange'); // Null checks for all elements if (!summaryDateRangeEl || !summaryDataPointsEl || !summaryHighestPriceEl || !summaryHighestPriceDateEl || !summaryLowestPriceEl || !summaryLowestPriceDateEl || !summaryAveragePriceEl || !summaryNetChangeEl || !summaryPercentageChangeEl) { console.error("One or more summary statistic elements not found."); return; } if (this.marketData.length === 0) { this.clearSummaryStatistics(); return; } const firstDataPoint = this.marketData[0]; const lastDataPoint = this.marketData[this.marketData.length - 1]; summaryDateRangeEl.textContent = `${firstDataPoint.date.toLocaleDateString()} - ${lastDataPoint.date.toLocaleDateString()}`; summaryDataPointsEl.textContent = this.marketData.length; let highestPrice = -Infinity; let highestPriceDate = ''; let lowestPrice = Infinity; let lowestPriceDate = ''; let sumPrices = 0; this.marketData.forEach(item => { if (item.price > highestPrice) { highestPrice = item.price; highestPriceDate = item.date.toLocaleDateString(); } if (item.price < lowestPrice) { lowestPrice = item.price; lowestPriceDate = item.date.toLocaleDateString(); } sumPrices += item.price; }); summaryHighestPriceEl.textContent = `$${highestPrice.toFixed(2)}`; summaryHighestPriceDateEl.textContent = highestPriceDate; summaryLowestPriceEl.textContent = `$${lowestPrice.toFixed(2)}`; summaryLowestPriceDateEl.textContent = lowestPriceDate; summaryAveragePriceEl.textContent = `$${(sumPrices / this.marketData.length).toFixed(2)}`; const netChange = lastDataPoint.price - firstDataPoint.price; const percentageChange = (firstDataPoint.price === 0) ? (netChange === 0 ? 0 : Infinity) : (netChange / firstDataPoint.price) * 100; summaryNetChangeEl.textContent = `${netChange >= 0 ? '+' : ''}$${netChange.toFixed(2)}`; summaryPercentageChangeEl.textContent = `${percentageChange.toFixed(2)}%`; }, clearSummaryStatistics: function() { const fields = ['cmtSummaryDateRange', 'cmtSummaryDataPoints', 'cmtSummaryHighestPrice', 'cmtSummaryHighestPriceDate', 'cmtSummaryLowestPrice', 'cmtSummaryLowestPriceDate', 'cmtSummaryAveragePrice', 'cmtSummaryNetChange', 'cmtSummaryPercentageChange']; fields.forEach(id => { const el = document.getElementById(id); if (el) el.textContent = '-'; // Null check before setting }); }, downloadResultsAsPDF: function() { // Prepare UI for printing: ensure Analysis tab is "active" for print styles to catch it // This is a bit of a hack; print styles should ideally make it visible regardless of JS state const analysisTab = document.getElementById('cmtAnalysisTab'); const dataInputTab = document.getElementById('cmtDataInputTab'); let originalDataInputDisplay = ''; if(dataInputTab) { originalDataInputDisplay = dataInputTab.style.display; dataInputTab.style.display = 'none'; // Hide input tab for print } if(analysisTab) analysisTab.style.display = 'block'; // Ensure analysis tab is block for print // Make sure the chart is rendered before printing if (this.marketData.length > 0 && (!this.chartInstance || this.currentTab !== 'cmtAnalysisTab')) { this.renderChart(); // Re-render if not currently visible or instance gone } // Give browser a moment to apply styles and render chart setTimeout(() => { window.print(); // Restore display after print dialog if(dataInputTab) dataInputTab.style.display = originalDataInputDisplay; if(analysisTab && this.currentTab !== 'cmtAnalysisTab') analysisTab.style.display = 'none'; if(analysisTab && this.currentTab === 'cmtAnalysisTab') analysisTab.style.display = 'block'; // if it was the active tab, restore to block }, 500); // Delay may need adjustment } }; CMT_App.init();