对前端开发者而言,KLineChart 是个不错的选择 ------ 这款基于 HTML5 Canvas 的开源金融图表工具,零依赖压缩包仅 40K,轻量特性很适合集成到各类金融应用中。它不仅支持多数据源渲染 K 线图,还内置了丰富的交互功能和指标计算接口,高度可定制的特性能适配多数业务场景。
而 DolphinDB 作为高性能数据库,在数据存储与分析层面的优势无需多言,更关键的是其提供的 JavaScript API 封装了完整的数据库操作能力 ------ 从连接节点、执行脚本到订阅流表等,让前端与数据库的对接变得直观高效。本文就以这两者的结合为例,聊聊如何基于 DolphinDB 存储的 K 线数据,用 KLineChart 快速实现前端可视化。
数据准备:从导入到类型对齐
数据导入
示例用的 K 线数据来自 candle_201801.csv,通过 DolphinDB 脚本导入并共享为可访问表:
ini
t = loadText("<yourPath>/candle_201801.csv")
share t as jsTable -- 共享为jsTable,供前端API调用
数据维度为单只股票的月度交易数据,包含开盘价、收盘价等核心字段。
类型适配要点
前端绘图的核心坑点往往在数据类型对齐上。KLineChart 对数据源有明确的字段规范:
typescript
{
timestamp: number, // 毫秒级时间戳,必填
open: number, // 开盘价,必填
close: number, // 收盘价,必填
high: number, // 最高价,必填
low: number, // 最低价,必填
volume?: number, // 成交量,可选
turnover?: number // 成交额,可选(EMV/AVP指标需此数据)
}
而 DolphinDB 数据类型与 JavaScript 存在默认映射关系,需重点关注:
DolphinDB 类型 | JavaScript 类型 | 注意事项 |
---|---|---|
TEMPORAL/STRING/SYMBOL 等 | String | 时间类型需手动转时间戳 |
LONG | BigInt | KLineChart 需 Number 类型,需转换 |
DOUBLE/FLOAT/INT/SHORT | Number | 无需额外处理 |
环境初始化
前端需引入两个核心资源:KLineChart 库和 DolphinDB JavaScript API:
xml
<!-- 引入 KLineChart -->
<script src="https://cdn.dolphindb.cn/vendors/klinecharts/dist/umd/klinecharts.min.js"></script>
<!-- 模块化引入 DolphinDB API 并建立连接 -->
<script type="module">
import { DDB } from 'https://cdn.dolphindb.cn/assets/api.js';
const conn = new DDB('ws://ip:port'); // 替换为实际节点地址
</script>
历史数据绘图:从查询到渲染
数据查询与类型转换
用 DolphinDB API 的 execute 方法执行 SQL 查询,直接获取绘图所需字段:
csharp
// 执行查询:提取timestamp及价格、成交量等字段
const re = await conn.execute(`
select unixTime as timestamp, open, high, low, close, volume, turnover from jsTable
`);
这里需注意 unixTime 字段 ------DolphinDB 中为 LONG 类型,默认转成 JavaScript 的 BigInt,但 KLineChart 要求 timestamp 为 Number。有两种解决方式:
- 数据库端转换(推荐) :查询时直接转成 DOUBLE 类型,避免前端循环处理:
csharp
const re = await conn.execute(`
select double(unixTime) as timestamp, open, high, low, close, volume, turnover from jsTable
`);
- 前端转换:遍历数据手动转类型(大数据量下效率较低):
ini
re.data.forEach(item => {
item.timestamp = Number(item.timestamp); // BigInt转Number
});
图表渲染实现
KLineChart 提供 applyNewData 接口处理全量数据,几行代码即可完成渲染:
kotlin
// 初始化图表实例(绑定DOM节点)
const chart = klinecharts.init('k-line-chart');
// 传入数据渲染
chart.applyNewData(re.data);
完整示例代码(可直接复用):
xml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://cdn.dolphindb.cn/vendors/klinecharts/dist/umd/klinecharts.min.js"></script>
</head>
<body>
<div id="k-line-chart" style="height:800px;"></div>
<script type="module">
import { DDB } from 'https://cdn.dolphindb.cn/assets/api.js';
const conn = new DDB('ws://<ip:port>'); // 替换节点地址
const re = await conn.execute(`
select double(unixTime) as timestamp, open, high, low, close, volume, turnover from jsTable
`);
klinecharts.init('k-line-chart').applyNewData(re.data);
</script>
</body>
</html>
实时数据绘图:两种方案对比
当数据源为实时流时,前端需动态更新图表。根据场景不同,有两种实现思路:
方案 1:流数据订阅(推荐高实时性场景)
利用 DolphinDB API 的流订阅能力,后端增量推送数据,前端通过回调实时更新图表,无需全量拉取。
实现步骤:
- 后端准备流表:创建流表并共享,用于推送实时数据:
sql
// 从历史数据生成示例流数据结构
t1 = select timestamp(unixTime) as ts, double(unixTime) as timestamp,
open, high, low, close, volume, turnover from jsTable
// 共享空流表st,供前端订阅
share streamTable(1:0,
['ts', 'timestamp', 'open', 'high', 'low', 'close', 'volume', 'turnover'],
[TIMESTAMP, DOUBLE, DOUBLE, DOUBLE, DOUBLE, DOUBLE, INT, DOUBLE]
) as st
- 前端订阅与渲染:通过 API 订阅流表,在回调中处理数据:
xml
<script type="module">
import { DDB } from 'https://cdn.dolphindb.cn/assets/api.js';
const chart = klinecharts.init('k-line-chart');
// 初始化连接时配置流订阅
const conn = new DDB('ws://<ip:port>', {
autologin: true,
username: 'admin',
password: '123456',
streaming: {
table: 'st', // 订阅流表st
action: 'sub',
handler(message) {
// 全量更新:直接用缓存的所有数据刷新
chart.applyNewData(message.window.data);
// 增量更新:逐条追加(性能略低)
// message.data.data.forEach(data => chart.updateData(data));
}
}
});
await conn.connect();
</script>
- 模拟实时数据:后端用 replay 函数回放数据,模拟实时流入:
ini
// 按ts字段匀速回放,每秒推1条
replay(inputTables=t1, outputTables=st, dateColumn=`ts, replayRate=1000, absoluteRate=true);
注意:流订阅默认从最新数据开始(offset=-1),需先启动前端再执行回放。
方案 2:SQL 定时轮询(适合低频次更新)
通过 setInterval 定时执行 SQL 查询,全量拉取最新数据后刷新图表。适合数据更新频率低、对实时性要求不高的场景。
实现步骤:
- 后端准备键值表:用键值表去重存储实时数据,避免重复:
csharp
// 创建流表st和键值表kt(按timestamp去重)
share streamTable(1:0, ['ts', 'timestamp', ...], [...]) as st
share keyedTable(`timestamp, 1:0, ['ts', 'timestamp', ...], [...]) as kt
// 订阅st,自动写入kt(自动去重)
subscribeTable(tableName="st", actionName="sub_st", handler=kt)
- 前端定时查询:封装异步查询函数,用定时器触发:
xml
<script type="module">
import { DDB } from 'https://cdn.dolphindb.cn/assets/api.js';
const chart = klinecharts.init('k-line-chart');
const conn = new DDB('ws://<ip:port>');
await conn.connect();
// 异步更新函数
async function updateChart() {
const re = await conn.execute('select * from kt'); // 查询去重后的kt表
chart.applyNewData(re.data); // 全量刷新
}
// 每秒执行一次(可按需调整)
setInterval(updateChart, 1000);
</script>
总结:高效集成的核心逻辑
本质上,整个流程是 "数据层 - 接口层 - 渲染层" 的串联:DolphinDB 负责存储与推送 K 线数据,其 JavaScript API 作为中间层完成数据格式转换与传输,最后 KLineChart 基于标准化数据实现可视化。
对有前端经验的开发者而言,核心是把握两点:一是数据类型的对齐(尤其是时间戳的转换),二是实时场景下的方案选择 ------ 流订阅适合高频实时数据,定时轮询适合低频次更新。借助这两个工具的封装能力,十多行核心代码就能完成从数据到图表的闭环,后续若需扩展指标,直接参考 KLineChart 官方文档的指标配置即可。