plotters_unstable/style/
color.rs

1use super::palette::Palette;
2use super::ShapeStyle;
3
4use plotters_backend::{BackendColor, BackendStyle};
5
6use std::marker::PhantomData;
7
8/// Any color representation
9pub trait Color: BackendStyle {
10    /// Convert the RGB representation to the standard RGB tuple
11    #[inline(always)]
12    fn rgb(&self) -> (u8, u8, u8) {
13        self.color().rgb
14    }
15
16    /// Get the alpha channel of the color
17    #[inline(always)]
18    fn alpha(&self) -> f64 {
19        self.color().alpha
20    }
21
22    /// Mix the color with given opacity
23    fn mix(&self, value: f64) -> RGBAColor {
24        let (r, g, b) = self.rgb();
25        let a = self.alpha() * value;
26        RGBAColor(r, g, b, a)
27    }
28
29    /// Convert the color into the RGBA color which is internally used by Plotters
30    fn to_rgba(&self) -> RGBAColor {
31        let (r, g, b) = self.rgb();
32        let a = self.alpha();
33        RGBAColor(r, g, b, a)
34    }
35
36    /// Make a filled style form the color
37    fn filled(&self) -> ShapeStyle
38    where
39        Self: Sized,
40    {
41        Into::<ShapeStyle>::into(self).filled()
42    }
43
44    /// Make a shape style with stroke width from a color
45    fn stroke_width(&self, width: u32) -> ShapeStyle
46    where
47        Self: Sized,
48    {
49        Into::<ShapeStyle>::into(self).stroke_width(width)
50    }
51}
52
53/// The RGBA representation of the color, Plotters use RGBA as the internal representation
54/// of color
55#[derive(Clone, PartialEq, Debug)]
56pub struct RGBAColor(pub(crate) u8, pub(crate) u8, pub(crate) u8, pub(crate) f64);
57
58impl BackendStyle for RGBAColor {
59    #[inline(always)]
60    fn color(&self) -> BackendColor {
61        BackendColor {
62            rgb: (self.0, self.1, self.2),
63            alpha: self.3,
64        }
65    }
66}
67impl Color for RGBAColor {}
68
69/// A color in the given palette
70pub struct PaletteColor<P: Palette>(usize, PhantomData<P>);
71
72impl<P: Palette> PaletteColor<P> {
73    /// Pick a color from the palette
74    pub fn pick(idx: usize) -> PaletteColor<P> {
75        PaletteColor(idx % P::COLORS.len(), PhantomData)
76    }
77}
78
79impl<P: Palette> BackendStyle for PaletteColor<P> {
80    #[inline(always)]
81    fn color(&self) -> BackendColor {
82        BackendColor {
83            rgb: P::COLORS[self.0],
84            alpha: 1.0,
85        }
86    }
87}
88
89impl<P: Palette> Color for PaletteColor<P> {}
90
91/// The color described by its RGB value
92#[derive(Debug)]
93pub struct RGBColor(pub u8, pub u8, pub u8);
94
95impl BackendStyle for RGBColor {
96    #[inline(always)]
97    fn color(&self) -> BackendColor {
98        BackendColor {
99            rgb: (self.0, self.1, self.2),
100            alpha: 1.0,
101        }
102    }
103}
104
105impl Color for RGBColor {}
106
107/// The color described by HSL color space
108pub struct HSLColor(pub f64, pub f64, pub f64);
109
110impl BackendStyle for HSLColor {
111    #[inline(always)]
112    #[allow(clippy::many_single_char_names)]
113    fn color(&self) -> BackendColor {
114        let (h, s, l) = (
115            self.0.min(1.0).max(0.0),
116            self.1.min(1.0).max(0.0),
117            self.2.min(1.0).max(0.0),
118        );
119
120        if s == 0.0 {
121            let value = (l * 255.0).round() as u8;
122            return BackendColor {
123                rgb: (value, value, value),
124                alpha: 1.0,
125            };
126        }
127
128        let q = if l < 0.5 {
129            l * (1.0 + s)
130        } else {
131            l + s - l * s
132        };
133        let p = 2.0 * l - q;
134
135        let cvt = |mut t| {
136            if t < 0.0 {
137                t += 1.0;
138            }
139            if t > 1.0 {
140                t -= 1.0;
141            }
142            let value = if t < 1.0 / 6.0 {
143                p + (q - p) * 6.0 * t
144            } else if t < 1.0 / 2.0 {
145                q
146            } else if t < 2.0 / 3.0 {
147                p + (q - p) * (2.0 / 3.0 - t) * 6.0
148            } else {
149                p
150            };
151            (value * 255.0).round() as u8
152        };
153
154        BackendColor {
155            rgb: (cvt(h + 1.0 / 3.0), cvt(h), cvt(h - 1.0 / 3.0)),
156            alpha: 1.0,
157        }
158    }
159}
160
161impl Color for HSLColor {}