use super::palette::Palette; use super::ShapeStyle; use plotters_backend::{BackendColor, BackendStyle}; use std::marker::PhantomData; /// Any color representation pub trait Color { /// Normalize this color representation to the backend color fn to_backend_color(&self) -> BackendColor; /// Convert the RGB representation to the standard RGB tuple #[inline(always)] fn rgb(&self) -> (u8, u8, u8) { self.to_backend_color().rgb } /// Get the alpha channel of the color #[inline(always)] fn alpha(&self) -> f64 { self.to_backend_color().alpha } /// Mix the color with given opacity fn mix(&self, value: f64) -> RGBAColor { let (r, g, b) = self.rgb(); let a = self.alpha() * value; RGBAColor(r, g, b, a) } /// Convert the color into the RGBA color which is internally used by Plotters fn to_rgba(&self) -> RGBAColor { let (r, g, b) = self.rgb(); let a = self.alpha(); RGBAColor(r, g, b, a) } /// Make a filled style form the color fn filled(&self) -> ShapeStyle where Self: Sized, { Into::::into(self).filled() } /// Make a shape style with stroke width from a color fn stroke_width(&self, width: u32) -> ShapeStyle where Self: Sized, { Into::::into(self).stroke_width(width) } } impl Color for &'_ T { fn to_backend_color(&self) -> BackendColor { ::to_backend_color(*self) } } /// The RGBA representation of the color, Plotters use RGBA as the internal representation /// of color /// /// If you want to directly create a RGB color with transparency use [RGBColor::mix] #[derive(Copy, Clone, PartialEq, Debug, Default)] pub struct RGBAColor(pub u8, pub u8, pub u8, pub f64); impl Color for RGBAColor { #[inline(always)] fn to_backend_color(&self) -> BackendColor { BackendColor { rgb: (self.0, self.1, self.2), alpha: self.3, } } } impl From for RGBAColor { fn from(rgb: RGBColor) -> Self { Self(rgb.0, rgb.1, rgb.2, 1.0) } } /// A color in the given palette #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] pub struct PaletteColor(usize, PhantomData

); impl PaletteColor

{ /// Pick a color from the palette pub fn pick(idx: usize) -> PaletteColor

{ PaletteColor(idx % P::COLORS.len(), PhantomData) } } impl Color for PaletteColor

{ #[inline(always)] fn to_backend_color(&self) -> BackendColor { BackendColor { rgb: P::COLORS[self.0], alpha: 1.0, } } } /// The color described by its RGB value #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Default)] pub struct RGBColor(pub u8, pub u8, pub u8); impl BackendStyle for RGBAColor { fn color(&self) -> BackendColor { self.to_backend_color() } } impl Color for RGBColor { #[inline(always)] fn to_backend_color(&self) -> BackendColor { BackendColor { rgb: (self.0, self.1, self.2), alpha: 1.0, } } } impl BackendStyle for RGBColor { fn color(&self) -> BackendColor { self.to_backend_color() } } /// The color described by HSL color space #[derive(Copy, Clone, PartialEq, Debug, Default)] pub struct HSLColor(pub f64, pub f64, pub f64); impl Color for HSLColor { #[inline(always)] #[allow(clippy::many_single_char_names)] fn to_backend_color(&self) -> BackendColor { let (h, s, l) = ( self.0.min(1.0).max(0.0), self.1.min(1.0).max(0.0), self.2.min(1.0).max(0.0), ); if s == 0.0 { let value = (l * 255.0).round() as u8; return BackendColor { rgb: (value, value, value), alpha: 1.0, }; } let q = if l < 0.5 { l * (1.0 + s) } else { l + s - l * s }; let p = 2.0 * l - q; let cvt = |mut t| { if t < 0.0 { t += 1.0; } if t > 1.0 { t -= 1.0; } let value = if t < 1.0 / 6.0 { p + (q - p) * 6.0 * t } else if t < 1.0 / 2.0 { q } else if t < 2.0 / 3.0 { p + (q - p) * (2.0 / 3.0 - t) * 6.0 } else { p }; (value * 255.0).round() as u8 }; BackendColor { rgb: (cvt(h + 1.0 / 3.0), cvt(h), cvt(h - 1.0 / 3.0)), alpha: 1.0, } } }