1use crate::{
2 chart::*,
3 coord::{Axes, Stick},
4 utils::cal_step::CalStep,
5};
6use chrono::{Datelike, Months, NaiveDate, NaiveDateTime, NaiveTime, ParseError};
7use std::vec;
8
9#[derive(Debug, Clone)]
10pub struct STime {
12 series: Vec<NaiveDateTime>,
13 format: String,
14 dirty: bool,
15 unit: String,
16}
17
18impl Default for STime {
19 fn default() -> Self {
20 Self {
21 series: Default::default(),
22 format: "%Y-%m-%d %H:%M:%S".to_string(),
23 dirty: false,
24 unit: "full".to_string(),
25 }
26 }
27}
28
29impl STime {
30 pub fn new(series: Vec<NaiveDateTime>) -> Self {
31 STime {
33 series,
34 format: "%Y-%m-%d %H:%M:%S".to_string(),
35 dirty: false,
36 unit: "full".to_string(),
37 }
38 }
39
40 pub fn set_format(&self, format: &str) -> Self {
41 STime {
42 series: self.series.clone(),
43 format: format.to_string(),
44 dirty: self.dirty,
45 unit: "full".to_string(),
46 }
47 }
48
49 pub fn set_data(&self, series: Vec<NaiveDateTime>) -> Self {
50 STime {
51 series: series,
52 format: self.format.clone(),
53 dirty: false,
54 unit: "full".to_string(),
55 }
56 }
57
58 pub fn get_unit(&self) -> String {
59 self.unit.clone()
60 }
61
62 pub fn get_format(&self) -> &str {
63 match self.unit.as_str() {
64 "date" => "%Y-%m-%d",
65 "month" => "%Y-%m",
66 "year" => "%Y",
67 "time" => "%H:%M:%S",
68 "hour" => "%H:%M:%S",
69 _ => "",
70 }
71 }
72
73 pub fn series(&self) -> Vec<NaiveDateTime> {
74 self.series.clone()
75 }
76
77 pub fn get_nv(&self, index: usize) -> NaiveDateTime {
78 self.series[index]
79 }
80
81 pub fn merge(&self, other: STime) -> Self {
82 let mut series = self.series.clone();
83 series.extend(&other.series);
84 Self {
85 series: series.clone(),
86 format: self.format.clone(),
87 dirty: self.dirty,
88 unit: self.unit.clone(),
89 }
90 }
91}
92
93impl From<(Vec<&str>, &str, &str)> for STime {
94 fn from(value: (Vec<&str>, &str, &str)) -> Self {
95 let vec = value.0;
96 let format = value.1.to_string();
97 let mut series: Vec<NaiveDateTime> = vec![];
98 let mut dirty = false;
99 let unit = value.2.to_string();
100 for i in 0..vec.len() {
101 let rndt = ndt_parse_from_str(vec[i], value.1, value.2);
102 match rndt {
103 Ok(ndt) => series.push(ndt),
104 Err(_) => dirty = true,
105 }
106 }
107 STime {
108 series,
109 format,
110 dirty,
111 unit,
112 }
113 }
114}
115
116fn ndt_parse_from_str(str: &str, format: &str, get: &str) -> Result<NaiveDateTime, ParseError> {
117 match get {
118 "full" => NaiveDateTime::parse_from_str(str, format),
119 "date" => {
120 let date = NaiveDate::parse_from_str(str, format);
121
122 match date {
123 Ok(d) => {
124 let time = NaiveTime::default();
125 Ok(NaiveDateTime::new(d, time))
126 }
127 Err(e) => Err(e),
128 }
129 }
130 "year" => {
131 let year = format!("{}-01-01", str);
132 ndt_parse_from_str(year.as_str(), "%Y-%m-%d", "date")
133 }
134 "month" => {
135 let month = format!("{}-01", str);
136 ndt_parse_from_str(&month.as_str(), "%Y-%m-%d", "date")
137 }
138
139 _ => NaiveDateTime::parse_from_str(str, format),
140 }
141}
142
143impl ScaleTime for STime {
144 fn domain(&self) -> (NaiveDateTime, NaiveDateTime) {
145 if self.series().len() > 0 {
146 let binding = self.series();
147 let min = binding.iter().min().unwrap();
148 let max = binding.iter().max().unwrap();
149 (*min, *max)
150 } else {
151 (NaiveDateTime::default(), NaiveDateTime::default())
152 }
153 }
154
155 fn domain_unix(&self) -> (f64, f64) {
156 let (min, max) = self.domain();
157 match self.unit.as_str() {
158 "year" => (min.year() as f64, max.year() as f64),
159 "month" => {
160 let min = min.year() as f64 * 12. + min.month0() as f64;
161 let max = max.year() as f64 * 12. + max.month0() as f64;
162 (min, max)
163 }
164 _ => (0., 0.),
165 }
166 }
167
168 fn scale(&self, value: NaiveDateTime) -> f64 {
194 let unit = self.get_unit();
195 match unit.as_str() {
196 "year" => {
197 let (min, max) = self.domain_unix();
198 let range = max - min;
199
200 let diff = value.year() as f64 - min;
201 diff / range
202 }
203 "month" => {
204 let (min, max) = self.domain_unix();
205 let range = max - min;
206 let diff = value.year() as f64 * 12. + value.month0() as f64 - min;
207 diff / range
208 }
209 _ => 1.,
210 }
211 }
212
213 fn gen_axes(&self) -> Axes {
214 let mut style = String::default();
215 let mut vec_stick: Vec<Stick> = vec![];
216 let mut step = 0.;
217 let unit = self.get_unit();
218
219 let (min, max) = self.domain_unix();
220
221 match unit.as_str() {
222 "year" => {
223 style = "time-year".to_string();
224 step = (max - min) / 5.;
225 step = CalStep::new(step).cal_scale();
226
227 let first_stick = (min / step).ceil() * step;
228 let last_stick = (max / step).floor() * step;
229 for value in ((first_stick as i64)..(last_stick as i64 + 1)).step_by(step as usize)
230 {
231 let string_value = value.to_string();
232 let nv = ndt_parse_from_str(string_value.as_str(), "%Y", "year").unwrap();
233 let stick = Stick::new(value.to_string(), self.scale(nv));
234 vec_stick.push(stick);
235 }
236 }
237 "month" => {
238 style = "time-month".to_string();
239 step = cal_scale_time(max - min, "month");
240
241 let first_stick = (min / step).ceil();
242 let last_stick = (max / step).floor();
243
244 let interval = last_stick - first_stick;
245
246 let count = (interval) as i64;
247
248 for index in 0..(count + 1) {
249 let value = (first_stick + index as f64) * step;
250 let year = (value / 12.) as i32;
251 let month = ((value / 12. - year as f64) * 12.).round();
252 let nd = NaiveDate::from_ymd_opt(year, 1, 1).unwrap();
253 let nd = nd.checked_add_months(Months::new(month as u32)).unwrap();
254 let nv = NaiveDateTime::new(nd, NaiveTime::default());
255 let stick = Stick::new(nv.format("%Y-%m").to_string(), self.scale(nv));
256 vec_stick.push(stick);
257 }
258 }
259 _ => (),
260 }
261
262 let sticks = vec_stick
263 .into_iter()
264 .filter(|stick| stick.value >= -0.0000001 && stick.value <= 1.0000001)
265 .collect::<Vec<_>>();
266
267 Axes {
268 sticks,
269 step,
270 style,
271 }
272 }
273
274 fn to_stick(&self) -> Vec<Stick> {
275 let mut vec_stick: Vec<Stick> = vec![];
276 let unit = self.get_unit();
277 let len = self.series().len();
278 match unit.as_str() {
279 "year" => {
280 for index in 0..len {
281 let nv = self.get_nv(index);
282 let string_value = nv.format(self.get_format()).to_string();
283 let stick = Stick::new(string_value, self.scale(nv));
284 vec_stick.push(stick);
285 }
286 }
287 "month" => {
288 for index in 0..len {
289 let nv = self.get_nv(index);
290 let string_value = nv.format(self.get_format()).to_string();
291 let stick = Stick::new(string_value, self.scale(nv));
292 vec_stick.push(stick);
293 }
294 }
295 _ => (),
296 }
297
298 vec_stick
299 }
300}
301
302fn cal_scale_time(num: f64, unit: &str) -> f64 {
303 let num = num / 5.;
304 match unit {
305 "month" => {
306 let step_month = CalStep::new(num / 12.).cal_scale() * 12.;
307 if step_month > 1. {
308 return step_month.round();
309 } else {
310 step_month
311 }
312 }
313 _ => num,
314 }
315}