diff --git a/src/func_plot.rs b/src/func_plot.rs index 94457f8..67cffa0 100644 --- a/src/func_plot.rs +++ b/src/func_plot.rs @@ -1,18 +1,27 @@ use crate::DrawResult; +use meval::Expr; use plotters::prelude::*; use plotters_canvas::CanvasBackend; use web_sys::HtmlCanvasElement; -use meval::Expr; /// Draw power function f(x) = x^power. -pub fn draw(element: HtmlCanvasElement, func_str: &str, min_x: f32, max_x: f32, min_y: f32, max_y: f32, num_interval: usize, resolution: i32) -> DrawResult<(impl Fn((i32, i32))-> Option<(f32, f32)>, f32)> { +pub fn draw( + element: HtmlCanvasElement, + func_str: &str, + min_x: f32, + max_x: f32, + min_y: f32, + max_y: f32, + num_interval: usize, + resolution: i32, +) -> DrawResult<(impl Fn((i32, i32)) -> Option<(f32, f32)>, f32)> { let expr: Expr = func_str.parse().unwrap(); let func = expr.bind("x").unwrap(); - let absrange = (max_x-min_x).abs(); - let step = absrange/(num_interval as f32); + let absrange = (max_x - min_x).abs(); + let step = absrange / (num_interval as f32); let backend = CanvasBackend::with_canvas_object(element).unwrap(); - + let root = backend.into_drawing_area(); let font: FontDesc = ("sans-serif", 20.0).into(); @@ -24,20 +33,24 @@ pub fn draw(element: HtmlCanvasElement, func_str: &str, min_x: f32, max_x: f32, .x_label_area_size(30 as f32) .y_label_area_size(30 as f32) .build_cartesian_2d(min_x..max_x, min_y..max_y)?; - + chart.configure_mesh().x_labels(3).y_labels(3).draw()?; let data = (1..=resolution) - .map(|x| (((x as f32/resolution as f32))*(&absrange))+&min_x) + .map(|x| ((x as f32 / resolution as f32) * (&absrange)) + &min_x) .map(|x| (x, func(x as f64) as f32)) - .filter(|(_,y)| &min_y <= y && y <= &max_y); + .filter(|(_, y)| &min_y <= y && y <= &max_y); chart.draw_series(LineSeries::new(data, &RED))?; let (data2, area) = integral_rectangles(min_x, step, num_interval, &func); // Get rectangle coordinates and the total area // Draw rectangles - chart.draw_series(data2.iter().map(|(x1, x2, y)| Rectangle::new([(*x2, *y), (*x1, 0.0)], &BLUE)))?; + chart.draw_series( + data2 + .iter() + .map(|(x1, x2, y)| Rectangle::new([(*x2, *y), (*x1, 0.0)], &BLUE)), + )?; root.present()?; let output = chart.into_coord_trans(); @@ -46,7 +59,12 @@ pub fn draw(element: HtmlCanvasElement, func_str: &str, min_x: f32, max_x: f32, // Creates and does the math for creating all the rectangles under the graph #[inline(always)] -fn integral_rectangles(min_x: f32, step: f32, num_interval: usize, func: &dyn Fn(f64) -> f64) -> (Vec<(f32, f32, f32)>, f32) { +fn integral_rectangles( + min_x: f32, + step: f32, + num_interval: usize, + func: &dyn Fn(f64) -> f64, +) -> (Vec<(f32, f32, f32)>, f32) { let mut area: f32 = 0.0; // sum of all rectangles' areas let mut tmp1: f32; // Top left Y value that's tested let mut tmp2: f32; // Top right Y value that's tested @@ -55,12 +73,12 @@ fn integral_rectangles(min_x: f32, step: f32, num_interval: usize, func: &dyn Fn let mut x: f32; // X value of the left side of the rectangle let mut data2: Vec<(f32, f32, f32)> = Vec::new(); for e in 0..num_interval { - x = ((e as f32)*step)+min_x; + x = ((e as f32) * step) + min_x; if x > 0.0 { - x2 = x+step; + x2 = x + step; } else { - x2 = x-step; + x2 = x - step; } tmp1 = func(x as f64) as f32; tmp2 = func(x2 as f64) as f32; @@ -73,7 +91,7 @@ fn integral_rectangles(min_x: f32, step: f32, num_interval: usize, func: &dyn Fn // Add current rectangle's area to the total if !y.is_nan() { - area += y*step; + area += y * step; data2.push((x, x2, y)); } } diff --git a/src/lib.rs b/src/lib.rs index 6439158..538ab1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ pub type DrawResult = Result>; #[wasm_bindgen] pub struct Chart { convert: Box Option<(f32, f32)>>, - area: f32 + area: f32, } /// Result of screen to chart coordinates conversion. @@ -23,8 +23,27 @@ pub struct Point { #[wasm_bindgen] impl Chart { - pub fn draw(canvas: HtmlCanvasElement, func: &str, min_x: f32, max_x: f32, min_y: f32, max_y: f32, num_interval: usize, resolution: i32) -> Result { - let output = func_plot::draw(canvas, func, min_x, max_x, min_y, max_y, num_interval, resolution).map_err(|err| err.to_string())?; + pub fn draw( + canvas: HtmlCanvasElement, + func: &str, + min_x: f32, + max_x: f32, + min_y: f32, + max_y: f32, + num_interval: usize, + resolution: i32, + ) -> Result { + let output = func_plot::draw( + canvas, + func, + min_x, + max_x, + min_y, + max_y, + num_interval, + resolution, + ) + .map_err(|err| err.to_string())?; let map_coord = output.0; Ok(Chart { convert: Box::new(move |coord| map_coord(coord).map(|(x, y)| (x.into(), y.into()))),