chart_js_rs/objects/
chart_objects.rs

1use {
2    crate::{objects::helper_objects::*, traits::*},
3    serde::{de, Deserialize, Serialize},
4    serde_json::Value,
5    std::{collections::HashMap, fmt::Debug},
6};
7
8#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
9pub struct SinglePointDataset {
10    #[serde(skip_serializing_if = "Vec::is_empty", default)]
11    pub(crate) backgroundColor: Vec<String>,
12    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
13    pub(crate) barPercentage: NumberString,
14    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
15    pub(crate) barThickness: NumberString,
16    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
17    pub(crate) base: NumberString,
18    #[serde(skip_serializing_if = "String::is_empty", default)]
19    pub(crate) borderColor: String,
20    #[serde(skip_serializing_if = "String::is_empty", default)]
21    pub(crate) borderJoinStyle: String,
22    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
23    pub(crate) borderRadius: NumberString,
24    #[serde(skip_serializing_if = "String::is_empty", default)]
25    pub(crate) borderSkipped: String,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
28    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
29    pub(crate) categoryPercentage: NumberString,
30    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
31    pub(crate) clip: NumberString,
32    #[serde(skip_serializing_if = "Vec::is_empty", default)]
33    pub(crate) data: Vec<NumberString>,
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub(crate) datalabels: Option<DataLabels>,
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub(crate) grouped: Option<bool>,
38    #[serde(skip_serializing_if = "String::is_empty", default)]
39    pub(crate) hoverBackgroundColor: String,
40    #[serde(skip_serializing_if = "String::is_empty", default)]
41    pub(crate) hoverBorderColor: String,
42    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
43    pub(crate) hoverBorderRadius: NumberString,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub(crate) hoverBorderWidth: Option<NumberStringOrT<Border>>,
46    #[serde(skip_serializing_if = "String::is_empty", default)]
47    pub(crate) indexAxis: String,
48    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
49    pub(crate) inflateAmount: NumberString,
50    #[serde(skip_serializing_if = "String::is_empty", default)]
51    pub(crate) label: String,
52    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
53    pub(crate) maxBarThickness: NumberString,
54    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
55    pub(crate) minBarLength: NumberString,
56    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
57    pub(crate) order: NumberString,
58    #[serde(skip_serializing_if = "String::is_empty", default)]
59    pub(crate) pointBackgroundColor: String,
60    #[serde(skip_serializing_if = "String::is_empty", default)]
61    pub(crate) pointBorderColor: String,
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub(crate) pointBorderWidth: Option<NumberStringOrT<Border>>,
64    #[serde(skip_serializing_if = "String::is_empty", default)]
65    pub(crate) pointHoverBackgroundColor: String,
66    #[serde(skip_serializing_if = "Option::is_none")]
67    pub(crate) pointHoverBorderWidth: Option<NumberStringOrT<Border>>,
68    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
69    pub(crate) pointHoverRadius: NumberOrDateString,
70    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
71    pub(crate) pointRadius: NumberString,
72    #[serde(skip_serializing_if = "String::is_empty", default)]
73    pub(crate) pointStyle: String,
74    #[serde(rename = "type")]
75    #[serde(skip_serializing_if = "String::is_empty", default)]
76    pub(crate) r#type: String,
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub(crate) skipNull: Option<bool>,
79    #[serde(skip_serializing_if = "String::is_empty", default)]
80    pub(crate) stack: String,
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub(crate) stepped: Option<bool>,
83    #[serde(skip_serializing_if = "String::is_empty", default)]
84    pub(crate) xAxisID: String,
85    #[serde(skip_serializing_if = "String::is_empty", default)]
86    pub(crate) yAxisID: String,
87}
88
89#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
90pub struct XYDataset {
91    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
92    pub(crate) backgroundColor: FnWithArgsOrT<1, String>,
93    #[serde(
94        skip_serializing_if = "Vec::is_empty",
95        default,
96        rename(serialize = "backgroundColor")
97    )]
98    pub(crate) backgroundColorArray: Vec<String>,
99    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
100    pub(crate) barPercentage: NumberString,
101    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
102    pub(crate) barThickness: NumberString,
103    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
104    pub(crate) base: NumberString,
105    #[serde(skip_serializing_if = "String::is_empty", default)]
106    pub(crate) borderColor: String,
107    #[serde(skip_serializing_if = "Vec::is_empty", default)]
108    pub(crate) borderDash: Vec<NumberString>,
109    #[serde(skip_serializing_if = "String::is_empty", default)]
110    pub(crate) borderJoinStyle: String,
111    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
112    pub(crate) borderRadius: NumberString,
113    #[serde(skip_serializing_if = "String::is_empty", default)]
114    pub(crate) borderSkipped: String,
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
117    #[serde(skip_serializing_if = "String::is_empty", default)]
118    pub(crate) category_label: String,
119    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
120    pub(crate) categoryPercentage: NumberString,
121    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
122    pub(crate) clip: NumberString,
123    #[serde(skip_serializing_if = "DatasetData::is_empty", default)]
124    pub(crate) data: DatasetData,
125    /// Use Default::default() if this isn't required
126    pub(crate) datalabels: DataLabels,
127    #[serde(skip_serializing_if = "String::is_empty", default)]
128    pub(crate) description: String,
129    #[serde(skip_serializing_if = "String::is_empty", default)]
130    pub(crate) fill: String,
131    #[serde(skip_serializing_if = "Option::is_none")]
132    pub(crate) grouped: Option<bool>,
133    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
134    pub(crate) hitRadius: NumberString,
135    #[serde(skip_serializing_if = "String::is_empty", default)]
136    pub(crate) hoverBackgroundColor: String,
137    #[serde(skip_serializing_if = "String::is_empty", default)]
138    pub(crate) hoverBorderColor: String,
139    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
140    pub(crate) hoverBorderRadius: NumberString,
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub(crate) hoverBorderWidth: Option<NumberStringOrT<Border>>,
143    #[serde(skip_serializing_if = "String::is_empty", default)]
144    pub(crate) axis: String,
145    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
146    pub(crate) inflateAmount: NumberString,
147    #[serde(skip_serializing_if = "String::is_empty", default)]
148    pub(crate) label: String,
149    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
150    pub(crate) maxBarThickness: NumberString,
151    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
152    pub(crate) minBarLength: NumberString,
153    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
154    pub(crate) order: NumberString,
155    #[serde(skip_serializing_if = "String::is_empty", default)]
156    pub(crate) pointBackgroundColor: String,
157    #[serde(skip_serializing_if = "String::is_empty", default)]
158    pub(crate) pointBorderColor: String,
159    #[serde(skip_serializing_if = "Option::is_none")]
160    pub(crate) pointBorderWidth: Option<NumberStringOrT<Border>>,
161    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
162    pub(crate) pointHitRadius: NumberString,
163    #[serde(skip_serializing_if = "String::is_empty", default)]
164    pub(crate) pointHoverBackgroundColor: String,
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub(crate) pointHoverBorderWidth: Option<NumberStringOrT<Border>>,
167    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
168    pub(crate) pointHoverRadius: NumberOrDateString,
169    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
170    pub(crate) pointRadius: NumberString,
171    #[serde(skip_serializing_if = "String::is_empty", default)]
172    pub(crate) pointStyle: String,
173    #[serde(skip_serializing_if = "Option::is_none")]
174    pub(crate) segment: Option<Segment>,
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub(crate) skipNull: Option<bool>,
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub(crate) spanGaps: Option<bool>,
179    #[serde(skip_serializing_if = "String::is_empty", default)]
180    pub(crate) stack: String,
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub(crate) stepped: Option<BoolString>,
183    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
184    pub(crate) tension: NumberString,
185    #[serde(rename = "type")]
186    #[serde(skip_serializing_if = "String::is_empty", default)]
187    pub(crate) r#type: String,
188    #[serde(skip_serializing_if = "String::is_empty", default)]
189    pub(crate) xAxisID: String,
190    #[serde(skip_serializing_if = "String::is_empty", default)]
191    pub(crate) yAxisID: String,
192    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
193    pub(crate) z: NumberString,
194}
195#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
196pub struct FloatingDataset {
197    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
198    pub(crate) backgroundColor: FnWithArgsOrT<2, String>,
199    #[serde(
200        skip_serializing_if = "Vec::is_empty",
201        default,
202        rename(serialize = "backgroundColor")
203    )]
204    pub(crate) backgroundColorArray: Vec<String>,
205    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
206    pub(crate) barPercentage: NumberString,
207    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
208    pub(crate) barThickness: NumberString,
209    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
210    pub(crate) base: NumberString,
211    #[serde(skip_serializing_if = "String::is_empty", default)]
212    pub(crate) borderColor: String,
213    #[serde(skip_serializing_if = "Vec::is_empty", default)]
214    pub(crate) borderDash: Vec<NumberString>,
215    #[serde(skip_serializing_if = "String::is_empty", default)]
216    pub(crate) borderJoinStyle: String,
217    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
218    pub(crate) borderRadius: NumberString,
219    #[serde(skip_serializing_if = "String::is_empty", default)]
220    pub(crate) borderSkipped: String,
221    #[serde(skip_serializing_if = "Option::is_none")]
222    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
223    #[serde(skip_serializing_if = "String::is_empty", default)]
224    pub(crate) category_label: String,
225    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
226    pub(crate) categoryPercentage: NumberString,
227    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
228    pub(crate) clip: NumberString,
229    #[serde(skip_serializing_if = "DatasetData::is_empty", default)]
230    pub(crate) data: DatasetData,
231    /// Use Default::default() if this isn't required
232    pub(crate) datalabels: DataLabels,
233    #[serde(skip_serializing_if = "String::is_empty", default)]
234    pub(crate) description: String,
235    #[serde(skip_serializing_if = "String::is_empty", default)]
236    pub(crate) fill: String,
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub(crate) grouped: Option<bool>,
239    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
240    pub(crate) hitRadius: NumberString,
241    #[serde(skip_serializing_if = "String::is_empty", default)]
242    pub(crate) hoverBackgroundColor: String,
243    #[serde(skip_serializing_if = "String::is_empty", default)]
244    pub(crate) hoverBorderColor: String,
245    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
246    pub(crate) hoverBorderRadius: NumberString,
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub(crate) hoverBorderWidth: Option<NumberStringOrT<Border>>,
249    #[serde(skip_serializing_if = "String::is_empty", default)]
250    pub(crate) axis: String,
251    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
252    pub(crate) inflateAmount: NumberString,
253    #[serde(skip_serializing_if = "String::is_empty", default)]
254    pub(crate) label: String,
255    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
256    pub(crate) maxBarThickness: NumberString,
257    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
258    pub(crate) minBarLength: NumberString,
259    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
260    pub(crate) order: NumberString,
261    #[serde(skip_serializing_if = "String::is_empty", default)]
262    pub(crate) pointBackgroundColor: String,
263    #[serde(skip_serializing_if = "String::is_empty", default)]
264    pub(crate) pointBorderColor: String,
265    #[serde(skip_serializing_if = "Option::is_none")]
266    pub(crate) pointBorderWidth: Option<NumberStringOrT<Border>>,
267    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
268    pub(crate) pointHitRadius: NumberString,
269    #[serde(skip_serializing_if = "String::is_empty", default)]
270    pub(crate) pointHoverBackgroundColor: String,
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub(crate) pointHoverBorderWidth: Option<NumberStringOrT<Border>>,
273    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
274    pub(crate) pointHoverRadius: NumberOrDateString,
275    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
276    pub(crate) pointRadius: NumberString,
277    #[serde(skip_serializing_if = "String::is_empty", default)]
278    pub(crate) pointStyle: String,
279    #[serde(skip_serializing_if = "Option::is_none")]
280    pub(crate) segment: Option<Segment>,
281    #[serde(skip_serializing_if = "Option::is_none")]
282    pub(crate) skipNull: Option<bool>,
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub(crate) spanGaps: Option<bool>,
285    #[serde(skip_serializing_if = "String::is_empty", default)]
286    pub(crate) stack: String,
287    #[serde(skip_serializing_if = "Option::is_none")]
288    pub(crate) stepped: Option<BoolString>,
289    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
290    pub(crate) tension: NumberString,
291    #[serde(rename = "type")]
292    #[serde(skip_serializing_if = "String::is_empty", default)]
293    pub(crate) r#type: String,
294    #[serde(skip_serializing_if = "String::is_empty", default)]
295    pub(crate) xAxisID: String,
296    #[serde(skip_serializing_if = "String::is_empty", default)]
297    pub(crate) yAxisID: String,
298    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
299    pub(crate) z: NumberString,
300}
301#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
302pub struct XYPoint {
303    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
304    pub(crate) x: NumberOrDateString,
305
306    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
307    pub(crate) y: NumberString,
308
309    #[serde(skip_serializing_if = "serde_json::Value::is_null", default)]
310    pub(crate) description: serde_json::Value,
311}
312
313#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
314pub struct ChartOptions {
315    #[serde(skip_serializing_if = "Option::is_none")]
316    pub(crate) animation: Option<Animation>,
317    #[serde(skip_serializing_if = "Option::is_none")]
318    pub(crate) elements: Option<ChartElements>,
319    #[serde(skip_serializing_if = "Option::is_none")]
320    pub(crate) interaction: Option<ChartInteraction>,
321    #[serde(skip_serializing_if = "String::is_empty", default)]
322    pub(crate) indexAxis: String,
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub(crate) legend: Option<ChartLegend>,
325    #[serde(skip_serializing_if = "Option::is_none")]
326    pub(crate) layout: Option<ChartLayout>,
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub(crate) maintainAspectRatio: Option<bool>,
329    #[serde(skip_serializing_if = "Option::is_none")]
330    pub(crate) plugins: Option<ChartPlugins>,
331    #[serde(skip_serializing_if = "Option::is_none")]
332    pub(crate) responsive: Option<bool>,
333    #[serde(skip_serializing_if = "Option::is_none")]
334    pub(crate) scales: Option<HashMap<String, ChartScale>>,
335    #[serde(skip_serializing_if = "Option::is_none")]
336    pub(crate) spanGaps: Option<bool>,
337}
338
339#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
340pub struct Animation {
341    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
342    pub(crate) duration: NumberString,
343}
344
345#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
346pub struct ChartPlugins {
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub(crate) annotation: Option<Annotations>,
349    #[serde(skip_serializing_if = "Option::is_none")]
350    pub(crate) autocolors: Option<AutoColors>,
351    #[serde(skip_serializing_if = "Option::is_none")]
352    pub(crate) canvasBackgroundColor: Option<CanvasBackgroundColor>,
353    #[serde(skip_serializing_if = "Option::is_none")]
354    pub(crate) legend: Option<PluginLegend>,
355    #[serde(skip_serializing_if = "Option::is_none")]
356    pub(crate) title: Option<Title>,
357    #[serde(skip_serializing_if = "Option::is_none")]
358    pub(crate) tooltip: Option<TooltipPlugin>,
359}
360
361#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
362pub struct CanvasBackgroundColor {
363    #[serde(skip_serializing_if = "String::is_empty", default)]
364    pub(crate) color: String,
365}
366
367#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
368pub struct PluginLegend {
369    #[serde(skip_serializing_if = "Option::is_none")]
370    pub(crate) display: Option<bool>,
371    #[serde(skip_serializing_if = "Option::is_none")]
372    pub(crate) labels: Option<LegendLabel>,
373    #[serde(skip_serializing_if = "String::is_empty", default)]
374    pub(crate) position: String,
375    #[serde(skip_serializing_if = "Option::is_none")]
376    pub(crate) reverse: Option<bool>,
377}
378
379#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
380pub struct Annotations {
381    #[serde(skip_serializing_if = "Option::is_none")]
382    pub(crate) annotations: Option<HashMap<String, Annotation>>,
383}
384
385#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
386pub struct AutoColors {
387    #[serde(skip_serializing_if = "String::is_empty", default)]
388    pub(crate) mode: String,
389}
390
391#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
392pub struct TooltipPlugin {
393    #[serde(skip_serializing_if = "String::is_empty", default)]
394    pub(crate) backgroundColor: String,
395    #[serde(skip_serializing_if = "String::is_empty", default)]
396    pub(crate) bodyAlign: String,
397    #[serde(skip_serializing_if = "String::is_empty", default)]
398    pub(crate) bodyColor: String,
399    #[serde(skip_serializing_if = "Option::is_none")]
400    pub(crate) callbacks: Option<TooltipCallbacks>,
401    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
402    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
403    pub(crate) filter: FnWithArgs<1>,
404    #[serde(skip_serializing_if = "Option::is_none")]
405    pub(crate) displayColors: Option<bool>,
406    #[serde(skip_serializing_if = "Option::is_none")]
407    pub(crate) enabled: Option<bool>,
408    #[serde(skip_serializing_if = "String::is_empty", default)]
409    pub(crate) titleAlign: String,
410    #[serde(skip_serializing_if = "String::is_empty", default)]
411    pub(crate) titleColor: String,
412    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
413    pub(crate) titleMarginBottom: NumberString,
414}
415
416#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
417pub struct ChartLayout {
418    #[serde(skip_serializing_if = "Option::is_none")]
419    pub(crate) padding: Option<Padding>,
420}
421
422#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
423pub struct TooltipCallbacks {
424    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
425    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
426    pub(crate) label: FnWithArgs<1>,
427    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
428    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
429    pub(crate) title: FnWithArgs<1>,
430}
431
432#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
433pub struct ChartScale {
434    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
435    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
436    pub(crate) afterBuildTicks: FnWithArgs<1>,
437    #[serde(skip_serializing_if = "Option::is_none")]
438    pub(crate) alignToPixels: Option<bool>,
439    #[serde(skip_serializing_if = "String::is_empty", default)]
440    pub(crate) backgroundColor: String,
441    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
442    pub(crate) barPercentage: NumberString,
443    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
444    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
445    pub(crate) beforeFit: FnWithArgs<1>,
446    #[serde(skip_serializing_if = "Option::is_none")]
447    pub(crate) beginAtZero: Option<bool>,
448    #[serde(skip_serializing_if = "Option::is_none")]
449    pub(crate) border: Option<ScaleBorder>,
450    #[serde(skip_serializing_if = "String::is_empty", default)]
451    pub(crate) bounds: String,
452    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
453    pub(crate) categoryPercentage: NumberString,
454    #[serde(skip_serializing_if = "Option::is_none")]
455    pub(crate) display: Option<bool>,
456    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
457    pub(crate) grace: NumberOrDateString,
458    #[serde(skip_serializing_if = "Option::is_none")]
459    pub(crate) grid: Option<Grid>,
460    #[serde(skip_serializing_if = "Option::is_none")]
461    pub(crate) grouped: Option<bool>,
462    #[serde(skip_serializing_if = "Option::is_none")]
463    pub(crate) labels: Option<Vec<NumberOrDateString>>,
464    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
465    pub(crate) max: NumberOrDateString,
466    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
467    pub(crate) min: NumberOrDateString,
468    #[serde(skip_serializing_if = "Option::is_none")]
469    pub(crate) offset: Option<bool>,
470    #[serde(skip_serializing_if = "String::is_empty", default)]
471    pub(crate) position: String,
472    #[serde(skip_serializing_if = "Option::is_none")]
473    pub(crate) reverse: Option<bool>,
474    #[serde(skip_serializing_if = "Option::is_none")]
475    pub(crate) stacked: Option<bool>,
476    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
477    pub(crate) suggestedMax: NumberOrDateString,
478    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
479    pub(crate) suggestedMin: NumberOrDateString,
480    #[serde(skip_serializing_if = "Option::is_none")]
481    pub(crate) ticks: Option<ScaleTicks>,
482    #[serde(skip_serializing_if = "Option::is_none")]
483    pub(crate) time: Option<ScaleTime>,
484    #[serde(skip_serializing_if = "Option::is_none")]
485    pub(crate) title: Option<Title>,
486    #[serde(skip_serializing_if = "String::is_empty", default)]
487    #[serde(rename = "type")]
488    pub(crate) r#type: String,
489    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
490    pub(crate) weight: NumberString,
491}
492
493#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
494pub struct ScaleBorder {
495    #[serde(skip_serializing_if = "String::is_empty", default)]
496    pub(crate) color: String,
497    #[serde(skip_serializing_if = "Vec::is_empty", default)]
498    pub(crate) dash: Vec<NumberString>,
499    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
500    pub(crate) dashOffset: NumberString,
501    #[serde(skip_serializing_if = "Option::is_none")]
502    pub(crate) display: Option<bool>,
503    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
504    pub(crate) width: NumberString,
505    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
506    pub(crate) z: NumberString,
507}
508
509#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
510pub struct Grid {
511    #[serde(skip_serializing_if = "String::is_empty", default)]
512    pub(crate) color: String,
513    #[serde(skip_serializing_if = "Option::is_none")]
514    pub(crate) display: Option<bool>,
515    #[serde(skip_serializing_if = "Option::is_none")]
516    pub(crate) drawOnChartArea: Option<bool>,
517    #[serde(skip_serializing_if = "Option::is_none")]
518    pub(crate) offset: Option<bool>,
519    #[serde(skip_serializing_if = "String::is_empty", default, skip_deserializing)]
520    // the skip_deserializing needed because chartjs sets a default with a different type, FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
521    pub(crate) tickColor: String,
522    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
523    pub(crate) z: NumberString,
524}
525
526#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
527pub struct Callout {
528    #[serde(skip_serializing_if = "String::is_empty", default)]
529    pub(crate) backgroundColor: String,
530    #[serde(skip_serializing_if = "String::is_empty", default)]
531    pub(crate) borderColor: String,
532    #[serde(skip_serializing_if = "Vec::is_empty", default)]
533    pub(crate) borderDash: Vec<NumberString>,
534    #[serde(skip_serializing_if = "Option::is_none")]
535    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
536    #[serde(skip_serializing_if = "Option::is_none")]
537    pub(crate) display: Option<bool>,
538    #[serde(skip_serializing_if = "String::is_empty", default)]
539    pub(crate) position: String,
540    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
541    pub(crate) start: NumberString,
542}
543
544#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
545pub struct LabelAnnotation {
546    #[serde(skip_serializing_if = "String::is_empty", default)]
547    pub(crate) backgroundColor: String,
548    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
549    pub(crate) borderRadius: NumberString,
550    #[serde(skip_serializing_if = "String::is_empty", default)]
551    pub(crate) borderColor: String,
552    #[serde(skip_serializing_if = "Vec::is_empty", default)]
553    pub(crate) borderDash: Vec<NumberString>,
554    #[serde(skip_serializing_if = "Option::is_none")]
555    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
556    #[serde(skip_serializing_if = "Option::is_none")]
557    pub(crate) callout: Option<Callout>,
558    #[serde(skip_serializing_if = "String::is_empty", default)]
559    pub(crate) color: String,
560    #[serde(skip_serializing_if = "Vec::is_empty", default)]
561    pub(crate) content: Vec<String>,
562    #[serde(skip_serializing_if = "String::is_empty", default)]
563    pub(crate) drawTime: String,
564    #[serde(skip_serializing_if = "Option::is_none")]
565    pub(crate) display: Option<bool>,
566    #[serde(skip_serializing_if = "Option::is_none")]
567    pub(crate) font: Option<Font>,
568    #[serde(skip_serializing_if = "Option::is_none", skip_deserializing)]
569    // the skip_deserializing needed because chartjs sets a default with a different type
570    pub(crate) padding: Option<Padding>,
571    #[serde(skip_serializing_if = "String::is_empty", default)]
572    pub(crate) position: String,
573    #[serde(default, rename = "type")]
574    pub(crate) r#type: LabelAnnotationType,
575    #[serde(skip_serializing_if = "String::is_empty", default)]
576    pub(crate) textAlign: String,
577    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
578    pub(crate) xValue: NumberOrDateString,
579    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
580    pub(crate) xAdjust: NumberOrDateString,
581    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
582    pub(crate) yValue: NumberOrDateString,
583    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
584    pub(crate) yAdjust: NumberOrDateString,
585    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
586    pub(crate) xMax: NumberOrDateString,
587    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
588    pub(crate) xMin: NumberOrDateString,
589    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
590    pub(crate) yMax: NumberOrDateString,
591    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
592    pub(crate) yMin: NumberOrDateString,
593    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
594    pub(crate) yScaleID: NumberString,
595}
596#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
597pub struct LabelAnnotationType;
598
599#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
600pub struct LineAnnotation {
601    #[serde(skip_serializing_if = "String::is_empty", default)]
602    pub(crate) borderColor: String,
603    #[serde(skip_serializing_if = "Vec::is_empty", default)]
604    pub(crate) borderDash: Vec<NumberString>,
605    #[serde(skip_serializing_if = "Option::is_none")]
606    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
607    #[serde(skip_serializing_if = "String::is_empty", default)]
608    pub(crate) drawTime: String,
609    #[serde(skip_serializing_if = "Option::is_none")]
610    pub(crate) label: Option<LabelAnnotation>,
611    #[serde(default, rename = "type")]
612    pub(crate) r#type: LineAnnotationType,
613    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
614    pub(crate) xMax: NumberOrDateString,
615    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
616    pub(crate) xMin: NumberOrDateString,
617    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
618    pub(crate) yMax: NumberOrDateString,
619    #[serde(skip_serializing_if = "NumberOrDateString::is_empty", default)]
620    pub(crate) yMin: NumberOrDateString,
621    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
622    pub(crate) yScaleID: NumberString,
623}
624#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
625pub struct LineAnnotationType;
626
627#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
628pub struct BoxAnnotation {
629    #[serde(skip_serializing_if = "String::is_empty", default)]
630    pub(crate) backgroundColor: String,
631    #[serde(skip_serializing_if = "String::is_empty", default)]
632    pub(crate) borderColor: String,
633    #[serde(skip_serializing_if = "Vec::is_empty", default)]
634    pub(crate) borderDash: Vec<NumberString>,
635    #[serde(skip_serializing_if = "Option::is_none")]
636    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
637    #[serde(skip_serializing_if = "String::is_empty", default)]
638    pub(crate) drawTime: String,
639    #[serde(default, rename = "type")]
640    pub(crate) r#type: BoxAnnotationType,
641    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
642    pub(crate) xMax: NumberString,
643    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
644    pub(crate) xMin: NumberString,
645    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
646    pub(crate) yMax: NumberString,
647    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
648    pub(crate) yMin: NumberString,
649}
650#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
651pub struct BoxAnnotationType;
652
653#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
654pub struct ScaleTime {
655    #[serde(skip_serializing_if = "Option::is_none")]
656    pub(crate) displayFormats: Option<DisplayFormats>,
657    #[serde(skip_serializing_if = "String::is_empty", default)]
658    pub(crate) unit: String,
659}
660
661#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
662pub struct DisplayFormats {
663    #[serde(skip_serializing_if = "String::is_empty", default)]
664    pub(crate) day: String,
665    #[serde(skip_serializing_if = "String::is_empty", default)]
666    pub(crate) hour: String,
667    #[serde(skip_serializing_if = "String::is_empty", default)]
668    pub(crate) minute: String,
669    #[serde(skip_serializing_if = "String::is_empty", default)]
670    pub(crate) month: String,
671    #[serde(skip_serializing_if = "String::is_empty", default)]
672    pub(crate) quarter: String,
673    #[serde(skip_serializing_if = "String::is_empty", default)]
674    pub(crate) week: String,
675    #[serde(skip_serializing_if = "String::is_empty", default)]
676    pub(crate) year: String,
677}
678
679#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
680pub struct ScaleTicks {
681    #[serde(skip_serializing_if = "Option::is_none")]
682    pub(crate) autoSkip: Option<bool>,
683    #[serde(skip_serializing_if = "String::is_empty", default)]
684    pub(crate) align: String,
685    #[serde(
686        skip_serializing_if = "FnWithArgs::is_empty",
687        default,
688        skip_deserializing // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
689    )]
690    pub(crate) callback: FnWithArgs<3>,
691    #[serde(skip_serializing_if = "String::is_empty", default)]
692    pub(crate) color: String,
693    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
694    pub(crate) count: NumberString,
695    #[serde(skip_serializing_if = "Option::is_none")]
696    pub(crate) font: Option<Font>,
697    #[serde(skip_serializing_if = "Option::is_none")]
698    pub(crate) includeBounds: Option<bool>,
699    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
700    pub(crate) maxTicksLimit: NumberString,
701    #[serde(skip_serializing_if = "Option::is_none", skip_deserializing)]
702    // the skip_deserializing needed because chartjs sets a default with a different type
703    pub(crate) padding: Option<Padding>,
704    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
705    pub(crate) precision: NumberString,
706    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
707    pub(crate) stepSize: NumberString,
708}
709
710#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
711pub struct Title {
712    #[serde(skip_serializing_if = "String::is_empty", default)]
713    pub(crate) color: String,
714    #[serde(skip_serializing_if = "Option::is_none")]
715    pub(crate) display: Option<bool>,
716    #[serde(skip_serializing_if = "Option::is_none")]
717    pub(crate) font: Option<Font>,
718    #[serde(skip_serializing_if = "String::is_empty", default)]
719    pub(crate) text: String,
720}
721
722#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
723pub struct ChartInteraction {
724    #[serde(skip_serializing_if = "String::is_empty", default)]
725    pub(crate) axis: String,
726    #[serde(skip_serializing_if = "Option::is_none")]
727    pub(crate) intersect: Option<bool>,
728    #[serde(skip_serializing_if = "String::is_empty", default)]
729    pub(crate) mode: String,
730}
731
732#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
733pub struct ChartLegend {
734    #[serde(skip_serializing_if = "Option::is_none")]
735    pub(crate) display: Option<bool>,
736    #[serde(skip_serializing_if = "Option::is_none")]
737    pub(crate) labels: Option<LegendLabel>,
738    #[serde(skip_serializing_if = "String::is_empty", default)]
739    pub(crate) position: String,
740}
741
742#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
743pub struct LegendLabel {
744    #[serde(skip_serializing_if = "Option::is_none")]
745    pub(crate) boxHeight: Option<u32>,
746    #[serde(skip_serializing_if = "Option::is_none")]
747    pub(crate) boxWidth: Option<u32>,
748    #[serde(skip_serializing_if = "String::is_empty", default)]
749    pub(crate) color: String,
750    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
751    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
752    pub(crate) filter: FnWithArgs<2>,
753    #[serde(skip_serializing_if = "Option::is_none")]
754    pub(crate) font: Option<Font>,
755    #[serde(skip_serializing_if = "FnWithArgs::is_empty", default)]
756    pub(crate) generateLabels: FnWithArgs<1>,
757    #[serde(skip_serializing_if = "String::is_empty", default)]
758    pub(crate) pointStyle: String,
759    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
760    pub(crate) pointStyleWidth: NumberString,
761    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
762    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
763    pub(crate) sort: FnWithArgs<3>,
764    #[serde(skip_serializing_if = "Option::is_none")]
765    pub(crate) useBorderRadius: Option<bool>,
766    #[serde(skip_serializing_if = "Option::is_none")]
767    pub(crate) usePointStyle: Option<bool>,
768}
769
770#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
771pub struct ChartElements {
772    #[serde(skip_serializing_if = "Option::is_none")]
773    pub(crate) bar: Option<BarElementConfiguration>,
774    #[serde(skip_serializing_if = "Option::is_none")]
775    pub(crate) line: Option<LineElementConfiguration>,
776    #[serde(skip_serializing_if = "Option::is_none")]
777    pub(crate) point: Option<PointElementConfiguration>,
778}
779
780#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
781pub struct BarElementConfiguration {
782    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
783    pub(crate) borderRadius: NumberString,
784    #[serde(skip_serializing_if = "Option::is_none")]
785    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
786    #[serde(skip_serializing_if = "Option::is_none")]
787    pub(crate) fill: Option<bool>,
788    #[serde(skip_serializing_if = "Option::is_none")]
789    pub(crate) hoverBorderWidth: Option<NumberStringOrT<Border>>,
790}
791
792#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
793pub struct LineElementConfiguration {
794    #[serde(skip_serializing_if = "Option::is_none")]
795    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
796    #[serde(skip_serializing_if = "String::is_empty", default)]
797    pub(crate) cubicInterpolationMode: String,
798    #[serde(skip_serializing_if = "Option::is_none")]
799    pub(crate) fill: Option<bool>,
800}
801
802#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
803pub struct PointElementConfiguration {
804    #[serde(skip_serializing_if = "Option::is_none")]
805    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
806    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
807    pub(crate) hitRadius: NumberString,
808    #[serde(skip_serializing_if = "Option::is_none")]
809    pub(crate) hoverBorderWidth: Option<NumberStringOrT<Border>>,
810    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
811    pub(crate) hoverRadius: NumberString,
812    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
813    pub(crate) radius: NumberString,
814}
815
816#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
817pub struct DataLabels {
818    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
819    pub(crate) align: FnWithArgsOrT<1, String>,
820    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
821    pub(crate) anchor: FnWithArgsOrT<1, String>,
822    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
823    pub(crate) backgroundColor: FnWithArgsOrT<1, String>,
824    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
825    pub(crate) borderRadius: NumberString,
826    #[serde(skip_serializing_if = "Option::is_none")]
827    pub(crate) clamp: Option<bool>,
828    #[serde(skip_serializing_if = "Option::is_none")]
829    pub(crate) clip: Option<bool>,
830    #[serde(skip_serializing_if = "String::is_empty", default)]
831    pub(crate) color: String,
832    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
833    pub(crate) display: FnWithArgsOrT<1, BoolString>,
834    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
835    pub(crate) drawTime: NumberString,
836    #[serde(skip_serializing_if = "Option::is_none")]
837    pub(crate) font: Option<Font>,
838    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
839    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
840    pub(crate) formatter: FnWithArgs<2>,
841    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
842    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
843    pub(crate) offset: FnWithArgsOrT<1, NumberString>,
844    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
845    pub(crate) opacity: NumberString,
846    #[serde(skip_serializing_if = "Option::is_none")]
847    pub(crate) padding: Option<Padding>,
848    #[serde(skip_serializing_if = "Option::is_none")]
849    pub(crate) rotation: Option<i16>,
850    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
851    pub(crate) z: NumberString,
852}
853
854#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
855pub struct Border {
856    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
857    pub(crate) bottom: NumberString,
858    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
859    pub(crate) left: NumberString,
860    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
861    pub(crate) right: NumberString,
862    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
863    pub(crate) top: NumberString,
864}
865#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
866pub struct Padding {
867    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
868    pub(crate) bottom: NumberString,
869    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
870    pub(crate) left: NumberString,
871    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
872    pub(crate) right: NumberString,
873    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
874    pub(crate) top: NumberString,
875}
876
877#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
878pub struct Font {
879    #[serde(skip_serializing_if = "String::is_empty", default)]
880    pub(crate) family: String,
881    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
882    pub(crate) lineHeight: NumberString,
883    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
884    pub(crate) size: NumberString,
885    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
886    pub(crate) style: NumberString,
887    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
888    pub(crate) weight: NumberString,
889}
890
891#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord)]
892pub struct Segment {
893    #[serde(
894        skip_serializing_if = "FnWithArgs::is_empty",
895        default,
896        skip_deserializing // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
897    )]
898    pub(crate) borderColor: FnWithArgs<1>,
899    #[serde(
900        skip_serializing_if = "FnWithArgs::is_empty",
901        default,
902        skip_deserializing // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
903    )]
904    pub(crate) borderDash: FnWithArgs<1>,
905}
906
907//
908impl DatasetTrait for Vec<SinglePointDataset> {
909    fn labels(self) -> Vec<NumberOrDateString> {
910        let mut vec = self
911            .into_iter()
912            .map(|spd| spd.label.into())
913            .collect::<Vec<_>>();
914
915        vec.sort_by(crate::get_order_fn);
916        vec.dedup();
917        vec
918    }
919}
920impl DatasetTrait for Vec<XYDataset> {
921    fn labels(self) -> Vec<NumberOrDateString> {
922        let mut vec = self
923            .into_iter()
924            .filter_map(|xyd| {
925                let data = xyd.data.0.as_array()?;
926                // gloo_console::console_dbg!(&data);
927                let keys = data
928                    .iter()
929                    .filter_map(|xy| xy.as_object())
930                    .filter_map(|obj| obj.get("x"))
931                    .filter_map(|x| {
932                        x.as_str()
933                            .map(|s| s.to_string())
934                            .or(x.as_number().map(|num| num.to_string()))
935                    })
936                    .map(|x| x.into())
937                    .collect::<Vec<NumberOrDateString>>();
938                Some(keys)
939            })
940            .flatten()
941            .collect::<Vec<_>>();
942        // gloo_console::console_dbg!(&vec);
943
944        vec.sort_by(crate::get_order_fn);
945        vec.dedup();
946        vec
947    }
948}
949impl DatasetTrait for Vec<FloatingDataset> {
950    fn labels(self) -> Vec<NumberOrDateString> {
951        let mut vec = self
952            .into_iter()
953            .map(|spd| spd.label.into())
954            .collect::<Vec<_>>();
955
956        vec.sort_by(crate::get_order_fn);
957        vec.dedup();
958        vec
959    }
960}
961//
962#[allow(clippy::large_enum_variant)]
963#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
964#[serde(untagged)]
965pub enum Annotation {
966    Box(BoxAnnotation),
967    Line(LineAnnotation),
968    Label(LabelAnnotation),
969}
970
971impl Default for Annotation {
972    fn default() -> Self {
973        Self::Line(Default::default())
974    }
975}
976impl From<BoxAnnotation> for Annotation {
977    fn from(value: BoxAnnotation) -> Self {
978        Self::Box(value)
979    }
980}
981impl From<LineAnnotation> for Annotation {
982    fn from(value: LineAnnotation) -> Self {
983        Self::Line(value)
984    }
985}
986impl From<LabelAnnotation> for Annotation {
987    fn from(value: LabelAnnotation) -> Self {
988        Self::Label(value)
989    }
990}
991//
992impl From<(NumberOrDateString, NumberString, Option<Value>)> for XYPoint {
993    fn from((x, y, d): (NumberOrDateString, NumberString, Option<Value>)) -> Self {
994        XYPoint {
995            x,
996            y,
997            description: d.unwrap_or_default(),
998        }
999    }
1000}
1001//
1002impl Ord for XYPoint {
1003    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1004        self.x.cmp(&other.x)
1005    }
1006}
1007//
1008impl PartialOrd for XYPoint {
1009    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1010        Some(self.cmp(other))
1011    }
1012}
1013//
1014impl Serialize for BoxAnnotationType {
1015    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1016    where
1017        S: serde::Serializer,
1018    {
1019        serializer.serialize_str("box")
1020    }
1021}
1022//
1023impl Serialize for LineAnnotationType {
1024    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1025    where
1026        S: serde::Serializer,
1027    {
1028        serializer.serialize_str("line")
1029    }
1030}
1031//
1032impl Serialize for LabelAnnotationType {
1033    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1034    where
1035        S: serde::Serializer,
1036    {
1037        serializer.serialize_str("label")
1038    }
1039}
1040//
1041impl<'de> Deserialize<'de> for BoxAnnotationType {
1042    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1043    where
1044        D: serde::Deserializer<'de>,
1045    {
1046        match String::deserialize(deserializer)?.to_lowercase().as_str() {
1047            "box" => Ok(BoxAnnotationType),
1048            other => Err(de::Error::custom(format!(
1049                "`{other}` is not a valid BoxAnnotationType."
1050            ))),
1051        }
1052    }
1053}
1054//
1055impl<'de> Deserialize<'de> for LineAnnotationType {
1056    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1057    where
1058        D: serde::Deserializer<'de>,
1059    {
1060        match String::deserialize(deserializer)?.to_lowercase().as_str() {
1061            "line" => Ok(LineAnnotationType),
1062            other => Err(de::Error::custom(format!(
1063                "`{other}` is not a valid LineAnnotationType."
1064            ))),
1065        }
1066    }
1067}
1068//
1069impl<'de> Deserialize<'de> for LabelAnnotationType {
1070    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1071    where
1072        D: serde::Deserializer<'de>,
1073    {
1074        match String::deserialize(deserializer)?.to_lowercase().as_str() {
1075            "label" => Ok(LabelAnnotationType),
1076            other => Err(de::Error::custom(format!(
1077                "`{other}` is not a valid LabelAnnotationType."
1078            ))),
1079        }
1080    }
1081}
1082//