Chart View
The navi-chart crate provides ChartView<P, T> — a chart component that manages multiple Navi indicators, handles user interaction, and renders through a platform-agnostic drawing interface. The provider P determines how scripts are executed and where data comes from.
LocalChartProvider | Custom ChartProvider | |
|---|---|---|
| Script execution | Local — runs the VM in-process | Remote — your backend streams events |
| Provider trait | ChartProvider (Script = String) | ChartProvider (Script = your type) |
| Dependencies | Requires the local feature (pulls in navi-vm) | No VM dependency — always available |
| Use case | Desktop apps, CLI tools, playground | Web frontends, server-side execution |
Cargo Features
[dependencies]
# Remote/custom provider only (no VM):
navi-chart = { git = "https://github.com/longbridge/navi.git" }
# With LocalChartProvider (in-process VM):
navi-chart = { git = "https://github.com/longbridge/navi.git", features = ["local"] }| Feature | What it enables |
|---|---|
| (default — none) | ChartView + ChartProvider trait, no VM. |
local | Adds LocalChartProvider and pulls in navi-vm. |
Shared Concepts
Both usage patterns share the same rendering, interaction, and configuration APIs.
Platform
The Platform trait decouples the chart engine from the host runtime. Pass an implementation when constructing ChartView — the engine uses it for async task scheduling, periodic timers, the current time, and optional clipboard access.
| Method | Default | Description |
|---|---|---|
spawn(fut) | — | Spawn a fire-and-forget future on the host runtime. |
interval(interval_ms) | — | Start a periodic timer that yields () every interval_ms ms. Returns an IntervalStream; dropping the stream cancels the timer (RAII). |
now_ms() | — | Return the current time in milliseconds. The epoch is host-defined; the engine only uses differences. |
double_click_threshold_ms() | 500.0 | Maximum gap (ms) between two clicks to be recognised as a double-click. Override to read the OS preference. |
write_clipboard(text) | no-op | Write text to the system clipboard asynchronously. |
read_clipboard() | None | Read text from the system clipboard asynchronously. Returns None if access is denied or the clipboard is empty. |
The three required methods are spawn, interval, and now_ms. All others have defaults.
Reference implementation: The web playground's
WebPlatformuseswasm_bindgen_futures::spawn_local,setInterval, andjs_sys::Date::now().
DrawingContext
Implement the DrawingContext trait for your rendering platform (Canvas 2D, Skia, Cairo, etc.). All coordinates and sizes are in logical/CSS pixels.
Reference implementation: See the Canvas 2D backend used in the web playground.
Canvas
| Method | What it should do |
|---|---|
clear() | Erase all pixels to fully transparent (or the platform background). Called once at the start of each frame. |
Colors & Styles
These methods set persistent state that applies to subsequent draw calls.
| Method | What it should do |
|---|---|
set_fill_color(color) | Set the fill paint to a solid RGBA color. Used before fill, fill_rect, fill_text. |
set_stroke_color(color) | Set the stroke paint to a solid RGBA color. Used before stroke, stroke_rect. |
set_line_width(width) | Set the stroke line width in pixels. |
set_line_dash(pattern) | Set the dash pattern as alternating drawn/gap lengths (e.g., &[6.0, 3.0] = 6 px on, 3 px off). Pass an empty slice to return to a solid line. |
set_fill_linear_gradient(x0,y0,x1,y1,stops) | Set the fill paint to a linear gradient from (x0,y0) to (x1,y1). stops is a list of (offset, Color) where offset ∈ [0.0, 1.0]. Subsequent fill or fill_rect calls use this gradient. |
Text
| Method | What it should do |
|---|---|
set_font(size, formatting, family) | Set the active font. size is in CSS pixels. formatting is TextFormatting::Normal, Bold, or Italic. family is FontFamily::Default (sans-serif) or FontFamily::Monospace. |
set_text_align(align) | Set horizontal text alignment relative to the x coordinate passed to fill_text. Left = x is the left edge, Center = x is the midpoint, Right = x is the right edge. |
set_text_baseline(baseline) | Set vertical text baseline relative to the y coordinate passed to fill_text. Top = y is the top of the em box, Middle = y is the vertical center, Bottom = y is the bottom, Alphabetic = y is the standard alphabetic baseline. |
fill_text(text, x, y) | Draw text at pixel position (x, y) using the current font, fill color, alignment, and baseline. |
measure_text(text) -> f64 | Return the rendered width of text in pixels using the current font settings. Must be accurate — the chart uses this for label placement and overlap detection. |
font_metrics() -> FontMetrics | Return the vertical metrics (ascent and descent in pixels from the alphabetic baseline) for the current font. Used for precise multi-line text layout. The default implementation returns zeros; backends that can query real font metrics should override it. Canvas 2D backends should call measureText("M") and read fontBoundingBoxAscent / fontBoundingBoxDescent. |
Paths
Paths are built with begin_path / move_to / line_to / close_path / arc / arc_to, then painted with stroke or fill. This is the standard Canvas 2D path model.
| Method | What it should do |
|---|---|
begin_path() | Discard any previously accumulated path and start a new empty path. |
move_to(x, y) | Move the current point to (x, y) without drawing anything. Starts a new sub-path. |
line_to(x, y) | Append a straight line segment from the current point to (x, y), then update the current point. |
close_path() | Append a straight line from the current point back to the start of the current sub-path, then close it. |
arc(x, y, radius) | Append a full circle (0 to 2π) centered at (x, y) with the given radius. |
arc_to(x1,y1,x2,y2,radius) | Append a circular arc defined by two tangent lines (current point → (x1,y1) and (x1,y1) → (x2,y2)) with the given radius. Equivalent to Canvas 2D arcTo. Used for rounded corners. |
stroke() | Stroke the current path with the current stroke color and line width. |
fill() | Fill the interior of the current path with the current fill paint (color or gradient). |
Shapes
Convenience methods that don't require building a path manually.
| Method | What it should do |
|---|---|
fill_rect(rect) | Fill the rectangle rect with the current fill paint. Equivalent to begin_path + rect + fill. |
stroke_rect(rect) | Stroke the outline of rect with the current stroke color and line width. |
Clipping (optional)
| Method | What it should do |
|---|---|
set_clip(rect) | Some(rect) restricts all subsequent drawing to the given rectangle. A second set_clip(Some(other)) replaces the previous clip (no intersection). None removes the clip and restores unrestricted drawing. The default implementation is a no-op — override it if your backend supports clipping. Canvas 2D backends should use save/clip/restore internally. |
ChartEvent
Action events are accumulated inside the chart view and retrieved with poll_event() after each interaction call. Events carry only a ScriptId or AnnotationId; use helper methods to look up associated data once the borrow is released.
| Event | Description |
|---|---|
EditScript(ScriptId) | User clicked the ✎ edit button on a script's legend |
RemoveScript(ScriptId) | User clicked the ✕ remove button |
ShowError(ScriptId) | User clicked the ⚠ error icon — call cv.script_error(id) to retrieve the error |
ConfigureScript(ScriptId) | User clicked the ⚙ configure button — call cv.script_inputs_effective(id) to retrieve inputs |
DoubleClick(ChartElement) | User double-clicked a series graph or candlestick bar |
SelectionChanged(Option<ChartElement>) | The selected element changed or was cleared. ChartElement is either Bar(usize), Series { script_id, graph_id }, or Annotation(AnnotationId). |
AnnotationCreated(AnnotationId) | A new annotation was added — either by the user completing a drawing tool gesture, or by a direct add_annotation call |
AnnotationUpdated(AnnotationId) | An annotation's spec was replaced via update_annotation |
AnnotationDeleted(AnnotationId) | An annotation was removed via remove_annotation, clear_annotations, or the user pressing Delete while one is selected |
// After any interaction method, poll and handle pending events:
cv.on_mouse_up(pos);
while let Some(event) = cv.poll_event() {
match event {
ChartEvent::EditScript(id) => { /* open editor */ }
ChartEvent::RemoveScript(id) => { /* confirm and remove */ }
ChartEvent::ShowError(id) => {
let error = cv.script_error(id).unwrap();
// display error
}
ChartEvent::ConfigureScript(id) => {
let inputs = cv.script_inputs_effective(id).unwrap();
// open config dialog
}
ChartEvent::DoubleClick(element) => { /* handle */ }
ChartEvent::SelectionChanged(sel) => { /* handle */ }
ChartEvent::AnnotationCreated(id) => { /* persist new annotation */ }
ChartEvent::AnnotationUpdated(id) => { /* update persisted annotation */ }
ChartEvent::AnnotationDeleted(id) => { /* remove from persistence */ }
_ => {}
}
}ToggleVisibility is handled internally — the chart toggles visibility and re-renders automatically.
ScriptConfig
ScriptConfig manages script visual overrides and input value overrides:
pub struct ScriptConfig {
/// Visual overrides per series graph (colors, styles, visibility).
pub series_overrides: HashMap<SeriesGraphId, SeriesGraphOverride>,
/// Input value overrides. Key = input index, value = JSON value.
pub input_values: HashMap<usize, serde_json::Value>,
}See the ChartView page for the complete configuration UI guide.
ScriptId
ScriptId is an opaque identifier returned when adding a script. Use it to query, configure, or remove scripts.
Rendering & Interaction
All rendering and interaction APIs are documented in the sub-pages:
- Script Management — add, remove, query scripts
- Interaction — mouse, wheel, drag, cursor, selection
- Annotations — CRUD, properties, selection, clipboard
- Drawing Tools — tool state machine, sticky mode, magnet
- Viewport — pane ratios, scroll, zoom, highlighted bar
- Settings & Events — theme, locale, symbol/timeframe, strategy reports, poll_event