Linear

Struct Linear 

Source
pub struct Linear<D, N = f64>
where D: Float, N: Float,
{ /* private fields */ }
Expand description

Linear scale: affine mapping between a numeric domain and normalized [0, 1] range.

Linear provides a straightforward linear mapping between data values and a normalized [0, 1] range. This is the most common scale type for charting.

§Type Parameters

  • D: Domain type (the data values, typically f32 or f64)
  • N: Normalized type (typically f32 or f64, represents [0, 1] range)

§Features

  • Bidirectional mapping: Convert between domain and normalized values
  • Pan and zoom: Interactively adjust the visible domain
  • Tick generation: Automatically generate “nice” tick marks for axes
  • Reversed axes: Support both increasing and decreasing domains
  • No clamping: Out-of-range values map beyond [0, 1]

§Domain Ordering

Domain values are kept exactly as set (no implicit sorting), so both normal and reversed axes are supported:

  • Normal: new(0.0, 100.0) - larger values at the right/top
  • Reversed: new(100.0, 0.0) - larger values at the left/bottom

§Examples

§Basic Usage

use aksel::{Scale, scale::Linear};

let scale = Linear::<f64, f64>::new(0.0, 100.0);

// Normalize to [0, 1]
assert_eq!(scale.normalize(&0.0), 0.0);
assert_eq!(scale.normalize(&50.0), 0.5);
assert_eq!(scale.normalize(&100.0), 1.0);

// Denormalize back to domain
assert_eq!(scale.denormalize(0.0), 0.0);
assert_eq!(scale.denormalize(0.5), 50.0);
assert_eq!(scale.denormalize(1.0), 100.0);

§Mixed Type Precision

use aksel::{Scale, scale::Linear};

// f64 domain, f32 normalized (common for GPU rendering)
let scale = Linear::<f64, f32>::new(0.0, 100.0);

let normalized: f32 = scale.normalize(&50.0);
assert_eq!(normalized, 0.5f32);

§Pan and Zoom

use aksel::{Scale, scale::Linear};

let mut scale = Linear::<f64, f64>::new(0.0, 100.0);

// Pan by 20% of the range
scale.pan(0.2);
assert_eq!(scale.domain(), (&20.0, &120.0));

// Zoom in 2x around the center
let mut scale = Linear::<f64, f64>::new(0.0, 100.0);
scale.zoom(2.0, Some(0.5));
assert_eq!(scale.domain(), (&25.0, &75.0));

// Zoom in 2x around the left edge (25% position)
let mut scale = Linear::<f64, f64>::new(0.0, 100.0);
scale.zoom(2.0, Some(0.25));
assert_eq!(scale.domain(), (&12.5, &62.5));

§Reversed Axis

use aksel::{Scale, scale::Linear};

// Create a reversed scale (useful for Y-axes that go down)
let scale = Linear::<f64, f64>::new(100.0, 0.0);

assert_eq!(scale.normalize(&100.0), 0.0);
assert_eq!(scale.normalize(&0.0), 1.0);

§Custom Tick Generation

use aksel::{Scale, scale::{Linear, Tick}};

// Create a scale with custom ticks
let scale = Linear::<f64, f64>::new_with_tick_fn(0.0, 100.0, |_scale| {
    vec![
        Tick { value: 0.0, level: 0 },
        Tick { value: 50.0, level: 0 },
        Tick { value: 100.0, level: 0 },
    ]
});

assert_eq!(scale.ticks().len(), 3);

§Out-of-Range Values

use aksel::{Scale, scale::Linear};

let scale = Linear::<f64, f64>::new(0.0, 100.0);

// Values outside domain are not clamped
assert_eq!(scale.normalize(&150.0), 1.5);
assert_eq!(scale.normalize(&-50.0), -0.5);

Implementations§

Source§

impl<D, N> Linear<D, N>
where D: Float + 'static, N: Float + 'static,

Source

pub fn new(min: D, max: D) -> Self

Creates a new linear scale with the given domain range.

Uses the default tick generator which creates “nice” tick marks at round numbers (e.g., 0, 10, 20, 50, 100).

§Arguments
  • min - The minimum value of the domain
  • max - The maximum value of the domain
§Examples
use aksel::{Scale, scale::Linear};

let scale = Linear::<f64, f64>::new(0.0, 100.0);
assert_eq!(scale.domain(), (&0.0, &100.0));
Source

pub fn new_with_tick_generator<F>(min: D, max: D, tick_generator: F) -> Self
where F: Fn(&Self) -> TickIter<D> + 'static,

Creates a new linear scale with a custom tick generator.

The tick generator is a function that takes a reference to the scale and returns a TickIter that generates tick marks.

§Arguments
  • min - The minimum value of the domain
  • max - The maximum value of the domain
  • tick_generator - A function that generates ticks for this scale
§Examples
use aksel::{Scale, scale::{Linear, TickIter}};

let scale = Linear::<f64, f64>::new_with_tick_generator(0.0, 100.0, |_scale| {
    TickIter::empty()
});
assert!(scale.ticks().is_empty());
Source

pub fn new_with_tick_fn<F>(min: D, max: D, tick_fn: F) -> Self
where F: Fn(&Self) -> Vec<Tick<D>> + 'static,

Creates a new linear scale with a custom tick function.

This is a convenience method that wraps a function returning Vec<Tick<D>> into a tick generator. Use this when you want to provide a simple list of ticks rather than implementing an iterator.

§Arguments
  • min - The minimum value of the domain
  • max - The maximum value of the domain
  • tick_fn - A function that generates a vector of ticks
§Examples
use aksel::{Scale, scale::{Linear, Tick}};

let scale = Linear::<f64, f64>::new_with_tick_fn(0.0, 100.0, |_scale| {
    vec![
        Tick { value: 0.0, level: 0 },
        Tick { value: 50.0, level: 0 },
        Tick { value: 100.0, level: 0 },
    ]
});
assert_eq!(scale.ticks().len(), 3);

Trait Implementations§

Source§

impl<D, N> Scale for Linear<D, N>
where D: Float, N: Float,

Source§

type Domain = D

The type of values in the data domain (e.g., f64, f32).
Source§

type Normalized = N

The type for normalized [0, 1] values (e.g., f32, f64).
Source§

fn domain(&self) -> (&D, &D)

Returns the current data domain as (min, max).
Source§

fn set_domain(&mut self, min: D, max: D)

Sets the data domain to the given min and max values.
Source§

fn normalize_opt(&self, value: &D) -> Option<N>

Map a domain value into normalized [0.0, 1.0]. Returns None if numeric conversion fails.
Source§

fn denormalize_opt(&self, t: N) -> Option<D>

Map a normalized position [0.0, 1.0] back into domain. Returns None if numeric conversion fails.
Source§

fn pan_opt(&mut self, delta_norm: N) -> Option<()>

Pan the domain based on a normalized shift. Returns None if numeric conversion fails. Read more
Source§

fn zoom_opt(&mut self, factor: N, anchor_norm: Option<N>) -> Option<()>

Zoom around an optional normalized anchor. Returns None if numeric conversion fails. Read more
Source§

fn tick_iter(&self) -> TickIter<D>

Lazily generate multi-level ticks in domain space.
Source§

fn extend_domain(&mut self, other_min: &D, other_max: &D)

Extend domain so that [other_min, other_max] fits inside.
Source§

fn is_valid_domain_value(&self, _value: &D) -> bool

Whether this value is allowed for this scale.
Source§

fn normalize(&self, value: &Self::Domain) -> Self::Normalized

Map a domain value into normalized [0.0, 1.0]. Panics if numeric conversion fails.
Source§

fn denormalize(&self, t: Self::Normalized) -> Self::Domain

Map a normalized position [0.0, 1.0] back into domain. Panics if numeric conversion fails.
Source§

fn pan(&mut self, delta_norm: Self::Normalized)

Pan the domain based on a normalized shift. Panics if numeric conversion fails. Read more
Source§

fn zoom( &mut self, factor: Self::Normalized, anchor_norm: Option<Self::Normalized>, )

Zoom around an optional normalized anchor. Panics if numeric conversion fails. Read more
Source§

fn ticks(&self) -> Vec<Tick<Self::Domain>>

Collect ticks into a Vec. Prefer Scale::tick_iter when you only need to stream ticks.

Auto Trait Implementations§

§

impl<D, N> Freeze for Linear<D, N>
where D: Freeze,

§

impl<D, N = f64> !RefUnwindSafe for Linear<D, N>

§

impl<D, N = f64> !Send for Linear<D, N>

§

impl<D, N = f64> !Sync for Linear<D, N>

§

impl<D, N> Unpin for Linear<D, N>
where D: Unpin, N: Unpin,

§

impl<D, N = f64> !UnwindSafe for Linear<D, N>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.