自动刷新改用 tail update 与 scrollToPosition 恢复视窗,避免 setData 后跳到最右;拆分 chart_tv 模块并扩展 analyze/recent API。同步威科夫分析、pipeline 增量构建及相关策略与配置。 Co-authored-by: Cursor <cursoragent@cursor.com>
89 lines
3.1 KiB
JavaScript
89 lines
3.1 KiB
JavaScript
/* chart_format.js — split from chart.js */
|
||
/* chart.js */
|
||
function updateChartDisplay() {
|
||
if (typeof renderWyckoffCycleSummary === 'function') {
|
||
renderWyckoffCycleSummary();
|
||
}
|
||
if (currentData) {
|
||
// 检测K线周期是否切换
|
||
const curPeriod = $('#subSubPeriodKline').is(':checked') ? 'subsub' :
|
||
($('#elementPeriodKline').is(':checked') ? 'element' : 'main');
|
||
const periodChanged = (curPeriod !== _lastKlinePeriod);
|
||
_lastKlinePeriod = curPeriod;
|
||
|
||
// 保存当前的可见范围(周期切换时不保留,避免范围越界)
|
||
if (!periodChanged && tvWidget && tvWidget.mainChart) {
|
||
try {
|
||
window._pendingRestoreView = captureChartViewState(tvWidget.mainChart);
|
||
} catch (e) {
|
||
window._pendingRestoreView = null;
|
||
}
|
||
}
|
||
|
||
console.log('更新图表显示');
|
||
|
||
// 重新初始化图表(initTradingView 内部会在最终同步时读取 _pendingRestoreView)
|
||
initTradingView($('#symbol').val(), $('#timeframe').val());
|
||
}
|
||
}
|
||
// 确保所有时间处理都使用UTC时间,包括表格数据显示
|
||
function formatTime(timeStr) {
|
||
if (!timeStr) return '';
|
||
|
||
try {
|
||
// 使用用户选择的时区
|
||
const timezone = $('#timezone').val();
|
||
const date = new Date(timeStr);
|
||
|
||
// 添加调试信息
|
||
console.debug('表格时间格式化:', timeStr, '->',
|
||
date.toISOString(), '使用时区:', timezone);
|
||
|
||
// 使用toLocaleString带时区参数
|
||
return date.toLocaleString('zh-CN', {
|
||
timeZone: timezone,
|
||
year: 'numeric',
|
||
month: '2-digit',
|
||
day: '2-digit',
|
||
hour: '2-digit',
|
||
minute: '2-digit',
|
||
second: '2-digit'
|
||
});
|
||
} catch (e) {
|
||
console.error('时间格式化错误:', e, timeStr);
|
||
// 如果格式化失败,返回原始时间字符串
|
||
return timeStr;
|
||
}
|
||
}
|
||
|
||
// 专门用于确认时间的格式化函数,处理可能为空的情况
|
||
function formatConfirmTime(timeStr) {
|
||
if (!timeStr || timeStr === null || timeStr === 'null' || timeStr === '') {
|
||
return '<span class="text-muted">未确认</span>';
|
||
}
|
||
return formatTime(timeStr);
|
||
}
|
||
|
||
function formatDirection(direction) {
|
||
const dirText = direction === 1 ? '向上' : '向下';
|
||
const dirClass = direction === 1 ? 'direction-up' : 'direction-down';
|
||
return '<span class="' + dirClass + '">' + dirText + '</span>';
|
||
}
|
||
|
||
function formatPrice(price) {
|
||
return price !== null ? parseFloat(price).toFixed(2) : '';
|
||
}
|
||
|
||
function formatMacdValue(value) {
|
||
const numValue = parseFloat(value);
|
||
const valueClass = numValue >= 0 ? 'positive' : 'negative';
|
||
return '<span class="' + valueClass + '">' + numValue.toFixed(4) + '</span>';
|
||
}
|
||
|
||
function formatTradePointType(type) {
|
||
const typeText = type > 0 ? `买${Math.abs(type)}` : `卖${Math.abs(type)}`;
|
||
const typeClass = type > 0 ? 'direction-up' : 'direction-down';
|
||
return '<span class="' + typeClass + '">' + typeText + '</span>';
|
||
}
|
||
|