ChartModel
ChartModel<T> — concrete reactive multi-series chart data model.
ChartModel<T> owns an ordered collection of named series, each holding a
Vec<ChartDatum<T>> (a category: T paired with a numeric value: f32),
in a flat SlotMap arena — the same shape as crate::TreeModel. Every
mutation (series add/remove/move/rename/recolor/show-hide, point
push/insert/remove/update/replace) emits a ChartChange to all
registered observers and bumps one of two reactive version signals:
ChartModel::style_version (color changes only — a paint-only signal a
chart can bind at BindingLevel::RepaintOnly) or
ChartModel::structure_version (everything else — series/point shape,
bound at BindingLevel::Relayout/Rebuild). Series identity is a stable,
versioned SeriesId (a SlotMap key) that is never reused after removal.
Cloning produces a second handle to the same data — all handles share
series/points and receive the same change notifications. Register
observers via observe_changes; the
returned ObserverHandle is RAII — dropping it unregisters the callback.
For a bounded "last N points" streaming view use
ChartWindow. For bucketed/rolled-up display use
ChartAggregate. For point-level selection use
ChartSelection.
#![allow(unused)] fn main() { use teksilo_data::{ChartModel, ChartSeries, ChartDatum}; let model = ChartModel::from_series_vec(vec![ ChartSeries::new("Revenue").data(vec![ ChartDatum::new("Q1".to_string(), 10.0), ChartDatum::new("Q2".to_string(), 20.0), ]), ]); assert_eq!(model.series_count(), 1); let s = model.series_id_at(0).unwrap(); assert_eq!(model.point_count(s), 2); model.push_point(s, "Q3".to_string(), 30.0); assert_eq!(model.point_count(s), 3); }
Builder methods at a glance
from_series_vec, from_points, only_series, add_series, insert_series, remove_series, rename_series, set_series_color, clear_series_color, set_series_pattern, clear_series_pattern, set_series_visible, move_series, clear, push_point, insert_point, remove_point, update_point, replace_series_data, series_count, series_ids, series_id_at, series_index_of, point_count, with_series, with_point, with_series_view, with_all_series, structure_version, style_version, observe_changes, debug_named
API reference
📖 Full rustdoc API for this module
pub struct ChartDatum
One numeric data point at a category/x-axis position, with an optional per-point color that overrides the series color (bar charts only).
#![allow(unused)] fn main() { pub struct ChartDatum<T> { /* fields */ } }
Methods
pub fn new(category: T, value: f32) -> Self
pub fn with_color(mut self, color: impl Into<ColorProp>) -> Self
Override this point's color (a bar's fill). Ignored by line/pie charts, which color by series.
pub struct ChartSeries
A named series of data points with an optional explicit color and a
visibility flag, used to construct a ChartModel (via
ChartModel::from_series_vec) or to describe one series' desired
shape. Unlike the model, visible here is a plain bool — reactivity
lives in the model's ChartModel::structure_version /
ChartModel::style_version signals, not in this construction DTO.
#![allow(unused)] fn main() { pub struct ChartSeries<T> { /* fields */ } }
Methods
pub fn new(name: impl Into<String>) -> Self
pub fn color(mut self, color: impl Into<ColorProp>) -> Self
pub fn pattern(mut self, pattern: SeriesPattern) -> Self
Pin this series' non-colour channel instead of taking the one its
position implies. See SeriesPattern.
pub fn visibility(mut self, visible: bool) -> Self
pub fn push(&mut self, category: T, value: f32)
pub fn data(mut self, points: Vec<ChartDatum<T>>) -> Self
pub struct SeriesView
A read-only, borrowed view over one series — returned by
ChartModel::with_series_view / ChartModel::with_all_series.
#![allow(unused)] fn main() { pub struct SeriesView<'a, T> { /* fields */ } }
pub struct ChartModel
A concrete reactive multi-series chart data model.
ChartModel<T> is Clone — cloning produces a second handle to the same
data. Multiple charts can hold clones and all see the same series and
points, and receive the same ChartChange notifications.
#![allow(unused)] fn main() { pub struct ChartModel<T: 'static> { /* fields */ } }
Methods
pub fn new() -> Self
Create an empty chart model with no series.
pub fn from_series_vec(series: Vec<ChartSeries<T>>) -> Self
Build a model directly from a vector of ChartSeries DTOs — the
primary constructor. Populates the arena in one pass with no
per-item notification (mirrors crate::ListModel::from_vec).
pub fn from_points(points: Vec<ChartDatum<T>>) -> Self
Build a model with a single anonymous, visible series holding
points — the flat/pie-chart path where series structure doesn't
matter.
pub fn only_series(&self) -> Option<SeriesId>
The model's sole series id, iff it has exactly one series.
pub fn add_series(&self, name: impl Into<String>) -> SeriesId
Append a new, empty, visible series named name.
pub fn insert_series(&self, index: usize, name: impl Into<String>) -> SeriesId
Insert a new, empty, visible series named name at index.
Panics
Panics if index > series_count().
pub fn remove_series(&self, series: SeriesId)
Remove a series and all of its points.
Panics
Panics if series is unknown.
pub fn rename_series(&self, series: SeriesId, name: impl Into<String>)
Rename a series. A no-op (no notify, no version bump) if name
already matches the current value.
Panics
Panics if series is unknown.
pub fn set_series_color(&self, series: SeriesId, color: impl Into<ColorProp>)
Set a series' explicit color. Bumps Self::style_version (not
Self::structure_version) — this is a paint-only change. A no-op
(no notify, no version bump) if color already matches the current
value.
Panics
Panics if series is unknown.
pub fn clear_series_color(&self, series: SeriesId)
Clear a series' explicit color (falls back to the chart's palette).
Bumps Self::style_version. A no-op (no notify, no version bump)
if the series already has no explicit color.
Panics
Panics if series is unknown.
pub fn set_series_pattern(&self, series: SeriesId, pattern: SeriesPattern)
Set a series' explicit SeriesPattern — the non-colour channel that
identifies it. Bumps Self::style_version (paint-only), like
set_series_color. A no-op if unchanged.
Panics
Panics if series is unknown.
pub fn clear_series_pattern(&self, series: SeriesId)
Clear a series' explicit pattern, falling back to the one its position
implies. Bumps Self::style_version. A no-op if already unset.
Panics
Panics if series is unknown.
pub fn set_series_visible(&self, series: SeriesId, visible: bool)
Show or hide a series. A no-op (no notify, no version bump) if
visible already matches the current value.
Panics
Panics if series is unknown.
pub fn move_series(&self, series: SeriesId, to: usize)
Move a series to a new position among its siblings. A no-op (no
notify, no version bump) if to is already the series' position.
Panics
Panics if series is unknown or to is out of bounds.
pub fn clear(&self)
Remove every series.
pub fn push_point(&self, series: SeriesId, category: T, value: f32)
Append a point to the end of series.
Panics
Panics if series is unknown.
pub fn insert_point(&self, series: SeriesId, index: usize, category: T, value: f32)
Insert a point at index within series.
Panics
Panics if series is unknown or index > point_count(series).
pub fn remove_point(&self, series: SeriesId, index: usize) -> ChartDatum<T>
Remove and return the point at index within series.
Panics
Panics if series is unknown or index >= point_count(series).
pub fn update_point(&self, series: SeriesId, index: usize, category: T, value: f32)
Replace the point at index within series.
Panics
Panics if series is unknown or index >= point_count(series).
pub fn replace_series_data(&self, series: SeriesId, points: Vec<ChartDatum<T>>)
Replace series' entire point list.
Panics
Panics if series is unknown.
pub fn series_count(&self) -> usize
Number of series.
pub fn series_ids(&self) -> Vec<SeriesId>
The series ids, in display order.
pub fn series_id_at(&self, index: usize) -> Option<SeriesId>
The series id at index, if any.
pub fn series_index_of(&self, series: SeriesId) -> Option<usize>
The display index of series, if it exists.
pub fn point_count(&self, series: SeriesId) -> usize
Number of points in series (0 if unknown).
pub fn with_series<R>( &self, series: SeriesId, f: impl FnOnce(&str, Option<&ColorProp>, bool) -> R, ) -> Option<R>
Access a series' metadata (name, color, visibility) via a callback.
Returns None if series is unknown.
pub fn with_point<R>( &self, series: SeriesId, index: usize, f: impl FnOnce(&ChartDatum<T>) -> R, ) -> Option<R>
Access a point within series via a callback. Returns None if the
series or index is unknown.
pub fn with_series_view<R>( &self, series: SeriesId, f: impl FnOnce(SeriesView<'_, T>) -> R, ) -> Option<R>
Access a whole-series view (metadata + points slice) via a callback.
Returns None if series is unknown.
pub fn with_all_series<R>(&self, f: impl FnOnce(&[SeriesView<'_, T>]) -> R) -> R
Access every series as an ordered slice of views via a callback.
pub fn structure_version(&self) -> Signal<u64>
Structural version signal — bumped by every mutation except a color
change (series add/remove/move/rename/show-hide, all point ops).
Bind at BindingLevel::Relayout or Rebuild.
Ordering: every mutator notifies the ChartChange observers
registered via Self::observe_changes before bumping this
signal — see the note on observe_changes for what that means for a
callback that reads the signal back synchronously.
pub fn style_version(&self) -> Signal<u64>
Style version signal — bumped only by a series color change. Bind at
BindingLevel::RepaintOnly. Same notify-before-bump ordering as
Self::structure_version — see Self::observe_changes.
pub fn observe_changes(&self, f: impl Fn(&ChartChange) + 'static) -> ObserverHandle
Register an observer that is called on every mutation.
Returns an ObserverHandle — dropping it removes the callback.
Ordering contract: every mutator calls this observer before
bumping Self::structure_version / Self::style_version (see
e.g. rename_series, push_point) — notify, then bump. This is
intentional, not an implementation accident: it lets a ChartChange
callback distinguish "did I get here via the change I'm reacting to"
from "did something else bump the version already", by comparing the
version signal's value inside the callback against a value captured
before the mutation. The flip side: a callback that reads
structure_version()/style_version() synchronously inside
itself always observes the pre-bump value for the mutation
currently being notified — the bump hasn't happened yet. Don't use
the version signal from inside a ChartChange observer as a proxy
for "has this specific mutation been applied" — the ChartChange
argument already tells you that; use the signal for external
bind-and-rerun consumers (widgets), not from within the notify path
itself.
pub fn debug_named(self, _name: impl Into<String>) -> Self
Register this model with the debug inspector under name. In
release builds (!cfg(debug_assertions)) this is a no-op
pass-through so call sites stay free of #[cfg] lines.
Idempotent on repeated calls — the latest registration wins.
The registration drops automatically when the last ChartModel
handle is freed (the adapter the registry holds is Weak).