charts_rs_derive/
lib.rs

1extern crate proc_macro;
2use proc_macro::TokenStream;
3use quote::quote;
4use syn::DeriveInput;
5
6#[proc_macro_derive(Chart)]
7pub fn my_default(input: TokenStream) -> TokenStream {
8    let ast: DeriveInput = syn::parse(input).unwrap();
9    let id = ast.ident;
10
11    let gen = quote! {
12        impl #id {
13            /// Fills the default options of current theme.
14            fn fill_theme(&mut self, t: Arc<Theme>) {
15                self.font_family = t.font_family.clone();
16                self.margin = t.margin.clone();
17                self.width = t.width;
18                self.height = t.height;
19                self.background_color = t.background_color;
20                self.is_light = t.is_light;
21
22                self.title_font_color = t.title_font_color;
23                self.title_font_size = t.title_font_size;
24                self.title_font_weight = t.title_font_weight.clone();
25                self.title_margin = t.title_margin.clone();
26                self.title_align = t.title_align.clone();
27                self.title_height = t.title_height;
28
29                self.sub_title_font_color = t.sub_title_font_color;
30                self.sub_title_font_size = t.sub_title_font_size;
31                self.sub_title_margin = t.sub_title_margin.clone();
32                self.sub_title_align = t.sub_title_align.clone();
33                self.sub_title_height = t.sub_title_height;
34
35                self.legend_font_color = t.legend_font_color;
36                self.legend_font_size = t.legend_font_size;
37                self.legend_align = t.legend_align.clone();
38                self.legend_margin = t.legend_margin.clone();
39
40                self.x_axis_font_size = t.x_axis_font_size;
41                self.x_axis_font_color = t.x_axis_font_color;
42                self.x_axis_stroke_color = t.x_axis_stroke_color;
43                self.x_axis_name_gap = t.x_axis_name_gap;
44                self.x_axis_height = t.x_axis_height;
45
46                self.y_axis_configs = vec![
47                    YAxisConfig{
48                        axis_font_size: t.y_axis_font_size,
49                        axis_font_color: t.y_axis_font_color,
50                        axis_stroke_color: t.y_axis_stroke_color,
51                        axis_split_number: t.y_axis_split_number,
52                        axis_name_gap: t.y_axis_name_gap,
53                        ..Default::default()
54                    }
55                ];
56
57                self.grid_stroke_color = t.grid_stroke_color;
58                self.grid_stroke_width = t.grid_stroke_width;
59
60                self.series_colors = t.series_colors.clone();
61                self.series_label_font_color = t.series_label_font_color;
62                self.series_label_font_size = t.series_label_font_size;
63                self.series_stroke_width = t.series_stroke_width;
64
65                self.series_symbol = Some(Symbol::Circle(
66                    self.series_stroke_width,
67                    Some(self.background_color),
68                ));
69            }
70            /// Fills the options from json config.
71            fn fill_option(&mut self, data: &str) -> canvas::Result<serde_json::Value> {
72                let data: serde_json::Value = serde_json::from_str(data)?;
73                let series_list = get_series_list_from_value(&data).unwrap_or_default();
74                let theme = get_string_from_value(&data, "theme").unwrap_or_default();
75                let theme = get_theme(&theme);
76                self.fill_theme(theme.clone());
77                self.series_list = series_list;
78
79                if let Some(width) = get_f32_from_value(&data, "width") {
80                    self.width = width;
81                }
82                if let Some(height) = get_f32_from_value(&data, "height") {
83                    self.height = height;
84                }
85                if let Some(x) = get_f32_from_value(&data, "x") {
86                    self.x = x;
87                }
88                if let Some(y) = get_f32_from_value(&data, "y") {
89                    self.y = y;
90                }
91                if let Some(margin) = get_margin_from_value(&data, "margin") {
92                    self.margin = margin;
93                }
94                if let Some(font_family) = get_string_from_value(&data, "font_family") {
95                    self.font_family = font_family;
96                }
97                if let Some(title_text) = get_string_from_value(&data, "title_text") {
98                    self.title_text = title_text;
99                }
100                if let Some(title_font_size) = get_f32_from_value(&data, "title_font_size") {
101                    self.title_font_size = title_font_size;
102                }
103                if let Some(title_font_color) = get_color_from_value(&data, "title_font_color") {
104                    self.title_font_color = title_font_color;
105                }
106                if let Some(title_font_weight) = get_string_from_value(&data, "title_font_weight") {
107                    self.title_font_weight = Some(title_font_weight);
108                }
109                if let Some(title_margin) = get_margin_from_value(&data, "title_margin") {
110                    self.title_margin = Some(title_margin);
111                }
112                if let Some(title_align) = get_align_from_value(&data, "title_align") {
113                    self.title_align = title_align;
114                }
115                if let Some(title_height) = get_f32_from_value(&data, "title_height") {
116                    self.title_height = title_height;
117                }
118
119                if let Some(sub_title_text) = get_string_from_value(&data, "sub_title_text") {
120                    self.sub_title_text = sub_title_text;
121                }
122                if let Some(sub_title_font_size) = get_f32_from_value(&data, "sub_title_font_size") {
123                    self.sub_title_font_size = sub_title_font_size;
124                }
125                if let Some(sub_title_font_color) = get_color_from_value(&data, "sub_title_font_color") {
126                    self.sub_title_font_color = sub_title_font_color;
127                }
128                if let Some(sub_title_font_weight) = get_string_from_value(&data, "sub_title_font_weight") {
129                    self.sub_title_font_weight = Some(sub_title_font_weight);
130                }
131                if let Some(sub_title_margin) = get_margin_from_value(&data, "sub_title_margin") {
132                    self.sub_title_margin = Some(sub_title_margin);
133                }
134                if let Some(sub_title_align) = get_align_from_value(&data, "sub_title_align") {
135                    self.sub_title_align = sub_title_align;
136                }
137                if let Some(sub_title_height) = get_f32_from_value(&data, "sub_title_height") {
138                    self.sub_title_height = sub_title_height;
139                }
140
141                if let Some(legend_font_size) = get_f32_from_value(&data, "legend_font_size") {
142                    self.legend_font_size = legend_font_size;
143                }
144                if let Some(legend_font_color) = get_color_from_value(&data, "legend_font_color") {
145                    self.legend_font_color = legend_font_color;
146                }
147                if let Some(legend_font_weight) = get_string_from_value(&data, "legend_font_weight") {
148                    self.legend_font_weight = Some(legend_font_weight);
149                }
150                if let Some(legend_align) = get_align_from_value(&data, "legend_align") {
151                    self.legend_align = legend_align;
152                }
153                if let Some(legend_margin) = get_margin_from_value(&data, "legend_margin") {
154                    self.legend_margin = Some(legend_margin);
155                }
156                if let Some(legend_category) = get_legend_category_from_value(&data, "legend_category") {
157                    self.legend_category = legend_category;
158                }
159                if let Some(legend_show) = get_bool_from_value(&data, "legend_show") {
160                    self.legend_show = Some(legend_show);
161                }
162
163                if let Some(x_axis_data) = get_string_slice_from_value(&data, "x_axis_data") {
164                    self.x_axis_data = x_axis_data;
165                }
166                if let Some(x_axis_height) = get_f32_from_value(&data, "x_axis_height") {
167                    self.x_axis_height = x_axis_height;
168                }
169                if let Some(x_axis_stroke_color) = get_color_from_value(&data, "x_axis_stroke_color") {
170                    self.x_axis_stroke_color = x_axis_stroke_color;
171                }
172                if let Some(x_axis_font_size) = get_f32_from_value(&data, "x_axis_font_size") {
173                    self.x_axis_font_size = x_axis_font_size;
174                }
175                if let Some(x_axis_font_color) = get_color_from_value(&data, "x_axis_font_color") {
176                    self.x_axis_font_color = x_axis_font_color;
177                }
178                if let Some(x_axis_font_weight) = get_string_from_value(&data, "x_axis_font_weight") {
179                    self.x_axis_font_weight = Some(x_axis_font_weight);
180                }
181                if let Some(x_axis_name_gap) = get_f32_from_value(&data, "x_axis_name_gap") {
182                    self.x_axis_name_gap = x_axis_name_gap;
183                }
184                if let Some(x_axis_name_rotate) = get_f32_from_value(&data, "x_axis_name_rotate") {
185                    self.x_axis_name_rotate = x_axis_name_rotate;
186                }
187                if let Some(x_axis_margin) = get_margin_from_value(&data, "x_axis_margin") {
188                    self.x_axis_margin = Some(x_axis_margin);
189                }
190                if let Some(x_boundary_gap) = get_bool_from_value(&data, "x_boundary_gap") {
191                    self.x_boundary_gap = Some(x_boundary_gap);
192                }
193
194                if let Some(y_axis_configs) = get_y_axis_configs_from_value(theme.clone(), &data, "y_axis_configs") {
195                    self.y_axis_configs = y_axis_configs;
196                }
197
198                if let Some(grid_stroke_color) = get_color_from_value(&data, "grid_stroke_color") {
199                    self.grid_stroke_color = grid_stroke_color;
200                }
201                if let Some(grid_stroke_width) = get_f32_from_value(&data, "grid_stroke_width") {
202                    self.grid_stroke_width = grid_stroke_width;
203                }
204
205                if let Some(series_stroke_width) = get_f32_from_value(&data, "series_stroke_width") {
206                    self.series_stroke_width = series_stroke_width;
207                }
208                if let Some(series_label_font_color) =
209                    get_color_from_value(&data, "series_label_font_color")
210                {
211                    self.series_label_font_color = series_label_font_color;
212                }
213                if let Some(series_label_font_size) = get_f32_from_value(&data, "series_label_font_size") {
214                    self.series_label_font_size = series_label_font_size;
215                }
216                if let Some(series_label_font_weight) = get_string_from_value(&data, "series_label_font_weight") {
217                    self.series_label_font_weight = Some(series_label_font_weight);
218                }
219                if let Some(series_label_formatter) = get_string_from_value(&data, "series_label_formatter") {
220                    self.series_label_formatter = series_label_formatter;
221                }
222
223                if let Some(series_colors) = get_color_slice_from_value(&data, "series_colors") {
224                    self.series_colors = series_colors;
225                }
226                if let Some(series_symbol) = get_series_symbol_from_value(&data, "series_symbol") {
227                    self.series_symbol = Some(series_symbol);
228                }
229                if let Some(series_smooth) = get_bool_from_value(&data, "series_smooth") {
230                    self.series_smooth = series_smooth;
231                }
232                if let Some(series_fill) = get_bool_from_value(&data, "series_fill") {
233                    self.series_fill = series_fill;
234                }
235
236                Ok(data)
237            }
238            /// Gets y axis config by index.
239            fn get_y_axis_config(&self, index: usize) -> YAxisConfig {
240                let size = self.y_axis_configs.len();
241                if size == 0 {
242                    YAxisConfig::default()
243                } else if index < size {
244                    self.y_axis_configs[index].clone()
245                } else {
246                    self.y_axis_configs[0].clone()
247                }
248            }
249            /// Gets y axis values by index.
250            fn get_y_axis_values(&self, y_axis_index: usize) -> (AxisValues, f32) {
251                let y_axis_config = self.get_y_axis_config(y_axis_index);
252                let mut data_list = vec![];
253                for series in self.series_list.iter() {
254                    if series.y_axis_index == y_axis_index {
255                        data_list.append(series.data.clone().as_mut());
256                    }
257                }
258                if data_list.is_empty() {
259                   return (AxisValues::default(), 0.0);
260                }
261                let mut thousands_format = false;
262                if let Some(ref value) = y_axis_config.axis_formatter {
263                    thousands_format = value.contains(THOUSANDS_FORMAT_LABEL);
264                }
265                let y_axis_values = get_axis_values(AxisValueParams {
266                    data_list,
267                    split_number: y_axis_config.axis_split_number,
268                    reverse: Some(true),
269                    min: y_axis_config.axis_min,
270                    max: y_axis_config.axis_max,
271                    thousands_format,
272                });
273                let y_axis_width = if let Some(value) = y_axis_config.axis_width {
274                    value
275                } else {
276                    let y_axis_formatter = &y_axis_config.axis_formatter.clone().unwrap_or_default();
277                    let mut longest_item: &str = "";
278                    for item in &y_axis_values.data {
279                        if item.chars().count() > longest_item.chars().count() { longest_item = item }
280                    }
281                    let value = format_string(longest_item, y_axis_formatter);
282                    if let Ok(b) = measure_text_width_family(&self.font_family, y_axis_config.axis_font_size, &value)
283                    {
284                        b.width() + 5.0
285                    } else {
286                        DEFAULT_Y_AXIS_WIDTH
287                    }
288                };
289                (y_axis_values, y_axis_width)
290            }
291            /// Renders background for canvas.
292            fn render_background(&self, c: Canvas) {
293                if self.background_color.is_transparent() {
294                    return;
295                }
296                let mut c1 = c;
297                c1.rect(Rect {
298                    fill: Some(self.background_color),
299                    left: 0.0,
300                    top: 0.0,
301                    width: self.width,
302                    height: self.height,
303                    ..Default::default()
304                });
305            }
306            /// Render title widget for canvas.
307            fn render_title(&self, c: Canvas) -> f32 {
308                let mut title_height = 0.0;
309
310                if !self.title_text.is_empty() {
311                    let title_margin = self.title_margin.clone().unwrap_or_default();
312                    let mut x = 0.0;
313                    if let Ok(title_box) =
314                        measure_text_width_family(&self.font_family, self.title_font_size, &self.title_text)
315                    {
316                        x = match self.title_align {
317                            Align::Center => (c.width() - title_box.width()) / 2.0,
318                            Align::Right => c.width() - title_box.width(),
319                            _ => 0.0,
320                        }
321                    }
322                    let title_margin_bottom = title_margin.bottom;
323                    let b = c.child(title_margin).text(Text {
324                        text: self.title_text.clone(),
325                        font_family: Some(self.font_family.clone()),
326                        font_size: Some(self.title_font_size),
327                        font_weight: self.title_font_weight.clone(),
328                        font_color: Some(self.title_font_color),
329                        line_height: Some(self.title_height),
330                        x: Some(x),
331                        ..Default::default()
332                    });
333                    title_height = b.outer_height() + title_margin_bottom;
334                }
335                if !self.sub_title_text.is_empty() {
336                    let mut sub_title_margin = self.sub_title_margin.clone().unwrap_or_default();
337                    let mut x = 0.0;
338                    if let Ok(sub_title_box) = measure_text_width_family(
339                        &self.font_family,
340                        self.sub_title_font_size,
341                        &self.sub_title_text,
342                    ) {
343                        x = match self.sub_title_align {
344                            Align::Center => (c.width() - sub_title_box.width()) / 2.0,
345                            Align::Right => c.width() - sub_title_box.width(),
346                            _ => 0.0,
347                        }
348                    }
349                    let sub_title_margin_bottom = sub_title_margin.bottom;
350                    sub_title_margin.top += self.title_height;
351                    let b = c.child(sub_title_margin).text(Text {
352                        text: self.sub_title_text.clone(),
353                        font_family: Some(self.font_family.clone()),
354                        font_size: Some(self.sub_title_font_size),
355                        font_color: Some(self.sub_title_font_color),
356                        line_height: Some(self.sub_title_height),
357                        font_weight: self.sub_title_font_weight.clone(),
358                        x: Some(x),
359                        ..Default::default()
360                    });
361                    title_height = b.outer_height() + sub_title_margin_bottom;
362                }
363                title_height
364            }
365            /// Renders legend widget for canvas.
366            fn render_legend(&self, c: Canvas) -> f32 {
367                if !self.legend_show.unwrap_or(true) || self.series_list.is_empty() {
368                    return 0.0
369                }
370                let legends: Vec<&str> = self
371                    .series_list
372                    .iter()
373                    .map(|item| item.name.as_str())
374                    .collect();
375                let legend_margin = self.legend_margin.clone().unwrap_or_default();
376                let legend_margin_value = legend_margin.top + legend_margin.bottom;
377                let mut legend_canvas = c.child(legend_margin);
378                let legend_canvas_width = legend_canvas.width();
379                let rows = wrap_legends_to_rows(&self.font_family, self.legend_font_size, &legends, legend_canvas_width);
380                let mut current_legend_index = 0;
381                let legend_unit_height = self.legend_font_size + LEGEND_MARGIN;
382                let mut legend_top = 0.0;
383                let row_count = rows.len();
384                for (row_index, (legend_width, legend_texts)) in rows.iter().enumerate() {
385                    let mut legend_left = match self.legend_align {
386                        Align::Right => legend_canvas_width - legend_width,
387                        Align::Left => 0.0,
388                        Align::Center => (legend_canvas_width - legend_width) / 2.0,
389                    };
390                    if legend_left < 0.0 {
391                        legend_left = 0.0;
392                    }
393                    for text in legend_texts.iter() {
394                        let index = current_legend_index;
395                        current_legend_index += 1;
396                        let Some(series) = &self.series_list.get(index) else {
397                            continue;
398                        };
399                        if series.name.is_empty() {
400                            continue;
401                        }
402                        let color = get_color(&self.series_colors, series.index.unwrap_or(index));
403                        let fill = if self.is_light {
404                            Some(self.background_color)
405                        } else {
406                            Some(color)
407                        };
408                        let b = legend_canvas.legend(Legend {
409                            text: series.name.to_string(),
410                            font_size: self.legend_font_size,
411                            font_family: self.font_family.clone(),
412                            font_color: Some(self.legend_font_color),
413                            font_weight: self.legend_font_weight.clone(),
414                            stroke_color: Some(color),
415                            fill,
416                            left: legend_left,
417                            top: legend_top,
418                            category: self.legend_category.clone(),
419                        });
420                        legend_left += b.width() + LEGEND_MARGIN;
421                    }
422                    // if not the last row, add the legend unit height
423                    if row_index < row_count - 1 {
424                        legend_top += legend_unit_height;
425                    }
426                }
427                legend_unit_height + legend_top + legend_margin_value
428            }
429            /// Renders grid for canvas, the axis width is the right padding of grid canvas,
430            /// and the axis height is the bottom padding of grid canvas.
431            fn render_grid(&self, c: Canvas, axis_width: f32, axis_height: f32) {
432                let mut c1 = c;
433                let y_axis_config = self.get_y_axis_config(0);
434                let axis_split_number = y_axis_config.axis_split_number;
435                c1.grid(Grid {
436                    right: axis_width,
437                    bottom: axis_height,
438                    color: Some(self.grid_stroke_color),
439                    stroke_width: self.grid_stroke_width,
440                    horizontals: axis_split_number,
441                    hidden_horizontals: vec![axis_split_number],
442                    ..Default::default()
443                });
444            }
445            /// Renders y axis for canvas, if the axis index greater than zero means the right y axis.
446            fn render_y_axis(&self, c: Canvas, data: Vec<String>, axis_height: f32, axis_width: f32, axis_index: usize) {
447                let mut c1 = c;
448                let y_axis_config = &self.get_y_axis_config(axis_index);
449                let mut position = Position::Left;
450                if axis_index > 0 {
451                    position = Position::Right;
452                }
453                let mut name_align = Align::Left;
454                if let Some(value) = &y_axis_config.axis_name_align {
455                    name_align = value.clone();
456                }
457                let margin = y_axis_config.axis_margin.clone().unwrap_or_default();
458                c1.child(margin).axis(Axis {
459                    position,
460                    height: axis_height,
461                    width: axis_width,
462                    split_number: y_axis_config.axis_split_number,
463                    font_family: self.font_family.clone(),
464                    stroke_color: Some(y_axis_config.axis_stroke_color),
465                    name_align,
466                    name_gap: y_axis_config.axis_name_gap,
467                    font_color: Some(y_axis_config.axis_font_color),
468                    font_size: y_axis_config.axis_font_size,
469                    font_weight: y_axis_config.axis_font_weight.clone(),
470                    data,
471                    formatter: y_axis_config.axis_formatter.clone(),
472                    ..Default::default()
473                });
474            }
475            /// Renders x axis widget for canvas, the x_boundary_gap parameter set to false,
476            /// the align will be left.
477            fn render_x_axis(&self, c: Canvas, data: Vec<String>, axis_width: f32) {
478                let mut c1 = c;
479
480                let mut split_number = data.len();
481                let name_align = if self.x_boundary_gap.unwrap_or(true) {
482                    Align::Center
483                } else {
484                    split_number -= 1;
485                    Align::Left
486                };
487                let margin = self.x_axis_margin.clone().unwrap_or_default();
488                c1.child(margin).axis(Axis {
489                    height: self.x_axis_height,
490                    width: axis_width,
491                    split_number,
492                    font_family: self.font_family.clone(),
493                    data,
494                    font_color: Some(self.x_axis_font_color),
495                    font_weight: self.x_axis_font_weight.clone(),
496                    stroke_color: Some(self.x_axis_stroke_color),
497                    font_size: self.x_axis_font_size,
498                    name_gap: self.x_axis_name_gap,
499                    name_rotate: self.x_axis_name_rotate,
500                    name_align,
501                    ..Default::default()
502                });
503            }
504            /// Renders series label widget for canvas.
505            fn render_series_label(&self, c:Canvas, series_labels_list: Vec<Vec<SeriesLabel>>) {
506                if series_labels_list.is_empty() {
507                    return;
508                }
509                let mut c1 = c;
510                for series_labels in series_labels_list.iter() {
511                    for series_label in series_labels.iter() {
512                        let mut dx = None;
513                        if let Ok(value) = measure_text_width_family(
514                            &self.font_family,
515                            self.series_label_font_size,
516                            &series_label.text,
517                        ) {
518                            dx = Some(-value.width() / 2.0);
519                        }
520                        c1.text(Text {
521                            text: series_label.text.clone(),
522                            dy: Some(-8.0),
523                            dx,
524                            font_family: Some(self.font_family.clone()),
525                            font_color: Some(self.series_label_font_color),
526                            font_size: Some(self.series_label_font_size),
527                            font_weight: self.series_label_font_weight.clone(),
528                            x: Some(series_label.point.x),
529                            y: Some(series_label.point.y),
530                            ..Default::default()
531                        });
532                    }
533                }
534            }
535            /// Renders the bar widget for canvas.
536            fn render_bar(
537                &self,
538                c: Canvas,
539                series_list: &[&Series],
540                y_axis_values_list: &[&AxisValues],
541                max_height: f32,
542                series_data_count: usize,
543                radius: Option<f32>,
544            ) -> Vec<Vec<SeriesLabel>> {
545                if series_list.is_empty() {
546                    return vec![];
547                }
548                let mut c1 = c;
549
550                let unit_width = c1.width() / series_data_count as f32;
551                let bar_chart_margin = 5.0_f32;
552                let bar_chart_gap = 3.0_f32;
553
554                let bar_chart_margin_width = bar_chart_margin * 2.0;
555                let bar_chart_gap_width = bar_chart_gap * (series_list.len() - 1) as f32;
556                let bar_width = (unit_width - bar_chart_margin_width - bar_chart_gap_width) / series_list.len() as f32;
557                let half_bar_width = bar_width / 2.0;
558
559                let mut series_labels_list = vec![];
560                let get_bar_color = |colors: &Option<Vec<Option<Color>>>, index: usize| -> Option<Color> {
561                    if let Some(colors) = &colors  {
562                        if colors.len() <= index {
563                            return None;
564                        }
565                        if let Some(color) = colors[index] {
566                            return Some(color);
567                        }
568                    }
569                    None
570                };
571                for (index, series) in series_list.iter().enumerate() {
572                    let y_axis_values = if index >= y_axis_values_list.len() {
573                        y_axis_values_list[0]
574                    } else {
575                        y_axis_values_list[series.y_axis_index]
576                    };
577                    let color = get_color(&self.series_colors, series.index.unwrap_or(index));
578                    let mut series_labels = vec![];
579                    for (i, p) in series.data.iter().enumerate() {
580                        let value = p.to_owned();
581                        // nil value忽略
582                        if value == NIL_VALUE {
583                            continue;
584                        }
585                        let mut left = unit_width * (i + series.start_index) as f32 + bar_chart_margin;
586                        left += (bar_width + bar_chart_gap) * index as f32;
587
588                        let y = y_axis_values.get_offset_height(value, max_height);
589
590                        let mut fill = get_bar_color(&series.colors, i);
591                        if fill.is_none() {
592                            fill = Some(color);
593                        }
594
595                        c1.rect(Rect {
596                            fill,
597                            left,
598                            top: y,
599                            width: bar_width,
600                            height: max_height - y,
601                            rx: radius,
602                            ry: radius,
603                            ..Default::default()
604                        });
605                        series_labels.push(SeriesLabel{
606                            point: (left + half_bar_width, y).into(),
607                            text: format_series_value(p.to_owned(), &self.series_label_formatter),
608                        })
609                    }
610                    if series.label_show {
611                        series_labels_list.push(series_labels);
612                    }
613                }
614                series_labels_list
615            }
616            /// Renders the line widget for canvas.
617            fn render_line(
618                &self,
619                c: Canvas,
620                series_list: &[&Series],
621                y_axis_values_list: &[&AxisValues],
622                max_height: f32,
623                axis_height: f32,
624                series_data_count: usize,
625            ) -> Vec<Vec<SeriesLabel>> {
626                if series_list.is_empty() {
627                    return vec![];
628                }
629                let mut c1 = c;
630                let x_boundary_gap = self.x_boundary_gap.unwrap_or(true);
631                let mut split_unit_offset = 0.0;
632                if !x_boundary_gap {
633                    split_unit_offset = 1.0;
634                }
635                let mut series_labels_list = vec![];
636
637                for (index, series) in series_list.iter().enumerate() {
638                    let y_axis_values = if series.y_axis_index >= y_axis_values_list.len() {
639                        y_axis_values_list[0]
640                    } else {
641                        y_axis_values_list[series.y_axis_index]
642                    };
643                    let split_unit_count = series_data_count as f32 - split_unit_offset;
644                    let unit_width = c1.width() / split_unit_count;
645                    let mut points: Vec<Point> = vec![];
646                    let mut points_list: Vec<Vec<Point>> = vec![];
647                    let mut series_labels = vec![];
648
649                    let mut max_value = f32::MIN;
650                    let mut min_value = f32::MAX;
651                    let mut max_index = 0;
652                    let mut min_index = 0;
653                    for (i, p) in series.data.iter().enumerate() {
654                        let value = p.to_owned();
655                        if value == NIL_VALUE {
656                            if !points.is_empty() {
657                                points_list.push(points);
658                                points = vec![];
659                            }
660                            continue;
661                        }
662                        if value > max_value {
663                            max_value = value;
664                            max_index = i;
665                        }
666                        if value < min_value {
667                            min_value = value;
668                            min_index = i;
669                        }
670                        // 居中
671                        let mut x = unit_width * (i + series.start_index) as f32;
672                        if x_boundary_gap {
673                            x += unit_width / 2.0;
674                        }
675                        let y = y_axis_values.get_offset_height(value, max_height);
676                        points.push((x, y).into());
677                        series_labels.push(SeriesLabel{
678                            point: (x, y).into(),
679                            text: format_series_value(value, &self.series_label_formatter),
680                        })
681                    }
682                    if series.label_show {
683                        series_labels_list.push(series_labels.clone());
684                    }
685                    if !points.is_empty() {
686                        points_list.push(points);
687                    }
688
689                    let color = get_color(&self.series_colors, series.index.unwrap_or(index));
690
691                    let fill = color.with_alpha(100);
692                    let series_fill = self.series_fill;
693                    for points in points_list.iter() {
694                        if self.series_smooth {
695                            if series_fill {
696                                c1.smooth_line_fill(SmoothLineFill {
697                                    fill,
698                                    points: points.clone(),
699                                    bottom: axis_height,
700                                });
701                            }
702                            c1.smooth_line(SmoothLine {
703                                points: points.clone(),
704                                color: Some(color),
705                                stroke_width: self.series_stroke_width,
706                                symbol: self.series_symbol.clone(),
707                                stroke_dash_array: series.stroke_dash_array.clone(),
708                            });
709                        } else {
710                            if series_fill {
711                                c1.straight_line_fill(StraightLineFill {
712                                    fill,
713                                    points: points.clone(),
714                                    bottom: axis_height,
715                                    ..Default::default()
716                                });
717                            }
718                            c1.straight_line(StraightLine {
719                                points: points.clone(),
720                                color: Some(color),
721                                stroke_width: self.series_stroke_width,
722                                symbol: self.series_symbol.clone(),
723                                stroke_dash_array: series.stroke_dash_array.clone(),
724                                ..Default::default()
725                            });
726                        }
727                    }
728                    for mark_point in series.mark_points.iter() {
729                        let index = match mark_point.category {
730                            MarkPointCategory::Max => max_index,
731                            MarkPointCategory::Min => min_index,
732                        };
733                        if let Some(ref label) = series_labels.get(index) {
734                            let r = 15.0;
735                            let y = label.point.y - r * 2.0;
736                            c1.bubble(Bubble{
737                                x: label.point.x,
738                                y,
739                                r,
740                                fill: color,
741                            });
742                            let mut dx = None;
743                            if let Ok(value) = measure_text_width_family(
744                                &self.font_family,
745                                self.series_label_font_size,
746                                &label.text,
747                            ) {
748                                dx = Some(-value.width() / 2.0 + 1.0);
749                            }
750                            let font_color = if color.is_light() {
751                                "#464646".into()
752                            } else {
753                                "#D8D9DA".into()
754                            };
755                            c1.text(Text {
756                                text: label.text.clone(),
757                                line_height: Some(r) ,
758                                dx,
759                                font_color: Some(font_color),
760                                font_family: Some(self.font_family.clone()),
761                                font_size: Some(self.series_label_font_size),
762                                x: Some(label.point.x),
763                                y: Some(y - r * 0.5 + 2.0),
764                                ..Default::default()
765                            });
766                        }
767                    }
768
769                }
770                series_labels_list
771            }
772        }
773    };
774    gen.into()
775}