jej
This commit is contained in:
parent
e13969a610
commit
d712c0dd90
@ -11,17 +11,7 @@ add_executable(GraphWeb
|
|||||||
)
|
)
|
||||||
if (CMAKE_SYSTEM_NAME STREQUAL Emscripten)
|
if (CMAKE_SYSTEM_NAME STREQUAL Emscripten)
|
||||||
set(CMAKE_EXECUTABLE_SUFFIX .html)
|
set(CMAKE_EXECUTABLE_SUFFIX .html)
|
||||||
|
set_target_properties(GraphWeb PROPERTIES LINK_FLAGS "--bind -sEXPORTED_FUNCTIONS='[\"_main\", \"_draw_graph\", \"_set_expr\", \"_set_num_exprs\", \"_print_errors\"]' -sEXPORTED_RUNTIME_METHODS='[\"cwrap\", \"ccall\"]' --shell-file ${CMAKE_SOURCE_DIR}/shell.html")
|
||||||
# Specify the custom HTML shell
|
|
||||||
# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --shell-file ${CMAKE_SOURCE_DIR}/shell.html")
|
|
||||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --shell-file ${CMAKE_SOURCE_DIR}/shell.html")
|
|
||||||
|
|
||||||
# target_compile_options(GraphWeb PRIVATE --shell-file ${CMAKE_SOURCE_DIR}/shell.html)
|
|
||||||
# target_link_options(GraphWeb PRIVATE )
|
|
||||||
set_target_properties(GraphWeb PROPERTIES LINK_FLAGS "--bind -sEXPORTED_FUNCTIONS='[\"_main\", \"_draw_graph\"]' -sEXPORTED_RUNTIME_METHODS='[\"cwrap\", \"ccall\"]' --shell-file ${CMAKE_SOURCE_DIR}/shell.html")
|
|
||||||
# target_link_options(GraphWeb PRIVATE -)
|
|
||||||
|
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
169
canvas_graph.cpp
169
canvas_graph.cpp
@ -1,6 +1,4 @@
|
|||||||
extern "C" {
|
#include "canvas_graph.hpp"
|
||||||
#include "canvas_graph.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
@ -31,11 +29,7 @@ void draw_grid(emscripten::val& ctx, const struct graph_range *range, double can
|
|||||||
// grid
|
// grid
|
||||||
double big_range = std::max(range->xmax - range->xmin, range->ymax - range->ymin);
|
double big_range = std::max(range->xmax - range->xmin, range->ymax - range->ymin);
|
||||||
double log_base = 2.0;
|
double log_base = 2.0;
|
||||||
double grid_size = std::pow(log_base, std::floor(std::log(big_range * 0.05) / std::log(log_base)));
|
double grid_size = std::pow(log_base, std::floor(std::log(big_range * 0.02) / std::log(log_base)));
|
||||||
// double grid_size = std::pow(10.0, std::floor(std::log10(big_range * 0.1)));
|
|
||||||
|
|
||||||
// if (grid_size < 0.1)
|
|
||||||
// grid_size = 0.1;
|
|
||||||
|
|
||||||
static std::vector<Line> origin_lines;
|
static std::vector<Line> origin_lines;
|
||||||
static std::vector<Line> bold_grid_lines;
|
static std::vector<Line> bold_grid_lines;
|
||||||
@ -101,61 +95,10 @@ void draw_grid(emscripten::val& ctx, const struct graph_range *range, double can
|
|||||||
draw_lines(ctx, origin_lines, "#000000", 1.5);
|
draw_lines(ctx, origin_lines, "#000000", 1.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void canvas_generate_graph(const struct expr_node *node, const struct graph_range *range, const char *function) {
|
void draw_expr_graph(emscripten::val& ctx, const Expression& expr, const struct graph_range *range, const char* style, double width, double canvas_width, double canvas_height) {
|
||||||
const val document = val::global("document");
|
|
||||||
// val temp = document.call<val>("getElementById", val("temp"));
|
|
||||||
|
|
||||||
// std::string out;
|
ctx.set("strokeStyle", val(style));
|
||||||
|
ctx.set("lineWidth", val(width));
|
||||||
// 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));
|
|
||||||
|
|
||||||
draw_grid(ctx, range, canvas_width, canvas_height);
|
|
||||||
|
|
||||||
// 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");
|
ctx.call<void>("beginPath");
|
||||||
double segment_size = (range->xmax - range->xmin) / 1000.0;
|
double segment_size = (range->xmax - range->xmin) / 1000.0;
|
||||||
double first_x = (int)(range->xmin / segment_size) * segment_size;
|
double first_x = (int)(range->xmin / segment_size) * segment_size;
|
||||||
@ -163,9 +106,10 @@ void canvas_generate_graph(const struct expr_node *node, const struct graph_rang
|
|||||||
bool use_moveto = true;
|
bool use_moveto = true;
|
||||||
for (int i = 0; (x = first_x + i * segment_size) <= range->xmax; ++i) {
|
for (int i = 0; (x = first_x + i * segment_size) <= range->xmax; ++i) {
|
||||||
double y;
|
double y;
|
||||||
eval_result res = node_eval(node, x, &y);
|
// eval_result res = node_eval(node, x, &y);
|
||||||
|
bool res = expr.Evaluate(x, y);
|
||||||
|
|
||||||
if (res != EVAL_OK) {
|
if (!res) {
|
||||||
use_moveto = true;
|
use_moveto = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -183,4 +127,101 @@ void canvas_generate_graph(const struct expr_node *node, const struct graph_rang
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx.call<void>("stroke");
|
ctx.call<void>("stroke");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const colors[] = {
|
||||||
|
"#000088",
|
||||||
|
"#880000",
|
||||||
|
"#008800",
|
||||||
|
"#880088",
|
||||||
|
"#008888",
|
||||||
|
"#888800",
|
||||||
|
"#000000",
|
||||||
|
"#888888",
|
||||||
|
"#444444",
|
||||||
|
"#ff0000",
|
||||||
|
"#00ff00",
|
||||||
|
"#0000ff",
|
||||||
|
"#ff00ff",
|
||||||
|
"#00ffff",
|
||||||
|
"#ffff00",
|
||||||
|
"#ffffff",
|
||||||
|
};
|
||||||
|
|
||||||
|
const size_t color_count = sizeof(colors) / sizeof(colors[0]);
|
||||||
|
|
||||||
|
#define IDX_NOT_FOUND SIZE_MAX
|
||||||
|
|
||||||
|
void canvas_generate_graph(const Expression* expr, size_t expr_count, const struct graph_range *range, double pointer_x, double pointer_y) {
|
||||||
|
const val document = val::global("document");
|
||||||
|
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
ctx.set("font", val("12px Arial"));
|
||||||
|
|
||||||
|
draw_grid(ctx, range, canvas_width, canvas_height);
|
||||||
|
|
||||||
|
size_t closest_expr_idx = IDX_NOT_FOUND;
|
||||||
|
double closest_dist = std::numeric_limits<double>::max();
|
||||||
|
double closest_y_canvas = 0;
|
||||||
|
double closest_x_value = 0;
|
||||||
|
double closest_y_value = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < expr_count; ++i) {
|
||||||
|
if (!expr[i].IsValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double x = pointer_x * (range->xmax - range->xmin) / canvas_width + range->xmin;
|
||||||
|
double y;
|
||||||
|
bool res = expr[i].Evaluate(x, y);
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double y_canvas = (range->ymax - y) / (range->ymax - range->ymin) * canvas_height;
|
||||||
|
double dist = std::abs(y_canvas - pointer_y);
|
||||||
|
|
||||||
|
if (dist > 50) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dist < closest_dist) {
|
||||||
|
closest_dist = dist;
|
||||||
|
closest_expr_idx = i;
|
||||||
|
closest_y_canvas = y_canvas;
|
||||||
|
closest_x_value = x;
|
||||||
|
closest_y_value = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < expr_count; ++i) {
|
||||||
|
if (!expr[i].IsValid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double width = 2.0;
|
||||||
|
if (i == closest_expr_idx) {
|
||||||
|
width = 2.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_expr_graph(ctx, expr[i], range, colors[i % color_count], width, canvas_width, canvas_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closest_expr_idx != IDX_NOT_FOUND) {
|
||||||
|
std::string text = "f(" + std::to_string(closest_x_value) + ") = " + std::to_string(closest_y_value);
|
||||||
|
ctx.set("fillStyle", val("#000000"));
|
||||||
|
ctx.call<void>("beginPath");
|
||||||
|
ctx.call<void>("arc", val(pointer_x), val(closest_y_canvas), val(2.5), val(0), val(2 * M_PI));
|
||||||
|
ctx.call<void>("fill");
|
||||||
|
ctx.call<void>("fillText", val(text.c_str()), val(pointer_x), val(closest_y_canvas - 5));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,14 +0,0 @@
|
|||||||
#ifndef CANVAS_GRAPH_H
|
|
||||||
#define CANVAS_GRAPH_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include "tree.h"
|
|
||||||
|
|
||||||
struct graph_range {
|
|
||||||
double xmin, xmax;
|
|
||||||
double ymin, ymax;
|
|
||||||
};
|
|
||||||
|
|
||||||
void canvas_generate_graph(const struct expr_node *node, const struct graph_range *range, const char *function);
|
|
||||||
|
|
||||||
#endif /* CANVAS_GRAPH_H */
|
|
||||||
17
canvas_graph.hpp
Executable file
17
canvas_graph.hpp
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef CANVAS_GRAPH_H
|
||||||
|
#define CANVAS_GRAPH_H
|
||||||
|
|
||||||
|
// #include <stdio.h>
|
||||||
|
#include <cstdio>
|
||||||
|
// #include "tree.h"
|
||||||
|
#include "expression.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
struct graph_range {
|
||||||
|
double xmin, xmax;
|
||||||
|
double ymin, ymax;
|
||||||
|
};
|
||||||
|
|
||||||
|
void canvas_generate_graph(const Expression* expr, size_t expr_count, const struct graph_range *range, double pointer_x, double pointer_y);
|
||||||
|
|
||||||
|
#endif /* CANVAS_GRAPH_H */
|
||||||
101
expression.hpp
Normal file
101
expression.hpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "tree.h"
|
||||||
|
#include "parser.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Expression {
|
||||||
|
std::string m_expr_str;
|
||||||
|
struct parser m_parser;
|
||||||
|
struct expr_node* m_root;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Expression(const std::string& expr_str) {
|
||||||
|
m_root = nullptr;
|
||||||
|
SetExpression(expr_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression() : Expression("") {}
|
||||||
|
|
||||||
|
Expression(const Expression&) = delete;
|
||||||
|
Expression& operator=(const Expression&) = delete;
|
||||||
|
|
||||||
|
Expression(Expression&& other) {
|
||||||
|
m_expr_str = std::move(other.m_expr_str);
|
||||||
|
m_parser = other.m_parser;
|
||||||
|
m_root = other.m_root;
|
||||||
|
|
||||||
|
other.m_root = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression& operator=(Expression&& other) {
|
||||||
|
if (this != &other) {
|
||||||
|
if (m_root) {
|
||||||
|
node_free(m_root);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_expr_str = std::move(other.m_expr_str);
|
||||||
|
m_parser = other.m_parser;
|
||||||
|
m_root = other.m_root;
|
||||||
|
|
||||||
|
other.m_root = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetExpression(const std::string& expr_str) {
|
||||||
|
if (expr_str == m_expr_str) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_expr_str = expr_str;
|
||||||
|
|
||||||
|
if (m_root) {
|
||||||
|
node_free(m_root);
|
||||||
|
m_root = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_expr_str.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_root = parser_parse(&m_parser, m_expr_str.c_str(), "x");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Evaluate(double x, double& y) const {
|
||||||
|
if (!m_root) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node_eval(m_root, x, &y) == EVAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValid() const {
|
||||||
|
return m_root != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetErrorText() const {
|
||||||
|
if (parser_get_error(&m_parser) == ERR_NO_ERR) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_expr_str.empty()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parser_get_error_text(&m_parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Expression() {
|
||||||
|
if (m_root) {
|
||||||
|
node_free(m_root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
78
main.cpp
78
main.cpp
@ -2,57 +2,45 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
extern "C" {
|
#include "canvas_graph.hpp"
|
||||||
#include "lex.h"
|
|
||||||
#include "parser.h"
|
|
||||||
#include "canvas_graph.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
static void draw_graph_impl(struct error_buffer *eb, const char *expr, const struct graph_range *range) {
|
|
||||||
struct parser parser;
|
|
||||||
struct expr_node *node;
|
|
||||||
|
|
||||||
error_buffer_init(eb);
|
|
||||||
|
|
||||||
/* zpracování výrazu */
|
|
||||||
node = parser_parse(&parser, expr, "x");
|
|
||||||
|
|
||||||
if (!node) {
|
|
||||||
/* vypsání chyby */
|
|
||||||
error_set(eb, parser_get_error(&parser));
|
|
||||||
error_printf(eb, "%s", parser_get_error_text(&parser));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vygenerování grafu */
|
|
||||||
canvas_generate_graph(node, range, expr);
|
|
||||||
|
|
||||||
/* uvolnění paměti */
|
|
||||||
node_free(node);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace emscripten;
|
using namespace emscripten;
|
||||||
|
|
||||||
extern "C" void draw_graph(const char *expr, double xmin, double xmax, double ymin, double ymax) {
|
static std::vector<Expression> s_exprs;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void set_num_exprs(size_t num_exprs) {
|
||||||
|
s_exprs.resize(num_exprs);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void set_expr(size_t idx, const char *expr) {
|
||||||
|
if (idx >= s_exprs.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
s_exprs[idx].SetExpression(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void print_errors() {
|
||||||
const val document = val::global("document");
|
const val document = val::global("document");
|
||||||
val p = document.call<val>("getElementById", val("output"));
|
val p = document.call<val>("getElementById", val("output"));
|
||||||
|
|
||||||
struct error_buffer eb;
|
|
||||||
struct graph_range range = {xmin, xmax, ymin, ymax};
|
|
||||||
draw_graph_impl(&eb, expr, &range);
|
|
||||||
|
|
||||||
if (error_get(&eb) != ERR_NO_ERR) {
|
std::string errors;
|
||||||
p.set("innerText", error_get_text(&eb));
|
|
||||||
}
|
for (const auto& expr : s_exprs) {
|
||||||
else {
|
const char* error_text = expr.GetErrorText();
|
||||||
p.set("innerText", "");
|
if (error_text) {
|
||||||
|
errors += error_text;
|
||||||
|
errors += "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.set("innerText", errors.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void draw_graph(double xmin, double xmax, double ymin, double ymax, double pointer_x, double pointer_y) {
|
||||||
|
struct graph_range range = {xmin, xmax, ymin, ymax};
|
||||||
|
canvas_generate_graph(s_exprs.data(), s_exprs.size(), &range, pointer_x, pointer_y);
|
||||||
}
|
}
|
||||||
|
|||||||
67
shell.html
67
shell.html
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#input {
|
#input {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
|
height: 300px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
@ -54,6 +55,10 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
let drawGraph = null;
|
let drawGraph = null;
|
||||||
|
let setExpr = null;
|
||||||
|
let setNumExprs = null;
|
||||||
|
let printErrors = null;
|
||||||
|
|
||||||
const fnInput = document.getElementById("input");
|
const fnInput = document.getElementById("input");
|
||||||
|
|
||||||
let centerX = 0;
|
let centerX = 0;
|
||||||
@ -62,13 +67,15 @@
|
|||||||
|
|
||||||
const canvas = document.getElementById("canvas");
|
const canvas = document.getElementById("canvas");
|
||||||
|
|
||||||
Module = {
|
|
||||||
onRuntimeInitialized: function() {
|
|
||||||
drawGraph = Module.cwrap("draw_graph", "void", ["string", "number", "number", "number", "number"]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function fnChanged() {
|
function fnChanged() {
|
||||||
|
const fns = fnInput.value.split("\n");
|
||||||
|
setNumExprs(fns.length);
|
||||||
|
for (let i = 0; i < fns.length; i++) {
|
||||||
|
setExpr(i, fns[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printErrors();
|
||||||
|
|
||||||
redraw();
|
redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,10 +83,6 @@
|
|||||||
let lastY = 0;
|
let lastY = 0;
|
||||||
let mouseDown = false;
|
let mouseDown = false;
|
||||||
|
|
||||||
function moveCenter(event) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.addEventListener("mousedown", function(event) {
|
canvas.addEventListener("mousedown", function(event) {
|
||||||
mouseDown = true;
|
mouseDown = true;
|
||||||
});
|
});
|
||||||
@ -95,11 +98,11 @@
|
|||||||
|
|
||||||
centerX -= dx * 2 * zoom / canvas.width;
|
centerX -= dx * 2 * zoom / canvas.width;
|
||||||
centerY += dy * 2 * zoom / canvas.width;
|
centerY += dy * 2 * zoom / canvas.width;
|
||||||
redraw();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lastX = event.clientX;
|
lastX = event.clientX;
|
||||||
lastY = event.clientY;
|
lastY = event.clientY;
|
||||||
|
redraw();
|
||||||
});
|
});
|
||||||
|
|
||||||
canvas.addEventListener("wheel", function(event) {
|
canvas.addEventListener("wheel", function(event) {
|
||||||
@ -109,19 +112,34 @@
|
|||||||
redraw();
|
redraw();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let shouldRedraw = false;
|
||||||
|
|
||||||
function redraw() {
|
function redraw() {
|
||||||
if (drawGraph) {
|
shouldRedraw = true;
|
||||||
const fn = fnInput.value;
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
if (drawGraph && shouldRedraw) {
|
||||||
|
// const fn = fnInput.value;
|
||||||
const xMin = -zoom + centerX;
|
const xMin = -zoom + centerX;
|
||||||
const xMax = zoom + centerX;
|
const xMax = zoom + centerX;
|
||||||
const aspect = canvas.width / canvas.height;
|
const aspect = canvas.width / canvas.height;
|
||||||
const yMin = -zoom / aspect + centerY;
|
const yMin = -zoom / aspect + centerY;
|
||||||
const yMax = zoom / aspect + centerY;
|
const yMax = zoom / aspect + centerY;
|
||||||
|
|
||||||
drawGraph(fn, xMin, xMax, yMin, yMax);
|
const pointerXcanvas = lastX;
|
||||||
|
const pointerYcanvas = lastY;
|
||||||
|
|
||||||
|
drawGraph(xMin, xMax, yMin, yMax, pointerXcanvas, pointerYcanvas);
|
||||||
|
|
||||||
|
shouldRedraw = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.requestAnimationFrame(animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
animate();
|
||||||
|
|
||||||
// resize canvas size
|
// resize canvas size
|
||||||
function resizeCanvas() {
|
function resizeCanvas() {
|
||||||
canvas.width = window.innerWidth;
|
canvas.width = window.innerWidth;
|
||||||
@ -130,7 +148,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener("resize", resizeCanvas);
|
window.addEventListener("resize", resizeCanvas);
|
||||||
resizeCanvas();
|
|
||||||
|
Module = {
|
||||||
|
onRuntimeInitialized: function() {
|
||||||
|
drawGraph = Module.cwrap("draw_graph", "void", ["number", "number", "number", "number", "number", "number"]);
|
||||||
|
setExpr = Module.cwrap("set_expr", "void", ["number", "string"]);
|
||||||
|
setNumExprs = Module.cwrap("set_num_exprs", "void", ["number"]);
|
||||||
|
printErrors = Module.cwrap("print_errors", "void", []);
|
||||||
|
|
||||||
|
resizeCanvas();
|
||||||
|
|
||||||
|
if (fnInput.value === "") {
|
||||||
|
fnInput.value = "x\nx^2\nsin(x)\nskibidi\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
fnChanged();
|
||||||
|
fnInput.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{{ SCRIPT }}}
|
{{{ SCRIPT }}}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user