website: chart improvements

This commit is contained in:
nym21
2026-02-05 10:31:28 +01:00
parent b5c2d6ce9e
commit dc15cceb1e
+34 -12
View File
@@ -120,6 +120,10 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
/** @type {Set<(data: number[]) => void>} */ /** @type {Set<(data: number[]) => void>} */
let timeCallbacks = new Set(); let timeCallbacks = new Set();
// Memory cache for instant index switching
/** @type {Map<string, MetricData<any>>} */
const cache = new Map();
// Range state: localStorage stores all ranges per-index, URL stores current range only // Range state: localStorage stores all ranges per-index, URL stores current range only
/** @typedef {{ from: number, to: number }} Range */ /** @typedef {{ from: number, to: number }} Range */
const ranges = createPersistedValue({ const ranges = createPersistedValue({
@@ -229,6 +233,10 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
ichart.timeScale().setVisibleLogicalRange(initialRange); ichart.timeScale().setVisibleLogicalRange(initialRange);
} }
// Flag to prevent range persistence until first data load completes
// This prevents the URL range from being overwritten during chart initialization
let initialLoadComplete = false;
let visibleBarsCount = initialRange let visibleBarsCount = initialRange
? initialRange.to - initialRange.from ? initialRange.to - initialRange.from
: Infinity; : Infinity;
@@ -243,6 +251,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
ichart.timeScale().subscribeVisibleLogicalRangeChange( ichart.timeScale().subscribeVisibleLogicalRangeChange(
throttle((range) => { throttle((range) => {
if (!range) return; if (!range) return;
if (!initialLoadComplete) return; // Ignore range changes during initial load
const count = range.to - range.from; const count = range.to - range.from;
if (count === visibleBarsCount) return; if (count === visibleBarsCount) return;
visibleBarsCount = count; visibleBarsCount = count;
@@ -252,6 +261,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
// Debounced range persistence // Debounced range persistence
const debouncedSetRange = debounce((/** @type {Range | null} */ range) => { const debouncedSetRange = debounce((/** @type {Range | null} */ range) => {
if (!initialLoadComplete) return; // Skip persistence during initial load
if (range && range.from < range.to) { if (range && range.from < range.to) {
setRange({ from: range.from, to: range.to }); setRange({ from: range.from, to: range.to });
} }
@@ -689,6 +699,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
// Delay until chart has applied the range // Delay until chart has applied the range
requestAnimationFrame(() => { requestAnimationFrame(() => {
if (seriesGeneration !== generation) return; if (seriesGeneration !== generation) return;
initialLoadComplete = true;
blueprints.onDataLoaded?.(); blueprints.onDataLoaded?.();
}); });
} else { } else {
@@ -727,7 +738,14 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
timeCallbacks.add(state.onTime); timeCallbacks.add(state.onTime);
if (sharedTimeData) state.onTime(sharedTimeData); if (sharedTimeData) state.onTime(sharedTimeData);
const cachedValues = cache.get(valuesEndpoint.path);
if (cachedValues) {
valuesData = cachedValues.data;
valuesStamp = cachedValues.stamp;
tryProcess();
}
await valuesEndpoint.slice(-10000).fetch((result) => { await valuesEndpoint.slice(-10000).fetch((result) => {
cache.set(valuesEndpoint.path, result);
valuesData = result.data; valuesData = result.data;
valuesStamp = result.stamp; valuesStamp = result.stamp;
tryProcess(); tryProcess();
@@ -834,7 +852,6 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
showLine = newShowLine; showLine = newShowLine;
update(); update();
} }
onZoomChange.add(handleZoom);
const removeSeriesThemeListener = onThemeChange(update); const removeSeriesThemeListener = onThemeChange(update);
const series = serieses.create({ const series = serieses.create({
@@ -876,10 +893,7 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
lineISeries.setData(lineData); lineISeries.setData(lineData);
requestAnimationFrame(() => { requestAnimationFrame(() => {
if (seriesGeneration !== generation) return; if (seriesGeneration !== generation) return;
const range = ichart.timeScale().getVisibleLogicalRange(); showLine = shouldShowLine(visibleBarsCount);
if (range) {
showLine = shouldShowLine(range.to - range.from);
}
update(); update();
}); });
}, },
@@ -896,6 +910,9 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
}, },
}); });
// Add zoom handler after series is created to avoid TDZ error
onZoomChange.add(handleZoom);
panes.register(paneIndex, series, [candlestickISeries, lineISeries]); panes.register(paneIndex, series, [candlestickISeries, lineISeries]);
return series; return series;
@@ -1627,17 +1644,22 @@ export function createChart({ parent, id: chartId, brk, fitContent }) {
rebuild() { rebuild() {
generation++; generation++;
initialLoadComplete = false; // Reset to prevent saving stale ranges during load
const currentGen = generation; const currentGen = generation;
const idx = index.get(); const idx = index.get();
sharedTimeData = null; sharedTimeData = null;
timeCallbacks = new Set(); timeCallbacks = new Set();
getTimeEndpoint(idx) const timeEndpoint = getTimeEndpoint(idx);
.slice(-10000) const cached = cache.get(timeEndpoint.path);
.fetch((result) => { if (cached) {
if (currentGen !== generation) return; // Ignore stale fetch sharedTimeData = cached.data;
sharedTimeData = result.data; }
timeCallbacks.forEach((cb) => cb(result.data)); timeEndpoint.slice(-10000).fetch((result) => {
}); if (currentGen !== generation) return;
cache.set(timeEndpoint.path, result);
sharedTimeData = result.data;
timeCallbacks.forEach((cb) => cb(result.data));
});
this.rebuildPane(0); this.rebuildPane(0);
this.rebuildPane(1); this.rebuildPane(1);
}, },