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