GraphWeb/canvas_graph.cpp
2025-01-16 13:55:12 +01:00

96 lines
3.0 KiB
C++
Executable File

extern "C" {
#include "canvas_graph.h"
}
#include <emscripten/val.h>
using namespace emscripten;
void canvas_generate_graph(const struct expr_node *node, const struct graph_range *range, const char *function) {
const val document = val::global("document");
val temp = document.call<val>("getElementById", val("temp"));
std::string out;
for (int i = -10; i <= 10; ++i) {
double x = i * 0.1;
double y;
eval_result res = node_eval(node, x, &y);
if (res == EVAL_OK) {
out += std::to_string(y);
out += "\n";
}
}
temp.set("innerText", out);
val canvas = document.call<val>("getElementById", val("canvas"));
val ctx = canvas.call<val>("getContext", val("2d"));
double canvas_width = canvas["width"].as<double>();
double canvas_height = canvas["height"].as<double>();
// clear canvas
ctx.call<void>("clearRect", val(0), val(0), val(canvas_width), val(canvas_height));
// grid
double big_range = std::max(range->xmax - range->xmin, range->ymax - range->ymin);
double grid_size = std::pow((int)std::log10(big_range), 10.0);
if (grid_size < 0.1)
grid_size = 0.1;
ctx.set("strokeStyle", val("#888888"));
ctx.set("lineWidth", val(1.0));
ctx.call<void>("beginPath");
double first_grid_x = (int)(range->xmin / grid_size) * grid_size;
double grid_x;
for (int i = 0; (grid_x = first_grid_x + i * grid_size) <= range->xmax; ++i) {
double x_canvas = (grid_x - range->xmin) / (range->xmax - range->xmin) * canvas_width;
ctx.call<void>("moveTo", val(x_canvas), val(0));
ctx.call<void>("lineTo", val(x_canvas), val(canvas_height));
}
double first_grid_y = (int)(range->ymin / grid_size) * grid_size;
double grid_y;
for (int i = 0; (grid_y = first_grid_y + i * grid_size) <= range->ymax; ++i) {
double y_canvas = (range->ymax - grid_y) / (range->ymax - range->ymin) * canvas_height;
ctx.call<void>("moveTo", val(0), val(y_canvas));
ctx.call<void>("lineTo", val(canvas_width), val(y_canvas));
}
ctx.call<void>("stroke");
// graph
ctx.set("strokeStyle", val("#000088"));
ctx.set("lineWidth", val(2.0));
ctx.call<void>("beginPath");
double segment_size = (range->xmax - range->xmin) / 1000.0;
double first_x = (int)(range->xmin / segment_size) * segment_size;
double x;
bool use_moveto = true;
for (int i = 0; (x = first_x + i * segment_size) <= range->xmax; ++i) {
double y;
eval_result res = node_eval(node, x, &y);
if (res != EVAL_OK) {
use_moveto = true;
continue;
}
double x_canvas = (x - range->xmin) / (range->xmax - range->xmin) * canvas_width;
double y_canvas = (range->ymax - y) / (range->ymax - range->ymin) * canvas_height;
const char* cmd = "lineTo";
if (use_moveto) {
cmd = "moveTo";
use_moveto = false;
}
ctx.call<void>(cmd, val(x_canvas), val(y_canvas));
}
ctx.call<void>("stroke");
}