1
/*!
2
The `page` module provides structures for laying out and rendering multiple views.
3
*/
4

5
use std::ffi::OsStr;
6
use std::path::Path;
7

8
use svg;
9
use svg::Document;
10
use svg::Node;
11

12
use crate::errors::Result;
13
use crate::view::View;
14

15
use failure::ResultExt;
16

17
/**
18
A single page page laying out the views in a grid
19
*/
20
pub struct Page<'a> {
21
    views: Vec<&'a dyn View>,
22
    num_views: u32,
23
    dimensions: (u32, u32),
24
}
25

26
impl<'a> Page<'a> {
27
    /**
28
    Creates an empty page container for plots to be added to
29
    */
30 2
    pub fn empty() -> Self {
31
        Page {
32 2
            views: Vec::new(),
33
            num_views: 0,
34 2
            dimensions: (600, 400),
35
        }
36
    }
37

38
    /**
39
    Creates a plot containing a single view
40
    */
41 2
    pub fn single(view: &'a dyn View) -> Self {
42 2
        Page::empty().add_plot(view)
43
    }
44

45
    /// Set the dimensions of the plot.
46 0
    pub fn dimensions(mut self, x: u32, y: u32) -> Self {
47 0
        self.dimensions = (x, y);
48 0
        self
49
    }
50

51
    /// Add a view to the plot
52 2
    pub fn add_plot(mut self, view: &'a dyn View) -> Self {
53 2
        self.views.push(view);
54 2
        self.num_views += 1;
55 2
        self
56
    }
57

58
    /**
59
    Render the plot to an svg document
60
    */
61 2
    pub fn to_svg(&self) -> Result<svg::Document> {
62 2
        let (width, height) = self.dimensions;
63 2
        let mut document = Document::new().set("viewBox", (0, 0, width, height));
64

65 2
        let x_margin = 120; // should actually depend on y-axis label font size
66 2
        let y_margin = 60;
67 2
        let x_offset = 0.6 * f64::from(x_margin);
68 2
        let y_offset = 0.6 * f64::from(y_margin);
69

70
        // TODO put multiple views in correct places
71 2
        for &view in &self.views {
72 2
            let view_group = view
73 2
                .to_svg(f64::from(width - x_margin), f64::from(height - y_margin))?
74 0
                .set(
75 0
                    "transform",
76 2
                    format!("translate({}, {})", x_offset, f64::from(height) - y_offset),
77
                );
78 2
            document.append(view_group);
79
        }
80 2
        Ok(document)
81
    }
82

83
    /**
84
    Render the plot to an `String`
85
    */
86 0
    pub fn to_text(&self) -> Result<String> {
87 0
        let (width, height) = self.dimensions;
88
        // TODO compose multiple views into a page
89 0
        let view = self.views[0];
90 0
        view.to_text(width, height)
91
    }
92

93
    /**
94
    Save the plot to a file.
95

96
    The type of file will be based on the file extension.
97
    */
98

99 2
    pub fn save<P>(&self, path: P) -> Result<()>
100
    where
101
        P: AsRef<Path>,
102
    {
103 2
        match path.as_ref().extension().and_then(OsStr::to_str) {
104 2
            Some("svg") => svg::save(path, &self.to_svg()?)
105
                .context("saving svg")
106 2
                .map_err(From::from),
107 0
            _ => Ok(()),
108
        }
109
    }
110
}

Read our documentation on viewing source code .

Loading