103 lines
4.0 KiB
JavaScript
103 lines
4.0 KiB
JavaScript
document.addEventListener('DOMContentLoaded', function () {
|
|
const POLLING_INTERVAL = 3000; // 3 seconds
|
|
|
|
// --- Configuration for Live Tickers ---
|
|
const liveTickers = [
|
|
{ symbol: 'BTCUSDT', elementId: 'live-crypto-row-btc', lastPrice: 0 },
|
|
{ symbol: 'ETHUSDT', elementId: 'live-crypto-row-eth', lastPrice: 0 }
|
|
];
|
|
|
|
// --- Generic Fetch and Update Functions ---
|
|
|
|
/**
|
|
* Fetches the latest price for a given symbol and updates its corresponding row.
|
|
* @param {object} ticker - The ticker object from the liveTickers array.
|
|
* @param {HTMLElement} rowElement - The table row element to update.
|
|
*/
|
|
async function fetchAndupdate(ticker, rowElement) {
|
|
try {
|
|
const response = await fetch(`api/ticker.php?symbol=${ticker.symbol}`);
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
}
|
|
const data = await response.json();
|
|
|
|
if (data.error) {
|
|
throw new Error(`API Error: ${data.error}`);
|
|
}
|
|
|
|
updateRow(data, ticker, rowElement);
|
|
|
|
} catch (error) {
|
|
console.error(`Failed to fetch live price for ${ticker.symbol}:`, error);
|
|
// Optionally, display an error state in the specific row
|
|
const priceCell = rowElement.querySelector('.price');
|
|
if (priceCell) priceCell.textContent = 'Error';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the DOM of a specific row with new data.
|
|
* @param {object} data - The data object from the API.
|
|
* @param {object} ticker - The ticker object being updated.
|
|
* @param {HTMLElement} rowElement - The table row element.
|
|
*/
|
|
function updateRow(data, ticker, rowElement) {
|
|
const priceCell = rowElement.querySelector('.price');
|
|
const changeCell = rowElement.querySelector('.change');
|
|
const symbolCell = rowElement.querySelector('.symbol');
|
|
const exchangeCell = rowElement.querySelector('.exchange');
|
|
|
|
if (!priceCell || !changeCell || !symbolCell || !exchangeCell) {
|
|
console.error(`One or more required elements not found in row for ${ticker.symbol}`);
|
|
return;
|
|
}
|
|
|
|
const currentPrice = parseFloat(data.price);
|
|
const priceChange = currentPrice - ticker.lastPrice;
|
|
|
|
// Update text content
|
|
priceCell.textContent = `$${currentPrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
|
|
symbolCell.textContent = data.symbol.replace('_SPBL', '');
|
|
exchangeCell.textContent = data.exchange;
|
|
|
|
// Update 24h change
|
|
const changePercent = parseFloat(data.change_24h_percent);
|
|
changeCell.textContent = `${changePercent.toFixed(2)}%`;
|
|
changeCell.classList.toggle('text-success', changePercent >= 0);
|
|
changeCell.classList.toggle('text-danger', changePercent < 0);
|
|
|
|
// Visual flash on price change
|
|
if (ticker.lastPrice !== 0 && priceChange !== 0) {
|
|
const flashClass = priceChange > 0 ? 'flash-success' : 'flash-danger';
|
|
priceCell.classList.add(flashClass);
|
|
setTimeout(() => priceCell.classList.remove(flashClass), 750);
|
|
}
|
|
|
|
ticker.lastPrice = currentPrice; // Update the last price for this specific ticker
|
|
}
|
|
|
|
// --- Initialization ---
|
|
|
|
/**
|
|
* Initializes the polling for all configured tickers.
|
|
*/
|
|
function initializeLiveTickers() {
|
|
liveTickers.forEach(ticker => {
|
|
const rowElement = document.getElementById(ticker.elementId);
|
|
if (!rowElement) {
|
|
console.error(`Element with ID #${ticker.elementId} not found for symbol ${ticker.symbol}.`);
|
|
return; // Skip this ticker if its row doesn't exist
|
|
}
|
|
|
|
// Initial fetch
|
|
fetchAndupdate(ticker, rowElement);
|
|
|
|
// Start polling every X seconds
|
|
setInterval(() => fetchAndupdate(ticker, rowElement), POLLING_INTERVAL);
|
|
});
|
|
}
|
|
|
|
initializeLiveTickers();
|
|
});
|