diff --git a/src/lib.rs b/src/lib.rs index f68641a..33b18fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ pub struct ChartManager { min_y: f32, max_y: f32, num_interval: usize, - resolution: i32, + resolution: usize, back_cache: Cache>, front_cache: Cache<(Vec<(f32, f32, f32)>, f32)>, } @@ -39,7 +39,7 @@ pub struct ChartManager { impl ChartManager { pub fn new( func_str: String, min_x: f32, max_x: f32, min_y: f32, max_y: f32, num_interval: usize, - resolution: i32, + resolution: usize, ) -> Self { Self { func_str, @@ -63,6 +63,7 @@ impl ChartManager { func } + // Tests function to make sure it's able to be parsed. Returns the string of the Error produced, or an empty string if it runs successfully. pub fn test_func(function_string: String) -> String { let new_func_str: String = add_asterisks(function_string.clone()); let expr_result = new_func_str.parse(); @@ -87,13 +88,6 @@ impl ChartManager { "".to_string() } - // Recommends a possible solution to an error from method `test_func` - pub fn error_recommend(error_string: String) -> String { - match error_string.as_str() { - _ => "Make sure you're using proper syntax! Check the 'Frequent issues' for possible fixes." - }.to_string() - } - #[inline] fn draw( &mut self, element: HtmlCanvasElement, dark_mode: bool @@ -192,7 +186,7 @@ impl ChartManager { #[allow(clippy::too_many_arguments)] pub fn update( &mut self, canvas: HtmlCanvasElement, func_str_new: String, min_x: f32, max_x: f32, min_y: f32, - max_y: f32, num_interval: usize, resolution: i32, dark_mode: bool + max_y: f32, num_interval: usize, resolution: usize, dark_mode: bool ) -> Result { let func_str: String = add_asterisks(func_str_new); @@ -204,20 +198,6 @@ impl ChartManager { | (max_y != self.max_y); - if 0 > resolution { - panic!("resolution cannot be less than 0"); - } - - if underlying_update { - if min_x >= max_x { - panic!("min_x is greater than (or equal to) than max_x!"); - } - - if min_y >= max_y { - panic!("min_y is greater than (or equal to) than max_y!"); - } - } - if underlying_update | (self.resolution != resolution) { self.back_cache.invalidate(); } diff --git a/src/misc.rs b/src/misc.rs index 11aec77..8284532 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -2,9 +2,11 @@ use wasm_bindgen::prelude::*; pub type DrawResult = Result>; -// EXTREMELY Janky function that tries to put asterisks in the proper places to be parsed. This is so cursed +// EXTREMELY Janky function that tries to put asterisks in the proper places to be parsed. This is so cursed. But it works, and I hopefully won't ever have to touch it again. +// One limitation though, variables with multiple characters like `pi` cannot be multiplied (like `pipipipi` won't result in `pi*pi*pi*pi`). But that's such a niche use case (and that same thing could be done by using exponents) that it doesn't really matter. pub fn add_asterisks(function_in: String) -> String { let function = function_in.replace("log10(", "log("); // replace log10 with log + let valid_variables: Vec = "xe".chars().collect(); let letters: Vec= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".chars().collect(); let numbers: Vec = "0123456789".chars().collect(); let function_chars: Vec = function.chars().collect(); @@ -12,6 +14,7 @@ pub fn add_asterisks(function_in: String) -> String { let mut output_string: String = String::new(); let mut prev_chars: Vec = Vec::new(); for c in function_chars.clone() { + let mut add_asterisk: bool = false; let prev_chars_len = prev_chars.len(); let curr_i: usize = func_chars_len-prev_chars_len; @@ -41,32 +44,37 @@ pub fn add_asterisks(function_in: String) -> String { let prev_pi = (prev_prev_char == 'p') && (prev_char == 'i'); let for_pi = (for_char == 'i') && (c == 'p'); + if prev_char == ')' { if (c == '(') | numbers.contains(&c) | letters.contains(&c) { - output_string += "*"; + add_asterisk = true; } } else if c == '(' { - if ((prev_char == 'x') | (prev_char == 'e') | (prev_char == ')') | numbers.contains(&prev_char)) && !letters.contains(&prev_prev_char) { - output_string += "*"; + if (valid_variables.contains(&prev_char) | (prev_char == ')') | numbers.contains(&prev_char)) && !letters.contains(&prev_prev_char) { + add_asterisk = true; } else if prev_pi { - output_string += "*"; + add_asterisk = true; } } else if numbers.contains(&prev_char) { if (c == '(') | letters.contains(&c) | for_pi { - output_string += "*"; + add_asterisk = true; } } else if letters.contains(&c) { if numbers.contains(&prev_char) { - output_string += "*"; - } else if ((c == 'x') | (c == 'e')) && ((prev_char == 'x') | (prev_char == 'e')) | prev_pi { - output_string += "*"; + add_asterisk = true; + } else if (valid_variables.contains(&prev_char) && valid_variables.contains(&c)) | prev_pi { + add_asterisk = true; } } else if numbers.contains(&c) { if letters.contains(&prev_char) | prev_pi { - output_string += "*"; + add_asterisk = true; } } + if add_asterisk { + output_string += "*"; + } + prev_chars.push(c); output_string += &c.to_string(); } @@ -153,6 +161,7 @@ impl Cache { pub fn is_valid(&self) -> bool { self.valid } } +// Tests to make sure my cursed function works as intended #[test] fn asterisk_test() { assert_eq!(&add_asterisks("2x".to_string()), "2*x"); diff --git a/www/index.html b/www/index.html index c7038db..a0f378a 100644 --- a/www/index.html +++ b/www/index.html @@ -25,9 +25,9 @@

- +

- +

Area:
diff --git a/www/index.js b/www/index.js index c79f306..66e527f 100644 --- a/www/index.js +++ b/www/index.js @@ -32,7 +32,8 @@ export function setup(WasmChart) { /** Add event listeners. */ function setupUI() { - + status.innerText = "WebAssembly loaded!"; + // Handles browser color preferences if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { darkMode = true; @@ -44,7 +45,6 @@ function setupUI() { updatePlot(); }); - status.innerText = "WebAssembly loaded!"; math_function.addEventListener("change", updatePlot); minX.addEventListener("input", updatePlot); maxX.addEventListener("input", updatePlot); @@ -95,9 +95,8 @@ function postNormalStatus(string) { status.innerText = string; } -function updatePlot() { - postNormalStatus(`Rendering y=${math_function.value}...`); - +// Checks variables put in input fields +function checkVariables() { if (minX.value >= maxX.value) { postErrorStatus("minX must be smaller than maxX!"); return; @@ -114,27 +113,46 @@ function updatePlot() { } if (0 > resolution.value) { - postErrorStatus("resolution (Number of Points) is smaller than 0!"); + postErrorStatus("Number of Points is smaller than 0!"); return; } +} +// Generates a possible "tip" to assist the user when an error occurs. +function errorRecommend(error_string) { + if (error_string.includes("Evaluation error: unknown variable ")) { + return "This variable is not considered valid. Make sure you used a valid variable."; + } else { + return "Make sure you're using proper syntax! Check console log (f12) as well for more details."; + } +} + + +function updatePlot() { + checkVariables(); if (chart_manager == null) { - chart_manager = ChartManager.new(math_function.value, Number(minX.value), Number(maxX.value), Number(minY.value), Number(maxY.value), Number(num_interval.value), Number(resolution.value)); + try { + chart_manager = ChartManager.new(math_function.value, Number(minX.value), Number(maxX.value), Number(minY.value), Number(maxY.value), Number(num_interval.value), Number(resolution.value)); + } catch(err) { + postErrorStatus("Error during ChartManager creation! Check logs for details."); + return; + } } const test_result = ChartManager.test_func(math_function.value); if (test_result != "") { - const error_recommendation = ChartManager.error_recommend(test_result); - if (error_recommendation == "") { - postErrorStatus(test_result); - } else { - postErrorStatus(`${test_result}\nTip: ${error_recommendation}`); + const error_recommendation = errorRecommend(test_result); + let error_status_str = test_result; + if (error_recommendation != "") { + error_status_str += `\nTip: ${error_recommendation}`; } + postErrorStatus(error_status_str); return; } try { + postNormalStatus(`Rendering y=${math_function.value}...`); const start = performance.now(); chart = chart_manager.update(canvas, math_function.value, Number(minX.value), Number(maxX.value), Number(minY.value), Number(maxY.value), Number(num_interval.value), Number(resolution.value), false); // TODO: improve darkmode support const end = performance.now(); diff --git a/www/style.css.new b/www/style.css.new index 09d9c92..7685c70 100644 --- a/www/style.css.new +++ b/www/style.css.new @@ -6,6 +6,7 @@ html { } @media (prefers-color-scheme: dark) { + input, body { color: #c9d1d9; font-family: 'Open Sans', sans-serif; @@ -23,6 +24,7 @@ html { } @media (prefers-color-scheme: light) { + input, body { color: #444; font-family: 'Open Sans', sans-serif;