1use plotly_derive::FieldSetter;
2use serde::Serialize;
3
4use crate::color::Color;
5use crate::common::{Anchor, Font, Orientation, Title};
6use crate::layout::VAlign;
7
8#[derive(Serialize, Debug, Clone)]
9#[serde(rename_all = "lowercase")]
10pub enum TraceOrder {
11 Reversed,
12 Grouped,
13 #[serde(rename = "reversed+grouped")]
14 ReversedGrouped,
15 Normal,
16}
17
18#[derive(Serialize, Debug, Clone)]
19#[serde(rename_all = "lowercase")]
20pub enum ItemSizing {
21 Trace,
22 Constant,
23}
24
25#[derive(Debug, Clone)]
26pub enum ItemClick {
27 Toggle,
28 ToggleOthers,
29 False,
30}
31
32impl Serialize for ItemClick {
33 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
34 where
35 S: serde::Serializer,
36 {
37 match *self {
38 Self::Toggle => serializer.serialize_str("toggle"),
39 Self::ToggleOthers => serializer.serialize_str("toggleothers"),
40 Self::False => serializer.serialize_bool(false),
41 }
42 }
43}
44
45#[derive(Serialize, Debug, Clone)]
46#[serde(rename_all = "lowercase")]
47pub enum GroupClick {
48 ToggleItem,
49 ToggleGroup,
50}
51
52#[serde_with::skip_serializing_none]
53#[derive(Serialize, Debug, Clone, FieldSetter)]
54pub struct Legend {
55 #[serde(rename = "bgcolor")]
56 background_color: Option<Box<dyn Color>>,
57 #[serde(rename = "bordercolor")]
58 border_color: Option<Box<dyn Color>>,
59 #[serde(rename = "borderwidth")]
60 border_width: Option<usize>,
61 font: Option<Font>,
62 orientation: Option<Orientation>,
63 #[serde(rename = "traceorder")]
64 trace_order: Option<TraceOrder>,
65 #[serde(rename = "tracegroupgap")]
66 trace_group_gap: Option<usize>,
67 #[serde(rename = "itemsizing")]
68 item_sizing: Option<ItemSizing>,
69 #[serde(rename = "itemclick")]
70 item_click: Option<ItemClick>,
71 #[serde(rename = "itemdoubleclick")]
72 item_double_click: Option<ItemClick>,
73 x: Option<f64>,
74 #[serde(rename = "xanchor")]
75 x_anchor: Option<Anchor>,
76 y: Option<f64>,
77 #[serde(rename = "yanchor")]
78 y_anchor: Option<Anchor>,
79 valign: Option<VAlign>,
80 title: Option<Title>,
81 #[serde(rename = "groupclick")]
82 group_click: Option<GroupClick>,
83 #[serde(rename = "itemwidth")]
84 item_width: Option<usize>,
85}
86
87impl Legend {
88 pub fn new() -> Self {
89 Default::default()
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use serde_json::{json, to_value};
96
97 use super::*;
98
99 #[test]
100 #[rustfmt::skip]
101 fn serialize_trace_order() {
102 assert_eq!(to_value(TraceOrder::Reversed).unwrap(), json!("reversed"));
103 assert_eq!(to_value(TraceOrder::Grouped).unwrap(), json!("grouped"));
104 assert_eq!(to_value(TraceOrder::ReversedGrouped).unwrap(), json!("reversed+grouped"));
105 assert_eq!(to_value(TraceOrder::Normal).unwrap(), json!("normal"));
106 }
107
108 #[test]
109 fn serialize_item_sizing() {
110 assert_eq!(to_value(ItemSizing::Trace).unwrap(), json!("trace"));
111 assert_eq!(to_value(ItemSizing::Constant).unwrap(), json!("constant"));
112 }
113
114 #[test]
115 #[rustfmt::skip]
116 fn serialize_item_click() {
117 assert_eq!(to_value(ItemClick::Toggle).unwrap(), json!("toggle"));
118 assert_eq!(to_value(ItemClick::ToggleOthers).unwrap(), json!("toggleothers"));
119 assert_eq!(to_value(ItemClick::False).unwrap(), json!(false));
120 }
121
122 #[test]
123 #[rustfmt::skip]
124 fn serialize_group_click() {
125 assert_eq!(to_value(GroupClick::ToggleItem).unwrap(), json!("toggleitem"));
126 assert_eq!(to_value(GroupClick::ToggleGroup).unwrap(), json!("togglegroup"));
127 }
128
129 #[test]
130 fn serialize_legend() {
131 let legend = Legend::new()
132 .background_color("#123123")
133 .border_color("#321321")
134 .border_width(500)
135 .font(Font::new())
136 .orientation(Orientation::Vertical)
137 .trace_order(TraceOrder::Normal)
138 .trace_group_gap(10)
139 .item_sizing(ItemSizing::Trace)
140 .item_click(ItemClick::Toggle)
141 .item_double_click(ItemClick::False)
142 .x(1.0)
143 .x_anchor(Anchor::Auto)
144 .y(2.0)
145 .y_anchor(Anchor::Left)
146 .valign(VAlign::Middle)
147 .title("title")
148 .group_click(GroupClick::ToggleItem)
149 .item_width(50);
150
151 let expected = json!({
152 "bgcolor": "#123123",
153 "bordercolor": "#321321",
154 "borderwidth": 500,
155 "font": {},
156 "orientation": "v",
157 "traceorder": "normal",
158 "tracegroupgap": 10,
159 "itemsizing": "trace",
160 "itemclick": "toggle",
161 "itemdoubleclick": false,
162 "x": 1.0,
163 "xanchor": "auto",
164 "y": 2.0,
165 "yanchor": "left",
166 "valign": "middle",
167 "title": {"text": "title"},
168 "groupclick": "toggleitem",
169 "itemwidth": 50
170 });
171
172 assert_eq!(to_value(legend).unwrap(), expected)
173 }
174}