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<2, 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 = "String::is_empty", default)]
756    pub(crate) pointStyle: String,
757    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
758    pub(crate) pointStyleWidth: NumberString,
759    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
760    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
761    pub(crate) sort: FnWithArgs<3>,
762    #[serde(skip_serializing_if = "Option::is_none")]
763    pub(crate) useBorderRadius: Option<bool>,
764    #[serde(skip_serializing_if = "Option::is_none")]
765    pub(crate) usePointStyle: Option<bool>,
766}
767
768#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
769pub struct ChartElements {
770    #[serde(skip_serializing_if = "Option::is_none")]
771    pub(crate) bar: Option<BarElementConfiguration>,
772    #[serde(skip_serializing_if = "Option::is_none")]
773    pub(crate) line: Option<LineElementConfiguration>,
774    #[serde(skip_serializing_if = "Option::is_none")]
775    pub(crate) point: Option<PointElementConfiguration>,
776}
777
778#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
779pub struct BarElementConfiguration {
780    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
781    pub(crate) borderRadius: NumberString,
782    #[serde(skip_serializing_if = "Option::is_none")]
783    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
784    #[serde(skip_serializing_if = "Option::is_none")]
785    pub(crate) fill: Option<bool>,
786    #[serde(skip_serializing_if = "Option::is_none")]
787    pub(crate) hoverBorderWidth: Option<NumberStringOrT<Border>>,
788}
789
790#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
791pub struct LineElementConfiguration {
792    #[serde(skip_serializing_if = "Option::is_none")]
793    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
794    #[serde(skip_serializing_if = "String::is_empty", default)]
795    pub(crate) cubicInterpolationMode: String,
796    #[serde(skip_serializing_if = "Option::is_none")]
797    pub(crate) fill: Option<bool>,
798}
799
800#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
801pub struct PointElementConfiguration {
802    #[serde(skip_serializing_if = "Option::is_none")]
803    pub(crate) borderWidth: Option<NumberStringOrT<Border>>,
804    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
805    pub(crate) hitRadius: NumberString,
806    #[serde(skip_serializing_if = "Option::is_none")]
807    pub(crate) hoverBorderWidth: Option<NumberStringOrT<Border>>,
808    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
809    pub(crate) hoverRadius: NumberString,
810    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
811    pub(crate) radius: NumberString,
812}
813
814#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
815pub struct DataLabels {
816    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
817    pub(crate) align: FnWithArgsOrT<1, String>,
818    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
819    pub(crate) anchor: FnWithArgsOrT<1, String>,
820    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
821    pub(crate) backgroundColor: FnWithArgsOrT<1, String>,
822    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
823    pub(crate) borderRadius: NumberString,
824    #[serde(skip_serializing_if = "Option::is_none")]
825    pub(crate) clamp: Option<bool>,
826    #[serde(skip_serializing_if = "Option::is_none")]
827    pub(crate) clip: Option<bool>,
828    #[serde(skip_serializing_if = "String::is_empty", default)]
829    pub(crate) color: String,
830    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
831    pub(crate) display: FnWithArgsOrT<1, BoolString>,
832    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
833    pub(crate) drawTime: NumberString,
834    #[serde(skip_serializing_if = "Option::is_none")]
835    pub(crate) font: Option<Font>,
836    #[serde(skip_serializing_if = "FnWithArgs::is_empty", skip_deserializing)]
837    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
838    pub(crate) formatter: FnWithArgs<2>,
839    #[serde(skip_serializing_if = "FnWithArgsOrT::is_empty", default)]
840    // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
841    pub(crate) offset: FnWithArgsOrT<1, NumberString>,
842    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
843    pub(crate) opacity: NumberString,
844    #[serde(skip_serializing_if = "Option::is_none")]
845    pub(crate) padding: Option<Padding>,
846    #[serde(skip_serializing_if = "Option::is_none")]
847    pub(crate) rotation: Option<i16>,
848    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
849    pub(crate) z: NumberString,
850}
851
852#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
853pub struct Border {
854    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
855    pub(crate) bottom: NumberString,
856    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
857    pub(crate) left: NumberString,
858    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
859    pub(crate) right: NumberString,
860    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
861    pub(crate) top: NumberString,
862}
863#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
864pub struct Padding {
865    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
866    pub(crate) bottom: NumberString,
867    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
868    pub(crate) left: NumberString,
869    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
870    pub(crate) right: NumberString,
871    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
872    pub(crate) top: NumberString,
873}
874
875#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord)]
876pub struct Font {
877    #[serde(skip_serializing_if = "String::is_empty", default)]
878    pub(crate) family: String,
879    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
880    pub(crate) lineHeight: NumberString,
881    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
882    pub(crate) size: NumberString,
883    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
884    pub(crate) style: NumberString,
885    #[serde(skip_serializing_if = "NumberString::is_empty", default)]
886    pub(crate) weight: NumberString,
887}
888
889#[derive(Debug, Clone, Serialize, Deserialize, Default, PartialEq, Eq, PartialOrd, Ord)]
890pub struct Segment {
891    #[serde(
892        skip_serializing_if = "FnWithArgs::is_empty",
893        default,
894        skip_deserializing // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
895    )]
896    pub(crate) borderColor: FnWithArgs<1>,
897    #[serde(
898        skip_serializing_if = "FnWithArgs::is_empty",
899        default,
900        skip_deserializing // FnWithArgs can't deser right now, might be solved in the future with a fancy serde deserializer
901    )]
902    pub(crate) borderDash: FnWithArgs<1>,
903}
904
905//
906impl DatasetTrait for Vec<SinglePointDataset> {
907    fn labels(self) -> Vec<NumberOrDateString> {
908        let mut vec = self
909            .into_iter()
910            .map(|spd| spd.label.into())
911            .collect::<Vec<_>>();
912
913        vec.sort_by(crate::get_order_fn);
914        vec.dedup();
915        vec
916    }
917}
918impl DatasetTrait for Vec<XYDataset> {
919    fn labels(self) -> Vec<NumberOrDateString> {
920        let mut vec = self
921            .into_iter()
922            .filter_map(|xyd| {
923                let data = xyd.data.0.as_array()?;
924                // gloo_console::console_dbg!(&data);
925                let keys = data
926                    .iter()
927                    .filter_map(|xy| xy.as_object())
928                    .filter_map(|obj| obj.get("x"))
929                    .filter_map(|x| {
930                        x.as_str()
931                            .map(|s| s.to_string())
932                            .or(x.as_number().map(|num| num.to_string()))
933                    })
934                    .map(|x| x.into())
935                    .collect::<Vec<NumberOrDateString>>();
936                Some(keys)
937            })
938            .flatten()
939            .collect::<Vec<_>>();
940        // gloo_console::console_dbg!(&vec);
941
942        vec.sort_by(crate::get_order_fn);
943        vec.dedup();
944        vec
945    }
946}
947impl DatasetTrait for Vec<FloatingDataset> {
948    fn labels(self) -> Vec<NumberOrDateString> {
949        let mut vec = self
950            .into_iter()
951            .map(|spd| spd.label.into())
952            .collect::<Vec<_>>();
953
954        vec.sort_by(crate::get_order_fn);
955        vec.dedup();
956        vec
957    }
958}
959//
960#[allow(clippy::large_enum_variant)]
961#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
962#[serde(untagged)]
963pub enum Annotation {
964    Box(BoxAnnotation),
965    Line(LineAnnotation),
966    Label(LabelAnnotation),
967}
968
969impl Default for Annotation {
970    fn default() -> Self {
971        Self::Line(Default::default())
972    }
973}
974impl From<BoxAnnotation> for Annotation {
975    fn from(value: BoxAnnotation) -> Self {
976        Self::Box(value)
977    }
978}
979impl From<LineAnnotation> for Annotation {
980    fn from(value: LineAnnotation) -> Self {
981        Self::Line(value)
982    }
983}
984impl From<LabelAnnotation> for Annotation {
985    fn from(value: LabelAnnotation) -> Self {
986        Self::Label(value)
987    }
988}
989//
990impl From<(NumberOrDateString, NumberString, Option<Value>)> for XYPoint {
991    fn from((x, y, d): (NumberOrDateString, NumberString, Option<Value>)) -> Self {
992        XYPoint {
993            x,
994            y,
995            description: d.unwrap_or_default(),
996        }
997    }
998}
999//
1000impl Ord for XYPoint {
1001    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
1002        self.x.cmp(&other.x)
1003    }
1004}
1005//
1006impl PartialOrd for XYPoint {
1007    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
1008        Some(self.cmp(other))
1009    }
1010}
1011//
1012impl Serialize for BoxAnnotationType {
1013    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1014    where
1015        S: serde::Serializer,
1016    {
1017        serializer.serialize_str("box")
1018    }
1019}
1020//
1021impl Serialize for LineAnnotationType {
1022    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1023    where
1024        S: serde::Serializer,
1025    {
1026        serializer.serialize_str("line")
1027    }
1028}
1029//
1030impl Serialize for LabelAnnotationType {
1031    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1032    where
1033        S: serde::Serializer,
1034    {
1035        serializer.serialize_str("label")
1036    }
1037}
1038//
1039impl<'de> Deserialize<'de> for BoxAnnotationType {
1040    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1041    where
1042        D: serde::Deserializer<'de>,
1043    {
1044        match String::deserialize(deserializer)?.to_lowercase().as_str() {
1045            "box" => Ok(BoxAnnotationType),
1046            other => Err(de::Error::custom(format!(
1047                "`{other}` is not a valid BoxAnnotationType."
1048            ))),
1049        }
1050    }
1051}
1052//
1053impl<'de> Deserialize<'de> for LineAnnotationType {
1054    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1055    where
1056        D: serde::Deserializer<'de>,
1057    {
1058        match String::deserialize(deserializer)?.to_lowercase().as_str() {
1059            "line" => Ok(LineAnnotationType),
1060            other => Err(de::Error::custom(format!(
1061                "`{other}` is not a valid LineAnnotationType."
1062            ))),
1063        }
1064    }
1065}
1066//
1067impl<'de> Deserialize<'de> for LabelAnnotationType {
1068    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1069    where
1070        D: serde::Deserializer<'de>,
1071    {
1072        match String::deserialize(deserializer)?.to_lowercase().as_str() {
1073            "label" => Ok(LabelAnnotationType),
1074            other => Err(de::Error::custom(format!(
1075                "`{other}` is not a valid LabelAnnotationType."
1076            ))),
1077        }
1078    }
1079}
1080//