增加K线
This commit is contained in:
+19
-29
@@ -1,4 +1,4 @@
|
|||||||
/** 多周期 K 线 · SQLite 后端 + localStorage · 弹窗全屏 Lightweight Charts */
|
/** 多周期 K 线 · SQLite 后端 + localStorage · 弹窗大图 Lightweight Charts */
|
||||||
|
|
||||||
const CHART_INTERVALS = ["5m", "15m", "30m", "1h", "4h", "1d", "1w"];
|
const CHART_INTERVALS = ["5m", "15m", "30m", "1h", "4h", "1d", "1w"];
|
||||||
const INTERVAL_LIMITS = {
|
const INTERVAL_LIMITS = {
|
||||||
@@ -30,6 +30,8 @@ const COLORS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const MINI_SIZE = { w: 380, h: 100 };
|
const MINI_SIZE = { w: 380, h: 100 };
|
||||||
|
/** 弹窗图表最小尺寸;实际按视口放大(带鱼屏可接近全宽) */
|
||||||
|
const MODAL_CHART_MIN = { w: 1280, h: 560 };
|
||||||
const DEFAULT_MINI_INTERVAL = "1d";
|
const DEFAULT_MINI_INTERVAL = "1d";
|
||||||
|
|
||||||
let chartModalSymbol = "";
|
let chartModalSymbol = "";
|
||||||
@@ -47,15 +49,12 @@ function limitForInterval(interval) {
|
|||||||
return INTERVAL_LIMITS[interval] || 500;
|
return INTERVAL_LIMITS[interval] || 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
function modalSize() {
|
function modalChartSize() {
|
||||||
const fs = document.fullscreenElement;
|
const padX = 32;
|
||||||
if (fs) {
|
const chromeY = 150;
|
||||||
return {
|
const w = Math.max(MODAL_CHART_MIN.w, window.innerWidth - padX * 2);
|
||||||
w: Math.max(800, window.innerWidth - 48),
|
const h = Math.max(MODAL_CHART_MIN.h, window.innerHeight - chromeY);
|
||||||
h: Math.max(480, window.innerHeight - 160),
|
return { w, h };
|
||||||
};
|
|
||||||
}
|
|
||||||
return { w: 1280, h: 680 };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadKlineFromLS(symbol, interval) {
|
function loadKlineFromLS(symbol, interval) {
|
||||||
@@ -171,7 +170,7 @@ function drawCandlestickChart(canvas, candles, options = {}) {
|
|||||||
if (!canvas || !candles.length) return;
|
if (!canvas || !candles.length) return;
|
||||||
|
|
||||||
const large = options.large === true;
|
const large = options.large === true;
|
||||||
const size = large ? modalSize() : MINI_SIZE;
|
const size = large ? modalChartSize() : MINI_SIZE;
|
||||||
const volRatio = large ? 0.22 : 0.32;
|
const volRatio = large ? 0.22 : 0.32;
|
||||||
const pad = large
|
const pad = large
|
||||||
? { t: 16, r: 16, b: 28, l: 56 }
|
? { t: 16, r: 16, b: 28, l: 56 }
|
||||||
@@ -298,7 +297,7 @@ async function loadMiniChart(box) {
|
|||||||
drawCandlestickChart(canvas, candles, { large: false });
|
drawCandlestickChart(canvas, candles, { large: false });
|
||||||
box.dataset.loaded = "1";
|
box.dataset.loaded = "1";
|
||||||
if (status) status.textContent = `${candles.length}日·${sourceLabel(source)}`;
|
if (status) status.textContent = `${candles.length}日·${sourceLabel(source)}`;
|
||||||
box.title = `${symbol} 日K ${candles.length}根 (${sourceLabel(source)}),点击全屏`;
|
box.title = `${symbol} 日K ${candles.length}根 (${sourceLabel(source)}),点击查看大图`;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (status) status.textContent = "—";
|
if (status) status.textContent = "—";
|
||||||
box.title = `${symbol}: ${e.message}`;
|
box.title = `${symbol}: ${e.message}`;
|
||||||
@@ -328,7 +327,7 @@ function ensureLwcChart(container) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
destroyLwcChart();
|
destroyLwcChart();
|
||||||
const { w, h } = modalSize();
|
const { w, h } = modalChartSize();
|
||||||
container.style.width = `${w}px`;
|
container.style.width = `${w}px`;
|
||||||
container.style.height = `${h}px`;
|
container.style.height = `${h}px`;
|
||||||
|
|
||||||
@@ -407,7 +406,7 @@ function updateModalMeta(candles, source, interval) {
|
|||||||
title.textContent = `${chartModalSymbol} · ${interval.toUpperCase()} K线`;
|
title.textContent = `${chartModalSymbol} · ${interval.toUpperCase()} K线`;
|
||||||
}
|
}
|
||||||
if (hint) {
|
if (hint) {
|
||||||
hint.textContent = `${candles.length} 根 · ${sourceLabel(source)} · 滚轮缩放 · 拖拽平移 · 十字线 · Esc 退出`;
|
hint.textContent = `${candles.length} 根 · ${sourceLabel(source)} · 滚轮缩放 · 拖拽平移 · 十字线 · Esc 或点击遮罩关闭`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -439,9 +438,6 @@ function closeChartModal() {
|
|||||||
modal.classList.add("hidden");
|
modal.classList.add("hidden");
|
||||||
destroyLwcChart();
|
destroyLwcChart();
|
||||||
chartModalSymbol = "";
|
chartModalSymbol = "";
|
||||||
if (document.fullscreenElement) {
|
|
||||||
document.exitFullscreen?.().catch(() => {});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openChartModal(symbol) {
|
async function openChartModal(symbol) {
|
||||||
@@ -465,12 +461,6 @@ async function openChartModal(symbol) {
|
|||||||
if (container) container.innerHTML = "";
|
if (container) container.innerHTML = "";
|
||||||
|
|
||||||
await loadModalChart(DEFAULT_MINI_INTERVAL);
|
await loadModalChart(DEFAULT_MINI_INTERVAL);
|
||||||
|
|
||||||
const inner = modal.querySelector(".chart-modal-inner");
|
|
||||||
const req = inner.requestFullscreen || inner.webkitRequestFullscreen;
|
|
||||||
if (req) {
|
|
||||||
req.call(inner).catch(() => {});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupChartModal() {
|
function setupChartModal() {
|
||||||
@@ -514,14 +504,14 @@ function setupChartModal() {
|
|||||||
document.addEventListener("keydown", (e) => {
|
document.addEventListener("keydown", (e) => {
|
||||||
if (e.key === "Escape") closeChartModal();
|
if (e.key === "Escape") closeChartModal();
|
||||||
});
|
});
|
||||||
document.addEventListener("fullscreenchange", () => {
|
window.addEventListener("resize", () => {
|
||||||
if (!chartModalSymbol || !lwcChart) return;
|
if (!chartModalSymbol || !lwcChart) return;
|
||||||
const container = document.getElementById("chart-modal-container");
|
const container = document.getElementById("chart-modal-container");
|
||||||
if (!container) return;
|
if (!container?.isConnected) return;
|
||||||
const rect = container.getBoundingClientRect();
|
const { w, h } = modalChartSize();
|
||||||
if (rect.width > 0 && rect.height > 0) {
|
container.style.width = `${w}px`;
|
||||||
lwcChart.applyOptions({ width: rect.width, height: rect.height });
|
container.style.height = `${h}px`;
|
||||||
}
|
lwcChart.applyOptions({ width: w, height: h });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-35
@@ -334,34 +334,11 @@ button:hover {
|
|||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 1.25rem 1.5rem 1.5rem;
|
padding: 1.25rem 1.5rem 1.5rem;
|
||||||
max-width: 96vw;
|
width: calc(100vw - 2rem);
|
||||||
|
max-width: none;
|
||||||
max-height: 96vh;
|
max-height: 96vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
|
||||||
|
|
||||||
.chart-modal-inner:fullscreen {
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
max-width: none;
|
|
||||||
max-height: none;
|
|
||||||
border-radius: 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-modal-inner:fullscreen .chart-modal-canvas-wrap {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-modal-inner:fullscreen .chart-lwc-container {
|
|
||||||
flex: 1;
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
min-height: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-modal-head {
|
.chart-modal-head {
|
||||||
@@ -402,7 +379,9 @@ button:hover {
|
|||||||
|
|
||||||
.chart-lwc-container {
|
.chart-lwc-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 480px;
|
min-width: 1280px;
|
||||||
|
min-height: 560px;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-lwc-fallback {
|
.chart-lwc-fallback {
|
||||||
@@ -411,14 +390,6 @@ button:hover {
|
|||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-modal-inner:fullscreen .chart-modal-head {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chart-modal-inner:fullscreen .chart-modal-hint {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stats-table .stats-total-vol {
|
.stats-table .stats-total-vol {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
Reference in New Issue
Block a user