feat(web): 增量自动刷新、结构区修复与默认指标/周期
自动刷新常态只拉 recent 尾部 K,每 1 分钟全量重算缠论;修复结构区缓存导入;默认指标/4h·1h·15m/近30天;同步 ECR-009 screener 相关改动。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,11 +9,26 @@ function updateTradingViewData() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 保存当前的可视范围
|
||||
// 优先用请求前冻结的视窗;否则现场拍(自动刷新短间隔 delta≈0,两种都稳)
|
||||
const frozen = window._preserveViewOnRefresh;
|
||||
const oldBarCount = window._preserveViewBarCount || 0;
|
||||
let savedScrollPosition = null;
|
||||
if (tvWidget.mainChart) {
|
||||
tvWidget.state.visibleRange = tvWidget.mainChart.timeScale().getVisibleRange();
|
||||
tvWidget.state.logicalRange = tvWidget.mainChart.timeScale().getVisibleLogicalRange();
|
||||
const ts = tvWidget.mainChart.timeScale();
|
||||
if (frozen) {
|
||||
tvWidget.state.visibleRange = frozen.visibleRange;
|
||||
tvWidget.state.logicalRange = frozen.logicalRange;
|
||||
savedScrollPosition = (typeof frozen.scrollPosition === 'number') ? frozen.scrollPosition : null;
|
||||
} else {
|
||||
tvWidget.state.visibleRange = ts.getVisibleRange();
|
||||
tvWidget.state.logicalRange = ts.getVisibleLogicalRange();
|
||||
try {
|
||||
savedScrollPosition = ts.scrollPosition ? ts.scrollPosition() : null;
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
window._preserveViewOnRefresh = null;
|
||||
window._preserveViewBarCount = 0;
|
||||
|
||||
// 检查是否显示原始K线
|
||||
const showOriginalKline = $('#showOriginalKline').is(':checked');
|
||||
@@ -71,6 +86,9 @@ function updateTradingViewData() {
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const newBarCount = candles.length;
|
||||
const barDelta = (oldBarCount > 0 && newBarCount > 0) ? (newBarCount - oldBarCount) : 0;
|
||||
|
||||
// 更新主系列数据(根据klineType)
|
||||
const klineType = ($('#klineType').val() || (showOriginalKline ? 'candlestick' : 'line'));
|
||||
@@ -270,23 +288,54 @@ function updateTradingViewData() {
|
||||
// 更新EMA52显示
|
||||
updateEMA52Display(currentData);
|
||||
|
||||
// 恢复之前的可视范围 - 优先使用visibleRange以确保时间轴对齐
|
||||
// 与自动刷新一致:增量更新绝不碰 barSpacing(缩放本来就留在图表实例上)。
|
||||
// 一写 barSpacing,LWC 会按右边缘重锚 → 放大往右、缩小往左。
|
||||
// 这里只在 setData 之后把位置扳回刷新前的 logical / time 窗口。
|
||||
if (tvWidget.mainChart) {
|
||||
if (tvWidget.state.visibleRange) {
|
||||
console.log('🔄 恢复可见范围:', tvWidget.state.visibleRange);
|
||||
tvWidget.mainChart.timeScale().setVisibleRange(tvWidget.state.visibleRange);
|
||||
if (tvWidget.volumeChart) tvWidget.volumeChart.timeScale().setVisibleRange(tvWidget.state.visibleRange);
|
||||
if (tvWidget.atrChart) tvWidget.atrChart.timeScale().setVisibleRange(tvWidget.state.visibleRange);
|
||||
if (tvWidget.macdChart) tvWidget.macdChart.timeScale().setVisibleRange(tvWidget.state.visibleRange);
|
||||
if (tvWidget.chanMacdChart) tvWidget.chanMacdChart.timeScale().setVisibleRange(tvWidget.state.visibleRange);
|
||||
} else if (tvWidget.state.logicalRange) {
|
||||
console.log('🔄 恢复逻辑范围:', tvWidget.state.logicalRange);
|
||||
tvWidget.mainChart.timeScale().setVisibleLogicalRange(tvWidget.state.logicalRange);
|
||||
if (tvWidget.volumeChart) tvWidget.volumeChart.timeScale().setVisibleLogicalRange(tvWidget.state.logicalRange);
|
||||
if (tvWidget.atrChart) tvWidget.atrChart.timeScale().setVisibleLogicalRange(tvWidget.state.logicalRange);
|
||||
if (tvWidget.macdChart) tvWidget.macdChart.timeScale().setVisibleLogicalRange(tvWidget.state.logicalRange);
|
||||
if (tvWidget.chanMacdChart) tvWidget.chanMacdChart.timeScale().setVisibleLogicalRange(tvWidget.state.logicalRange);
|
||||
}
|
||||
const charts = [
|
||||
tvWidget.mainChart,
|
||||
tvWidget.volumeChart,
|
||||
tvWidget.atrChart,
|
||||
tvWidget.macdChart,
|
||||
tvWidget.chanMacdChart
|
||||
].filter(Boolean);
|
||||
|
||||
const vr = tvWidget.state.visibleRange;
|
||||
const lr = tvWidget.state.logicalRange;
|
||||
const savedScroll = savedScrollPosition;
|
||||
|
||||
const applyPosition = function (tag) {
|
||||
let ok = false;
|
||||
if (lr && lr.from !== undefined && lr.to !== undefined) {
|
||||
charts.forEach(c => {
|
||||
try {
|
||||
c.timeScale().setVisibleLogicalRange({ from: lr.from, to: lr.to });
|
||||
ok = true;
|
||||
} catch (e) {}
|
||||
});
|
||||
if (ok) console.log('🔄 恢复位置 logical' + (tag || '') + ':', lr);
|
||||
}
|
||||
if (!ok && vr && vr.from !== undefined && vr.to !== undefined) {
|
||||
charts.forEach(c => {
|
||||
try {
|
||||
c.timeScale().setVisibleRange(vr);
|
||||
ok = true;
|
||||
} catch (e) {}
|
||||
});
|
||||
if (ok) console.log('🔄 恢复位置 time' + (tag || '') + ':', vr);
|
||||
}
|
||||
if (!ok && typeof savedScroll === 'number') {
|
||||
const pos = savedScroll + (barDelta || 0);
|
||||
charts.forEach(c => {
|
||||
try { c.timeScale().scrollToPosition(pos, false); } catch (e) {}
|
||||
});
|
||||
console.log('🔄 恢复位置 scroll' + (tag || '') + ':', pos);
|
||||
}
|
||||
};
|
||||
|
||||
applyPosition('');
|
||||
setTimeout(function () { applyPosition('@0'); }, 0);
|
||||
setTimeout(function () { applyPosition('@50'); }, 50);
|
||||
}
|
||||
|
||||
console.log('增量更新图表完成');
|
||||
|
||||
Reference in New Issue
Block a user