1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
5pub enum ExtendValue {
6 Right,
7 Left,
8 Both,
9 None,
10}
11
12#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
13pub enum YLocValue {
14 Price,
15 AboveBar,
16 BelowBar,
17}
18
19#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
20pub enum LabelStyleValue {
21 None,
22 XCross,
23 Cross,
24 TriangleUp,
25 TriangleDown,
26 Flag,
27 Circle,
28 ArrowUp,
29 ArrowDown,
30 LabelUp,
31 LabelDown,
32 LabelLeft,
33 LabelRight,
34 LabelLowerLeft,
35 LabelLowerRight,
36 LabelUpperLeft,
37 LabelUpperRight,
38 LabelCenter,
39 Square,
40 Diamond,
41}
42
43#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
44pub enum LineStyleValue {
45 Solid,
46 Dotted,
47 Dashed,
48 ArrowLeft,
49 ArrowRight,
50 ArrowBoth,
51}
52
53#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq, Eq, Hash)]
54pub enum BoxStyleValue {
55 Solid,
56 Dotted,
57 Dashed,
58}
59
60#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
61pub struct GraphicLabel {
62 pub id: u64,
63 pub x: Option<f64>,
64 pub y: f64,
65 pub y_loc: YLocValue,
66 pub text: String,
67 pub style: LabelStyleValue,
68 pub color: u32,
69 pub text_color: u32,
70 pub size: String,
71 pub text_align: String,
72 pub tool_tip: String,
73}
74
75#[derive(Debug, Clone, Deserialize, Serialize, Copy, PartialEq)]
76pub struct GraphicLine {
77 pub id: u64,
78 pub x1: Option<f64>,
79 pub y1: f64,
80 pub x2: Option<f64>,
81 pub y2: f64,
82 pub extend: ExtendValue,
83 pub style: LineStyleValue,
84 pub color: u32,
85 pub width: f64,
86}
87
88#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
89pub struct GraphicBox {
90 pub id: u64,
91 pub x1: Option<f64>,
92 pub y1: f64,
93 pub x2: Option<f64>,
94 pub y2: f64,
95 pub color: u32,
96 pub bg_color: u32,
97 pub extend: ExtendValue,
98 pub style: BoxStyleValue,
99 pub width: f64,
100 pub text: String,
101 pub text_size: String,
102 pub text_color: u32,
103 pub text_v_align: String,
104 pub text_h_align: String,
105 pub text_wrap: String,
106}
107
108#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
109pub struct GraphicData {
110 pub labels: Vec<GraphicLabel>,
111 pub lines: Vec<GraphicLine>,
112 pub boxes: Vec<GraphicBox>,
113}
114
115fn translate_extend(value: &str) -> ExtendValue {
116 match value {
117 "r" => ExtendValue::Right,
118 "l" => ExtendValue::Left,
119 "b" => ExtendValue::Both,
120 "n" => ExtendValue::None,
121 _ => ExtendValue::None,
122 }
123}
124
125fn translate_y_loc(value: &str) -> YLocValue {
126 match value {
127 "pr" => YLocValue::Price,
128 "ab" => YLocValue::AboveBar,
129 "bl" => YLocValue::BelowBar,
130 _ => YLocValue::Price,
131 }
132}
133
134fn translate_label_style(value: &str) -> LabelStyleValue {
135 match value {
136 "n" => LabelStyleValue::None,
137 "xcr" => LabelStyleValue::XCross,
138 "cr" => LabelStyleValue::Cross,
139 "tup" => LabelStyleValue::TriangleUp,
140 "tdn" => LabelStyleValue::TriangleDown,
141 "flg" => LabelStyleValue::Flag,
142 "cir" => LabelStyleValue::Circle,
143 "aup" => LabelStyleValue::ArrowUp,
144 "adn" => LabelStyleValue::ArrowDown,
145 "lup" => LabelStyleValue::LabelUp,
146 "ldn" => LabelStyleValue::LabelDown,
147 "llf" => LabelStyleValue::LabelLeft,
148 "lrg" => LabelStyleValue::LabelRight,
149 "llwlf" => LabelStyleValue::LabelLowerLeft,
150 "llwrg" => LabelStyleValue::LabelLowerRight,
151 "luplf" => LabelStyleValue::LabelUpperLeft,
152 "luprg" => LabelStyleValue::LabelUpperRight,
153 "lcn" => LabelStyleValue::LabelCenter,
154 "sq" => LabelStyleValue::Square,
155 "dia" => LabelStyleValue::Diamond,
156 _ => LabelStyleValue::None,
157 }
158}
159
160fn translate_line_style(value: &str) -> LineStyleValue {
161 match value {
162 "sol" => LineStyleValue::Solid,
163 "dot" => LineStyleValue::Dotted,
164 "dsh" => LineStyleValue::Dashed,
165 "al" => LineStyleValue::ArrowLeft,
166 "ar" => LineStyleValue::ArrowRight,
167 "ab" => LineStyleValue::ArrowBoth,
168 _ => LineStyleValue::Solid,
169 }
170}
171
172fn translate_box_style(value: &str) -> BoxStyleValue {
173 match value {
174 "sol" => BoxStyleValue::Solid,
175 "dot" => BoxStyleValue::Dotted,
176 "dsh" => BoxStyleValue::Dashed,
177 _ => BoxStyleValue::Solid,
178 }
179}
180
181pub fn graphics_parser(data: &Value) -> GraphicData {
182 let indexes = data
183 .get("indexes")
184 .and_then(|v| v.as_array().cloned())
185 .unwrap_or_default();
186
187 let raw_graphic = data.get("graphic").unwrap_or(&Value::Null);
188
189 let labels = if let Some(dwglabels) = raw_graphic.get("dwglabels").and_then(|v| v.as_object()) {
191 dwglabels
192 .values()
193 .filter_map(|l| {
194 Some(GraphicLabel {
195 id: l.get("id")?.as_u64()?,
196 x: l.get("x")
197 .and_then(|x| x.as_u64())
198 .and_then(|idx| indexes.get(idx as usize))
199 .and_then(|v| v.as_f64()),
200 y: l.get("y")?.as_f64()?,
201 y_loc: translate_y_loc(l.get("yl")?.as_str()?),
202 text: l.get("t")?.as_str()?.to_string(),
203 style: translate_label_style(l.get("st")?.as_str()?),
204 color: l.get("ci")?.as_u64()? as u32,
205 text_color: l.get("tci")?.as_u64()? as u32,
206 size: l.get("sz")?.as_str()?.to_string(),
207 text_align: l.get("ta")?.as_str()?.to_string(),
208 tool_tip: l.get("tt")?.as_str()?.to_string(),
209 })
210 })
211 .collect()
212 } else {
213 vec![]
214 };
215
216 let lines = if let Some(dwglines) = raw_graphic.get("dwglines").and_then(|v| v.as_object()) {
218 dwglines
219 .values()
220 .filter_map(|l| {
221 Some(GraphicLine {
222 id: l.get("id")?.as_u64()?,
223 x1: l
224 .get("x1")
225 .and_then(|x| x.as_u64())
226 .and_then(|idx| indexes.get(idx as usize))
227 .and_then(|v| v.as_f64()),
228 y1: l.get("y1")?.as_f64()?,
229 x2: l
230 .get("x2")
231 .and_then(|x| x.as_u64())
232 .and_then(|idx| indexes.get(idx as usize))
233 .and_then(|v| v.as_f64()),
234 y2: l.get("y2")?.as_f64()?,
235 extend: translate_extend(l.get("ex")?.as_str()?),
236 style: translate_line_style(l.get("st")?.as_str()?),
237 color: l.get("ci")?.as_u64()? as u32,
238 width: l.get("w")?.as_f64()?,
239 })
240 })
241 .collect()
242 } else {
243 vec![]
244 };
245
246 let boxes = if let Some(dwgboxes) = raw_graphic.get("dwgboxes").and_then(|v| v.as_object()) {
248 dwgboxes
249 .values()
250 .filter_map(|b| {
251 Some(GraphicBox {
252 id: b.get("id")?.as_u64()?,
253 x1: b
254 .get("x1")
255 .and_then(|x| x.as_u64())
256 .and_then(|idx| indexes.get(idx as usize))
257 .and_then(|v| v.as_f64()),
258 y1: b.get("y1")?.as_f64()?,
259 x2: b
260 .get("x2")
261 .and_then(|x| x.as_u64())
262 .and_then(|idx| indexes.get(idx as usize))
263 .and_then(|v| v.as_f64()),
264 y2: b.get("y2")?.as_f64()?,
265 color: b.get("c")?.as_u64()? as u32,
266 bg_color: b.get("bc")?.as_u64()? as u32,
267 extend: translate_extend(b.get("ex")?.as_str()?),
268 style: translate_box_style(b.get("st")?.as_str()?),
269 width: b.get("w")?.as_f64()?,
270 text: b.get("t")?.as_str()?.to_string(),
271 text_size: b.get("ts")?.as_str()?.to_string(),
272 text_color: b.get("tc")?.as_u64()? as u32,
273 text_v_align: b.get("tva")?.as_str()?.to_string(),
274 text_h_align: b.get("tha")?.as_str()?.to_string(),
275 text_wrap: b.get("tw")?.as_str()?.to_string(),
276 })
277 })
278 .collect()
279 } else {
280 vec![]
281 };
282
283 GraphicData {
284 labels,
285 lines,
286 boxes,
287 }
288}