extern "C" { #include "canvas_graph.h" } #include 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("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("getElementById", val("canvas")); val ctx = canvas.call("getContext", val("2d")); double canvas_width = canvas["width"].as(); double canvas_height = canvas["height"].as(); // clear canvas ctx.call("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("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("moveTo", val(x_canvas), val(0)); ctx.call("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("moveTo", val(0), val(y_canvas)); ctx.call("lineTo", val(canvas_width), val(y_canvas)); } ctx.call("stroke"); // graph ctx.set("strokeStyle", val("#000088")); ctx.set("lineWidth", val(2.0)); ctx.call("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(cmd, val(x_canvas), val(y_canvas)); } ctx.call("stroke"); }