Spaces:
Running
Running
Update js/ui.js
Browse files
js/ui.js
CHANGED
|
@@ -1,23 +1,71 @@
|
|
| 1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
export function updatePrice(price) {
|
| 3 |
-
document.getElementById('price-ticker')
|
|
|
|
| 4 |
}
|
| 5 |
|
| 6 |
-
// Timezone
|
| 7 |
export function detectTimezone() {
|
| 8 |
-
document.getElementById('timezone-label')
|
|
|
|
| 9 |
}
|
| 10 |
|
| 11 |
-
// Status
|
| 12 |
export function setStatus(text, type) {
|
| 13 |
const el = document.getElementById('status-text');
|
|
|
|
| 14 |
el.innerText = text;
|
| 15 |
el.className = type === 'live' ? "text-green-600 blink" : "text-orange-500 font-bold";
|
| 16 |
}
|
| 17 |
|
| 18 |
-
// DOM Renderer
|
| 19 |
export function renderDom(bids, asks) {
|
| 20 |
const domBox = document.getElementById('dom-box');
|
|
|
|
|
|
|
| 21 |
const cleanAsks = asks.slice(0, 8).reverse();
|
| 22 |
const cleanBids = bids.slice(0, 8);
|
| 23 |
|
|
@@ -41,15 +89,16 @@ function makeRow(price, qty, type) {
|
|
| 41 |
</div>`;
|
| 42 |
}
|
| 43 |
|
| 44 |
-
// Bubble Renderer
|
| 45 |
export function spawnBubble(qty, isMaker) {
|
| 46 |
const box = document.getElementById('bubble-box');
|
|
|
|
|
|
|
| 47 |
const b = document.createElement('div');
|
| 48 |
b.className = 'bubble';
|
| 49 |
const size = Math.min(qty * 50 + 20, 100);
|
| 50 |
b.style.width = size + 'px'; b.style.height = size + 'px';
|
| 51 |
b.style.left = Math.random() * 80 + '%';
|
| 52 |
-
b.style.backgroundColor = isMaker ? '#fb7185' : '#bef264';
|
| 53 |
b.innerHTML = `<span>${parseFloat(qty).toFixed(3)}</span>`;
|
| 54 |
box.appendChild(b);
|
| 55 |
setTimeout(() => b.remove(), 4000);
|
|
|
|
| 1 |
+
import { state } from './state.js';
|
| 2 |
+
|
| 3 |
+
// --- FOOTPRINT / DELTA LOGIC ---
|
| 4 |
+
let volBuy = 0;
|
| 5 |
+
let volSell = 0;
|
| 6 |
+
|
| 7 |
+
export function updateDelta(qty, isMaker) {
|
| 8 |
+
// Binance API: If isMaker (m) = true, it means Taker SOLD.
|
| 9 |
+
if(isMaker) volSell += parseFloat(qty);
|
| 10 |
+
else volBuy += parseFloat(qty);
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
export function initFootprint() {
|
| 14 |
+
const box = document.getElementById('footprint-box');
|
| 15 |
+
|
| 16 |
+
// Every 3 seconds, push a new bar
|
| 17 |
+
setInterval(() => {
|
| 18 |
+
if (volBuy === 0 && volSell === 0) return; // No data, do nothing
|
| 19 |
+
|
| 20 |
+
const total = volBuy + volSell;
|
| 21 |
+
const buyPct = (volBuy / total) * 100;
|
| 22 |
+
const sellPct = (volSell / total) * 100;
|
| 23 |
+
|
| 24 |
+
const bar = document.createElement('div');
|
| 25 |
+
// Tailwind classes for a vertical stacked bar
|
| 26 |
+
bar.className = "w-2 h-full border-r border-gray-300 shrink-0 flex flex-col-reverse";
|
| 27 |
+
|
| 28 |
+
bar.innerHTML = `
|
| 29 |
+
<div style="height:${buyPct}%" class="bg-[#bef264]" title="Buy: ${volBuy.toFixed(2)}"></div>
|
| 30 |
+
<div style="height:${sellPct}%" class="bg-[#fb7185]" title="Sell: ${volSell.toFixed(2)}"></div>
|
| 31 |
+
`;
|
| 32 |
+
|
| 33 |
+
box.appendChild(bar);
|
| 34 |
+
|
| 35 |
+
// Keep list clean (remove old bars)
|
| 36 |
+
if(box.children.length > 50) {
|
| 37 |
+
box.removeChild(box.firstChild);
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
// Reset counters for next 3s interval
|
| 41 |
+
volBuy = 0;
|
| 42 |
+
volSell = 0;
|
| 43 |
+
}, 3000);
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
// --- EXISTING UI FUNCTIONS (Keep these) ---
|
| 47 |
+
|
| 48 |
export function updatePrice(price) {
|
| 49 |
+
const el = document.getElementById('price-ticker');
|
| 50 |
+
if(el) el.innerText = parseFloat(price).toFixed(2);
|
| 51 |
}
|
| 52 |
|
|
|
|
| 53 |
export function detectTimezone() {
|
| 54 |
+
const el = document.getElementById('timezone-label');
|
| 55 |
+
if(el) el.innerText = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
| 56 |
}
|
| 57 |
|
|
|
|
| 58 |
export function setStatus(text, type) {
|
| 59 |
const el = document.getElementById('status-text');
|
| 60 |
+
if(!el) return;
|
| 61 |
el.innerText = text;
|
| 62 |
el.className = type === 'live' ? "text-green-600 blink" : "text-orange-500 font-bold";
|
| 63 |
}
|
| 64 |
|
|
|
|
| 65 |
export function renderDom(bids, asks) {
|
| 66 |
const domBox = document.getElementById('dom-box');
|
| 67 |
+
if(!domBox) return;
|
| 68 |
+
|
| 69 |
const cleanAsks = asks.slice(0, 8).reverse();
|
| 70 |
const cleanBids = bids.slice(0, 8);
|
| 71 |
|
|
|
|
| 89 |
</div>`;
|
| 90 |
}
|
| 91 |
|
|
|
|
| 92 |
export function spawnBubble(qty, isMaker) {
|
| 93 |
const box = document.getElementById('bubble-box');
|
| 94 |
+
if(!box) return;
|
| 95 |
+
|
| 96 |
const b = document.createElement('div');
|
| 97 |
b.className = 'bubble';
|
| 98 |
const size = Math.min(qty * 50 + 20, 100);
|
| 99 |
b.style.width = size + 'px'; b.style.height = size + 'px';
|
| 100 |
b.style.left = Math.random() * 80 + '%';
|
| 101 |
+
b.style.backgroundColor = isMaker ? '#fb7185' : '#bef264';
|
| 102 |
b.innerHTML = `<span>${parseFloat(qty).toFixed(3)}</span>`;
|
| 103 |
box.appendChild(b);
|
| 104 |
setTimeout(() => b.remove(), 4000);
|