1#[derive(Debug)]
3pub struct Plotter {
4    dataset: Dataset,
5}
6
7use std::net::{TcpListener, TcpStream};
8use std::io::{Read, Write};
9
10impl Plotter {
11    pub fn new(dataset: Dataset) -> Plotter {
18        Plotter { dataset }
19    }
20
21    pub fn plot(&self, size: (u32, u32), name: &'static str, port: String, options: PlotOptions) {
35        let mut addr = String::from("127.0.0.1:");
36        addr.push_str(&port);
37        let listener = TcpListener::bind(&addr).expect(&format!("Error binding to {}", addr));
38
39        let mut content = format!("var canvas = document.getElementById('c');\ncanvas.height = {};\ncanvas.width = {};\nvar ctx = canvas.getContext('2d');", size.1 + 10, size.0);
40        content.push_str(&format!("ctx.fillStyle = '{}';\n", options.fg_colour.unwrap_or(String::from("black"))));
41
42        let data = self.dataset.data.clone();
43        
44        let max_x = data.clone().into_iter().fold(0.0, |x, acc| if x > acc.x {x} else {acc.x});
45        let min_x = data.clone().into_iter().fold(0.0, |x, acc| if x < acc.x {x} else {acc.x});
46        let max_y = data.clone().into_iter().fold(0.0, |y, acc| if y > acc.x {y} else {acc.y});
47        let min_y = data.clone().into_iter().fold(0.0, |y, acc| if y < acc.x {y} else {acc.y});
48
49        let x_range = max_x - min_x;
50        let y_range = max_y - min_y;
51
52        for point in data {
53            content.push_str(&format!("ctx.fillRect({},{},{});\n",format!("{},{}",
54                ((point.x - min_x)/x_range) * size.0 as f64, 
55                (size.1 as f64 - ((point.y - min_y)/y_range) * size.1 as f64)),
56                options.shape.unwrap_or((10.0,10.0)).0,options.shape.unwrap_or((10.0,10.0)).1
57                ));
58        }
59
60        for stream in listener.incoming() {
61            let stream = stream.unwrap();
62
63            self.handle_connection(stream, &content);
64        }
65    }
66
67    fn handle_connection(&self, mut stream: TcpStream, content: &String) {
68        let mut buffer = [0; 512];
69
70        stream.read(&mut buffer).expect("Error reading request");
71
72        let contents = format!(
73            "<!DOCTYPE html><html><head></head><body><canvas id='c'></canvas><script>{}</script></body></html>",content
74        );
75
76        let response = format!("HTTP/1.1 200 OK\r\n\r\n{}", contents);
77
78        stream
79            .write(response.as_bytes())
80            .expect("Error Formatting response");
81        stream.flush().unwrap();
82    }
83}
84
85#[derive(Clone,Debug)]
87pub struct Dataset {
88    data: Vec<Point>,
89}
90
91impl Dataset {
92    pub fn new() -> Dataset {
94        Dataset { data: Vec::new() }
95    }
96
97    pub fn from_fn(
115        f: &Fn(f64) -> f64,
116        range: (f64, f64),
117        interval: f64,
118        cap: Option<(f64, f64)>,
119    ) -> Dataset {
120        let mut data = Vec::new();
121        let mut c = range.0;
122        while c <= range.1 {
123            let prev_c = c;
124            let result = f(c);
125            c += interval;
126            if cap.is_some(){
127                if (cap.unwrap().0 > result) | (result > cap.unwrap().1) {
128                continue;
129                }
130            }
131            data.push(Point {
132                x: prev_c,
133                y: result,
134            });
135        }
136        Dataset { data }
137    }
138
139    pub fn add_point(&mut self, p: Point) {
147        self.data.push(p);
148    }
149    
150    pub fn join(&mut self, mut other: Dataset) {
164        self.data.append(&mut other.data);
165    }
166}
167
168#[derive(Copy,Clone,Debug)]
170pub struct Point {
171    x: f64,
172    y: f64,
173}
174
175impl Point {
176    pub fn new(x: f64, y: f64) -> Point {
178        Point { x, y }
179    }
180}
181
182pub struct PlotOptions {
191    bg_colour: Option<String>,
192    fg_colour: Option<String>,
193    shape: Option<(f64,f64)>,
194}
195
196impl PlotOptions {
197    pub fn new() -> PlotOptions {
199        PlotOptions {
200            bg_colour: None,
201            fg_colour: None,
202            shape: None,
203        }
204    }
205
206    pub fn with_fg(&self, c:String) -> PlotOptions {
208        PlotOptions {
209            bg_colour: self.bg_colour.clone(),
210            fg_colour: Some(c),
211            shape: self.shape.clone(),
212        }
213    }
214
215    pub fn with_shape(&self, s:(f64,f64)) -> PlotOptions {
217        PlotOptions {
218            bg_colour: self.bg_colour.clone(),
219            fg_colour: self.fg_colour.clone(),
220            shape: Some(s)
221        }
222    }
223}