更新记录

2.0.0(2026-07-19)

在 1.0.0(十万根丝滑手势 + 原生视图直贴)基础上,六件全家桶升级,v1 API 全部兼容(加性、零破坏,v1 契约回归套件锁定 4 冻结黄金图 byte-identical)。14 → 29 引擎 API

  • ① 10 种技术指标 + 多副图:新增 WR(威廉 %R)/ CCI(顺势)/ OBV(能量潮) 副图 + SAR(抛物线转向) 主图叠加;sub 单副图升级为 subs 数组(最多 3 个副图纵向排列,如 MACD+KDJ+RSI 同屏)。
  • ② 画线子系统(8 API):程序化 CRUD(addDrawing/updateDrawing/removeDrawing/clearDrawings/listDrawings)+ 跨会话存盘exportDrawings/importDrawings 无损,锚点存绝对 (ts,price))+ 命中测试 hitTestAt。五种画线:趋势线 / 水平线 / 射线 / 矩形 / 斐波那契回撤。组件 drawMode 手势画线 + 点选拖拽编辑(三端 H5/Android/iOS 对称,@drawingadd/@drawingselect/@drawingchange 事件)。
  • **③

平台兼容性

uni-app x(5.14)

Chrome Safari Android iOS 鸿蒙 微信小程序
5.0 12 × ×

nex-kline 专业级 K 线全家桶(自研原生渲染 + 原生视图直贴)

十万根级 K 线丝滑手势,热环路零桥接开销 + 专业行情全家桶:自研原生内核(列式存储 + 周期聚合 + 10 种技术指标 + 多副图 + 视口窗口渲染 + 画线/分时/复权/深度/联动)+ App 端原生视图组件——手势 → 视口 → 渲染 → Bitmap/CALayer 直贴全程原生线程,零桥接开销往返。同一份 自研引擎在 Android / iOS / H5 三端跑出一致输出;纯本地渲染、零网络依赖、不吃 WebView Canvas 性能。

v2.0 六件全家桶:多指标 · 画线 · 分时 · 复权 · 深度 · 联动。v1 API 全部兼容(加性升级、零破坏)。

特性

  • 原生视图热环路(卖点):<uni-nex-kline-view> App 原生视图——单指平移 / 双指捏合缩放 / 单击十字线全在原生层完成,帧循环(Android onDraw vsync 合帧 / iOS CADisplayLink-级)里调 原生 渲染出 RGBA 直贴位图,手势零桥接开销,十万根级 K 线丝滑
  • <nex-kline> 统一组件即插即用(easycom 自动注册):三端一套 props/事件契约——App 走原生视图、H5 走 canvas putImageData 帧循环,业务代码一份
  • 列式存储 + 事务化装载:SoA 列存(10 万根 ≈ 4.8MB),扁平六元组 [ts,o,h,l,c,v] 高速装载 / JSON 兼容入口,整批 OHLC 校验通过才生效(非法数据不污染现有状态)
  • 周期聚合1m/5m/15m/60m/1d 按 ts 整除分桶(UTC),停牌缺口自然成稀疏桶;tick(appendCandle/updateLastCandle)尾桶增量重算
  • 10 种技术指标 + 多副图(v2):MA / EMA / BOLL / SAR(主图叠加)+ MACD / KDJ / RSI / WR / CCI / OBV(副图,subs 数组最多 3 个纵向排列,如 MACD+KDJ+RSI 同屏)——期望值全部公式手推 + 黄金向量对照,非拍脑袋
  • 画线子系统(v2):五种画线(趋势线 / 水平线 / 射线 / 矩形 / 斐波那契回撤)程序化 CRUD + 跨会话存盘(export/import 无损)+ 组件 drawMode 手势画线 + 点选拖拽编辑@drawingadd/@drawingselect/@drawingchange);锚点存绝对 (ts,price),切复权/切周期不漂移
  • 分时图 + 复权 + 深度 + 联动(v2):setChartMode('timeshare') 分时(收盘连线 + 均价 + 量柱);前/后复权(setAdjustMode + 除权因子外供);setChartMode('depth') 盘口深度阶梯(买绿卖红双轴);多图多周期联动(setCrosshairAt/setViewportByTime + getMeta 视口 ts)
  • dpr 真超采样高清:位图按 逻辑×dpr 物理像素渲染,2x/3x 屏不发虚
  • 十字线吸附getCrosshairData 返回命中蜡烛 OHLCV + 各指标值 + 像素锚点(v2 形态按 chartMode 分派:candle/timeshare/depth),组件内置十字线/tooltip
  • 三端同源:App(Android/iOS) 走 原生绑定层 原生绑定,H5 走同一自研原生内核编译的 H5 端引擎——不是"H5 降级实现"

快速上手

组件(推荐)

<template>
  <nex-kline
    :engine-id="engineId"
    :width-px="360"
    :height-px="480"
    :revision="revision"
    @crosshair="onCrosshair"
    @viewportchange="onViewport"
    @loadmore="onLoadMore"
  />
</template>

<script>
  import {
    createKlineEngine, loadCandlesFlat, appendCandle, setPeriod, setIndicators
  } from '@/uni_modules/nex-kline'
  // #ifdef H5
  import { ensureReady } from '@/uni_modules/nex-kline'
  // #endif

  export default {
    data() {
      return { engineId: 0, revision: 0 }
    },
    onReady() {
      // #ifdef H5
      ensureReady().then(() => { this.boot() })
      // #endif
      // #ifndef H5
      this.boot()
      // #endif
    },
    methods: {
      boot() {
        const id = createKlineEngine('{"theme":"light","indicators":{"ma":[5,10,20],"sub":"macd"}}')
        // 扁平六元组 [ts,o,h,l,c,v] × N(ts 毫秒,严格递增)
        loadCandlesFlat(id, [0, 100, 102, 98, 101, 1000,  60000, 101, 105, 100, 104, 1200])
        this.engineId = id
        this.revision++          // 数据变更 → 组件重渲(revision 刷新协议)
      },
      pushTick() {
        // 实时行情:追加新蜡烛后自增 revision
        appendCandle(this.engineId, 120000, 104, 106, 103, 105, 900)
        this.revision++
      },
      onCrosshair(e: string) { /* 十字线 JSON(v2 按 mode 分派):candle/timeshare→{mode,index,ts,OHLC,volume,indicators};depth→{mode:"depth",price,cumBid,cumAsk} */ },
      onViewport(e: string) { /* 手势平移/缩放结束的视口元信息 */ },
      onLoadMore(e: string) { /* 视口触最左边界 → 可加载更早历史 */ }
    }
  }
</script>

组件 Props:

prop 类型 默认 说明
engineId Number 必填 引擎句柄(createKlineEngine 返回值);0 = 未绑定
widthPx / heightPx Number 必填 组件尺寸(逻辑像素;内核按设备 dpr 超采样)
revision Number 0 数据版本号:每次改数据后自增 → 组件重渲(组件不轮询引擎)
crosshairEnabled Boolean true 单击是否内置显示十字线/tooltip(关掉只发 @crosshair
drawMode(v2) String 'none' 画线模式:'none'(正常 pan/zoom/crosshair)/'trendline'/'horizontal'/'ray'/'rect'/'fib'优先级 drawMode > crosshair > pan/zoom:非 none 时 tap 落锚点 → 自动 addDrawing;none 时 tap 命中已有画线 → 选中可拖锚点编辑

事件:@crosshair(十字线 JSON)、@viewportchange(视口元信息 JSON)、@loadmore(触最左边界,{});v2 画线@drawingadd(落线完成,新画线 JSON 含 id)、@drawingselect(点选命中已有画线)、@drawingchange(拖锚点编辑后,据此存盘)。

画线工具栏(v2,drawMode + 事件)

<template>
  <!-- 工具栏切 drawMode -->
  <view class="toolbar">
    <button @click="mode='trendline'">趋势线</button>
    <button @click="mode='fib'">斐波那契</button>
    <button @click="mode='none'">选择/编辑</button>
    <button v-if="selectedId>=0" @click="delSelected">删除选中</button>
  </view>
  <nex-kline :engine-id="engineId" :width-px="360" :height-px="480" :revision="revision"
    :draw-mode="mode" @drawingadd="onAdd" @drawingselect="" @drawingchange="onChange" />
</template>
<script>
  import { exportDrawings, importDrawings, removeDrawing } from '@/uni_modules/nex-kline'
  export default {
    data() { return { engineId: 0, revision: 0, mode: 'none', selectedId: -1, savedJson: '' } },
    methods: {
      // drawMode='trendline' 时 tap 两次落两锚点 → 自动画线 → 回带含 id 的画线 JSON
      onAdd(e: string) { const d = JSON.parse(e); /* d.id / d.kind / d.anchors,存盘 */ },
      // drawMode='none' 时 tap 命中已有画线 → 选中(可拖锚点编辑)
      (e: string) { this.selectedId = JSON.parse(e).id },
      // 拖锚点编辑后 → 更新后画线 JSON(据此存盘)
      onChange(e: string) { /* 覆盖存盘该 id */ },
      delSelected() { removeDrawing(this.engineId, this.selectedId); this.selectedId = -1; this.revision++ },
      // 跨会话保存/恢复画线
      save() { this.savedJson = exportDrawings(this.engineId) },
      restore() { importDrawings(this.engineId, this.savedJson); this.revision++ }
    }
  }
</script>

画线锚点存绝对 (ts,price),切复权/切周期不漂移。画线主用 candle 模式(分时/深度模式画线的纵向命中是 v2.0 已知边界,见「限制」)。

API 模式(29 引擎 API)

import {
  // 基础 14(v1)
  createKlineEngine, loadCandlesFlat, loadCandlesJson, appendCandle, updateLastCandle,
  setPeriod, setIndicators, setTheme, setViewport, renderFrame, getCrosshairData,
  getMeta, destroyEngine, klineVersion,
  // 画线 8(v2)
  addDrawing, updateDrawing, removeDrawing, clearDrawings, listDrawings, exportDrawings, importDrawings, hitTestAt,
  // 形态/昨收/复权/深度/联动 7(v2)
  setChartMode, setPrevClose, setAdjustMode, setAdjustFactors, setDepthData, setCrosshairAt, setViewportByTime
} from '@/uni_modules/nex-kline'

const id = createKlineEngine('{}')                          // 建引擎返 engineId
loadCandlesFlat(id, [/* [ts,o,h,l,c,v]×N 扁平 */])          // 高速装载(事务化)
setPeriod(id, '5m')                                          // 周期聚合
setIndicators(id, '{"ma":[5,10,20],"subs":["macd","kdj"]}') // v2:subs 数组多副图
setViewport(id, 0, 120)                                      // 视口(起始 index + 可见根数)
// v2 画线(程序化):
const drawId = addDrawing(id, '{"kind":"trendline","anchors":[{"ts":0,"price":100},{"ts":60000,"price":104}]}')
// v2 分时 / 复权 / 深度 / 联动:
setChartMode(id, 'timeshare'); setPrevClose(id, 100)        // 分时 + 昨收基准
setAdjustFactors(id, '[{"ts":60000,"factor":0.9}]'); setAdjustMode(id, 'forward')  // 前复权
setDepthData(id, '{"bids":[[99.9,10]],"asks":[[100.1,15]]}'); setChartMode(id, 'depth')  // 深度
const meta = getMeta(id)                                     // {candleCount, viewport, chartMode, viewportStartTs, ...}
const cross = getCrosshairData(id, 100)                      // 十字线数据(形态按 mode 分派,须先 renderFrame)
destroyEngine(id)                                            // 用完释放(防注册表泄漏)

renderFrame(id, w, h, dpr) 返回 RGBA 帧字节——热环路由原生视图内部调用,业务层一般不用(用 <nex-kline> 组件即可)。自绘场景才手动取字节。

多图多周期联动(v2)

两个 <nex-kline> 实例监听彼此事件互调 setter(联动策略在 JS,引擎不做跨实例广播):

// 图 A 十字线动 → 驱动图 B 十字线到同一时间(跨周期天然对齐)
onCrosshairA(e: string) { setCrosshairAt(engineB, JSON.parse(e).ts) }
// 图 A 视口变 → 图 B 视口对齐同一时间段(各自周期桶区间)
onViewportA(e: string) { const m = JSON.parse(e); setViewportByTime(engineB, m.viewportStartTs, m.viewportEndTs) }

H5 注意事项

// #ifdef H5
import { ensureReady } from '@/uni_modules/nex-kline'
await ensureReady()   / 异步初始化,构造引擎前等一次
// #endif

H5 端 <nex-kline> 用 canvas putImageData 帧循环渲染,手势(平移/双指缩放/单击十字线)在浏览器端处理。价/时间轴标签是纯数字,无需额外字体(内核内嵌 NotoSans)。

蜡烛数据与指标

  • 扁平六元组 [ts, o, h, l, c, v]ts 毫秒(严格递增),OHLC 须满足 h ≥ max(o,c)l ≤ min(o,c);非法数据整批拒绝(事务化)。
  • JSON 入口loadCandlesJson 接受 [{ts,open|o,high|h,low|l,close|c,volume|v}](短键别名,volume 可缺省)。
  • 实时 tickappendCandle(新一根,ts > last)/ updateLastCandle(改写最后一根,ts == last),配合 revision++ 驱动组件重渲。
  • 指标 DSL(v2 扩展):{"ma":[5,10,20],"ema":[12],"boll":[20,2],"sar":[0.02,0.2],"subs":["macd","kdj","rsi"],"macd":[12,26,9],"kdj":9,"rsi":14,"wr":14,"cci":20}——ma/ema 窗口数组、boll[n,k] 数组、macd[fast,slow,signal] 数组、kdj/rsi/wr/cci 为单个数字(窗口)、sar[step,max](主图叠加);subs 数组(最多 3 个副图名,sub 单值仍兼容 v1);窗口参数 ∈ [1,500],越界报错。
  • 画线 JSON{"kind":"trendline"|"horizontal"|"ray"|"rect"|"fib","anchors":[{"ts":..,"price":..},…]}(trendline/ray/rect/fib 两锚点、horizontal 一锚点),可选 "color":"#RRGGBB"/"snapToCandle":bool;锚点是绝对 (ts,price) 数据坐标。
  • 复权 / 深度 / 联动setAdjustFactors('[{"ts":..,"factor":..}]')(factor>0、按 ts 升序);setDepthData('{"bids":[[price,qty],…],"asks":[…]}')(各 ≤500 档);setCrosshairAt(ts)(负 ts 清除)/setViewportByTime(startTs,endTs)

限制与防护(内核硬校验,超限报错不静默截断)

  • 单引擎蜡烛数 ≤ 100 万根;指标窗口 ∈ [1,500];副图 ≤ 3;深度档 ≤ 500
  • 画布 逻辑×dpr ≤ 4096;dpr ∈ [1,4]
  • 网络拉数据 / 后端对接 / 图表动画 / log 轴:不承诺@loadmore 只上抛边界事件,加载历史由使用方自理)
  • v2.0 已知边界(记 v2.1):① 分时模式十字线 py 与画线纵向命中按蜡烛几何反推(横向 index/ts/OHLC 全对、纵向像素偏——画线主用 candle 模式);② 组件画线编辑无可视锚点手柄点,拖锚点价 snap 蜡烛收盘(无自由改价);③ 同类型多副图 crosshair 字段名会撞(建议 subs 元素类型不重复);④ SAR 为简化变体,与 TA-Lib 不逐字一致(趋势方向/转向时机一致);⑤ 复权只 OHLC 价、量不变

常见问题

  • Android 标准基座报"找不到 jna":原生插件须自定义基座(插件依赖 原生运行依赖,标准基座不含)。制作自定义基座后即可正常运行。
  • 组件不刷新:改数据(append/updateLast/setPeriod/setIndicators/setTheme)后记得自增 revision prop——组件按 revision 变更重渲,不主动轮询引擎。
  • 十字线报错"未渲染"getCrosshairData 须在至少渲染过一帧后调用(组件已自动处理;自绘时先 renderFrame 再取十字线)。
  • iOS 显示异常 / 手势不跟手:iOS 原生视图转译为全仓 gated 项(cli --compile 空挂),CGImage 字节序 / 手势 recognizer 形态待离线基座/真机微调;H5 与 Android 已验证。

平台说明

实现 说明
Android 原生扩展库(arm64-v8a / armeabi-v7a / x86_64)+ 原生绑定层 Kotlin 绑定 + 原生 View 视图 需自定义基座(云打包);手势热环路零桥接开销
iOS 原生扩展库(device + simulator)+ 原生绑定层 Swift 绑定 + 原生 UIView 视图 宿主工程需开启"支持 Swift";转译 gated(v2 含 drawMode 分支随家族 iOS 迁移轮验证;绑定层 swiftc 已验)
H5 同一自研原生内核编译 H5 端引擎(base64 内嵌,免静态资源配置)+ canvas putImageData 首次调用前 await ensureReady()

技术支持 / 问题反馈:插件评论区或仓库 issue。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据。所有计算/处理均在本地完成,无任何网络请求、不发送数据到任何服务器。

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。