gpui_component/plot/scale/
point.rs

1// @reference: https://d3js.org/d3-scale/point
2
3use itertools::Itertools;
4use num_traits::Zero;
5
6use super::Scale;
7
8#[derive(Clone)]
9pub struct ScalePoint<T> {
10    domain: Vec<T>,
11    range_tick: f32,
12}
13
14impl<T> ScalePoint<T>
15where
16    T: PartialEq,
17{
18    pub fn new(domain: Vec<T>, range: Vec<f32>) -> Self {
19        let len = domain.len();
20        let range_tick = if len.is_zero() {
21            0.
22        } else {
23            let range_diff = range
24                .iter()
25                .minmax()
26                .into_option()
27                .map_or(0., |(min, max)| max - min);
28
29            if len == 1 {
30                range_diff
31            } else {
32                range_diff / len.saturating_sub(1) as f32
33            }
34        };
35
36        Self { domain, range_tick }
37    }
38}
39
40impl<T> Scale<T> for ScalePoint<T>
41where
42    T: PartialEq,
43{
44    fn tick(&self, value: &T) -> Option<f32> {
45        if self.domain.len() == 1 {
46            Some(self.range_tick / 2.)
47        } else {
48            let index = self.domain.iter().position(|v| v == value)?;
49            Some(index as f32 * self.range_tick)
50        }
51    }
52
53    fn least_index(&self, tick: f32) -> usize {
54        if self.domain.is_empty() {
55            return 0;
56        }
57
58        let index = (tick / self.range_tick).round() as usize;
59        index.min(self.domain.len().saturating_sub(1))
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn test_scale_point() {
69        let scale = ScalePoint::new(vec![1, 2, 3], vec![0., 100.]);
70        assert_eq!(scale.tick(&1), Some(0.));
71        assert_eq!(scale.tick(&2), Some(50.));
72        assert_eq!(scale.tick(&3), Some(100.));
73    }
74
75    #[test]
76    fn test_scale_point_empty() {
77        let scale = ScalePoint::new(vec![], vec![0., 100.]);
78        assert_eq!(scale.tick(&1), None);
79        assert_eq!(scale.tick(&2), None);
80        assert_eq!(scale.tick(&3), None);
81
82        let scale = ScalePoint::new(vec![1, 2, 3], vec![]);
83        assert_eq!(scale.tick(&1), Some(0.));
84        assert_eq!(scale.tick(&2), Some(0.));
85        assert_eq!(scale.tick(&3), Some(0.));
86    }
87
88    #[test]
89    fn test_scale_point_single() {
90        let scale = ScalePoint::new(vec![1], vec![0., 100.]);
91        assert_eq!(scale.tick(&1), Some(50.));
92    }
93}