esoc_chart/grammar/
chart.rs1use crate::error::Result;
5use crate::grammar::annotation::Annotation;
6use crate::grammar::coord::CoordSystem;
7use crate::grammar::facet::{Facet, FacetScales};
8use crate::grammar::layer::Layer;
9use crate::new_theme::NewTheme;
10use esoc_scene::SceneGraph;
11
12#[derive(Clone, Debug)]
14pub struct Chart {
15 pub layers: Vec<Layer>,
17 pub title: Option<String>,
19 pub x_label: Option<String>,
21 pub y_label: Option<String>,
23 pub width: f32,
25 pub height: f32,
27 pub theme: NewTheme,
29 pub annotations: Vec<Annotation>,
31 pub subtitle: Option<String>,
33 pub caption: Option<String>,
35 pub description: Option<String>,
37 pub coord: CoordSystem,
39 pub facet: Facet,
41 pub facet_scales: FacetScales,
43 pub x_domain: Option<(f64, f64)>,
45 pub y_domain: Option<(f64, f64)>,
47 pub legend_title: Option<String>,
49}
50
51impl Chart {
52 pub fn new() -> Self {
54 Self {
55 layers: Vec::new(),
56 title: None,
57 x_label: None,
58 y_label: None,
59 width: 800.0,
60 height: 600.0,
61 theme: NewTheme::default(),
62 annotations: Vec::new(),
63 subtitle: None,
64 caption: None,
65 description: None,
66 coord: CoordSystem::default(),
67 facet: Facet::default(),
68 facet_scales: FacetScales::default(),
69 x_domain: None,
70 y_domain: None,
71 legend_title: None,
72 }
73 }
74
75 pub fn layer(mut self, layer: Layer) -> Self {
77 self.layers.push(layer);
78 self
79 }
80
81 pub fn title(mut self, title: impl Into<String>) -> Self {
83 self.title = Some(title.into());
84 self
85 }
86
87 pub fn x_label(mut self, label: impl Into<String>) -> Self {
89 self.x_label = Some(label.into());
90 self
91 }
92
93 pub fn y_label(mut self, label: impl Into<String>) -> Self {
95 self.y_label = Some(label.into());
96 self
97 }
98
99 pub fn size(mut self, width: f32, height: f32) -> Self {
101 self.width = width;
102 self.height = height;
103 self
104 }
105
106 pub fn theme(mut self, theme: NewTheme) -> Self {
108 self.theme = theme;
109 self
110 }
111
112 pub fn annotate(mut self, annotation: Annotation) -> Self {
114 self.annotations.push(annotation);
115 self
116 }
117
118 pub fn subtitle(mut self, subtitle: impl Into<String>) -> Self {
120 self.subtitle = Some(subtitle.into());
121 self
122 }
123
124 pub fn caption(mut self, caption: impl Into<String>) -> Self {
126 self.caption = Some(caption.into());
127 self
128 }
129
130 pub fn description(mut self, desc: impl Into<String>) -> Self {
132 self.description = Some(desc.into());
133 self
134 }
135
136 pub fn coord(mut self, coord: CoordSystem) -> Self {
138 self.coord = coord;
139 self
140 }
141
142 pub fn facet(mut self, facet: Facet) -> Self {
144 self.facet = facet;
145 self
146 }
147
148 pub fn facet_scales(mut self, scales: FacetScales) -> Self {
150 self.facet_scales = scales;
151 self
152 }
153
154 pub fn x_domain(mut self, min: f64, max: f64) -> Self {
156 self.x_domain = Some((min, max));
157 self
158 }
159
160 pub fn y_domain(mut self, min: f64, max: f64) -> Self {
162 self.y_domain = Some((min, max));
163 self
164 }
165
166 pub fn legend_title(mut self, title: impl Into<String>) -> Self {
168 self.legend_title = Some(title.into());
169 self
170 }
171
172 pub fn build(&self) -> Result<SceneGraph> {
174 crate::compile::compile_chart(self)
175 }
176
177 pub fn to_svg(&self) -> Result<String> {
179 let scene = self.build()?;
180 let svg = esoc_gfx::scene_svg::render_scene_svg_with_metadata(
181 &scene,
182 self.width,
183 self.height,
184 self.title.as_deref(),
185 self.description.as_deref(),
186 )?;
187 Ok(svg)
188 }
189
190 #[deprecated(note = "Use save_svg_to(path) which accepts impl AsRef<Path>")]
192 pub fn save_svg(&self, path: &str) -> Result<()> {
193 self.save_svg_to(path)
194 }
195
196 pub fn save_svg_to(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
198 let svg = self.to_svg()?;
199 std::fs::write(path, svg)?;
200 Ok(())
201 }
202
203 #[cfg(feature = "png")]
205 pub fn to_png(&self) -> Result<Vec<u8>> {
206 let scene = self.build()?;
207 let bytes = esoc_gfx::scene_svg::render_scene_png(&scene, self.width, self.height)?;
208 Ok(bytes)
209 }
210
211 #[cfg(feature = "png")]
213 #[deprecated(note = "Use save_png_to(path) which accepts impl AsRef<Path>")]
214 pub fn save_png(&self, path: &str) -> Result<()> {
215 self.save_png_to(path)
216 }
217
218 #[cfg(feature = "png")]
220 pub fn save_png_to(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
221 let bytes = self.to_png()?;
222 std::fs::write(path, bytes)?;
223 Ok(())
224 }
225}
226
227impl Default for Chart {
228 fn default() -> Self {
229 Self::new()
230 }
231}