aksel/
lib.rs

1//! akselharting library
2//!
3//! `aksel` is a charting library that provides coordinate transformations and scale mappings
4//! for data visualization. It focuses on the mathematical foundations of charting:
5//! mapping data values to screen coordinates and generating axis tick marks.
6//!
7//! # Core Concepts
8//!
9//! ## Scales
10//!
11//! Scales map data values (domain) to a normalized [0, 1] range. They support:
12//! - Linear and logarithmic mappings
13//! - Pan and zoom operations
14//! - Automatic tick generation for axis labels
15//! - Bidirectional mapping (normalize and denormalize)
16//!
17//! Available scale types:
18//! - [`scale::Linear`] - Affine mapping for linear data
19//! - [`scale::Logarithmic`] - Logarithmic mapping for exponential data
20//!
21//! ## Transforms
22//!
23//! Transforms connect scales to screen coordinates, converting between:
24//! - [`PlotPoint`] - Data values in chart space
25//! - [`ScreenPoint`] - Pixel coordinates in screen space
26//!
27//! The [`Transform`] type handles y-axis inversion (screen coordinates typically
28//! increase downward, while chart coordinates increase upward).
29//!
30//! # Examples
31//!
32//! ## Basic Linear Scale
33//!
34//! ```rust
35//! use aksel::{Scale, scale::Linear};
36//!
37//! // Create a scale mapping [0.0, 100.0] to [0.0, 1.0]
38//! let scale = Linear::<f64, f64>::new(0.0, 100.0);
39//!
40//! // Normalize values to [0.0, 1.0]
41//! assert_eq!(scale.normalize(&0.0), 0.0);
42//! assert_eq!(scale.normalize(&50.0), 0.5);
43//! assert_eq!(scale.normalize(&100.0), 1.0);
44//!
45//! // Denormalize back to domain
46//! assert_eq!(scale.denormalize(0.5), 50.0);
47//! ```
48//!
49//! ## Pan and Zoom
50//!
51//! ```rust
52//! use aksel::{Scale, scale::Linear};
53//!
54//! let mut scale = Linear::<f64, f64>::new(0.0, 100.0);
55//!
56//! // Pan by 10% (shifts by 10 units)
57//! scale.pan(0.1);
58//! assert_eq!(scale.domain(), (&10.0, &110.0));
59//!
60//! // Zoom in by 2x at center
61//! let mut scale = Linear::<f64, f64>::new(0.0, 100.0);
62//! scale.zoom(2.0, Some(0.5));
63//! assert_eq!(scale.domain(), (&25.0, &75.0));
64//! ```
65//!
66//! ## Coordinate Transformation
67//!
68//! ```rust
69//! use aksel::{Transform, scale::Linear, ScreenRect, PlotPoint};
70//!
71//! let x_scale = Linear::<f64, f32>::new(0.0, 100.0);
72//! let y_scale = Linear::<f64, f32>::new(0.0, 50.0);
73//! let screen = ScreenRect { x: 0.0, y: 0.0, width: 800.0, height: 400.0 };
74//!
75//! let transform = Transform::new(&screen, &x_scale, &y_scale);
76//!
77//! // Convert plot coordinates to screen pixels
78//! let plot_point = PlotPoint::new(50.0, 25.0);
79//! let screen_point = transform.chart_to_screen(&plot_point);
80//! // screen_point is at (400.0, 200.0) - center of screen
81//! ```
82//!
83//! ## Generating Ticks
84//!
85//! ```rust
86//! use aksel::{Scale, scale::Linear};
87//!
88//! let scale = Linear::<f64, f64>::new(0.0, 100.0);
89//! let ticks = scale.ticks();
90//!
91//! // Ticks include both major (level 0) and minor (level 1) marks
92//! for tick in ticks {
93//!     if tick.level == 0 {
94//!         println!("Major tick at: {}", tick.value);
95//!     }
96//! }
97//! ```
98//!
99
100pub mod scale;
101pub mod transform;
102
103pub use num_traits::Float;
104pub use scale::{Scale, Tick, TickIter};
105pub use transform::{PlotPoint, PlotRect, ScreenPoint, ScreenRect, Transform};