在重绘k线图的实时行情数据的candlestick时,如何不重绘整个k线图。
本地加载历史数据,实时行情数据通过ws从网络上获取。当没有行情时,chart显示的是历史数据;当有行情时,历史数据+实时数据,然后显示在chart里。我想要的chart的样子是这样:当有行情数据时,chart里原有的candlesticks向左平移,给新数据留出最右边空间来显示。此时,左右拖拽或缩放等不会受到新行情数据的刷新而回到chart拖拽或缩放前的样子,或者说只更新实时数据对应的那条candlestick,其它的不受影响,或者干脆一点就像行情软件里一样,缩放等操作不会被新行情数据刷新到操作前的样子。
现在的问题是,不能实现上述要求。下面我给出相关代码,请帮忙诊断一下!
<body>
<div id="chart_container">
<div id="text_show">
<textarea id="info_textarea" readonly></textarea>
</div>
<div id="candlesticks">
<div id="real_chart">"real_chart"</div>
<div id="real_text">
<div id="real">实时行情</div>
<div id="kdj">kdj指标</div>
</div>
</div>
</div>
<div id="chart2">
<div id="table_container">"table_container"</div>
<div id="input_container">
<input id="search-box" type="text" placeholder="输入股票代码或名称" />
<div id="suggestions" class="suggestions"></div>
</div>
</div>
<script>
// 全局变量
let g_his_data = null; // 历史数据
let g_his_data_len = 0; // 历史数据长度
let g_stk_code = "000001.SH"; // 默认股票代码
const chart = echarts.init(document.getElementById("real_chart"));
const option = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "cross",
link: { xAxisIndex: "all" },
label: {
show: true,
position: "outside",
offset: [0, -10],
},
},
backgroundColor: "rgba(245, 245, 145, 1)",
position: function (point, params, dom, rect, size) {
// 将 tooltip 放在 cross 十字线交点的右下方
return [point[0] + 30, point[1] + 10];
},
},
axisPointer: {
link: [
{
xAxisIndex: "all",
},
],
label: {
backgroundColor: "#777",
},
},
grid: [
{
top: "1%",
height: "75%",
left: "2%",
right: "1%",
containLabel: true,
},
{
top: "75%",
height: "21%",
left: "2%",
right: "1%",
containLabel: true,
},
],
xAxis: [
{
type: "category",
data: [], // 日期,
boundaryGap: true,
gridIndex: 0,
},
{
type: "category",
data: [], // 日期,
boundaryGap: true,
axisTick: { show: false },
splitLine: { show: false },
axisLabel: { show: false },
gridIndex: 1,
},
],
yAxis: [
{
scale: true,
axisLine: { onZero: false },
position: "left",
gridIndex: 0,
splitLine: {
show: false,
lineStyle: {
type: "dashed", // 设置为虚线
},
},
min: "dataMin",
max: "dataMax",
axisLabel: { show: false },
},
{
scale: true,
axisLine: { onZero: false },
position: "left",
gridIndex: 1,
splitLine: {
show: false,
lineStyle: {
type: "dashed", // 设置为虚线
},
},
axisLabel: { show: false },
},
],
dataZoom: [
{
type: "inside",
xAxisIndex: [0, 1],
start: 70,
end: 100,
},
{
type: "slider",
xAxisIndex: [0, 1],
start: 70,
end: 100,
top: "97.5%",
},
],
series: [
{
name: "Candlestick",
type: "candlestick",
data: [], // 初始为空,后续通过历史数据填充
itemStyle: {
color: "#ef232a",
color0: "#14b143",
borderColor: "#ef232a",
borderColor0: "#14b143",
},
xAxisIndex: 0,
yAxisIndex: 0,
},
],
};
// 在loadHisData函数中,使用initChart函数初始化图表
function initChart(his_data) {
const dates = his_data.dates;
const candlestick = his_data.candlestick;
option.xAxis[0].data = dates;
option.xAxis[1].data = dates;
option.series[0].data = candlestick;
chart.setOption(option, false);
}
</script>
<script>
// 加载股票数据,并绘制图表
async function loadHisData(code) {
try {
// 获取历史数据
g_stk_code = code;
const hisResponse = await fetch(`/stock/${code}`);
g_his_data = await hisResponse.json();
g_his_data_len = g_his_data.dates.length;
// 绘制图表
initChart(g_his_data);
} catch (error) {
console.error("Error loading initial data:", error);
}
}
</script>
<script>
// 建立ws连接,处理实时数据。
let socket = new WebSocket("ws://localhost:8000/ws");
// 发送股票代码到后端
function sendStockCode() {
// 将 g_stk_code 从 "000001.SZ" 格式转换为 "sz000001",这样符合easyquotation的要求
const formattedCode = g_stk_code
.split(".")
.reverse()
.join("")
.toLowerCase();
socket.send(JSON.stringify({ stock_code: formattedCode }));
}
// 定时发送股票代码
setInterval(sendStockCode, 2000);
socket.onmessage = function (event) {
let data = JSON.parse(event.data);
if ((data.high > 0) && (data.date > data.old_date)) {
if (g_his_data.length < g_his_data_len) {
g_his_data.dates.push(data.date);
g_his_data.candlestick.push([data.open, data.now, data.low, data.high,]);
} else {
g_his_data.dates[g_his_data_len] = data.date;
g_his_data.candlestick[g_his_data_len] = [data.open, data.now, data.low, data.high,];
}
initChart(g_his_data);
}
};
socket.onopen = function (event) {
console.log("WebSocket connection opened");
sendStockCode();
};
socket.onclose = function (event) {
console.log("WebSocket connection closed");
};
socket.onerror = function (error) {
console.error("WebSocket error:", error);
};
</script>
</body>
问过各个AI,其建议是在websocket中把新数据push到g_his_data上,然后单独设置option的series。这些建议没有解决我的问题。
在
socket.onmessage
中直接更新g_his_data
的dates
和candlestick
,不调用initChart
重绘。使用
chart.setOption
更新图表只更新需要变更的K线和X轴,并设第二个参数为false
避免重绘。下面是稍微改动了下的代码↓