diff --git a/manual_trading_hub/static/chart.js b/manual_trading_hub/static/chart.js index 16e1e38..27618b0 100644 --- a/manual_trading_hub/static/chart.js +++ b/manual_trading_hub/static/chart.js @@ -175,6 +175,9 @@ let chartViewEpoch = 0; let rangeUiTimer = null; let loadOlderTimer = null; + let chartRangeUserLocked = false; + let chartRangeLockTimer = null; + let suppressRangeUserLock = false; let priceTagTimer = null; let tfDigitBuf = ""; let tfDigitTimer = null; @@ -1950,6 +1953,9 @@ }); chart.timeScale().subscribeVisibleLogicalRangeChange(function (range) { + if (!chartDataLoading && range && !suppressRangeUserLock) { + markChartRangeUserAdjusted(); + } scheduleRangeUiUpdate(); if ( !range || @@ -2025,6 +2031,23 @@ return range.to >= maxTo - 24; } + function markChartRangeUserAdjusted() { + chartRangeUserLocked = true; + if (chartRangeLockTimer) clearTimeout(chartRangeLockTimer); + chartRangeLockTimer = setTimeout(function () { + chartRangeLockTimer = null; + chartRangeUserLocked = false; + }, 30000); + } + + function restoreVisibleLogicalRange(range, candleCount) { + if (!chart || !range || !isVisibleRangeValidForCandles(range, candleCount)) return false; + suppressRangeUserLock = true; + chart.timeScale().setVisibleLogicalRange(range); + suppressRangeUserLock = false; + return true; + } + function shouldLoadOlderOnRange(range) { if (!range || !lastCandles.length) return false; const n = lastCandles.length; @@ -2100,7 +2123,12 @@ return merged; } - function applyCandlesToChart(candles, rangeShift) { + function applyCandlesToChart(candles, rangeShift, opts) { + opts = opts || {}; + let savedRange = null; + if (opts.preserveRange && chart) { + savedRange = chart.timeScale().getVisibleLogicalRange(); + } lastCandles = alignCandlesToTick(candles); indexCandles(lastCandles); candleSeries.setData(lastCandles); @@ -2109,13 +2137,19 @@ if (rangeShift && chart) { const range = chart.timeScale().getVisibleLogicalRange(); if (range) { + suppressRangeUserLock = true; chart.timeScale().setVisibleLogicalRange({ from: range.from + rangeShift, to: range.to + rangeShift, }); + suppressRangeUserLock = false; } + } else if (savedRange) { + restoreVisibleLogicalRange(savedRange, lastCandles.length); + } + if (!opts.skipAutoScale) { + applyPriceAutoScale(); } - applyPriceAutoScale(); updateVisibleRangeMarkers(); try { updateIndicators(); @@ -2194,8 +2228,6 @@ const candleCountBefore = lastCandles.length; let savedRange = null; if (chart) savedRange = chart.timeScale().getVisibleLogicalRange(); - const wasViewingTail = - !savedRange || isViewingChartTail(savedRange, candleCountBefore); try { const data = await fetchChartChunk({ exchange_key: exKey, @@ -2216,20 +2248,18 @@ applyChartPriceFormat(); } } - applyCandlesToChart(mergeCandles(lastCandles, alignCandlesToTick(data.candles), { prepend: false }), 0); + applyCandlesToChart( + mergeCandles(lastCandles, alignCandlesToTick(data.candles), { prepend: false }), + 0, + { preserveRange: true, skipAutoScale: chartRangeUserLocked } + ); if (epochAtStart !== chartViewEpoch) return; const n = lastCandles.length; - const curRange = chart && chart.timeScale().getVisibleLogicalRange(); - const minorTailUpdate = Math.abs(n - candleCountBefore) <= 5; - if ( - savedRange && - isVisibleRangeValidForCandles(savedRange, n) && - (minorTailUpdate || !wasViewingTail) - ) { - chart.timeScale().setVisibleLogicalRange(savedRange); - } else if (!isVisibleRangeValidForCandles(curRange, n)) { - const tailRange = tailVisibleLogicalRange(n); - if (tailRange) chart.timeScale().setVisibleLogicalRange(tailRange); + if (!restoreVisibleLogicalRange(savedRange, n)) { + const curRange = chart && chart.timeScale().getVisibleLogicalRange(); + if (!chartRangeUserLocked && curRange && !isVisibleRangeValidForCandles(curRange, n)) { + restoreVisibleLogicalRange(tailVisibleLogicalRange(n), n); + } } scheduleRangeUiUpdate(); if (posContext) { @@ -2258,7 +2288,7 @@ const r = tailVisibleLogicalRange(lastCandles.length); if (!r) return; applyChartRightGap(); - chart.timeScale().setVisibleLogicalRange(r); + restoreVisibleLogicalRange(r, lastCandles.length); updateVisibleRangeMarkers(); } applyOnce(); @@ -2482,6 +2512,11 @@ chartDataLoading = true; if (resetView) { chartViewEpoch += 1; + chartRangeUserLocked = false; + if (chartRangeLockTimer) { + clearTimeout(chartRangeLockTimer); + chartRangeLockTimer = null; + } resetChartHistoryState(); lastViewKey = ""; clearChartSeriesData();