Skip to content

Annotations

The AnnotationManagement trait provides programmatic CRUD for annotations — trend lines, shapes, text labels, Fibonacci tools, and more — on any chart view. Both ChartView and ChartView implement this trait, so annotation management code is reusable across both.

Import

rust
use navi_chart::{
    ChartView, ChartView, AnnotationManagement, SystemAnnotationManagement,
    AnnotationSpec, AnnotationFlags, AnnotationKind, AnnotationPane, ControlPoint,
    Stroke, Color, LineStyle, ExtendMode,
};

Usage

rust
use navi_chart::{AnnotationManagement, AnnotationSpec, AnnotationId};

fn add_trend_line<C>(cv: &C, t1: i64, p1: f64, t2: i64, p2: f64) -> AnnotationId
where
    C: AnnotationManagement,
{
    cv.add_annotation(AnnotationSpec {
        kind: AnnotationKind::TrendLine {
            extend: ExtendMode::None,
            stroke: Stroke {
                color: Color::from_rgba(41, 98, 255, 255),
                width: 2.0,
                style: LineStyle::Solid,
            },
            text: String::new(),
        },
        points: vec![
            ControlPoint { time: t1, price: p1 },
            ControlPoint { time: t2, price: p2 },
        ],
        pane: AnnotationPane::Main,
        flags: AnnotationFlags::default(), // VISIBLE | SELECTABLE, not locked
    })
}

// Works with either view type:
let id = add_trend_line(&local_cv, t1, 150.0, t2, 165.0);
let id = add_trend_line(&remote_cv, t1, 150.0, t2, 165.0);

Method Reference

MethodDescription
add_annotation(spec)Add a new annotation. Immediately re-renders and pushes AnnotationCreated. Returns a stable, non-zero AnnotationId.
update_annotation(id, spec)Replace the full spec of an existing annotation. Re-renders and pushes AnnotationUpdated.
remove_annotation(id)Remove an annotation by id. Re-renders and pushes AnnotationDeleted.
clear_annotations()Remove all annotations. Pushes AnnotationDeleted for each.
annotation(id)Return a reference to an annotation by id, or None if not found.
annotations()Return all annotations in z-order (back to front).
annotation_properties(id)Return the property descriptors for an annotation, localised to the chart's current locale. Use these to build a style toolbar or properties panel. Returns None if the annotation id is not found.
get_annotation_property(id, name)Read a single property by its path name (e.g. "stroke.color", "stroke.width"). Returns None if the id is unknown.
set_annotation_property(id, name, value)Write a single property. On VIRTUAL properties (e.g. "colorAll" on a ParallelChannel) the write fans out to all underlying fields. Re-renders immediately. Returns Err(ChartPropertyError) if the id, property name, or value type is invalid — see errors below.
delete_selected_annotation()Delete the currently selected annotation. No-op if nothing is selected. Pushes AnnotationDeleted.
bring_selected_annotation_to_front()Move the selected annotation to the top of the z-order. No-op if nothing is selected.
send_selected_annotation_to_back()Move the selected annotation to the bottom of the z-order. No-op if nothing is selected.
toggle_selected_annotation_lock()Toggle the LOCKED flag on the selected annotation (AnnotationFlags::LOCKED). Locked annotations cannot be moved or edited by the user. No-op if nothing is selected.
copy_selected_annotation()Copy the selected annotation to the chart's internal clipboard. No-op if nothing is selected.
cut_selected_annotation()Copy the selected annotation to the clipboard and then delete it. No-op if nothing is selected.
paste_annotation()Paste the clipboard annotation as a new annotation, slightly offset from the original. Pushes AnnotationCreated. No-op if the clipboard is empty.
has_clipboard_annotation()Return true if the clipboard contains a copied annotation.
selected_annotation_bounds()Return the bounding box of the selected annotation in canvas pixels. Useful for positioning a floating toolbar. Returns None if nothing is selected.
annotation_bounds(id)Return the pixel-space AABB of the user annotation with the given id. Uses per-kind accurate geometry (e.g. full pane width for horizontal lines, rendered rect for images, TextBounds for text annotations). Returns None if the id is unknown or the projection is degenerate.
selected_annotation_is_highlighter()Return true if the selected annotation is a Highlighter brush stroke. Useful for showing a highlighting-specific toolbar.
dispatch_context_menu_action(action)Execute a context menu action string on the selected annotation (e.g. "delete", "lock", "bring-to-front", "send-to-back", "copy", "cut", "paste"). Call this after the user selects an item from the menu populated by context_menu_items(pos).
annotation_control_point_flags(id)Return the ControlPointFlags for each control point of annotation id, in order, or None if not found. Use these flags to know which coordinate axes are locked when building a Coordinates editor tab.
set_annotation_default(tool_id, kind)Save a per-tool style default for the given drawing tool. The next annotation of that tool created via the drawing flow will use these properties instead of the factory defaults.
reset_annotation_to_default(id)Reset an annotation's style properties to factory defaults and clear any saved per-tool default for that tool. Pushes AnnotationUpdated and re-renders.

Notes on selection-based methods

delete_selected_annotation, bring_selected_annotation_to_front, send_selected_annotation_to_back, toggle_selected_annotation_lock, copy_selected_annotation, cut_selected_annotation, and selected_annotation_bounds all operate on the currently selected annotation. They are no-ops when no annotation is selected — safe to call from toolbar buttons unconditionally.

Notes on annotation_bounds

annotation_bounds(id) and system_annotation_bounds(id) accept an explicit id and return per-kind accurate bounds (not just a control-point AABB). For example, a HorizontalLine returns the full pane width; a Text annotation returns its rendered text box; an Image returns its scaled destination rect.

set_annotation_property errors

set_annotation_property returns Err(ChartPropertyError) when:

  • The annotation id is not found.
  • The property name does not exist for that annotation kind.
  • The value type does not match the property kind.

Example: Properties Toolbar

rust
use navi_chart::{AnnotationManagement, ChartInteraction, PropertyValue, Color};

fn apply_color_from_toolbar<C>(cv: &C, color: Color)
where
    C: AnnotationManagement + ChartInteraction,
{
    if let Some(ChartElement::Annotation(id)) = cv.selection() {
        // Try the virtual property first (fans out to all strokes)
        let _ = cv.set_annotation_property(id, "colorAll", PropertyValue::Color(color))
            .or_else(|_| cv.set_annotation_property(id, "stroke.color", PropertyValue::Color(color)));
    }
}

Example: Persistence Round-trip

rust
use navi_chart::{AnnotationManagement, Annotation, AnnotationSpec};

fn save_annotations<C>(cv: &C) -> String
where
    C: AnnotationManagement,
{
    let annotations: Vec<Annotation> = cv.annotations();
    serde_json::to_string(&annotations).unwrap()
}

fn restore_annotations<C>(cv: &C, json: &str)
where
    C: AnnotationManagement,
{
    let saved: Vec<Annotation> = serde_json::from_str(json).unwrap();
    cv.clear_annotations();
    for ann in saved {
        cv.add_annotation(ann.spec);
    }
}

AnnotationFlags

AnnotationSpec.flags is a bitflags field that replaces the old visible: bool and locked: bool fields:

FlagDefaultDescription
VISIBLEThe annotation is rendered. Clear to hide without deleting.
LOCKEDControl points are not draggable. The annotation is still selectable so the user can unlock it.
SELECTABLEClicking the annotation updates the selection and shows handles. When cleared, AnnotationClicked still fires but no selection change occurs.

AnnotationFlags::default() gives VISIBLE | SELECTABLE (the standard interactive annotation). Construct custom flags with the bitwise operators:

rust
use navi_chart::annotation::AnnotationFlags;

// Hidden, not selectable — a purely decorative overlay
let decorative = AnnotationFlags::VISIBLE;

// Visible, locked, selectable (user can click but not drag)
let read_only = AnnotationFlags::VISIBLE | AnnotationFlags::LOCKED | AnnotationFlags::SELECTABLE;

ControlPointFlags

annotation_control_point_flags(id) returns one ControlPointFlags per control point of the annotation. Use these flags when building a Coordinates editor to decide which axis inputs to show or hide.

FlagBitEffect
LOCK_BAR_INDEX0b0001The X axis (bar index / time) is fixed for this point. Hide the bar-index input. Set for HorizontalLine (spans the full pane width; anchor bar is irrelevant).
LOCK_PRICE0b0010The Y axis (price) is fixed for this point. Hide the price input.
FOLLOW_FIRST_BAR_INDEX0b0100During drawing, this point inherits the X value from the first point.
FOLLOW_FIRST_PRICE0b1000During drawing, this point inherits the Y value from the first point.
rust
use navi_chart::{AnnotationManagement, annotation::ControlPointFlags};

fn build_coordinates_tab<C: AnnotationManagement>(cv: &C, id: AnnotationId) {
    let annotation = cv.annotation(id).unwrap();
    let flags_per_point = cv.annotation_control_point_flags(id).unwrap_or_default();

    for (i, point) in annotation.spec.points.iter().enumerate() {
        let flags = flags_per_point.get(i).copied().unwrap_or_default();

        if !flags.contains(ControlPointFlags::LOCK_BAR_INDEX) {
            render_bar_index_input(i, point.time);
        }
        if !flags.contains(ControlPointFlags::LOCK_PRICE) {
            render_price_input(i, point.price);
        }
    }
}

System Annotation Layer

The SystemAnnotationManagement trait provides a parallel API for programmatic overlays (order lines, signals, etc.) that render below user-drawn annotations:

  • Excluded from undo/redo, annotations(), and save snapshots.
  • Fires AnnotationCreated / AnnotationUpdated / AnnotationDeleted (same as user annotations).
  • Dragging a system annotation fires AnnotationUpdated but skips the undo stack.
  • Keyboard Delete does not affect system annotations — remove them via remove_system_annotation.
rust
use navi_chart::{SystemAnnotationManagement, AnnotationSpec, AnnotationFlags, AnnotationKind, AnnotationPane, ControlPoint};

// Add an order line
let id = cv.add_system_annotation(AnnotationSpec {
    kind: AnnotationKind::HorizontalLine(Default::default()),
    points: vec![ControlPoint { time: bar_time, price: order_price }],
    pane: AnnotationPane::Main,
    flags: AnnotationFlags::VISIBLE | AnnotationFlags::SELECTABLE,
    ..Default::default()
});

// Update when the order price changes
cv.update_system_annotation(id, updated_spec);

// Remove when the order is filled
cv.remove_system_annotation(id);

// Clear all system annotations
cv.clear_system_annotations();

SystemAnnotationManagement method reference

MethodDescription
add_system_annotation(spec)Add a system annotation. Fires AnnotationCreated. Returns the allocated AnnotationId.
update_system_annotation(id, spec)Replace the spec. Fires AnnotationUpdated.
remove_system_annotation(id)Remove by id. Fires AnnotationDeleted.
clear_system_annotations()Remove all system annotations.
system_annotations()Return all system annotations in z-order.
system_annotation_bounds(id)Return the pixel-space AABB of the system annotation with the given id. Same per-kind accuracy as annotation_bounds. Returns None if not found or projection is degenerate.

For the full AnnotationKind variant list, AnnotationSpec structure, PropertyDescriptor fields, and style sub-structs, see ChartView.

Released under the MIT License.