Показать сообщение отдельно
  #18 (permalink)  
Старый 24.08.2022, 21:21
Аватар для Alikberov
Кандидат Javascript-наук
Отправить личное сообщение для Alikberov Посмотреть профиль Найти все сообщения от Alikberov
 
Регистрация: 16.08.2018
Сообщений: 109

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>
Ответить с цитированием