A вот такой вариант не подойдёт?
<html><head>
<script>
class Functions {
constructor(props) {
this.grid = {
min_x :props && "min_x" in props ? props.min_x : -50,
max_x :props && "max_x" in props ? props.max_x : 100,
min_y :props && "min_y" in props ? props.min_y : -80,
max_y :props && "max_y" in props ? props.max_y : 100,
step_x :(props && props.step_x) || 10,
step_y :(props && props.step_y) || 20,
size :(props && props.size) || 25
};
this.domElement = document.createElement("canvas");
this.domElement.width = props && props.width || 640;
this.domElement.height = props && props.height || 480;
this.context = this.domElement.getContext("2d");
this.clear();
if(props && props.fn)
this.draw(props.fn);
return this;
}
clear() {
var from_x = 20, last_x = this.domElement.width - 8;
var from_y = 8, last_y = this.domElement.height - 24;
var width = last_x - from_x;
var height = last_y - from_y;
var size_x = this.grid.max_x - this.grid.min_x;
var size_y = this.grid.max_y - this.grid.min_y;
var left, right, top, bottom;
var i, x, y;
this.context.fillStyle = "white";
this.context.fillRect(0, 0, this.domElement.width, this.domElement.height);
this.context.strokeStyle = "black";
this.context.fillStyle = "black";
this.context.textAlign = "right";
this.context.beginPath();
if(this.grid.min_x * this.grid.max_x >= 0 && this.grid.min_y * this.grid.max_y >= 0) {
this.context.rect(from_x, from_y, width, height);
left = from_x + 2;
right = last_x - 2;
top = from_y + 2;
bottom = last_y - 2;
} else {
left = from_x - width / size_x * this.grid.min_x;
right = left;
top = last_y + height / size_y * this.grid.min_y;
bottom = top;
this.context.moveTo(left, from_y);
this.context.lineTo(left, last_y);
this.context.moveTo(from_x, top);
this.context.lineTo(last_x, top);
}
for(i = this.grid.min_x; i <= this.grid.max_x; i += this.grid.step_x) {
x = from_x + (i - this.grid.min_x) / size_x * width;
this.context.moveTo(x, top - 2);
this.context.lineTo(x, top + 2);
this.context.moveTo(x, bottom - 2);
this.context.lineTo(x, bottom + 2);
this.context.fillText(String(i), x + 4, bottom + 14);
}
for(i = this.grid.min_y; i <= this.grid.max_y; i += this.grid.step_y) {
y = from_y + (i - this.grid.min_y) / size_y * height;
this.context.moveTo(left - 2, y);
this.context.lineTo(left + 2, y);
this.context.moveTo(right - 2, y);
this.context.lineTo(right + 2, y);
this.context.fillText(String((this.grid.max_y - i + this.grid.min_y)), left - 4, y + 8);
}
this.context.stroke();
this.context.fillText("X", right, bottom);
this.context.textAlign = "left";
this.context.fillText("Y", left, top + 12);
return this;
}
draw(functions) {
var from_x = 20, last_x = this.domElement.width - 8;
var from_y = 8, last_y = this.domElement.height - 24;
var width = last_x - from_x;
var height = last_y - from_y;
var size_x = this.grid.max_x - this.grid.min_x;
var size_y = this.grid.max_y - this.grid.min_y;
for(var grafic of functions) {
var min_x = Math.max(this.grid.min_x, grafic.x1 || 0);
var max_x = Math.min(this.grid.max_x, grafic.x2 || 0);
var min_y = Math.max(this.grid.min_y, grafic.y1 || 0);
var max_y = Math.min(this.grid.max_y, grafic.y2 || 0);
var fn = grafic.fn;
var left = from_x - this.grid.min_x / size_x * width + width / size_x * min_x;
var right = last_x - this.grid.max_x / size_x * width + width / size_x * max_x;
var top = last_y + this.grid.min_y / size_y * height + height / size_y * min_y;
var bottom = last_y + this.grid.min_y / size_y * height + height / size_y * max_y;
var maxi, exprs;
this.context.textAlign = "right";
if(fn) {
exprs = fn.replace(/\*\*2/g, "\u00B2").replace(/\*\*3/g, "\u00B3").replace(/\*/g, "");
fn = fn.replace(/(cos|sin|tan|exp)/g, "Math.$1");
if(isFinite(grafic.x1) && isFinite(grafic.x2)) {
this.context.beginPath();
this.context.strokeStyle = grafic.color || "black";
maxi = this.grid.min_y;
for(var x0 = left; x0 < right; ++ x0) {
var x = (x0 - from_x) / width * size_x + this.grid.min_x, y = 0;
try {
y = eval(fn);
y = y / size_y * height;
maxi = Math.max(maxi, y);
} catch(err) {
}
this.context.lineTo(x0, bottom - y);
}
this.context.stroke();
this.context.beginPath();
this.context.moveTo(x0, from_y);
this.context.lineTo(x0, last_y);
this.context.setLineDash([1, 2]);
this.context.strokeStyle = "black";
this.context.stroke();
this.context.setLineDash([]);
this.context.fillText(exprs, left + (right - left) / 2, bottom - maxi / 2);
} else
if(isFinite(grafic.y1) && isFinite(grafic.y2)) {
this.context.beginPath();
this.context.strokeStyle = grafic.color || "black";
maxi = this.grid.min_x;
for(var y0 = top; y0 < bottom; ++ y0) {
var x = 0, y = (bottom - y0 - from_y) / height * size_y + this.grid.min_y;
try {
x = eval(fn);
x = x / size_x * width;
maxi = Math.max(maxi, x);
} catch(err) {
}
this.context.lineTo(left - x, last_y - y0 - (this.grid.min_y) / size_y * height);
}
this.context.stroke();
this.context.beginPath();
this.context.moveTo(from_x, last_y - y0 - (this.grid.min_y) / size_y * height);
this.context.lineTo(last_x, last_y - y0 - (this.grid.min_y) / size_y * height);
this.context.setLineDash([1, 2]);
this.context.strokeStyle = "black";
this.context.stroke();
this.context.setLineDash([]);
this.context.fillText(exprs, left + maxi / 2, top + (bottom - top) / 2);
}
}
}
}
}
function Draw_Fn() {
document.body.appendChild(
new Functions({
min_x: 0,
max_x: 10,
min_y: 0,
max_y: 100,
step_x: 1,
step_y: 20,
width: 390,
height: 120,
fn: [
{
x1:0, x2:100,
color: "red",
fn: "x**2"
}
]
}).domElement
);
document.body.appendChild(document.createElement("hr"));
document.body.appendChild(
new Functions({
min_x: 0,
max_x: 10,
min_y: 0,
max_y: 100,
step_x: 1,
step_y: 20,
width: 390,
height: 120,
fn: [
{
x1:-1, x2:2,
color: "magenta",
fn: "x+1"
},
{
x1:2, x2:5,
color: "red",
fn: "x**2+4"
},
{
x1:5, x2:10,
color: "orange",
fn: "x**2-2*x+1"
}
]
}).domElement
);
document.body.appendChild(document.createElement("hr"));
document.body.appendChild(
new Functions({
min_x: -5,
max_x: 10,
min_y: -50,
max_y: 100,
step_x: 5,
step_y: 25,
width: 390,
height: 240,
fn: [
{
x1:0, x2:10,
color: "red",
fn: "x**2"
},
{
y1:-35, y2:50,
color: "blue",
fn: "sin(y/10)"
},
{
x1:-5, x2:10,
color: "green",
fn: "exp(x/2)"
}
]
}).domElement
);
}
</script>
<style>
canvas {
display: block;
}
body {
background-color: silver;
}
</style>
</head>
<body onload='Draw_Fn()'>
</body>