plotters/style/
color.rs
1use super::palette::Palette;
2use super::ShapeStyle;
3
4use plotters_backend::{BackendColor, BackendStyle};
5
6use std::marker::PhantomData;
7
8pub trait Color {
10 fn to_backend_color(&self) -> BackendColor;
12
13 #[inline(always)]
15 fn rgb(&self) -> (u8, u8, u8) {
16 self.to_backend_color().rgb
17 }
18
19 #[inline(always)]
21 fn alpha(&self) -> f64 {
22 self.to_backend_color().alpha
23 }
24
25 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 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 fn filled(&self) -> ShapeStyle
41 where
42 Self: Sized,
43 {
44 Into::<ShapeStyle>::into(self).filled()
45 }
46
47 fn stroke_width(&self, width: u32) -> ShapeStyle
49 where
50 Self: Sized,
51 {
52 Into::<ShapeStyle>::into(self).stroke_width(width)
53 }
54}
55
56impl<T: Color> Color for &'_ T {
57 fn to_backend_color(&self) -> BackendColor {
58 <T as Color>::to_backend_color(*self)
59 }
60}
61
62#[derive(Copy, Clone, PartialEq, Debug, Default)]
65pub struct RGBAColor(pub(crate) u8, pub(crate) u8, pub(crate) u8, pub(crate) f64);
66
67impl Color for RGBAColor {
68 #[inline(always)]
69 fn to_backend_color(&self) -> BackendColor {
70 BackendColor {
71 rgb: (self.0, self.1, self.2),
72 alpha: self.3,
73 }
74 }
75}
76
77pub struct PaletteColor<P: Palette>(usize, PhantomData<P>);
79
80impl<P: Palette> PaletteColor<P> {
81 pub fn pick(idx: usize) -> PaletteColor<P> {
83 PaletteColor(idx % P::COLORS.len(), PhantomData)
84 }
85}
86
87impl<P: Palette> Color for PaletteColor<P> {
88 #[inline(always)]
89 fn to_backend_color(&self) -> BackendColor {
90 BackendColor {
91 rgb: P::COLORS[self.0],
92 alpha: 1.0,
93 }
94 }
95}
96
97#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)]
99pub struct RGBColor(pub u8, pub u8, pub u8);
100
101impl BackendStyle for RGBAColor {
102 fn color(&self) -> BackendColor {
103 self.to_backend_color()
104 }
105}
106
107impl Color for RGBColor {
108 #[inline(always)]
109 fn to_backend_color(&self) -> BackendColor {
110 BackendColor {
111 rgb: (self.0, self.1, self.2),
112 alpha: 1.0,
113 }
114 }
115}
116impl BackendStyle for RGBColor {
117 fn color(&self) -> BackendColor {
118 self.to_backend_color()
119 }
120}
121
122pub struct HSLColor(pub f64, pub f64, pub f64);
124
125impl Color for HSLColor {
126 #[inline(always)]
127 #[allow(clippy::many_single_char_names)]
128 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}