// Initialize charts let priceChart; let candleChart; document.addEventListener('DOMContentLoaded', function () { // Create candlestick chart const candleCtx = document.getElementById('candleChart'); if (!candleCtx) { console.error("Canvas element with ID 'candleChart' not found!"); return; } const context = candleCtx.getContext('2d'); if (!context) { console.error("Could not get 2D context from canvas element."); return; } // Generates simple random walk candle data function generateCandleData(count) { const data = []; let date = new Date(); date.setHours(date.getHours() - count, 0, 0, 0); let open = 80000; // Arbitrary starting point for (let i = 0; i < count; i++) { const time = date.getTime(); // Simple random change for close price const change = (Math.random() - 0.5) * 500; const close = open + change; // High and Low based on random volatility around open/close const high = Math.max(open, close) + Math.random() * 250; const low = Math.min(open, close) - Math.random() * 250; data.push({ x: time, o: open, h: high, l: low, c: close }); date.setHours(date.getHours() + 1); open = close; } return data; } const candleData = generateCandleData(60); // --- Update UI with latest price and percentage change ---\n if (candleData.length > 1) { // Need at least 2 points for change\n const latestDataPoint = candleData[candleData.length - 1];\n const previousDataPoint = candleData[candleData.length - 2];\n const latestPrice = latestDataPoint.c; // Latest closing price\n const previousPrice = previousDataPoint.c; // Previous closing price\n\n const priceChange = latestPrice - previousPrice;\n const percentageChange = (priceChange / previousPrice) * 100;\n const isPriceUp = priceChange >= 0;\n\n // Format the price (example: $XX,XXX.XX)\n const formattedPrice = `$${latestPrice.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;\n // Format percentage (e.g., +1.23%, -0.50%)\n const formattedPercentage = `${percentageChange >= 0 ? '+' : ''}${percentageChange.toFixed(2)}%`;\n // Format rounded price for watchlist\n const formattedPriceRounded = `$${Math.round(latestPrice).toLocaleString('en-US')}`;\n\n // Get UI elements\n const headerPriceElement = document.getElementById('latest-price-header');\n const headerChangeElement = document.getElementById('latest-price-change-header');\n const watchlistPriceElement = document.getElementById('watchlist-btc-price');\n // TODO: Add ID and update watchlist percentage element too\n \n // Update header price\n if (headerPriceElement) {\n headerPriceElement.textContent = formattedPrice;\n headerPriceElement.classList.toggle('text-green-mono', isPriceUp);\n headerPriceElement.classList.toggle('text-red-mono', !isPriceUp);\n }\n\n // Update header percentage change\n if (headerChangeElement) {\n headerChangeElement.textContent = formattedPercentage;\n headerChangeElement.classList.toggle('text-green-mono', isPriceUp);\n headerChangeElement.classList.toggle('text-red-mono', !isPriceUp);\n }\n\n // Update watchlist BTC price\n if (watchlistPriceElement) {\n watchlistPriceElement.textContent = formattedPriceRounded;\n // Note: Watchlist percentage/color update requires separate logic or IDs\n }\n }\n // --- End Price Update ---\n try { candleChart = new Chart(context, { type: 'candlestick', data: { datasets: [{ label: 'BTC/USDT', data: candleData, color: { up: '#10b981', down: '#ef4444', unchanged: '#94a3b8' }, borderColor: { up: '#10b981', down: '#ef4444', unchanged: '#94a3b8' }, borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } }, scales: { x: { type: 'time', time: { unit: 'hour', // Changed from day displayFormats: { hour: 'HH:mm' } // Changed format }, grid: { color: 'rgba(255, 255, 255, 0.05)' }, ticks: { color: '#94a3b8' } }, y: { position: 'right', grid: { color: 'rgba(255, 255, 255, 0.1)', // Slightly more visible grid borderDash: [5, 5] // Added dashed lines }, ticks: { color: '#94a3b8' } } } } }); // ResizeObserver to handle chart resizing when container changes const chartContainer = document.querySelector('.main-chart-container'); if (chartContainer && candleChart) { const resizeObserver = new ResizeObserver(entries => { // Removed requestAnimationFrame for potentially faster reaction if (!Array.isArray(entries) || !entries.length) { return; } // Call resize directly on the chart instance candleChart.resize(); }); resizeObserver.observe(chartContainer); } else { console.error("Could not find chart container or chart instance for ResizeObserver."); } } catch (error) { console.error("Error creating chart:", error); } // Buy/Sell button functionality const buyBtn = document.getElementById('buy-btn'); const sellBtn = document.getElementById('sell-btn'); const placeOrderBtn = document.getElementById('place-order-btn'); buyBtn.addEventListener('click', function () { buyBtn.classList.add('bg-green-600', 'text-white'); buyBtn.classList.remove('bg-green-900', 'bg-opacity-30', 'text-green-400'); sellBtn.classList.add('bg-red-900', 'bg-opacity-30', 'text-red-400'); sellBtn.classList.remove('bg-red-600', 'text-white'); placeOrderBtn.classList.add('bg-green-600'); placeOrderBtn.classList.remove('bg-red-600'); placeOrderBtn.textContent = 'Buy BTC'; }); sellBtn.addEventListener('click', function () { sellBtn.classList.add('bg-red-600', 'text-white'); sellBtn.classList.remove('bg-red-900', 'bg-opacity-30', 'text-red-400'); buyBtn.classList.add('bg-green-900', 'bg-opacity-30', 'text-green-400'); buyBtn.classList.remove('bg-green-600', 'text-white'); placeOrderBtn.classList.add('bg-red-600'); placeOrderBtn.classList.remove('bg-green-600'); placeOrderBtn.textContent = 'Sell BTC'; }); }); // Feed switching functionality function switchFeed(feedType) { // Preserve chart dimensions by forcing a layout calculation before DOM changes if (candleChart) { candleChart.resize(); } // Switch feed tabs - use visibility instead of display to maintain layout const feeds = ['posts-feed', 'chat-feed', 'video-feed']; feeds.forEach(feed => { const feedElement = document.getElementById(feed); if (feed === feedType + '-feed') { feedElement.style.visibility = 'visible'; feedElement.style.zIndex = '1'; } else { feedElement.style.visibility = 'hidden'; feedElement.style.zIndex = '0'; } }); // Update active button state const buttons = document.querySelectorAll('.feed-switch-btn'); buttons.forEach(btn => { btn.classList.remove('active'); if (btn.getAttribute('onclick') === `switchFeed('${feedType}')`) { btn.classList.add('active'); } }); // Force chart resize after tab switch to ensure proper rendering if (candleChart) { // Immediate resize candleChart.resize(); // Another resize after a small delay to ensure everything has settled setTimeout(() => { if (candleChart) { candleChart.resize(); } }, 50); } } // Placeholder function for indicator buttons function updateChart(indicatorType) { // In a real implementation, you would update the chart data or options here // based on the selected indicator. // For now, we can just highlight the button. // Remove active class from all indicator buttons inside the dropdown const indicatorButtons = document.querySelectorAll('#indicators-menu button'); // Updated selector indicatorButtons.forEach(btn => btn.classList.remove('indicator-active')); // Add active class to the clicked button const clickedButton = document.getElementById(`${indicatorType}-btn`); if (clickedButton) { clickedButton.classList.add('indicator-active'); } // Example: Add/remove datasets based on indicatorType (requires more complex logic) // if (indicatorType === 'sma') { ... } } // Dropdown Toggle Function function toggleDropdown(menuId) { const menu = document.getElementById(menuId); if (menu) { menu.classList.toggle('hidden'); // Update aria-expanded attribute for accessibility const button = document.querySelector(`[onclick*="toggleDropdown('${menuId}')"]`); if (button) { const isExpanded = !menu.classList.contains('hidden'); button.setAttribute('aria-expanded', isExpanded.toString()); } } } // Close Dropdown Function function closeDropdown(menuId) { const menu = document.getElementById(menuId); if (menu && !menu.classList.contains('hidden')) { menu.classList.add('hidden'); const button = document.querySelector(`[onclick*="toggleDropdown('${menuId}')"]`); if (button) { button.setAttribute('aria-expanded', 'false'); } } } // Close dropdown if clicked outside document.addEventListener('click', function(event) { const dropdownContainer = document.getElementById('indicators-dropdown'); // ID of the main dropdown container div const menu = document.getElementById('indicators-menu'); // Check if the click is outside the dropdown container if (dropdownContainer && menu && !dropdownContainer.contains(event.target)) { closeDropdown('indicators-menu'); } }); // --- Resizable Panel Logic --- document.addEventListener('DOMContentLoaded', () => { const handle = document.getElementById('bottom-panel'); const chartArea = document.getElementById('chart-area'); const tabContent = document.getElementById('tab-content'); const mainTerminal = document.getElementById('main-terminal'); // Parent container if (!handle || !chartArea || !tabContent || !mainTerminal) { console.error("Resizable panel elements not found."); return; } let isResizing = false; let startY = 0; let startChartHeight = 0; let startTabContentHeight = 0; const startResize = (e) => { isResizing = true; startY = e.clientY; startChartHeight = chartArea.offsetHeight; startTabContentHeight = tabContent.offsetHeight; // Prevent text selection during drag document.body.style.userSelect = 'none'; document.body.style.cursor = 'row-resize'; // Indicate resizing globally // Add listeners to the whole document for robust dragging document.addEventListener('mousemove', doResize); document.addEventListener('mouseup', stopResize); // Also add mouseleave from body to stop if cursor leaves window document.body.addEventListener('mouseleave', stopResize); }; const doResize = (e) => { if (!isResizing) return; const deltaY = e.clientY - startY; const totalHeight = mainTerminal.clientHeight; // Use parent height const handleHeight = handle.offsetHeight; // Calculate new heights, respecting minimums (e.g., 50px) let newChartHeight = Math.max(50, startChartHeight + deltaY); let newTabContentHeight = Math.max(50, startTabContentHeight - deltaY); // Ensure total height doesn't exceed parent minus handle const availableHeight = totalHeight - handleHeight; if (newChartHeight + newTabContentHeight > availableHeight) { // Prioritize adjusting the element being shrunk (tabContent) newTabContentHeight = availableHeight - newChartHeight; if (newTabContentHeight < 50) { newTabContentHeight = 50; newChartHeight = availableHeight - 50; } } // Apply heights using flex-basis for better flexbox behavior chartArea.style.flexBasis = `${newChartHeight}px`; tabContent.style.flexBasis = `${newTabContentHeight}px`; // Crucially, resize the chart canvas after changing container size if (window.candleChart) { window.candleChart.resize(); } }; const stopResize = () => { if (isResizing) { isResizing = false; // Remove global listeners document.removeEventListener('mousemove', doResize); document.removeEventListener('mouseup', stopResize); document.body.removeEventListener('mouseleave', stopResize); // Restore default body styles document.body.style.userSelect = ''; document.body.style.cursor = ''; } }; handle.addEventListener('mousedown', startResize); }); //