1use std::fmt::Debug;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use crate::builder::AxisKindMarker;
5use crate::builder::AxisInfo;
6use crate::common::Percent;
7
8#[derive(Serialize, Deserialize, Debug, Clone)]
10#[serde(rename_all = "camelCase")]
11pub struct EChartsOption<X:AxisKindMarker,Y:AxisKindMarker> {
12 #[serde(skip_serializing_if = "Option::is_none")]
14 pub title: Option<Title>,
15
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub grid: Option<Grid>,
19
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub tooltip: Option<Tooltip>,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub legend: Option<Legend>,
27
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub dataset: Option<Vec<DatasetComponent<X,Y>>>,
31
32 pub x_axis: Axis<X>,
34
35 pub y_axis: Axis<Y>,
37
38 #[serde(skip_serializing_if = "Option::is_none")]
40 pub series: Option<Vec<Series<X,Y>>>,
41
42 #[serde(flatten)]
44 pub extra: Option<Value>,
45}
46
47#[derive(Serialize, Deserialize, Debug, Clone)]
49#[serde(rename_all = "camelCase")]
50pub enum PositionKeyword {
51 Left,
52 Right,
53 Top,
54 Bottom,
55 Middle,
56 Center,
57 Auto
58}
59
60
61#[derive(Serialize, Deserialize, Debug, Clone)]
63#[serde(untagged)]
64pub enum Position {
65 Keyword(PositionKeyword),
67 Number(f64),
69 Percent(Percent)
71}
72
73#[derive(Serialize, Deserialize, Debug, Clone,Default)]
75#[serde(rename_all = "camelCase")]
76pub struct Title {
77 pub text: Option<String>,
79
80 #[serde(skip_serializing_if = "Option::is_none")]
82 pub sub_text: Option<String>,
83
84 #[serde(skip_serializing_if = "Option::is_none")]
86 pub link: Option<String>,
87
88 #[serde(skip_serializing_if = "Option::is_none")]
90 pub left: Option<Position>,
91
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub top: Option<Position>,
95
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub right: Option<Position>,
99
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub bottom: Option<Position>,
103
104 #[serde(flatten)]
106 pub extra: Option<Value>,
107}
108
109impl Title {
110 pub(crate) fn new(text: &str) -> Title {
111 Self{
112 text: Some(text.to_string()),
113 sub_text: None,
114 link: None,
115 left: None,
116 top: None,
117 right: None,
118 bottom: None,
119 extra: None,
120 }
121 }
122}
123
124#[derive(Serialize, Deserialize, Debug, Clone)]
126#[serde(rename_all = "camelCase")]
127pub struct Grid {
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub left: Option<Position>,
131
132 #[serde(skip_serializing_if = "Option::is_none")]
134 pub right: Option<Position>,
135
136 #[serde(skip_serializing_if = "Option::is_none")]
138 pub top: Option<Position>,
139
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub bottom: Option<Position>,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub contain_label: Option<bool>,
147
148 #[serde(skip_serializing_if = "Option::is_none")]
150 pub background_color: Option<Value>,
151
152 #[serde(skip_serializing_if = "Option::is_none")]
154 pub border_color: Option<Value>,
155
156 #[serde(skip_serializing_if = "Option::is_none")]
158 pub border_width: Option<f64>,
159
160 #[serde(skip_serializing_if = "Option::is_none")]
162 pub show: Option<bool>,
163
164 #[serde(skip_serializing_if = "Option::is_none")]
166 pub z: Option<i32>,
167
168 #[serde(skip_serializing_if = "Option::is_none")]
170 pub zlevel: Option<i32>,
171
172 #[serde(flatten)]
174 pub extra: Option<Value>,
175}
176
177#[derive(Serialize, Deserialize, Debug, Clone)]
178#[serde(rename_all = "camelCase")]
179pub enum TooltipTrigger {
180 Item,
181 Axis,
182 None
183}
184
185#[derive(Serialize, Deserialize, Debug, Clone)]
186#[serde(rename_all = "camelCase")]
187pub enum AxisPointerType {
188 Cross,
189 Line,
190 Shadow,
191 None
192}
193
194#[derive(Serialize, Deserialize, Debug, Clone)]
195#[serde(rename_all = "camelCase")]
196pub enum AxisPointerTargetAxis{
197 Auto,
198 X,
199 Y,
200 Radius,
201 Angle
202}
203
204
205#[derive(Serialize, Deserialize, Debug, Clone)]
206#[serde(rename_all = "camelCase")]
207pub struct AxisPointer{
208 #[serde(skip_serializing_if = "Option::is_none")]
209 pub r#type: Option<AxisPointerType>,
210
211 #[serde(skip_serializing_if = "Option::is_none")]
212 pub snap : Option<bool>,
213
214 #[serde(skip_serializing_if = "Option::is_none")]
215 pub animation : Option<bool>,
216
217 #[serde(skip_serializing_if = "Option::is_none")]
218 pub axis: Option<AxisPointerTargetAxis>
219
220
221}
222
223#[derive(Serialize, Deserialize, Debug, Clone)]
225#[serde(rename_all = "camelCase")]
226pub struct Tooltip {
227 pub show: bool,
228
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub show_delay: Option<i32>,
231
232 #[serde(skip_serializing_if = "Option::is_none")]
233 pub hide_delay: Option<i32>,
234
235 #[serde(skip_serializing_if = "Option::is_none")]
237 pub trigger: Option<TooltipTrigger>,
238
239 #[serde(skip_serializing_if = "Option::is_none")]
241 pub formatter: Option<Value>,
242
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub axis_pointer: Option<AxisPointer>,
245
246}
247
248#[derive(Serialize, Deserialize, Debug, Clone)]
250#[serde(rename_all = "camelCase")]
251pub struct Legend {
252 #[serde(skip_serializing_if = "Option::is_none")]
254 pub data: Option<Vec<String>>,
255
256 #[serde(skip_serializing_if = "Option::is_none")]
258 pub orient: Option<String>,
259
260 #[serde(skip_serializing_if = "Option::is_none")]
262 pub left: Option<Position>,
263
264 #[serde(flatten)]
266 pub extra: Option<Value>,
267}
268
269#[derive(Serialize, Deserialize, Debug, Clone)]
271#[serde(rename_all = "lowercase")]
272pub enum AxisType {
273 Value,
274 Category,
275 Time,
276 Log,
277 #[serde(other)]
279 Unknown,
280}
281
282
283
284
285#[derive(Serialize, Deserialize, Debug, Clone)]
286#[serde(rename_all = "camelCase")]
287pub struct NamedValuePair<X,Y>{
288 value: (X,Y),
289 name: String,
290}
291
292impl<X,Y> NamedValuePair<X,Y> {
293 pub fn new(x: X, y: Y, name: String) -> Self {
294 Self{
295 value: (x, y),
296 name,
297 }
298 }
299
300}
301
302#[derive(Serialize, Deserialize, Debug, Clone)]
303#[serde(rename_all = "camelCase")]
304pub struct NamedValue<X>{
305 value: X,
306 name: String,
307}
308
309
310#[derive(Serialize, Deserialize, Debug, Clone)]
312#[serde(rename_all = "camelCase")]
313pub struct Axis<T:AxisKindMarker> {
314 pub r#type: AxisType,
316
317 #[serde(skip_serializing_if = "Option::is_none")]
319 pub name: Option<String>,
320
321 #[serde(skip_serializing_if = "Option::is_none")]
323 pub data: Option<Vec<T>>,
324
325 #[serde(flatten)]
327 pub extra: Option<Value>,
328}
329
330impl<T:AxisKindMarker> Default for Axis<T> {
331 fn default() -> Self {
332 Self{
333 r#type: T::AxisType::AXIS_TYPE,
334 name: None,
335 data: None,
336 extra: None,
337 }
338 }
339}
340
341
342impl<T:AxisKindMarker> Axis<T>{
343 pub fn new(name: &str)-> Self{
344 Self{
345 r#type: T::AxisType::AXIS_TYPE,
346 name: Some(name.to_string()),
347 data: None,
348 extra: None,
349 }
350 }
351}
352
353
354#[derive(Serialize, Deserialize, Debug, Clone)]
356#[serde(rename_all = "camelCase")]
357pub enum SeriesType {
358 Line,
359 Bar,
360 Pie,
361 Scatter,
362 EffectScatter,
363 Radar,
364 Tree,
365 Treemap,
366 Sunburst,
367 Boxplot,
368 Candlestick,
369 Heatmap,
370 Map,
371 Parallel,
372 Lines,
373 Graph,
374 Sankey,
375 Funnel,
376 Gauge,
377 PictorialBar,
378 ThemeRiver,
379 Custom,
380 #[serde(other)]
382 Unknown,
383}
384
385
386#[derive(Serialize, Deserialize, Debug, Clone)]
387#[serde(untagged)]
388pub enum DataVariant<X,Y>{
389 Data(Vec<X>),
391
392 Pair(Vec<(X,Y)>),
394
395 Named(Vec<NamedValue<X>>),
397
398 NamedPair(Vec<NamedValuePair<X,Y>>),
400}
401
402#[derive(Serialize, Deserialize, Debug, Clone)]
404#[serde(rename_all = "camelCase")]
405pub enum SeriesDataSource<X,Y>{
406 Data(DataVariant<X,Y>),
408 DatasetIndex(usize)
410}
411
412impl<X,Y> Into<SeriesDataSource<X,Y>> for Vec<(X, Y)>
413{
414 fn into(self) -> SeriesDataSource<X,Y> {
415 SeriesDataSource::from_pairs(self)
416 }
417
418}
419
420impl<X,Y> Into<SeriesDataSource<X,Y>> for Vec<(X, Y, String)>
421{
422 fn into(self) -> SeriesDataSource<X,Y> {
423 SeriesDataSource::from_tuples_with_label(self)
424 }
425}
426
427impl<X,Y> Into<SeriesDataSource<X,Y>> for Vec<X>
428{
429 fn into(self) -> SeriesDataSource<X,Y> {
430 SeriesDataSource::from_values(self)
431 }
432}
433
434impl<X,Y> SeriesDataSource<X,Y> {
435 pub fn from_dataset_index(index: usize) -> Self {
437 Self::DatasetIndex(index)
438 }
439
440 pub fn from_values(values: Vec<X>) -> Self {
442 Self::Data(DataVariant::Data(values))
443 }
444
445 pub fn from_pairs(pairs: Vec<(X,Y)>) -> Self {
447 Self::Data(DataVariant::Pair(pairs))
448 }
449
450 pub fn from_named_value_pairs(named_pairs: Vec<NamedValuePair<X,Y>>) -> Self{
451 Self::Data(DataVariant::NamedPair(named_pairs))
452 }
453
454
455 pub fn with_named_values(named_values: Vec<NamedValue<X>>) -> Self {
457 Self::Data(DataVariant::Named(named_values))
458 }
459
460 pub fn from_labeled_values(values: Vec<(X, String)>) -> Self
461 {
462 let data_named_values = values.into_iter().map(|(x,label)| NamedValue{
463 value: x.into(),
464 name: label
465 }).collect();
466 Self::with_named_values(data_named_values)
467 }
468
469 pub fn from_tuples_with_label(values: Vec<(X, Y, String)>) -> Self
471 {
472 let data_named_pairs = values.into_iter()
473 .map(|(x, y,label) | NamedValuePair::new(x.into(), y.into(),label))
474 .collect();
475 Self::from_named_value_pairs(data_named_pairs)
476 }
477
478}
479
480
481#[derive(Serialize, Deserialize, Debug, Clone)]
482#[serde(rename_all = "camelCase")]
483pub enum DataPointSymbol {
484 Circle,
485 Rect,
486 RoundRect,
487 Triangle,
488 Diamond,
489 Pin,
490 Arrow,
491 None
492}
493
494#[derive(Serialize, Deserialize, Debug, Clone)]
496#[serde(rename_all = "camelCase")]
497pub struct Series<X,Y> {
498 #[serde(skip_serializing_if = "Option::is_none")]
500 pub r#type: Option<SeriesType>,
501
502 #[serde(skip_serializing_if = "Option::is_none")]
504 pub name: Option<String>,
505
506 #[serde(skip_serializing_if = "Option::is_none")]
507 pub smooth: Option<bool>,
508
509 #[serde(skip_serializing_if = "Option::is_none")]
510 pub area_style: Option<AreaStyle>,
511
512 #[serde(flatten)]
514 pub data: SeriesDataSource<X,Y>,
515
516 #[serde(skip_serializing_if = "Option::is_none")]
517 pub symbol: Option<DataPointSymbol>,
518
519 #[serde(skip_serializing_if = "Option::is_none")]
520 pub symbol_size: Option<usize>,
521
522 #[serde(flatten)]
524 pub extra: Option<Value>,
525}
526
527impl<X,Y> Series <X,Y>{
528 pub fn new(name:&str, r#type: SeriesType, data: SeriesDataSource<X,Y>) -> Series<X,Y> {
529 Self{
530 r#type: Some(r#type),
531 name: Some(name.to_string()),
532 smooth: None,
533 area_style: None,
534 data,
535 symbol: None,
536 symbol_size: None,
537 extra: None,
538 }
539 }
540}
541
542
543#[derive(Serialize, Deserialize, Debug, Clone)]
544#[serde(rename_all = "camelCase")]
545pub enum AxisFillOrigin{
546 Auto,
547 Start,
548 End,
549 Number
550}
551
552#[derive(Serialize, Deserialize, Debug, Clone)]
553#[serde(rename_all = "camelCase")]
554pub struct AreaStyle{
555 #[serde(skip_serializing_if = "Option::is_none")]
556 color: Option<Value>,
557 #[serde(skip_serializing_if = "Option::is_none")]
558 origin: Option<AxisFillOrigin>
559}
560
561
562
563#[derive(Serialize, Deserialize, Debug, Clone)]
564#[serde(rename_all = "camelCase")]
565pub struct Transform{
566 pub transform: DatasetTransform,
567
568 #[serde(skip_serializing_if = "Option::is_none")]
569 pub from_dataset_index: Option<usize>
570}
571
572#[derive(Serialize, Deserialize, Debug, Clone)]
573#[serde(rename_all = "camelCase")]
574pub struct Source<X,Y>{
575 pub source: Vec<(X,Y)>,
576}
577
578#[derive(Serialize, Deserialize, Debug, Clone)]
579#[serde(rename_all = "camelCase")]
580pub struct LabelledSource<X,Y>{
581 pub source: Vec<(X,Y,String)>,
582}
583
584
585#[derive(Serialize, Deserialize, Debug, Clone)]
587#[serde(rename_all = "camelCase")]
588#[serde(untagged)]
589pub enum DatasetComponent<X,Y> {
590 Source(Source<X,Y>),
591 LabelledSource(LabelledSource<X,Y>),
592 Transform(Vec<Transform>)
593}
594
595
596impl<X,Y> Into<DatasetComponent<X,Y>> for Vec<(X,Y)>
597{
598 fn into(self) -> DatasetComponent<X,Y> {
599 DatasetComponent::src(self)
600 }
601}
602
603impl<X,Y> Into<DatasetComponent<X,Y>> for Vec<(X,Y,String)>
604{
605 fn into(self) -> DatasetComponent<X,Y> {
606 DatasetComponent::labelled_source(self)
607 }
608}
609
610
611
612impl<X,Y> DatasetComponent<X,Y> {
613 pub fn tr(transform: DatasetTransform, index: usize) -> Self{
614 Self::Transform(vec![Transform {
615 transform,
616 from_dataset_index: Some(index),
617 }])
618 }
619
620 pub fn trs(transform: Vec<DatasetTransform>, index: usize) -> Self{
621 Self::Transform(
622 transform
623 .into_iter()
624 .map(|tr|
625 Transform {
626 transform:tr,
627 from_dataset_index: Some(index)
628 }
629 )
630 .collect()
631 )
632 }
633
634 pub fn src(source: Vec<(X,Y)>) -> Self {
635 Self::Source(
636 Source {
637 source
638 }
639 )
640 }
641
642 pub fn labelled_source(source: Vec<(X,Y,String)>) -> Self {
644 Self::LabelledSource(
645 LabelledSource{
646 source
647 }
648 )
649 }
650}
651
652#[derive(Serialize, Deserialize, Debug, Clone)]
653#[serde(rename_all = "camelCase")]
654pub enum DatasetTransformType {
655 Filter,
656 Sort,
657 Boxplot,
658 #[serde(rename = "ecStat:regression")]
659 Regression,
660 #[serde(rename = "ecStat:clustering")]
661 Clustering
662}
663
664#[derive(Serialize, Deserialize, Debug, Clone)]
666#[serde(rename_all = "camelCase")]
667pub struct DatasetTransform {
668 r#type: DatasetTransformType,
670
671 config: DatasetTransformConfig,
673
674}
675
676
677impl DatasetTransform {
678
679 pub fn regression(config: RegressionConfig) -> Self {
680 Self{
681 r#type: DatasetTransformType::Regression,
682 config: DatasetTransformConfig::Regression(config)
683 }
684 }
685
686 pub fn clustering(clustering_config: ClusteringConfig)->Self{
687 Self{
688 r#type: DatasetTransformType::Clustering,
689 config: DatasetTransformConfig::Clustering(clustering_config)
690 }
691 }
692
693 pub fn sort(sort_config: SortConfig) -> Self {
694 Self{
695 r#type: DatasetTransformType::Sort,
696 config: DatasetTransformConfig::Sort(sort_config)
697 }
698 }
699
700}
701
702
703#[derive(Serialize, Deserialize, Debug, Clone)]
704#[serde(untagged)]
705enum DatasetTransformConfig {
706 Regression(RegressionConfig),
707 Clustering(ClusteringConfig),
708 Sort(SortConfig)
709}
710
711
712#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
714#[serde(rename_all = "lowercase")]
715pub enum RegressionMethod {
716 Linear,
717 Exponential,
718 Logarithmic,
719 Polynomial,
720}
721
722#[derive(Serialize, Deserialize, Debug, Clone)]
723#[serde(rename_all = "camelCase")]
724pub struct SortConfig {
725 dimension: u8,
726 order : Order
727}
728
729#[derive(Serialize, Deserialize, Debug, Clone)]
730#[serde(rename_all = "camelCase")]
731pub enum Order {
732 Asc,
733 Desc
734}
735
736
737#[derive(Serialize, Deserialize, Debug, Clone)]
739#[serde(rename_all = "camelCase")]
740pub struct RegressionConfig {
741 pub method: RegressionMethod,
743
744 #[serde(skip_serializing_if = "Option::is_none")]
746 pub order: Option<u8>,
747
748 #[serde(flatten)]
750 pub extra: Option<Value>,
751}
752
753
754
755#[derive(Serialize, Deserialize, Debug, Clone)]
757#[serde(rename_all = "camelCase")]
758pub struct ClusteringConfig {
759
760 pub cluster_count: u8,
762
763 pub output_cluster_index_dimension: u8,
765
766 pub dimensions : Option<Vec<usize>>,
768
769}