图表视图
navi-chart crate 提供 ChartView<P, T> — 一个图表组件,管理多个 Navi 指标、处理用户交互,并通过平台无关的绘图接口渲染。Provider P 决定脚本如何执行及数据来自何处。
LocalChartProvider | 自定义 ChartProvider | |
|---|---|---|
| 脚本执行 | 本地 — 在进程内运行 VM | 远程 — 后端流式推送事件 |
| Provider trait | ChartProvider(Script = String) | ChartProvider(Script = 自定义类型) |
| 依赖 | 需要 local feature(引入 navi-vm) | 无 VM 依赖 — 默认即可用 |
| 适用场景 | 桌面应用、CLI 工具、Playground | Web 前端、服务端执行 |
Cargo Features
[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。 |
spawn、interval、now_ms 三个方法必须实现,其余均有默认值。
参考实现: Web Playground 的
WebPlatform使用wasm_bindgen_futures::spawn_local、setInterval、js_sys::Date::now()。
DrawingContext
为你的渲染平台(Canvas 2D、Skia、Cairo 等)实现 DrawingContext trait。所有坐标和尺寸均为逻辑/CSS 像素。
参考实现: 参见 Web Playground 使用的 Canvas 2D 后端。
画布
| 方法 | 作用 |
|---|---|
clear() | 将所有像素清除为完全透明(或平台背景色)。每帧开始时调用一次。 |
颜色与样式
这些方法设置持久状态,作用于后续的绘制调用。
| 方法 | 作用 |
|---|---|
set_fill_color(color) | 将填充画笔设置为纯 RGBA 颜色,用于 fill、fill_rect、fill_text 之前。 |
set_stroke_color(color) | 将描边画笔设置为纯 RGBA 颜色,用于 stroke、stroke_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 像素。formatting 为 TextFormatting::Normal、Bold 或 Italic。family 为 FontFamily::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 | 返回当前字体的垂直度量(ascent 和 descent,以字母基线为基准,单位像素),用于精确的多行文本排版。默认实现返回零;能查询真实字体度量的后端应覆盖此方法。Canvas 2D 后端应调用 measureText("M") 并读取 fontBoundingBoxAscent / fontBoundingBoxDescent。 |
路径
路径通过 begin_path / move_to / line_to / close_path / arc / arc_to 构建,再由 stroke 或 fill 绘制,与标准 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() 取出。事件仅携带 ScriptId 或 AnnotationId;在释放借用后再调用辅助方法查询关联数据。
| 事件 | 说明 |
|---|---|
EditScript(ScriptId) | 用户点击了指标图例上的 ✎ 编辑按钮 |
RemoveScript(ScriptId) | 用户点击了 ✕ 移除按钮 |
ShowError(ScriptId) | 用户点击了 ⚠ 错误图标 — 调用 cv.script_error(id) 获取错误信息 |
ConfigureScript(ScriptId) | 用户点击了 ⚙ 配置按钮 — 调用 cv.script_inputs_effective(id) 获取输入项 |
DoubleClick(ChartElement) | 用户双击了系列图形或 K 线柱 |
SelectionChanged(Option<ChartElement>) | 选中元素发生变化或被清除。ChartElement 为 Bar(usize)、Series { script_id, graph_id } 或 Annotation(AnnotationId) 之一 |
AnnotationCreated(AnnotationId) | 新注释被添加 — 来自用户完成绘图手势,或直接调用 add_annotation |
AnnotationUpdated(AnnotationId) | 注释规格通过 update_annotation 被替换 |
AnnotationDeleted(AnnotationId) | 注释通过 remove_annotation、clear_annotations 或用户按下 Delete 键被删除 |
// 每次交互方法调用后,轮询并处理待处理事件:
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 管理脚本的视觉覆盖和输入值覆盖:
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 均在子页面中说明: