96 lines
3.0 KiB
C++
Executable File
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");
|
|
} |