Skip to content

图表视图

navi-chart crate 提供 ChartView<P, T> — 一个图表组件,管理多个 Navi 指标、处理用户交互,并通过平台无关的绘图接口渲染。Provider P 决定脚本如何执行及数据来自何处。

LocalChartProvider自定义 ChartProvider
脚本执行本地 — 在进程内运行 VM远程 — 后端流式推送事件
Provider traitChartProvider(Script = String)ChartProvider(Script = 自定义类型)
依赖需要 local feature(引入 navi-vm无 VM 依赖 — 默认即可用
适用场景桌面应用、CLI 工具、PlaygroundWeb 前端、服务端执行

Cargo Features

toml
[dependencies]
# 仅远程/自定义 Provider(无 VM):
navi-chart = { git = "https://github.com/longbridge/navi.git" }

# 使用 LocalChartProvider(进程内 VM):
navi-chart = { git = "https://github.com/longbridge/navi.git", features = ["local"] }
Feature启用内容
(默认 — 无)ChartView + ChartProvider trait,无 VM。
local添加 LocalChartProvider,引入 navi-vm

共享概念

两种用法共享相同的渲染、交互和配置 API。

Platform

Platform trait 将图表引擎与宿主运行时解耦。构造 ChartView 时传入实现——引擎通过它调度异步任务、定时器、获取当前时间以及访问剪贴板。

方法默认值说明
spawn(fut)在宿主运行时以 fire-and-forget 方式生成 future。
interval(interval_ms)interval_ms 毫秒产出一次 () 的定时器。返回 IntervalStream;drop 时自动取消(RAII)。
now_ms()返回当前时间(毫秒)。纪元由宿主定义,引擎只使用差值。
double_click_threshold_ms()500.0两次点击被识别为双击的最大间隔(毫秒)。可覆盖以读取系统偏好。
write_clipboard(text)空操作异步写入系统剪贴板。
read_clipboard()None异步读取系统剪贴板。拒绝访问或为空时返回 None

spawnintervalnow_ms 三个方法必须实现,其余均有默认值。

参考实现: Web Playground 的 WebPlatform 使用 wasm_bindgen_futures::spawn_localsetIntervaljs_sys::Date::now()

DrawingContext

为你的渲染平台(Canvas 2D、Skia、Cairo 等)实现 DrawingContext trait。所有坐标和尺寸均为逻辑/CSS 像素。

参考实现: 参见 Web Playground 使用的 Canvas 2D 后端

画布

方法作用
clear()将所有像素清除为完全透明(或平台背景色)。每帧开始时调用一次。

颜色与样式

这些方法设置持久状态,作用于后续的绘制调用。

方法作用
set_fill_color(color)将填充画笔设置为纯 RGBA 颜色,用于 fillfill_rectfill_text 之前。
set_stroke_color(color)将描边画笔设置为纯 RGBA 颜色,用于 strokestroke_rect 之前。
set_line_width(width)设置描边线宽(像素)。
set_line_dash(pattern)设置虚线样式,参数为交替的绘制/间隔长度(如 &[6.0, 3.0] = 6 px 实线、3 px 间隔)。传空切片恢复实线。
set_fill_linear_gradient(x0,y0,x1,y1,stops)将填充画笔设置为从 (x0,y0)(x1,y1) 的线性渐变。stops(offset, Color) 列表,offset ∈ [0.0, 1.0]。

文本

方法作用
set_font(size, formatting, family)设置当前字体。size 为 CSS 像素。formattingTextFormatting::NormalBoldItalicfamilyFontFamily::Default(无衬线)或 FontFamily::Monospace
set_text_align(align)设置相对于 fill_text 传入 x 坐标的水平对齐方式:Left = x 为左边缘,Center = x 为中点,Right = x 为右边缘。
set_text_baseline(baseline)设置相对于 fill_text 传入 y 坐标的垂直基线:Top = em 框顶部,Middle = 垂直居中,Bottom = 底部,Alphabetic = 标准字母基线。
fill_text(text, x, y)使用当前字体、填充颜色、对齐方式和基线,在像素位置 (x, y) 绘制文本。
measure_text(text) -> f64使用当前字体设置返回 text 的渲染宽度(像素)。必须精确 — 图表用于标签排版和重叠检测。
font_metrics() -> FontMetrics返回当前字体的垂直度量(ascentdescent,以字母基线为基准,单位像素),用于精确的多行文本排版。默认实现返回零;能查询真实字体度量的后端应覆盖此方法。Canvas 2D 后端应调用 measureText("M") 并读取 fontBoundingBoxAscent / fontBoundingBoxDescent

路径

路径通过 begin_path / move_to / line_to / close_path / arc / arc_to 构建,再由 strokefill 绘制,与标准 Canvas 2D 路径模型一致。

方法作用
begin_path()丢弃已有路径,开始新的空路径。
move_to(x, y)将当前点移动到 (x, y) 而不绘制任何内容,开始新子路径。
line_to(x, y)从当前点到 (x, y) 追加直线段,并更新当前点。
close_path()从当前点到当前子路径起点追加直线,然后闭合路径。
arc(x, y, radius)追加以 (x, y) 为圆心、给定半径的完整圆(0 到 2π)。
arc_to(x1,y1,x2,y2,radius)追加由两条切线(当前点 → (x1,y1)(x1,y1)(x2,y2))定义的圆弧,等同于 Canvas 2D arcTo,用于圆角。
stroke()用当前描边颜色和线宽绘制路径描边。
fill()用当前填充画笔(颜色或渐变)填充路径内部。

形状

无需手动构建路径的便捷方法。

方法作用
fill_rect(rect)用当前填充画笔填充矩形 rect。等同于 begin_path + rect + fill
stroke_rect(rect)用当前描边颜色和线宽绘制矩形 rect 的轮廓。

裁剪(可选)

方法作用
set_clip(rect)Some(rect) 将后续所有绘制限制在给定矩形内。第二次调用 set_clip(Some(other))替换前一个裁剪区域(不做交集)。None 移除裁剪并恢复无限制绘制。默认实现为空操作 — 如后端支持裁剪请覆盖。Canvas 2D 后端应在内部使用 save/clip/restore

ChartEvent

交互事件在图表视图内部积累,每次交互调用后通过 poll_event() 取出。事件仅携带 ScriptIdAnnotationId;在释放借用后再调用辅助方法查询关联数据。

事件说明
EditScript(ScriptId)用户点击了指标图例上的 ✎ 编辑按钮
RemoveScript(ScriptId)用户点击了 ✕ 移除按钮
ShowError(ScriptId)用户点击了 ⚠ 错误图标 — 调用 cv.script_error(id) 获取错误信息
ConfigureScript(ScriptId)用户点击了 ⚙ 配置按钮 — 调用 cv.script_inputs_effective(id) 获取输入项
DoubleClick(ChartElement)用户双击了系列图形或 K 线柱
SelectionChanged(Option<ChartElement>)选中元素发生变化或被清除。ChartElementBar(usize)Series { script_id, graph_id }Annotation(AnnotationId) 之一
AnnotationCreated(AnnotationId)新注释被添加 — 来自用户完成绘图手势,或直接调用 add_annotation
AnnotationUpdated(AnnotationId)注释规格通过 update_annotation 被替换
AnnotationDeleted(AnnotationId)注释通过 remove_annotationclear_annotations 或用户按下 Delete 键被删除
rust
// 每次交互方法调用后,轮询并处理待处理事件:
cv.on_mouse_up(pos);
while let Some(event) = cv.poll_event() {
    match event {
        ChartEvent::EditScript(id) => { /* 打开编辑器 */ }
        ChartEvent::RemoveScript(id) => { /* 确认并移除 */ }
        ChartEvent::ShowError(id) => {
            let error = cv.script_error(id).unwrap();
            // 显示错误信息
        }
        ChartEvent::ConfigureScript(id) => {
            let inputs = cv.script_inputs_effective(id).unwrap();
            // 打开配置对话框
        }
        ChartEvent::DoubleClick(element) => { /* 处理 */ }
        ChartEvent::SelectionChanged(sel) => { /* 处理 */ }
        ChartEvent::AnnotationCreated(id) => { /* 持久化新注释 */ }
        ChartEvent::AnnotationUpdated(id) => { /* 更新已持久化的注释 */ }
        ChartEvent::AnnotationDeleted(id) => { /* 从持久化中删除 */ }
        _ => {}
    }
}

ToggleVisibility 由内部处理 — 图表会自动切换可见性并重新渲染。

ScriptConfig

ScriptConfig 管理脚本的视觉覆盖和输入值覆盖:

rust
pub struct ScriptConfig {
    /// 每个系列图形的视觉覆盖(颜色、样式、可见性)。
    pub series_overrides: HashMap<SeriesGraphId, SeriesGraphOverride>,
    /// 输入值覆盖。Key = 输入项索引,value = JSON 值。
    pub input_values: HashMap<usize, serde_json::Value>,
}

完整的配置 UI 指南见 ChartView 页面。

ScriptId

ScriptId 是添加脚本时返回的不透明标识符,用于查询、配置或移除脚本。

渲染与交互

所有渲染和交互 API 均在子页面中说明:

  • 脚本管理 — 添加、移除、查询脚本
  • 交互 — 鼠标、滚轮、拖拽、光标、选择
  • 注释 — CRUD、属性、选择、剪贴板
  • 绘图工具 — 工具状态机、粘性模式、磁吸
  • 视口 — 面板比例、滚动、缩放、高亮 bar
  • 设置与事件 — 主题、语言、品种/时间周期、策略报告、poll_event

基于 MIT 许可证发布。