167 lines
5.2 KiB
JavaScript
167 lines
5.2 KiB
JavaScript
class ChartManager {}
|
|
|
|
const canvas = document.getElementById("canvas");
|
|
const coord = document.getElementById("coord");
|
|
const math_function = document.getElementById("math_function");
|
|
const status = document.getElementById("status");
|
|
|
|
const minX = document.getElementById("minX");
|
|
const maxX = document.getElementById("maxX");
|
|
const minY = document.getElementById("minY");
|
|
const maxY = document.getElementById("maxY");
|
|
const num_interval = document.getElementById("num_interval");
|
|
const area_msg = document.getElementById("area-msg");
|
|
const resolution = document.getElementById("resolution");
|
|
|
|
let darkMode = false;
|
|
|
|
let chart = null;
|
|
let chart_manager = null;
|
|
|
|
/** Main entry point */
|
|
export function main() {
|
|
setupUI();
|
|
setupCanvas();
|
|
}
|
|
|
|
/** This function is used in `bootstrap.js` to setup imports. */
|
|
export function setup(WasmChart) {
|
|
ChartManager = WasmChart;
|
|
ChartManager.init_panic_hook(); // Allows `panic!()` to log in the browser's console
|
|
}
|
|
|
|
/** 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;
|
|
}
|
|
|
|
// Watches for changes in color preferences
|
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
|
|
darkMode = event.matches;
|
|
updatePlot();
|
|
});
|
|
|
|
math_function.addEventListener("change", updatePlot);
|
|
minX.addEventListener("input", updatePlot);
|
|
maxX.addEventListener("input", updatePlot);
|
|
minY.addEventListener("input", updatePlot);
|
|
maxY.addEventListener("input", updatePlot);
|
|
num_interval.addEventListener("input", updatePlot);
|
|
resolution.addEventListener("input", updatePlot);
|
|
|
|
|
|
window.addEventListener("resize", setupCanvas);
|
|
window.addEventListener("mousemove", onMouseMove);
|
|
}
|
|
|
|
function setupCanvas() {
|
|
const aspectRatio = canvas.width / canvas.height;
|
|
const size = canvas.parentNode.offsetWidth * 0.8;
|
|
canvas.style.width = size + "px";
|
|
canvas.style.height = size / aspectRatio + "px";
|
|
canvas.width = size;
|
|
canvas.height = size / aspectRatio;
|
|
updatePlot();
|
|
}
|
|
|
|
function onMouseMove(event) {
|
|
if (chart) {
|
|
var text = "Mouse is outside Chart.";
|
|
|
|
if (event.target == canvas) {
|
|
let actualRect = canvas.getBoundingClientRect();
|
|
let logicX = event.offsetX * canvas.width / actualRect.width;
|
|
let logicY = event.offsetY * canvas.height / actualRect.height;
|
|
const point = chart.coord(logicX, logicY);
|
|
text = (point)
|
|
? `(${point.x.toFixed(3)}, ${point.y.toFixed(3)})`
|
|
: text;
|
|
}
|
|
coord.innerText = text;
|
|
}
|
|
}
|
|
|
|
function postErrorStatus(string) {
|
|
status.style.color = "red";
|
|
status.innerText = string;
|
|
}
|
|
|
|
function postNormalStatus(string) {
|
|
status.style.color = "grey";
|
|
status.innerText = string;
|
|
}
|
|
|
|
// Checks variables put in input fields
|
|
function checkVariables() {
|
|
if (minX.value >= maxX.value) {
|
|
postErrorStatus("minX must be smaller than maxX!");
|
|
return;
|
|
}
|
|
|
|
if (minY.value >= maxY.value) {
|
|
postErrorStatus("minY must be smaller than maxY!");
|
|
return;
|
|
}
|
|
|
|
if (0 > num_interval.value) {
|
|
postErrorStatus("Interval is smaller than 0!");
|
|
return;
|
|
}
|
|
|
|
if (0 > resolution.value) {
|
|
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) {
|
|
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 = 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();
|
|
|
|
area_msg.innerText = `Estimated Area: ${chart.get_area()}`;
|
|
|
|
postNormalStatus(`Rendered ${math_function.innerText} in ${Math.ceil(end - start)}ms`);
|
|
} catch(err) {
|
|
postErrorStatus(`Error! check console logs for more detail`);
|
|
}
|
|
}
|