use std;
use std::f64;
use svg;
use svg::Node;
use representation::Representation;
use axis;
use svg_render;
use text_render;
#[derive(Default)]
pub struct View<'a> {
pub representations: Vec<&'a Representation>,
x_range: Option<axis::Range>,
y_range: Option<axis::Range>,
x_label: Option<String>,
y_label: Option<String>,
}
impl<'a> View<'a> {
pub fn new() -> View<'a> {
View {
representations: vec![],
x_range: None,
y_range: None,
x_label: None,
y_label: None,
}
}
pub fn add(mut self, repr: &'a Representation) -> Self {
self.representations.push(repr);
self
}
pub fn x_range(mut self, min: f64, max: f64) -> Self {
self.x_range = Some(axis::Range::new(min, max));
self
}
pub fn y_range(mut self, min: f64, max: f64) -> Self {
self.y_range = Some(axis::Range::new(min, max));
self
}
pub fn x_label<T>(mut self, value: T) -> Self
where
T: Into<String>,
{
self.x_label = Some(value.into());
self
}
pub fn y_label<T>(mut self, value: T) -> Self
where
T: Into<String>,
{
self.y_label = Some(value.into());
self
}
fn default_x_range(&self) -> axis::Range {
let mut x_min = f64::INFINITY;
let mut x_max = f64::NEG_INFINITY;
for repr in &self.representations {
let (this_x_min, this_x_max) = repr.range(0);
x_min = x_min.min(this_x_min);
x_max = x_max.max(this_x_max);
}
axis::Range::new(x_min, x_max)
}
fn default_y_range(&self) -> axis::Range {
let mut y_min = f64::INFINITY;
let mut y_max = f64::NEG_INFINITY;
for repr in &self.representations {
let (this_y_min, this_y_max) = repr.range(1);
y_min = y_min.min(this_y_min);
y_max = y_max.max(this_y_max);
}
axis::Range::new(y_min, y_max)
}
fn create_axes(&self) -> (axis::Axis, axis::Axis) {
let default_x_range = self.default_x_range();
let x_range = self.x_range.as_ref().unwrap_or(&default_x_range);
let default_y_range = self.default_y_range();
let y_range = self.y_range.as_ref().unwrap_or(&default_y_range);
let default_x_label = "".to_string();
let x_label: String = self.x_label.clone().unwrap_or(default_x_label);
let default_y_label = "".to_string();
let y_label: String = self.y_label.clone().unwrap_or(default_y_label);
let x_axis = axis::Axis::new(x_range.lower, x_range.upper).label(x_label);
let y_axis = axis::Axis::new(y_range.lower, y_range.upper).label(y_label);
(x_axis, y_axis)
}
pub fn to_svg(&self, face_width: f64, face_height: f64) -> svg::node::element::Group {
let mut view_group = svg::node::element::Group::new();
let (x_axis, y_axis) = self.create_axes();
for repr in &self.representations {
let repr_group = repr.to_svg(&x_axis, &y_axis, face_width, face_height);
view_group.append(repr_group);
}
view_group.append(svg_render::draw_x_axis(&x_axis, face_width));
view_group.append(svg_render::draw_y_axis(&y_axis, face_height));
view_group
}
pub fn to_text(&self, face_width: u32, face_height: u32) -> String {
let (x_axis, y_axis) = self.create_axes();
let (y_axis_string, longest_y_label_width) =
text_render::render_y_axis_strings(&y_axis, face_height);
let (x_axis_string, start_offset) = text_render::render_x_axis_strings(&x_axis, face_width);
let left_gutter_width = std::cmp::max(
longest_y_label_width as i32 + 3,
start_offset.wrapping_neg(),
) as u32;
let view_width = face_width + 1 + left_gutter_width + 1;
let view_height = face_height + 4;
let blank: Vec<String> = (0..view_height)
.map(|_| (0..view_width).map(|_| ' ').collect())
.collect();
let mut view_string = blank.join("\n");
for repr in &self.representations {
let face_string = repr.to_text(&x_axis, &y_axis, face_width, face_height);
view_string =
text_render::overlay(&view_string, &face_string, left_gutter_width as i32 + 1, 0);
}
let view_string = text_render::overlay(
&view_string,
&y_axis_string,
left_gutter_width as i32 - 2 - longest_y_label_width,
0,
);
let view_string = text_render::overlay(
&view_string,
&x_axis_string,
left_gutter_width as i32,
face_height as i32,
);
view_string
}
}