use crate::error::Result;
use crate::grammar::annotation::Annotation;
use crate::grammar::coord::CoordSystem;
use crate::grammar::facet::{Facet, FacetScales};
use crate::grammar::layer::Layer;
use crate::new_theme::NewTheme;
use esoc_scene::SceneGraph;
#[derive(Clone, Debug)]
pub struct Chart {
pub layers: Vec<Layer>,
pub title: Option<String>,
pub x_label: Option<String>,
pub y_label: Option<String>,
pub width: f32,
pub height: f32,
pub theme: NewTheme,
pub annotations: Vec<Annotation>,
pub subtitle: Option<String>,
pub caption: Option<String>,
pub description: Option<String>,
pub coord: CoordSystem,
pub facet: Facet,
pub facet_scales: FacetScales,
pub x_domain: Option<(f64, f64)>,
pub y_domain: Option<(f64, f64)>,
pub legend_title: Option<String>,
}
impl Chart {
pub fn new() -> Self {
Self {
layers: Vec::new(),
title: None,
x_label: None,
y_label: None,
width: 800.0,
height: 600.0,
theme: NewTheme::default(),
annotations: Vec::new(),
subtitle: None,
caption: None,
description: None,
coord: CoordSystem::default(),
facet: Facet::default(),
facet_scales: FacetScales::default(),
x_domain: None,
y_domain: None,
legend_title: None,
}
}
pub fn layer(mut self, layer: Layer) -> Self {
self.layers.push(layer);
self
}
pub fn title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn x_label(mut self, label: impl Into<String>) -> Self {
self.x_label = Some(label.into());
self
}
pub fn y_label(mut self, label: impl Into<String>) -> Self {
self.y_label = Some(label.into());
self
}
pub fn size(mut self, width: f32, height: f32) -> Self {
self.width = width;
self.height = height;
self
}
pub fn theme(mut self, theme: NewTheme) -> Self {
self.theme = theme;
self
}
pub fn annotate(mut self, annotation: Annotation) -> Self {
self.annotations.push(annotation);
self
}
pub fn subtitle(mut self, subtitle: impl Into<String>) -> Self {
self.subtitle = Some(subtitle.into());
self
}
pub fn caption(mut self, caption: impl Into<String>) -> Self {
self.caption = Some(caption.into());
self
}
pub fn description(mut self, desc: impl Into<String>) -> Self {
self.description = Some(desc.into());
self
}
pub fn coord(mut self, coord: CoordSystem) -> Self {
self.coord = coord;
self
}
pub fn facet(mut self, facet: Facet) -> Self {
self.facet = facet;
self
}
pub fn facet_scales(mut self, scales: FacetScales) -> Self {
self.facet_scales = scales;
self
}
pub fn x_domain(mut self, min: f64, max: f64) -> Self {
self.x_domain = Some((min, max));
self
}
pub fn y_domain(mut self, min: f64, max: f64) -> Self {
self.y_domain = Some((min, max));
self
}
pub fn legend_title(mut self, title: impl Into<String>) -> Self {
self.legend_title = Some(title.into());
self
}
pub fn build(&self) -> Result<SceneGraph> {
crate::compile::compile_chart(self)
}
pub fn to_svg(&self) -> Result<String> {
let scene = self.build()?;
let svg = esoc_gfx::scene_svg::render_scene_svg_with_metadata(
&scene,
self.width,
self.height,
self.title.as_deref(),
self.description.as_deref(),
)?;
Ok(svg)
}
#[deprecated(note = "Use save_svg_to(path) which accepts impl AsRef<Path>")]
pub fn save_svg(&self, path: &str) -> Result<()> {
self.save_svg_to(path)
}
pub fn save_svg_to(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
let svg = self.to_svg()?;
std::fs::write(path, svg)?;
Ok(())
}
#[cfg(feature = "png")]
pub fn to_png(&self) -> Result<Vec<u8>> {
let scene = self.build()?;
let bytes = esoc_gfx::scene_svg::render_scene_png(&scene, self.width, self.height)?;
Ok(bytes)
}
#[cfg(feature = "png")]
#[deprecated(note = "Use save_png_to(path) which accepts impl AsRef<Path>")]
pub fn save_png(&self, path: &str) -> Result<()> {
self.save_png_to(path)
}
#[cfg(feature = "png")]
pub fn save_png_to(&self, path: impl AsRef<std::path::Path>) -> Result<()> {
let bytes = self.to_png()?;
std::fs::write(path, bytes)?;
Ok(())
}
}
impl Default for Chart {
fn default() -> Self {
Self::new()
}
}