diff --git a/api.js b/api.js index 0779f368..f1cfb9ee 100644 --- a/api.js +++ b/api.js @@ -246,67 +246,6 @@ export async function fetchProcessData(processName, periods, currentHeight) { } } - - -/** - * Fetches transaction counts for a specific process type over multiple time periods - * @param {string} processName - The name of the process - * @param {Array} periods - Array of time periods with start/end heights - * @returns {Promise} Array of transaction counts for each period - */ -export async function fetchVolumeData() { - try { - // Create a unique cache key for this request - const cacheKey = `volume-stats`; - - // Check if we have cached data that's less than 30min old - if (responseCache.has(cacheKey)) { - const { data, timestamp } = responseCache.get(cacheKey); - if (Date.now() - timestamp < 30 * 60 * 1000) { - return data; - } - } - - const response = await fetch ('https://raw.githubusercontent.com/Jonny-Ringo/the_eye_of_AO/main/data/volume-stats.json'); - if (!response.ok) { - throw new Error(`Network error: ${response.status} ${response.statusText}`); - - } - // Cache the result - const rawData = await response.json(); - - const volumeData = rawData.volumeData; - - // Transform the data into the required format - const processedData = { - AO: volumeData.AO.map(entry => ({ - timestamp: new Date(entry.date).getTime(), - value: entry.volume - })), - wAR: volumeData.wAR.map(entry => ({ - timestamp: new Date(entry.date).getTime(), - value: entry.volume - })), - wUSDC: volumeData.wUSDC.map(entry => ({ - timestamp: new Date(entry.date).getTime(), - value: entry.volume - })) - }; - - responseCache.set(cacheKey, { - data: processedData, - timestamp: Date.now() - }); - console.log('Processed volume data:', processedData); - return processedData; - } catch (error) { - console.error("Error fetching volume data:", error); - throw error; - } -} - - - /** * Fetches daily player stats for Stargrid Battle Tactics * @returns {Promise} Array of daily player count data @@ -361,10 +300,63 @@ export async function fetchStargridStats() { } } +/** + * Fetches Rune Realm Streaks data + * @returns {Promise} Object with streak breakdown data by day + */ +export async function fetchRuneRealmStats() { + try { + const cacheKey = 'rune-realm-streaks'; + // Use cached data if it's less than 15 minutes old + if (responseCache.has(cacheKey)) { + const { data, timestamp } = responseCache.get(cacheKey); + if (Date.now() - timestamp < 15 * 60 * 1000) { + return data; + } + } + + const response = await dryrun({ + process: 'GhNl98tr7ZQxIJHx4YcVdGh7WkT9dD7X4kmQOipvePQ', + data: '', + tags: [ + { name: "Action", value: "GetCheckinMapping" }, + { name: "Data-Protocol", value: "ao" }, + { name: "Type", value: "Message" }, + { name: "Variant", value: "ao.TN.1" } + ], + }); + + if (!response || !response.Messages || !response.Messages[0]) { + throw new Error('Invalid response from Rune Realm process'); + } + + // Get the first message's data + const message = response.Messages[0]; + const messageData = JSON.parse(message.Data); + + // Extract the History object from the data + if (!messageData || !messageData.History) { + throw new Error('No History data found in response'); + } + + const historyData = messageData.History; + + // Cache the result + responseCache.set(cacheKey, { + data: historyData, + timestamp: Date.now() + }); + + return historyData; + } catch (error) { + console.error("Error fetching Rune Realm stats:", error); + throw error; + } +} /** * Clears the API response cache */ export function clearCache() { responseCache.clear(); -} \ No newline at end of file +} diff --git a/charts.js b/charts.js index 4e1c9f97..eb50f6c4 100644 --- a/charts.js +++ b/charts.js @@ -1,15 +1,15 @@ /** * Chart creation and management for the Eye of AO dashboard */ -import { CHART_COLORS, CHART_DEFAULTS, TIME_FORMAT, UTC_TIMESTAMP_PROCESSES, NON_UTC_TIMESTAMP_PROCESSES } from './config.js'; +import { CHART_COLORS, CHART_DEFAULTS, TIME_FORMAT } from './config.js'; import { formatDate, formatDateUTCWithLocalTime, filterDataByTimeRange } from './utils.js'; import { getProcessDisplayName } from './processes.js'; import { setupTimeRangeButtons, toggleChartLoader, getChartTimeRange } from './ui.js'; -import { fetchStargridStats, fetchVolumeData } from './api.js' -import { fetchAdditionalData, updateVolumeChart, updateSupplyChart } from './index.js' +import { fetchStargridStats } from './api.js' +import { fetchAdditionalData } from './index.js' // Store all chart instances -export const charts = {}; +const charts = {}; // Historical data for each chart export const historicalData = {}; @@ -77,44 +77,20 @@ function createStandardTooltipCallbacks(processName) { return { label: function(context) { const dataIndex = context.dataIndex; + // Ensure we have data for this index if (!historicalData[processName] || !historicalData[processName][dataIndex]) { - return `Value: ${context.raw}`; + return `Count: ${context.raw}`; } const dataPoint = historicalData[processName][dataIndex]; + const count = dataPoint.count; - // For volume charts, handle the value differently - if (['AOVolume', 'wARVolume', 'wUSDCVolume'].includes(processName)) { - // Ensure we have a numeric value - const rawValue = Number(dataPoint.value || dataPoint.count || context.raw || 0); - - if (isNaN(rawValue)) { - console.warn(`Invalid value for ${processName}:`, dataPoint); - return 'Invalid value'; - } - - // Format based on token type - if (['AOVolume', 'wARVolume'].includes(processName)) { - const value = Math.floor(rawValue / Math.pow(10, 12)); - const tokenName = processName.replace('Volume', ''); - return `Volume: ${value.toLocaleString()} ${tokenName}`; - } else { - const value = Math.floor(rawValue / Math.pow(10, 6)); - return `Volume: ${value.toLocaleString()} wUSDC`; - } - } - - // For non-volume charts, use count - const count = dataPoint.count || 0; - const formattedValue = `Count: ${count.toLocaleString()}`; - - // Add current time for latest entry if (dataIndex === historicalData[processName].length - 1) { const currentTime = formatDate(new Date()); - return `${formattedValue} (Current data as of ${currentTime})`; + return `Count: ${count} (Current data as of ${currentTime})`; } - - return formattedValue; + + return `Count: ${count}`; }, title: function(context) { const dataIndex = context[0].dataIndex; @@ -125,17 +101,10 @@ function createStandardTooltipCallbacks(processName) { const dataPoint = historicalData[processName][dataIndex]; if (!dataPoint) return context[0].label; - // Then use it in the tooltip callback const date = new Date(dataPoint.timestamp); - if (NON_UTC_TIMESTAMP_PROCESSES.includes(processName)) { - // Add one day for non-UTC processes - const adjustedDate = new Date(date.getTime()); - return formatDate(adjustedDate, TIME_FORMAT.tooltip); - } else if (UTC_TIMESTAMP_PROCESSES.includes(processName)) { - return formatDateUTCWithLocalTime(date); - } else { - return formatDate(date, TIME_FORMAT.tooltip); - } + return processName === 'stargrid' + ? formatDateUTCWithLocalTime(date) + : formatDate(date, TIME_FORMAT.tooltip); } }; } @@ -154,6 +123,43 @@ function createSupplyTooltipCallbacks() { }; } +/** + * Creates tooltip callbacks for a multi-line chart + * @param {string} processName - The process name + * @returns {Object} Tooltip callback functions + */ +function createMultiLineTooltipCallbacks(processName) { + return { + label: function(context) { + // Skip the placeholder dataset + if (context.datasetIndex === 0) return null; + + const datasetIndex = context.datasetIndex; + const dataIndex = context.dataIndex; + const dataset = context.chart.data.datasets[datasetIndex]; + + const data = historicalData[processName]; + if (!data || dataIndex >= data.length) return `${dataset.label}: ${context.raw}`; + + // Get the value for this dataset and date + return `${dataset.label}: ${context.raw}`; + }, + title: function(context) { + const dataIndex = context[0].dataIndex; + const data = historicalData[processName]; + + if (!data || dataIndex >= data.length) return context[0].label; + + // Format the date nicely + const date = new Date(data[dataIndex].timestamp); + return formatDate(date, TIME_FORMAT.tooltip); + }, + filter: function(tooltipItem) { + // Filter out the placeholder dataset + return tooltipItem.datasetIndex !== 0; + } + }; +} /** * Creates a legend configuration that uses the correct colors @@ -319,6 +325,93 @@ function createCombinedChart(primaryProcess, secondaryProcess) { }); } +/** + * Creates a multi-line chart for Rune Realm Streaks + * @returns {Object} Chart instance + */ +function createMultiLineChart() { + const canvasId = 'runeRealmStreaksChart'; + const ctx = document.getElementById(canvasId)?.getContext('2d'); + + if (!ctx) { + console.error(`Cannot create chart: Canvas element ${canvasId} not found`); + return null; + } + + // Initialize historical data if not already done + if (!historicalData['runeRealmStreaks']) { + historicalData['runeRealmStreaks'] = []; + } + + // Set up the datasets with a placeholder dataset in the first position + // This is a workaround for Chart.js to ensure proper display + return new Chart(ctx, { + type: 'line', + data: { + labels: [], + datasets: [ + { + // Placeholder dataset (invisible) + label: 'Placeholder', + data: [], + borderColor: 'rgba(0,0,0,0)', + pointRadius: 0, + hidden: true + }, + { + label: 'Low', + data: [], + borderColor: 'rgb(75, 192, 192)', + tension: CHART_DEFAULTS.tension, + pointRadius: CHART_DEFAULTS.pointRadius + }, + { + label: 'Medium', + data: [], + borderColor: 'rgb(255, 159, 64)', + tension: CHART_DEFAULTS.tension, + pointRadius: CHART_DEFAULTS.pointRadius + }, + { + label: 'High', + data: [], + borderColor: 'rgb(255, 99, 132)', + tension: CHART_DEFAULTS.tension, + pointRadius: CHART_DEFAULTS.pointRadius + }, + { + label: 'Total', + data: [], + borderColor: 'rgb(54, 162, 235)', + tension: CHART_DEFAULTS.tension, + pointRadius: CHART_DEFAULTS.pointRadius + } + ] + }, + options: { + responsive: CHART_DEFAULTS.responsive, + maintainAspectRatio: CHART_DEFAULTS.maintainAspectRatio, + scales: createAxesConfig(), + plugins: { + legend: { + ...createLegendConfig(), + // Custom legend generation to filter out placeholder dataset + labels: { + ...createLegendConfig().labels, + filter: function(item, chart) { + // Filter out the placeholder dataset + return item.datasetIndex !== 0; + } + } + }, + tooltip: { + callbacks: createMultiLineTooltipCallbacks('runeRealmStreaks') + } + } + } + }); +} + /** * Creates a supply chart for wAR * @returns {Object} Chart instance @@ -380,48 +473,95 @@ function createSupplyChart() { }); } - export async function fetchChartData(processName, timeRange) { - if (['stargrid', 'AOVolume', 'wARVolume', 'wUSDCVolume'].includes(processName)) { - await updateChartWithStats(processName); + if (processName === 'stargrid') { + // For Stargrid, use the dedicated function + await updateStargridChart(); + } else if (processName === 'runeRealmStreaks') { + // For Rune Realm Streaks, use the dedicated function + await updateRuneRealmChart(); } else { console.log(`Using fetchAdditionalData for ${processName}`); await fetchAdditionalData(processName, timeRange); } } -export async function updateChartWithStats(processName) { + +export async function updateStargridChart() { try { - toggleChartLoader(processName, true); - - let data; - if (processName === 'stargrid') { - data = await fetchStargridStats(); - } else if (['AOVolume', 'wARVolume', 'wUSDCVolume'].includes(processName)) { - const volumeData = await updateVolumeChart(processName); - const tokenType = processName.replace('Volume', ''); - // Use the full dataset - data = volumeData[tokenType].map(entry => ({ - timestamp: entry.timestamp, - count: entry.value - })); - console.log(`Processing ${data.length} entries for ${processName}`); - } + toggleChartLoader('stargrid', true); - if (!data) throw new Error(`Failed to fetch ${processName} data`); + const stargridData = await fetchStargridStats(); + if (!stargridData) throw new Error('Failed to fetch stargrid data'); - // Store the complete dataset - historicalData[processName] = data; + const formatted = stargridData.map(entry => ({ + ...entry, + timestamp: new Date(entry.timestamp).toISOString() + })); - // Get and apply time range - const timeRange = getChartTimeRange(processName); - console.log(`Updating ${processName} with time range: ${timeRange}`); - updateChartTimeRange(processName, timeRange || '1M'); + historicalData['stargrid'] = formatted; - toggleChartLoader(processName, false); + const timeRange = getChartTimeRange('stargrid'); + updateChartTimeRange('stargrid', timeRange); + + toggleChartLoader('stargrid', false); } catch (error) { - console.error(`Error updating ${processName} chart:`, error); - toggleChartLoader(processName, false); + console.error('Error updating Stargrid chart:', error); + toggleChartLoader('stargrid', false); + } +} + +/** + * Updates the Rune Realm Streaks chart with data from the AO process + */ +export async function updateRuneRealmChart() { + try { + toggleChartLoader('runeRealmStreaks', true); + + // Import the fetchRuneRealmStats function from api.js + const { fetchRuneRealmStats } = await import('./api.js'); + const historyData = await fetchRuneRealmStats(); + + if (!historyData) throw new Error('Failed to fetch Rune Realm data'); + + // Transform the data into a format suitable for the chart + // Example data format from AO: {'20226': { Medium: 0, High: 3, Low: 11 }, ...} + const formattedData = []; + + // Convert unix day numbers to actual dates and structure the data for the chart + Object.entries(historyData).forEach(([day, stats]) => { + // Convert the unix day number to a JavaScript Date + // Unix day is number of days since Unix epoch (Jan 1, 1970) + const dayNumber = parseInt(day, 10); + const timestamp = new Date(dayNumber * 24 * 60 * 60 * 1000); + + // Calculate the total for all categories + const total = (stats.Low || 0) + (stats.Medium || 0) + (stats.High || 0); + + formattedData.push({ + timestamp: timestamp.toISOString(), + day: dayNumber, + Low: stats.Low || 0, + Medium: stats.Medium || 0, + High: stats.High || 0, + Total: total + }); + }); + + // Sort by timestamp ascending + formattedData.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp)); + + // Store in historicalData for tooltip access and filtering + historicalData['runeRealmStreaks'] = formattedData; + + // Apply time range filter and update chart + const timeRange = getChartTimeRange('runeRealmStreaks'); + updateMultiLineChart(timeRange); + + toggleChartLoader('runeRealmStreaks', false); + } catch (error) { + console.error('Error updating Rune Realm Streaks chart:', error); + toggleChartLoader('runeRealmStreaks', false); } } @@ -429,6 +569,55 @@ export async function updateChartWithStats(processName) { /** * Initialize all charts based on process definitions */ +/** + * Updates the multi-line chart for Rune Realm Streaks + * @param {string} timeRange - The selected time range + */ +export function updateMultiLineChart(timeRange) { + const chart = charts['runeRealmStreaks']; + if (!chart) { + console.error('No chart found for Rune Realm Streaks'); + return; + } + + const data = historicalData['runeRealmStreaks'] || []; + if (data.length === 0) { + console.warn('No data available for Rune Realm Streaks'); + return; + } + + // Filter data by time range + const filteredData = filterDataByTimeRange(data, timeRange); + + // Ensure data is sorted chronologically + const sortedData = [...filteredData].sort((a, b) => { + return new Date(a.timestamp) - new Date(b.timestamp); + }); + + // Create labels from timestamps + const labels = sortedData.map(d => { + const date = new Date(d.timestamp); + return formatDate(date); + }); + + // Extract values for each streak category + const lowValues = sortedData.map(d => d.Low); + const mediumValues = sortedData.map(d => d.Medium); + const highValues = sortedData.map(d => d.High); + const totalValues = sortedData.map(d => d.Total); + + // Update chart datasets (remember to keep the placeholder dataset at index 0) + chart.data.labels = labels; + chart.data.datasets[0].data = new Array(labels.length).fill(0); // Placeholder data + chart.data.datasets[1].data = lowValues; + chart.data.datasets[2].data = mediumValues; + chart.data.datasets[3].data = highValues; + chart.data.datasets[4].data = totalValues; + + // Update the chart with animation disabled for performance + chart.update('none'); +} + export function initializeCharts() { // Clear any existing chart instances to prevent memory leaks Object.keys(charts).forEach(chartId => { @@ -443,8 +632,11 @@ export function initializeCharts() { // Special case: wAR total supply chart charts['wARTotalSupply'] = createSupplyChart(); + // Special case: Rune Realm Streaks multi-line chart + charts['runeRealmStreaks'] = createMultiLineChart(); + // Standard charts for remaining processes - ['wUSDCVolume', 'wARweeklyTransfer', 'wARTransfer', 'wARVolume', 'AOTransfer','AOVolume', 'permaswap', 'botega', 'llamaLand', 'stargrid'].forEach(processName => { + ['wARweeklyTransfer', 'wARTransfer', 'AOTransfer', 'permaswap', 'botega', 'llamaLand', 'stargrid'].forEach(processName => { charts[processName] = createStandardChart(processName); }); @@ -459,7 +651,6 @@ export function initializeCharts() { * @param {Array} dataPoints - Array of data points */ export function updateStandardChart(processName, dataPoints) { - console.log(`Updating chart for ${processName} with`, dataPoints); const chart = charts[processName]; if (!chart) { console.error(`No chart found for process: ${processName}`); @@ -477,23 +668,11 @@ export function updateStandardChart(processName, dataPoints) { // Create labels from timestamps const labels = sortedData.map(d => { const date = new Date(d.timestamp); - return ['stargrid', 'wARVolume', 'AOVolume', 'wUSDCVolume'].includes(processName) - ? formatDateUTCWithLocalTime(date) - : formatDate(date); + return processName === 'stargrid' ? formatDateUTCWithLocalTime(date) : formatDate(date); }); - // Get the data values with proper decimal formatting - const values = sortedData.map(d => { - const rawValue = d.count || d.value || 0; - - // Format based on token type - if (['AOVolume', 'wARVolume'].includes(processName)) { - return rawValue / 1000000000000; // Remove 12 zeros for AO and wAR - } else if (processName === 'wUSDCVolume') { - return rawValue / 1000000; // Remove 6 zeros for wUSDC - } - return rawValue; - }); + // Get the data values + const values = sortedData.map(d => d.count); // Update chart chart.data.labels = labels; @@ -649,6 +828,44 @@ function createCombinedTooltipCallbacks(primaryProcess, secondaryProcess) { }; } +/** + * Updates the supply chart with wAR supply data + * @param {Array} supplyData - Array of supply data points + * @param {string} timeRange - The selected time range + */ +export function updateSupplyChart(supplyData, timeRange) { + const chart = charts['wARTotalSupply']; + if (!chart) { + console.error('No supply chart found'); + return; + } + + if (!supplyData || supplyData.length === 0) { + console.warn('No supply data available'); + return; + } + + // Filter by time range + const filteredData = filterDataByTimeRange(supplyData, timeRange); + + // Sort data by timestamp to ensure chronological order + const sortedData = [...filteredData].sort((a, b) => { + return new Date(a.timestamp) - new Date(b.timestamp); + }); + + // Create labels and datasets (just wAR now) + const labels = sortedData.map(d => formatDate(new Date(d.timestamp))); + const wARSupply = sortedData.map(d => d.wARSupply); + + // Update chart with only wAR data + chart.data.labels = labels; + chart.data.datasets[0].data = wARSupply; + chart.data.datasets[0].label = 'wAR Total Supply'; + + // Update the chart + chart.update('none'); +} + /** * Gets a chart instance by process name * @param {string} processName - The process name @@ -782,4 +999,4 @@ function removeDuplicateDates(data, isWeekly = false) { const sortedResult = result.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp)); return sortedResult; -} \ No newline at end of file +} diff --git a/config.js b/config.js index 627ae379..8ac30db5 100644 --- a/config.js +++ b/config.js @@ -7,15 +7,13 @@ export const CHART_COLORS = { permaswap: 'rgb(54, 162, 235)', botega: 'rgb(255, 99, 132)', wARTransfer: 'rgb(255, 159, 64)', - wARVolume: 'rgb(255, 159, 64)', wARweeklyTransfer: 'rgb(255, 159, 64)', llamaLand: 'rgb(255, 205, 86)', stargrid: 'rgb(131, 86, 255)', AOTransfer: 'rgb(47, 243, 8)', - AOVolume: 'rgb(47, 243, 8)', wUSDCTransfer: 'rgb(19, 62, 252)', - wUSDCVolume: 'rgb(19, 62, 252)', - USDATransfer: 'rgb(51, 139, 0)' + USDATransfer: 'rgb(51, 139, 0)', + runeRealmStreaks: 'rgb(75, 192, 192)' }; // Time range values in milliseconds @@ -26,23 +24,6 @@ export const TIME_RANGES = { '3M': 90 * 24 * 60 * 60 * 1000 // 3 months in milliseconds }; -export const UTC_TIMESTAMP_PROCESSES = [ - 'stargrid', - 'wARVolume', - 'AOVolume', - 'wUSDCVolume' -]; - -export const NON_UTC_TIMESTAMP_PROCESSES = [ - 'wARTransfer', - 'AOTransfer', - 'permaswap', - 'botega', - 'llamaLand', - 'wARTotalSupply' -]; - - // Default time range for all charts export const DEFAULT_TIME_RANGE = '1W'; @@ -78,4 +59,4 @@ export const CHART_DEFAULTS = { pointRadius: 5, responsive: true, maintainAspectRatio: false -}; \ No newline at end of file +}; diff --git a/index.html b/index.html index 093254e9..2524457c 100644 --- a/index.html +++ b/index.html @@ -110,50 +110,8 @@

👁️ The Eye of AO

AO Network Stats

-
- -
-
-

AO Daily Transaction Count

-
-
-
-
-
Fetching Transaction History...
-
-
- -
-
- - - -
-
-
- - -
-
-

AO Daily Volume

-
-
-
-
-
Fetching Transaction History...
-
-
- -
-
- - - -
-
-
- +

wUSDC/USDA Daily Transaction Count

@@ -176,15 +134,15 @@

wUSDC/USDA Daily Transaction Count

-

wUSDC Daily Volume

+

AO Daily Transaction Count

-
+
Fetching Transaction History...
- +
@@ -194,8 +152,6 @@

wUSDC Daily Volume

- -

wAR Daily Transaction Count

@@ -216,29 +172,6 @@

wAR Daily Transaction Count

- -
-
-

wAR Daily Volume

-
-
-
-
-
Fetching Transaction History...
-
-
- -
-
- - - -
-
-
- - -

wAR Weekly Transaction Count

@@ -368,6 +301,26 @@

Stargrid Battle Tactics Daily Player Count

+ +
+
+

Rune Realm Streaks

+
+
+
+
+
Fetching Streak History...
+
+
+ +
+
+ + + +
+
+
@@ -383,4 +336,4 @@

Stargrid Battle Tactics Daily Player Count

- \ No newline at end of file + diff --git a/index.js b/index.js index d16ede1e..e7b8f4ad 100644 --- a/index.js +++ b/index.js @@ -6,15 +6,14 @@ import { fetchProcessData, fetchSupplyHistory, fetchStargridStats, - fetchVolumeData + clearCache } from './api.js'; import { initializeCharts, historicalData, updateChartTimeRange, updateCombinedChart, - fetchChartData, - charts + fetchChartData } from './charts.js'; import { initializeUI, @@ -29,9 +28,7 @@ import { getWeeklyPeriods, getLastDailyCheckpoint, getLastSundayCheckpoint, - findBlockNearDate, - filterDataByTimeRange, - formatDate + findBlockNearDate } from './utils.js'; /** @@ -350,42 +347,39 @@ function generateExtendedDailyPeriods(currentHeight, blockData, days) { /** - * Updates the supply chart with wAR supply data - * @param {Array} supplyData - Array of supply data points - * @param {string} timeRange - The selected time range + * Updates the supply chart with data from the wAR processes */ -export function updateSupplyChart(supplyData, timeRange) { - console.log(`Updating supply chart with time range: ${timeRange}`); - const chart = charts['wARTotalSupply']; - if (!chart) { - console.error('No supply chart found'); - return; - } - - if (!supplyData || supplyData.length === 0) { - console.warn('No supply data available'); - return; +async function updateSupplyChart() { + try { + toggleChartLoader('wARTotalSupply', true); + + const supplyData = await fetchSupplyHistory(); + if (!supplyData) throw new Error('Failed to fetch supply data'); + + // Process only wAR supply data + const processedData = supplyData.wAR.map(d => ({ + timestamp: d.date, + wARSupply: Number(d.totalSupply) / 1e12 + })); + + // Ensure timestamps are properly formatted as date strings + const formattedData = processedData.map(entry => ({ + ...entry, + timestamp: new Date(entry.timestamp).toISOString() + })); + + // Update historical data + historicalData['wARTotalSupply'] = formattedData; + + // Update chart + const timeRange = getChartTimeRange('wARTotalSupply'); + updateChartTimeRange('wARTotalSupply', timeRange); + + toggleChartLoader('wARTotalSupply', false); + } catch (error) { + console.error('Error updating supply chart:', error); + toggleChartLoader('wARTotalSupply', false); } - - // Filter by time range - const filteredData = filterDataByTimeRange(supplyData, timeRange); - - // Sort data by timestamp to ensure chronological order - const sortedData = [...filteredData].sort((a, b) => { - return new Date(a.timestamp) - new Date(b.timestamp); - }); - - // Create labels and datasets (just wAR now) - const labels = sortedData.map(d => formatDate(new Date(d.timestamp))); - const wARSupply = sortedData.map(d => d.wARSupply); - - // Update chart with only wAR data - chart.data.labels = labels; - chart.data.datasets[0].data = wARSupply; - chart.data.datasets[0].label = 'wAR Total Supply'; - - // Update the chart - chart.update('none'); } /** @@ -418,42 +412,6 @@ export async function updateStargridChart() { } } -/** - * Updates volume charts with data from cache - * @param {string} processName - The chart to update ('AOVolume', 'wARVolume', or 'wUSDCVolume') - * @returns {Promise} The volume data - */ -export async function updateVolumeChart(processName) { - try { - // Get all volume data - const volumeData = await fetchVolumeData(); - - // Map process names to their data keys - const tokenType = processName.replace('Volume', ''); - - if (!volumeData[tokenType]) { - throw new Error(`No data found for ${tokenType}`); - } - - console.log(`Full ${tokenType} dataset:`, volumeData[tokenType].length, 'entries'); - - // Format the data - const formattedData = volumeData[tokenType].map(entry => ({ - timestamp: new Date(entry.timestamp).toISOString(), - value: entry.value - })); - - // Store complete dataset in historicalData - historicalData[processName] = formattedData; - - return volumeData; - - } catch (error) { - console.error(`Error updating ${processName} chart:`, error); - throw error; - } -} - /** * Fetches and updates data for a specific process @@ -847,20 +805,11 @@ async function initializeDashboard() { console.error("Error loading Stargrid chart:", error); toggleChartLoader('stargrid', false); }); - - loadVolumeChart('AOVolume').catch(error => { - console.error("Error loading AO Volume chart:", error); - toggleChartLoader('AOVolume', false); - }); - - loadVolumeChart('wARVolume').catch(error => { - console.error("Error loading wAR Volume chart:", error); - toggleChartLoader('wARVolume', false); - }); - - loadVolumeChart('wUSDCVolume').catch(error => { - console.error("Error loading wUSDC Volume chart:", error); - toggleChartLoader('wUSDCVolume', false); + + // Load Rune Realm Streaks chart + loadRuneRealmStreaksChart().catch(error => { + console.error("Error loading Rune Realm Streaks chart:", error); + toggleChartLoader('runeRealmStreaks', false); }); } catch (error) { @@ -869,6 +818,7 @@ async function initializeDashboard() { } } +// ... (rest of the code remains the same) /** * Loads the Stargrid chart with data from AO * @returns {Promise} Resolves when chart is loaded @@ -894,51 +844,31 @@ async function loadStargridChart() { } finally { toggleChartLoader('stargrid', false); } -} - + } /** - * Loads volume charts (AO, wAR, wUSDC) with data from the API - * @param {string} processName - The chart to load ('AOVolume', 'wARVolume', or 'wUSDCVolume') + * Loads the Rune Realm Streaks chart with data from AO * @returns {Promise} Resolves when chart is loaded */ -async function loadVolumeChart(processName) { - try { - console.log(`Loading ${processName} chart...`); - toggleChartLoader(processName, true); - - const volumeData = await fetchVolumeData(); - - // Map process names to their data keys - const dataKeys = { - 'AOVolume': 'AO', - 'wARVolume': 'wAR', - 'wUSDCVolume': 'wUSDC' - }; - - const dataKey = dataKeys[processName]; - if (!dataKey || !volumeData[dataKey]) { - throw new Error(`No data found for ${processName}`); - } - const chartData = volumeData[dataKey]; - - // Update historical data - if (chartData.length > 0) { - historicalData[processName] = chartData; - - // Update the chart - const timeRange = getChartTimeRange(processName); - console.log(`Time range for ${processName}:`, timeRange); - updateChartTimeRange(processName, timeRange); - } - } catch (error) { - console.error(`Error loading ${processName} chart:`, error); - } finally { - toggleChartLoader(processName, false); - } +async function loadRuneRealmStreaksChart() { + try { + console.log("Loading Rune Realm Streaks chart..."); + toggleChartLoader('runeRealmStreaks', true); + + // Import the updateRuneRealmChart function + const { updateRuneRealmChart } = await import('./charts.js'); + + // Call the update function which will fetch the data and update the chart + await updateRuneRealmChart(); + console.log("Rune Realm Streaks data loaded and chart updated"); + + } catch (error) { + console.error("Error loading Rune Realm Streaks chart:", error); + } finally { + toggleChartLoader('runeRealmStreaks', false); + } } - /** * Loads a process chart, handling both standard and combined charts * @param {string} processName - The process name @@ -1044,4 +974,4 @@ async function loadSupplyChart() { document.addEventListener('DOMContentLoaded', initializeDashboard); // Export for potential future use -export { initializeDashboard, fetchAllData }; \ No newline at end of file +export { initializeDashboard, fetchAllData };