• 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: BackendStyle {
10     /// Convert the RGB representation to the standard RGB tuple
11     #[inline(always)]
rgb(&self) -> (u8, u8, u8)12     fn rgb(&self) -> (u8, u8, u8) {
13         self.color().rgb
14     }
15 
16     /// Get the alpha channel of the color
17     #[inline(always)]
alpha(&self) -> f6418     fn alpha(&self) -> f64 {
19         self.color().alpha
20     }
21 
22     /// Mix the color with given opacity
mix(&self, value: f64) -> RGBAColor23     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
to_rgba(&self) -> RGBAColor30     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
filled(&self) -> ShapeStyle where Self: Sized,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
stroke_width(&self, width: u32) -> ShapeStyle where Self: Sized,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)]
56 pub struct RGBAColor(pub(crate) u8, pub(crate) u8, pub(crate) u8, pub(crate) f64);
57 
58 impl BackendStyle for RGBAColor {
59     #[inline(always)]
color(&self) -> BackendColor60     fn color(&self) -> BackendColor {
61         BackendColor {
62             rgb: (self.0, self.1, self.2),
63             alpha: self.3,
64         }
65     }
66 }
67 impl Color for RGBAColor {}
68 
69 /// A color in the given palette
70 pub struct PaletteColor<P: Palette>(usize, PhantomData<P>);
71 
72 impl<P: Palette> PaletteColor<P> {
73     /// Pick a color from the palette
pick(idx: usize) -> PaletteColor<P>74     pub fn pick(idx: usize) -> PaletteColor<P> {
75         PaletteColor(idx % P::COLORS.len(), PhantomData)
76     }
77 }
78 
79 impl<P: Palette> BackendStyle for PaletteColor<P> {
80     #[inline(always)]
color(&self) -> BackendColor81     fn color(&self) -> BackendColor {
82         BackendColor {
83             rgb: P::COLORS[self.0],
84             alpha: 1.0,
85         }
86     }
87 }
88 
89 impl<P: Palette> Color for PaletteColor<P> {}
90 
91 /// The color described by its RGB value
92 #[derive(Debug)]
93 pub struct RGBColor(pub u8, pub u8, pub u8);
94 
95 impl BackendStyle for RGBColor {
96     #[inline(always)]
color(&self) -> BackendColor97     fn color(&self) -> BackendColor {
98         BackendColor {
99             rgb: (self.0, self.1, self.2),
100             alpha: 1.0,
101         }
102     }
103 }
104 
105 impl Color for RGBColor {}
106 
107 /// The color described by HSL color space
108 pub struct HSLColor(pub f64, pub f64, pub f64);
109 
110 impl BackendStyle for HSLColor {
111     #[inline(always)]
112     #[allow(clippy::many_single_char_names)]
color(&self) -> BackendColor113     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 
161 impl Color for HSLColor {}
162