forge_charts/lib.rs
1#![forbid(unsafe_code)]
2#![allow(
3 clippy::missing_errors_doc,
4 clippy::missing_panics_doc,
5 // Chart math: cast bounds are well below 2^53 for f64 mantissa;
6 // float comparisons in loop bounds are guarded by an epsilon; doc
7 // paragraphs in math code are intentionally long. Pedantic noise.
8 clippy::cast_possible_truncation,
9 clippy::cast_precision_loss,
10 clippy::cast_sign_loss,
11 clippy::cast_possible_wrap,
12 clippy::while_float,
13 clippy::float_cmp,
14 clippy::suboptimal_flops,
15 clippy::format_push_string,
16 clippy::doc_markdown,
17 clippy::too_long_first_doc_paragraph,
18 clippy::needless_pass_by_value,
19 clippy::module_name_repetitions
20)]
21
22//! Pure-Rust + SVG interactive charts for Leptos CSR.
23//!
24//! v0.1 ships one chart type — [`AreaChart`] — with the visual style
25//! of ApexCharts (gradient fills, soft axes, modern legend) but
26//! implemented entirely in Rust + SVG. No JS, no canvas, no Tailwind.
27//! Designed to be project-agnostic: no consumer types leak into the
28//! public API.
29//!
30//! ## Quick start
31//!
32//! ```ignore
33//! use leptos::prelude::*;
34//! use forge_charts::{AreaChart, Series, CHART_CSS};
35//!
36//! #[derive(Clone)]
37//! struct Datum { date: String, opened: u32, closed: u32 }
38//!
39//! #[component]
40//! fn MyChart(data: Signal<Vec<Datum>>) -> impl IntoView {
41//! view! {
42//! <Stylesheet text=CHART_CSS />
43//! <AreaChart
44//! data=data
45//! x_label=|d: &Datum| d.date.clone()
46//! y_values=|d: &Datum| vec![f64::from(d.opened), f64::from(d.closed)]
47//! series=vec![
48//! Series::area("Opened", "opened"),
49//! Series::area("Closed", "closed"),
50//! ]
51//! height=320
52//! />
53//! }
54//! }
55//! ```
56//!
57//! ## Styling
58//!
59//! The crate ships a default stylesheet exposed as the [`CHART_CSS`]
60//! constant. Consumers inject it once via Leptos `<Stylesheet />` at
61//! the app root. CSS variables (`--charts-fg`, `--charts-grid-color`,
62//! `--charts-series-opened`, `--charts-series-closed`, …) let
63//! consumers theme without forking the stylesheet.
64//!
65//! ## Roadmap
66//!
67//! - **Phase B** (shipped): hover crosshair + consumer-provided
68//! tooltip slot.
69//! - **Phase C** (shipped): drag-to-zoom + reset.
70//! - **Future**: Bar / Line variants, smooth Bezier curves, stacked
71//! areas. Extract shared math when the second chart needs it.
72
73// All modules are internal implementation detail; the public surface
74// is the re-exports below. `pub(crate)` so the crate's SemVer surface
75// is the named items, not the module layout. The `unreachable_pub`
76// allow keeps the inner `pub fn` / `pub struct` markers as
77// module-local API documentation rather than forcing every item to
78// be `pub(crate)`.
79#[allow(unreachable_pub)]
80pub(crate) mod axis;
81#[allow(unreachable_pub)]
82pub(crate) mod chart;
83#[allow(unreachable_pub)]
84pub(crate) mod hover;
85#[allow(unreachable_pub)]
86pub(crate) mod path;
87#[allow(unreachable_pub)]
88pub(crate) mod scale;
89#[allow(unreachable_pub)]
90pub(crate) mod series;
91#[allow(unreachable_pub)]
92pub(crate) mod zoom;
93
94pub use chart::{AreaChart, TooltipSlot, YFormat, ZoomCommit};
95pub use hover::HoverState;
96pub use series::{Series, SeriesKind};
97pub use zoom::{MIN_ZOOM_SPAN, ZoomRange};
98
99/// Default stylesheet bundled with the crate. Inject once at the app
100/// root via `<Stylesheet text=CHART_CSS />` (Leptos meta).
101pub const CHART_CSS: &str = include_str!("charts.css");