Files
crypto_okx_hub/static/hub_quotes.js
T

153 lines
4.7 KiB
JavaScript

(function (global) {
function fmtQuotePx(n) {
const v = Number(n);
if (!Number.isFinite(v)) return "—";
const abs = Math.abs(v);
let digits = 2;
if (abs >= 10000) digits = 1;
else if (abs >= 1) digits = 2;
else digits = 4;
try {
return v.toLocaleString("en-US", {
minimumFractionDigits: digits,
maximumFractionDigits: digits,
});
} catch (e) {
return v.toFixed(digits);
}
}
function fmtQuoteSigned(n, isPct) {
const v = Number(n);
if (!Number.isFinite(v)) return "—";
const abs = Math.abs(v);
const digits = isPct ? 2 : abs >= 100 ? 1 : 2;
let body;
try {
body = abs.toLocaleString("en-US", {
minimumFractionDigits: digits,
maximumFractionDigits: digits,
});
} catch (e) {
body = abs.toFixed(digits);
}
const sign = v > 0 ? "" : v < 0 ? "-" : "";
return sign + body + (isPct ? "%" : "");
}
function quoteDirClass(n) {
const v = Number(n);
if (!Number.isFinite(v) || v === 0) return "nav-spot--flat";
return v > 0 ? "nav-spot--up" : "nav-spot--down";
}
function snapshotTickers(row) {
const snap = (row && row.snapshot) || {};
const quotes = snap.quotes && typeof snap.quotes === "object" ? snap.quotes : {};
const list = quotes.tickers;
return Array.isArray(list) ? list : [];
}
function tickersHaveLast(tickers) {
return (tickers || []).some(function (t) {
return t && t.last != null && t.last !== "" && Number.isFinite(Number(t.last));
});
}
function pickQuoteSource(list) {
let best = null;
(list || []).forEach(function (row) {
if (!row || !row.online) return;
const tickers = snapshotTickers(row);
if (!tickersHaveLast(tickers)) return;
const mode = String((((row.snapshot || {}).instance || {}).mode) || "").toLowerCase();
const live = mode === "live" ? 1 : 0;
const pulled = String(row.pulled_at || ((row.snapshot || {}).quotes || {}).updated_at || "");
const cand = { tickers: tickers, name: row.name || "", live: live, pulled: pulled };
if (!best) {
best = cand;
return;
}
if (cand.live !== best.live) {
if (cand.live > best.live) best = cand;
return;
}
if (cand.pulled > best.pulled) best = cand;
});
return best;
}
function paintRoot(root, tickers, src) {
["ETH", "BTC"].forEach(function (base) {
const row = root.querySelector('.nav-spot-row[data-base="' + base + '"]');
if (!row) return;
let t = null;
for (let i = 0; i < tickers.length; i++) {
if (String((tickers[i] && tickers[i].base) || "").toUpperCase() === base) {
t = tickers[i];
break;
}
}
row.classList.remove("nav-spot--up", "nav-spot--down", "nav-spot--flat");
const lastEl = row.querySelector('[data-field="last"]');
const chgEl = row.querySelector('[data-field="change"]');
const pctEl = row.querySelector('[data-field="change_pct"]');
if (!t || t.last == null) {
row.classList.add("nav-spot--flat");
if (lastEl) lastEl.textContent = "—";
if (chgEl) chgEl.textContent = "—";
if (pctEl) pctEl.textContent = "—";
return;
}
row.classList.add(quoteDirClass(t.change));
if (lastEl) lastEl.textContent = fmtQuotePx(t.last);
if (chgEl) chgEl.textContent = fmtQuoteSigned(t.change, false);
if (pctEl) pctEl.textContent = fmtQuoteSigned(t.change_pct, true);
});
if (src && src.name) {
root.title =
"来自 " +
src.name +
(src.live ? " · live" : " · sim") +
" · 相对北京 08:00";
} else {
root.title = "暂无在线客户端报价 · 相对北京 08:00";
}
}
function paint(list) {
const src = pickQuoteSource(list);
const tickers = src ? src.tickers : [];
document.querySelectorAll("[data-hub-quotes]").forEach(function (root) {
paintRoot(root, tickers, src);
});
}
let timer = null;
let inflight = false;
async function refresh() {
if (inflight) return;
inflight = true;
try {
const r = await fetch("/api/overview");
const d = await r.json();
paint((d && d.instances) || []);
} catch (e) {
paint([]);
} finally {
inflight = false;
}
}
function boot() {
if (!document.querySelector("[data-hub-quotes]")) return;
if (global.HubOverview) return;
refresh();
if (timer) clearInterval(timer);
timer = setInterval(refresh, 10000);
}
global.HubQuotes = { boot: boot, paint: paint, refresh: refresh };
})(window);