Fix chart tail viewport after 5m/15m timeframe switches.
Snap to latest candles on period change and only preserve scroll position when viewing history. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -178,6 +178,7 @@
|
|||||||
let exhaustedLeft = false;
|
let exhaustedLeft = false;
|
||||||
let loadingLeft = false;
|
let loadingLeft = false;
|
||||||
let chartDataLoading = false;
|
let chartDataLoading = false;
|
||||||
|
let chartViewEpoch = 0;
|
||||||
let priceTagTimer = null;
|
let priceTagTimer = null;
|
||||||
let tfDigitBuf = "";
|
let tfDigitBuf = "";
|
||||||
let tfDigitTimer = null;
|
let tfDigitTimer = null;
|
||||||
@@ -2025,6 +2026,22 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isViewingChartTail(range, candleCount) {
|
||||||
|
if (!range || candleCount <= 0) return true;
|
||||||
|
const maxTo = candleCount - 1 + RIGHT_OFFSET_BARS;
|
||||||
|
return range.to >= maxTo - 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tailVisibleLogicalRange(candleCount) {
|
||||||
|
const n = Math.max(0, Number(candleCount) || 0);
|
||||||
|
if (n <= 0) return null;
|
||||||
|
const visible = Math.min(DEFAULT_VISIBLE_BARS, n);
|
||||||
|
return {
|
||||||
|
from: Math.max(0, n - visible),
|
||||||
|
to: n - 1 + RIGHT_OFFSET_BARS,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function clearChartSeriesData() {
|
function clearChartSeriesData() {
|
||||||
lastCandles = [];
|
lastCandles = [];
|
||||||
candleByTime = {};
|
candleByTime = {};
|
||||||
@@ -2149,9 +2166,12 @@
|
|||||||
if (!exKey || !sym || !lastCandles.length || chartDataLoading) return;
|
if (!exKey || !sym || !lastCandles.length || chartDataLoading) return;
|
||||||
if (!lastViewKey || vKey !== lastViewKey) return;
|
if (!lastViewKey || vKey !== lastViewKey) return;
|
||||||
const myToken = loadToken;
|
const myToken = loadToken;
|
||||||
|
const epochAtStart = chartViewEpoch;
|
||||||
const candleCountBefore = lastCandles.length;
|
const candleCountBefore = lastCandles.length;
|
||||||
let savedRange = null;
|
let savedRange = null;
|
||||||
if (chart) savedRange = chart.timeScale().getVisibleLogicalRange();
|
if (chart) savedRange = chart.timeScale().getVisibleLogicalRange();
|
||||||
|
const wasViewingTail =
|
||||||
|
!savedRange || isViewingChartTail(savedRange, candleCountBefore);
|
||||||
try {
|
try {
|
||||||
const data = await fetchChartChunk({
|
const data = await fetchChartChunk({
|
||||||
exchange_key: exKey,
|
exchange_key: exKey,
|
||||||
@@ -2161,6 +2181,7 @@
|
|||||||
});
|
});
|
||||||
if (myToken !== loadToken) return;
|
if (myToken !== loadToken) return;
|
||||||
if (vKey !== lastViewKey) return;
|
if (vKey !== lastViewKey) return;
|
||||||
|
if (epochAtStart !== chartViewEpoch) return;
|
||||||
if (!data.ok || !data.candles || !data.candles.length) return;
|
if (!data.ok || !data.candles || !data.candles.length) return;
|
||||||
if (data.price_tick != null) {
|
if (data.price_tick != null) {
|
||||||
priceTick = data.price_tick;
|
priceTick = data.price_tick;
|
||||||
@@ -2172,13 +2193,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
applyCandlesToChart(mergeCandles(lastCandles, alignCandlesToTick(data.candles), { prepend: false }), 0);
|
applyCandlesToChart(mergeCandles(lastCandles, alignCandlesToTick(data.candles), { prepend: false }), 0);
|
||||||
if (
|
if (epochAtStart !== chartViewEpoch) return;
|
||||||
|
const n = lastCandles.length;
|
||||||
|
const curRange = chart && chart.timeScale().getVisibleLogicalRange();
|
||||||
|
if (wasViewingTail) {
|
||||||
|
const tailRange = tailVisibleLogicalRange(n);
|
||||||
|
if (tailRange) chart.timeScale().setVisibleLogicalRange(tailRange);
|
||||||
|
} else if (
|
||||||
savedRange &&
|
savedRange &&
|
||||||
isVisibleRangeValidForCandles(savedRange, lastCandles.length) &&
|
isVisibleRangeValidForCandles(savedRange, n) &&
|
||||||
Math.abs(lastCandles.length - candleCountBefore) < chartChunkLimit(tf)
|
Math.abs(n - candleCountBefore) < chartChunkLimit(tf)
|
||||||
) {
|
) {
|
||||||
chart.timeScale().setVisibleLogicalRange(savedRange);
|
chart.timeScale().setVisibleLogicalRange(savedRange);
|
||||||
|
} else if (!isVisibleRangeValidForCandles(curRange, n)) {
|
||||||
|
const tailRange = tailVisibleLogicalRange(n);
|
||||||
|
if (tailRange) chart.timeScale().setVisibleLogicalRange(tailRange);
|
||||||
}
|
}
|
||||||
|
updateVisibleRangeMarkers();
|
||||||
if (posContext) {
|
if (posContext) {
|
||||||
updateLivePosPnl();
|
updateLivePosPnl();
|
||||||
refreshPosPnlFromBoard();
|
refreshPosPnlFromBoard();
|
||||||
@@ -2200,18 +2231,17 @@
|
|||||||
|
|
||||||
function applyDefaultVisibleRange() {
|
function applyDefaultVisibleRange() {
|
||||||
if (!chart || !lastCandles.length) return;
|
if (!chart || !lastCandles.length) return;
|
||||||
const n = lastCandles.length;
|
function applyOnce() {
|
||||||
const visible = Math.min(DEFAULT_VISIBLE_BARS, n);
|
if (!chart || !lastCandles.length) return;
|
||||||
const from = Math.max(0, n - visible);
|
const r = tailVisibleLogicalRange(lastCandles.length);
|
||||||
const to = n - 1 + RIGHT_OFFSET_BARS;
|
if (!r) return;
|
||||||
applyChartRightGap();
|
applyChartRightGap();
|
||||||
requestAnimationFrame(function () {
|
chart.timeScale().setVisibleLogicalRange(r);
|
||||||
requestAnimationFrame(function () {
|
updateVisibleRangeMarkers();
|
||||||
if (!chart || !lastCandles.length) return;
|
}
|
||||||
chart.timeScale().setVisibleLogicalRange({ from: from, to: to });
|
applyOnce();
|
||||||
updateVisibleRangeMarkers();
|
requestAnimationFrame(applyOnce);
|
||||||
});
|
setTimeout(applyOnce, 0);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVisibleRangeMarkers() {
|
function updateVisibleRangeMarkers() {
|
||||||
@@ -2429,6 +2459,7 @@
|
|||||||
const resetView = !!force || vKey !== lastViewKey;
|
const resetView = !!force || vKey !== lastViewKey;
|
||||||
chartDataLoading = true;
|
chartDataLoading = true;
|
||||||
if (resetView) {
|
if (resetView) {
|
||||||
|
chartViewEpoch += 1;
|
||||||
resetChartHistoryState();
|
resetChartHistoryState();
|
||||||
lastViewKey = "";
|
lastViewKey = "";
|
||||||
clearChartSeriesData();
|
clearChartSeriesData();
|
||||||
@@ -2592,6 +2623,7 @@
|
|||||||
if (elFsTf) {
|
if (elFsTf) {
|
||||||
elFsTf.addEventListener("change", function () {
|
elFsTf.addEventListener("change", function () {
|
||||||
currentTf = elFsTf.value || "1d";
|
currentTf = elFsTf.value || "1d";
|
||||||
|
lastViewKey = "";
|
||||||
syncMainFromFsToolbar();
|
syncMainFromFsToolbar();
|
||||||
tickLiveClock();
|
tickLiveClock();
|
||||||
loadChart(false);
|
loadChart(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user