1use std::ffi::OsStr;
6use std::path::Path;
7
8use svg;
9use svg::Document;
10use svg::Node;
11
12use crate::errors::Result;
13use crate::view::View;
14
15use failure::ResultExt;
16
17pub struct Page<'a> {
21 views: Vec<&'a dyn View>,
22 num_views: u32,
23 dimensions: (u32, u32),
24}
25
26impl<'a> Page<'a> {
27 pub fn empty() -> Self {
31 Page {
32 views: Vec::new(),
33 num_views: 0,
34 dimensions: (600, 400),
35 }
36 }
37
38 pub fn single(view: &'a dyn View) -> Self {
42 Page::empty().add_plot(view)
43 }
44
45 pub fn dimensions(mut self, x: u32, y: u32) -> Self {
47 self.dimensions = (x, y);
48 self
49 }
50
51 pub fn add_plot(mut self, view: &'a dyn View) -> Self {
53 self.views.push(view);
54 self.num_views += 1;
55 self
56 }
57
58 pub fn to_svg(&self) -> Result<svg::Document> {
62 let (width, height) = self.dimensions;
63 let mut document = Document::new().set("viewBox", (0, 0, width, height));
64
65 let x_margin = 120; let y_margin = 60;
67 let x_offset = 0.6 * f64::from(x_margin);
68 let y_offset = 0.6 * f64::from(y_margin);
69
70 for &view in &self.views {
72 let view_group = view
73 .to_svg(f64::from(width - x_margin), f64::from(height - y_margin))?
74 .set(
75 "transform",
76 format!("translate({}, {})", x_offset, f64::from(height) - y_offset),
77 );
78 document.append(view_group);
79 }
80 Ok(document)
81 }
82
83 pub fn to_text(&self) -> Result<String> {
87 let (width, height) = self.dimensions;
88 let view = self.views[0];
90 view.to_text(width, height)
91 }
92
93 pub fn save<P>(&self, path: P) -> Result<()>
100 where
101 P: AsRef<Path>,
102 {
103 match path.as_ref().extension().and_then(OsStr::to_str) {
104 Some("svg") => svg::save(path, &self.to_svg()?)
105 .context("saving svg")
106 .map_err(From::from),
107 _ => Ok(()),
108 }
109 }
110}