1use plotly::color::Rgba;
2
3#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17#[allow(missing_docs)]
18pub enum NamedColor {
19 AliceBlue = 0xF0F8FF,
20 AntiqueWhite = 0xFAEBD7,
21 Aqua,
22 Aquamarine = 0x7FFFD4,
23 Azure = 0xF0FFFF,
24 Beige = 0xF5F5DC,
25 Bisque = 0xFFE4C4,
26 Black = 0x000000,
27 BlanchedAlmond = 0xFFEBCD,
28 Blue = 0x0000FF,
29 BlueViolet = 0x8A2BE2,
30 Brown = 0xA52A2A,
31 BurlyWood = 0xDEB887,
32 CadetBlue = 0x5F9EA0,
33 Chartreuse = 0x7FFF00,
34 Chocolate = 0xD2691E,
35 Coral = 0xFF7F50,
36 CornflowerBlue = 0x6495ED,
37 CornSilk = 0xFFF8DC,
38 Crimson = 0xDC143C,
39 Cyan = 0x00FFFF,
40 DarkBlue = 0x00008B,
41 DarkCyan = 0x008B8B,
42 DarkGoldenrod = 0xB8860B,
43 DarkGray = 0xA9A9A9,
44 DarkGreen = 0x006400,
45 DarkGrey,
46 DarkKhaki = 0xBDB76B,
47 DarkMagenta = 0x8B008B,
48 DarkOliveGreen = 0x556B2F,
49 DarkOrange = 0xFF8C00,
50 DarkOrchid = 0x9932CC,
51 DarkRed = 0x8B0000,
52 DarkSalmon = 0xE9967A,
53 DarkSeaGreen = 0x8FBC8F,
54 DarkSlateBlue = 0x483D8B,
55 DarkSlateGray = 0x2F4F4F,
56 DarkSlateGrey,
57 DarkTurquoise = 0x00CED1,
58 DarkViolet = 0x9400D3,
59 DeepPink = 0xFF1493,
60 DeepSkyBlue = 0x00BFFF,
61 DimGray = 0x696969,
62 DimGrey,
63 DodgerBlue = 0x1E90FF,
64 FireBrick = 0xB22222,
65 FloralWhite = 0xFFFAF0,
66 ForestGreen = 0x228B22,
67 Fuchsia,
68 Gainsboro = 0xDCDCDC,
69 GhostWhite = 0xF8F8FF,
70 Gold = 0xFFD700,
71 Goldenrod = 0xDAA520,
72 Gray = 0x808080,
73 Green = 0x008000,
74 GreenYellow = 0xADFF2F,
75 Grey,
76 Honeydew = 0xF0FFF0,
77 HotPink = 0xFF69B4,
78 IndianRed = 0xCD5C5C,
79 Indigo = 0x4B0082,
80 Ivory = 0xFFFFF0,
81 Khaki = 0xF0E68C,
82 Lavender = 0xE6E6FA,
83 LavenderBlush = 0xFFF0F5,
84 LawnGreen = 0x7CFC00,
85 LemonChiffon = 0xFFFACD,
86 LightBlue = 0xADD8E6,
87 LightCoral = 0xF08080,
88 LightCyan = 0xE0FFFF,
89 LightGoldenrodYellow = 0xFAFAD2,
90 LightGray = 0xD3D3D3,
91 LightGreen = 0x90EE90,
92 LightGrey,
93 LightPink = 0xFFB6C1,
94 LightSalmon = 0xFFA07A,
95 LightSeaGreen = 0x20B2AA,
96 LightSkyBlue = 0x87CEFA,
97 LightSlateGray = 0x778899,
98 LightSlateGrey,
99 LightSteelBlue = 0xB0C4DE,
100 LightYellow = 0xFFFFE0,
101 Lime = 0x00FF00,
102 LimeGreen = 0x32CD32,
103 Linen = 0xFAF0E6,
104 Magenta = 0xFF00FF,
105 Maroon = 0x800000,
106 MediumAquamarine = 0x66CDAA,
107 MediumBlue = 0x0000CD,
108 MediumOrchid = 0xBA55D3,
109 MediumPurple = 0x9370DB,
110 MediumSeaGreen = 0x3CB371,
111 MediumSlateBlue = 0x7B68EE,
112 MediumSpringGreen = 0x00FA9A,
113 MediumTurquoise = 0x48D1CC,
114 MediumVioletRed = 0xC71585,
115 MidnightBlue = 0x191970,
116 MintCream = 0xF5FFFA,
117 MistyRose = 0xFFE4E1,
118 Moccasin = 0xFFE4B5,
119 NavajoWhite = 0xFFDEAD,
120 Navy = 0x000080,
121 OldLace = 0xFDF5E6,
122 Olive = 0x808000,
123 OliveDrab = 0x6B8E23,
124 Orange = 0xFFA500,
125 OrangeRed = 0xFF4500,
126 Orchid = 0xDA70D6,
127 PaleGoldenrod = 0xEEE8AA,
128 PaleGreen = 0x98FB98,
129 PaleTurquoise = 0xAFEEEE,
130 PaleVioletRed = 0xDB7093,
131 PapayaWhip = 0xFFEFD5,
132 PeachPuff = 0xFFDAB9,
133 Peru = 0xCD853F,
134 Pink = 0xFFC0CB,
135 Plum = 0xDDA0DD,
136 PowderBlue = 0xB0E0E6,
137 Purple = 0x800080,
138 RebeccaPurple = 0x663399,
139 Red = 0xFF0000,
140 RosyBrown = 0xBC8F8F,
141 RoyalBlue = 0x4169E1,
142 SaddleBrown = 0x8B4513,
143 Salmon = 0xFA8072,
144 SandyBrown = 0xF4A460,
145 SeaGreen = 0x2E8B57,
146 Seashell = 0xFFF5EE,
147 Sienna = 0xA0522D,
148 Silver = 0xC0C0C0,
149 SkyBlue = 0x87CEEB,
150 SlateBlue = 0x6A5ACD,
151 SlateGray = 0x708090,
152 SlateGrey,
153 Snow = 0xFFFAFA,
154 SpringGreen = 0x00FF7F,
155 SteelBlue = 0x4682B4,
156 Tan = 0xD2B48C,
157 Teal = 0x008080,
158 Thistle = 0xD8BFD8,
159 Tomato = 0xFF6347,
160 Turquoise = 0x40E0D0,
161 Violet = 0xEE82EE,
162 Wheat = 0xF5DEB3,
163 White = 0xFFFFFF,
164 WhiteSmoke = 0xF5F5F5,
165 Yellow = 0xFFFF00,
166 YellowGreen = 0x9ACD32,
167}
168
169#[derive(Debug, PartialEq)]
193pub struct Color {
194 r: u8,
196
197 g: u8,
199
200 b: u8,
202
203 a: f64,
208}
209
210impl Color {
211 pub fn rgb(r: u8, g: u8, b: u8) -> Color {
223 Color { r, g, b, a: 1.0 }
224 }
225
226 pub fn rgba(r: u8, g: u8, b: u8, a: f64) -> Color {
240 Color::rgb(r, g, b).alpha(a)
241 }
242
243 pub fn named(color: NamedColor) -> Color {
253 let color = match color {
255 NamedColor::Aqua => NamedColor::Cyan,
256 NamedColor::DarkGrey => NamedColor::DarkGray,
257 NamedColor::DarkSlateGrey => NamedColor::DarkSlateGray,
258 NamedColor::DimGrey => NamedColor::DimGray,
259 NamedColor::Fuchsia => NamedColor::Magenta,
260 NamedColor::Grey => NamedColor::Gray,
261 NamedColor::LightGrey => NamedColor::LightGray,
262 NamedColor::LightSlateGrey => NamedColor::LightSlateGray,
263 NamedColor::SlateGrey => NamedColor::SlateGray,
264 _ => color, };
266
267 let hex = color as u32;
269
270 let r = ((hex >> 16) & 0xFF) as u8;
272 let g = ((hex >> 8) & 0xFF) as u8;
273 let b = (hex & 0xFF) as u8;
274
275 Color::rgb(r, g, b)
277 }
278
279 pub fn hex_literal(color: u32) -> Color {
298 if color > 0xFFFFFF {
300 return Color::default();
301 }
302
303 let r = ((color >> 16) & 0xFF) as u8;
305 let g = ((color >> 8) & 0xFF) as u8;
306 let b = (color & 0xFF) as u8;
307
308 Color::rgb(r, g, b)
310 }
311
312 pub fn hex_str(color: &str) -> Color {
327 let color = color.trim_start_matches('#');
329
330 if color.len() != 6 {
332 return Color::default();
333 }
334
335 let hex_literal = u32::from_str_radix(color, 16).unwrap_or(0x000000);
337
338 Color::hex_literal(hex_literal)
340 }
341
342 pub fn alpha(mut self, a: f64) -> Color {
353 self.a = a.clamp(0.0, 1.0);
354 self
355 }
356
357 pub fn to_plotly_rgba(&self) -> Rgba {
363 Rgba::new(self.r, self.g, self.b, self.a)
364 }
365}
366
367impl Default for Color {
368 fn default() -> Self {
384 Color::rgb(0, 0, 0)
385 }
386}
387
388#[cfg(test)]
389mod tests {
390 use super::*;
391
392 #[test]
393 fn test_partial_eq() {
394 let color_1 = Color::rgb(20, 30, 40);
396 let color_2 = Color::rgb(20, 30, 40);
397 assert_eq!(color_1, color_2);
398
399 let color_1 = Color::rgb(20, 30, 40);
401 let color_2 = Color::rgb(25, 30, 40);
402 assert_ne!(color_1, color_2);
403
404 let color_1 = Color::rgb(20, 30, 40);
406 let color_2 = Color::rgb(20, 35, 40);
407 assert_ne!(color_1, color_2);
408
409 let color_1 = Color::rgb(20, 30, 40);
411 let color_2 = Color::rgb(20, 30, 45);
412 assert_ne!(color_1, color_2);
413
414 let color_1 = Color::rgb(20, 30, 40).alpha(0.1);
416 let color_2 = Color::rgb(20, 30, 40).alpha(0.2);
417 assert_ne!(color_1, color_2);
418 }
419
420 #[test]
421 fn test_rgb() {
422 let color = Color::rgb(20, 30, 40);
423 assert_eq!(color.r, 20);
424 assert_eq!(color.g, 30);
425 assert_eq!(color.b, 40);
426 assert_eq!(color.a, 1.0);
427 }
428
429 #[test]
430 fn test_rgba() {
431 let color = Color::rgba(20, 30, 40, 0.5);
433 assert_eq!(color.r, 20);
434 assert_eq!(color.g, 30);
435 assert_eq!(color.b, 40);
436 assert_eq!(color.a, 0.5);
437
438 let color = Color::rgba(20, 30, 40, -0.1);
440 assert_eq!(color.a, 0.0);
441
442 let color = Color::rgba(20, 30, 40, 1.1);
444 assert_eq!(color.a, 1.0);
445 }
446
447 #[test]
448 fn test_named() {
449 assert_eq!(Color::named(NamedColor::Black), Color::rgb(0, 0, 0));
451 assert_eq!(Color::named(NamedColor::White), Color::rgb(255, 255, 255));
452 assert_eq!(Color::named(NamedColor::Red), Color::rgb(255, 0, 0));
453 assert_eq!(Color::named(NamedColor::Lime), Color::rgb(0, 255, 0));
454 assert_eq!(Color::named(NamedColor::Blue), Color::rgb(0, 0, 255));
455 assert_eq!(Color::named(NamedColor::Yellow), Color::rgb(255, 255, 0));
456 assert_eq!(Color::named(NamedColor::Magenta), Color::rgb(255, 0, 255));
457 assert_eq!(Color::named(NamedColor::Cyan), Color::rgb(0, 255, 255));
458 assert_eq!(Color::named(NamedColor::Green), Color::rgb(0, 128, 0));
459
460 assert_eq!(
462 Color::named(NamedColor::Aqua),
463 Color::named(NamedColor::Cyan)
464 );
465 assert_eq!(
466 Color::named(NamedColor::DarkGrey),
467 Color::named(NamedColor::DarkGray)
468 );
469 assert_eq!(
470 Color::named(NamedColor::DarkSlateGrey),
471 Color::named(NamedColor::DarkSlateGray)
472 );
473 assert_eq!(
474 Color::named(NamedColor::DimGrey),
475 Color::named(NamedColor::DimGray)
476 );
477 assert_eq!(
478 Color::named(NamedColor::Fuchsia),
479 Color::named(NamedColor::Magenta)
480 );
481 assert_eq!(
482 Color::named(NamedColor::Grey),
483 Color::named(NamedColor::Gray)
484 );
485 assert_eq!(
486 Color::named(NamedColor::LightGrey),
487 Color::named(NamedColor::LightGray)
488 );
489 assert_eq!(
490 Color::named(NamedColor::LightSlateGrey),
491 Color::named(NamedColor::LightSlateGray)
492 );
493 assert_eq!(
494 Color::named(NamedColor::SlateGrey),
495 Color::named(NamedColor::SlateGray)
496 );
497 }
498
499 #[test]
500 fn test_hex_literal() {
501 assert_eq!(Color::hex_literal(0x000000), Color::rgb(0, 0, 0));
503 assert_eq!(Color::hex_literal(0xFFFFFF), Color::rgb(255, 255, 255));
504 assert_eq!(Color::hex_literal(0xFF0000), Color::rgb(255, 0, 0));
505 assert_eq!(Color::hex_literal(0x00FF00), Color::rgb(0, 255, 0));
506 assert_eq!(Color::hex_literal(0x0000FF), Color::rgb(0, 0, 255));
507 assert_eq!(Color::hex_literal(0xFFFF00), Color::rgb(255, 255, 0));
508 assert_eq!(Color::hex_literal(0xFF00FF), Color::rgb(255, 0, 255));
509 assert_eq!(Color::hex_literal(0x00FFFF), Color::rgb(0, 255, 255));
510 assert_eq!(Color::hex_literal(0x008000), Color::rgb(0, 128, 0));
511
512 assert_eq!(Color::hex_literal(0xFFFFFFFF), Color::default());
514 }
515
516 #[test]
517 fn test_hex_str() {
518 assert_eq!(Color::hex_str("#000000"), Color::rgb(0, 0, 0));
520 assert_eq!(Color::hex_str("#FFFFFF"), Color::rgb(255, 255, 255));
521 assert_eq!(Color::hex_str("#FF0000"), Color::rgb(255, 0, 0));
522 assert_eq!(Color::hex_str("#00FF00"), Color::rgb(0, 255, 0));
523 assert_eq!(Color::hex_str("#0000FF"), Color::rgb(0, 0, 255));
524 assert_eq!(Color::hex_str("#FFFF00"), Color::rgb(255, 255, 0));
525 assert_eq!(Color::hex_str("#FF00FF"), Color::rgb(255, 0, 255));
526 assert_eq!(Color::hex_str("#00FFFF"), Color::rgb(0, 255, 255));
527 assert_eq!(Color::hex_str("#008000"), Color::rgb(0, 128, 0));
528
529 assert_eq!(Color::hex_str("000000"), Color::rgb(0, 0, 0));
531 assert_eq!(Color::hex_str("FFFFFF"), Color::rgb(255, 255, 255));
532 assert_eq!(Color::hex_str("FF0000"), Color::rgb(255, 0, 0));
533 assert_eq!(Color::hex_str("00FF00"), Color::rgb(0, 255, 0));
534 assert_eq!(Color::hex_str("0000FF"), Color::rgb(0, 0, 255));
535 assert_eq!(Color::hex_str("FFFF00"), Color::rgb(255, 255, 0));
536 assert_eq!(Color::hex_str("FF00FF"), Color::rgb(255, 0, 255));
537 assert_eq!(Color::hex_str("00FFFF"), Color::rgb(0, 255, 255));
538 assert_eq!(Color::hex_str("008000"), Color::rgb(0, 128, 0));
539
540 assert_eq!(Color::hex_str("#FFFFFFFF"), Color::default());
542 }
543
544 #[test]
545 fn test_alpha() {
546 assert_eq!(
548 Color::rgb(20, 30, 40).alpha(0.5),
549 Color::rgba(20, 30, 40, 0.5)
550 );
551
552 assert_eq!(
554 Color::rgb(20, 30, 40).alpha(-0.1),
555 Color::rgba(20, 30, 40, 0.0)
556 );
557
558 assert_eq!(
560 Color::rgb(20, 30, 40).alpha(1.1),
561 Color::rgba(20, 30, 40, 1.0)
562 );
563 }
564
565 #[test]
566 fn test_to_plotly_rgba() {
567 assert_eq!(
568 Color::rgba(20, 30, 40, 0.5).to_plotly_rgba(),
569 Rgba::new(20, 30, 40, 0.5)
570 );
571 }
572
573 #[test]
574 fn test_default() {
575 assert_eq!(Color::default(), Color::rgba(0, 0, 0, 1.0));
576 }
577}