Как в JawaScript Canvas нарисовать различные графики на разных участках числовой оси
Как в JawaScript Canvas нарисовать различные графики на разных участках числовой оси Х в Декартовой системе координат ?
|
Обычно, в JS на всей числовой оси X строиться график одной функции, например y(x) = x^2, на участке от 0 до 10, тоже например. А, надо построить графики нескольких функций на нескольких участках: y1(x) = x+1 на участке от 0 до 2; y2(x) = x^2+4 на участке от 2 до 5;y3(x) = x^2+2*x+1 на участке от 5 до 10; Фукции и интервалы выбраны совершенно произвольно.
|
Следует добавить, что это всё надо сделать на одной числовой оси Х
|
<html><head> <script> function DrawFn() { var ctx = document.querySelector("canvas").getContext("2d"); var drawer = ctx.moveTo.bind(ctx); var i, x0, x1, x2, x, y, el, fn, range; ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); for(i = 1; i <= 3; ++ i) { el = document.getElementById("Fn" + i); // Обращаемся к одному из input-элементов fn = el.value.split(/:/)[1]; // Выражение функции справа от двоеточия range = el.value.split(/:/)[0].split(".."); // Интервал участка задаётся форматом "от..до" слева от двоеточия x1 = parseInt(range[0]); x2 = parseInt(range[1]) ctx.strokeStyle = el.style.color; // Цвет линии графика соответствует цвету input-текста ctx.beginPath(); for(x0 = 0; x0 < ctx.canvas.width; ++ x0) { x = x0 / ctx.canvas.width * (x2 - x1) - x1; try { with(Math) { drawer(x0, ctx.canvas.height - eval(fn)); } } catch(err) { break; } drawer = ctx.lineTo.bind(ctx); } ctx.stroke(); } } </script> </head> <body onload='DrawFn()'> Y1(x)=<input type=text id=Fn1 value='0..10:x**2' onchange='DrawFn()' style=color:magenta><br> Y2(x)=<input type=text id=Fn1 value='0..2:x+1' onchange='DrawFn()' style=color:red><br> Y3(x)=<input type=text id=Fn2 value='2..5:x**2+4' onchange='DrawFn()' style=color:orange><br> Y4(x)=<input type=text id=Fn3 value='5..10:x**2+2*x+1' onchange='DrawFn()' style=color:blue><br> <canvas width=800px height=600px></canvas> </body> |
Правильно ли, я понял, что графики выходят из отной точки - 0 ? Если, это так, то извините - это не совсем то, что требуется. В дествительности каждый из трёх графиков должен быть построен на указанном ему интервале на одной числовой оси Х
|
Вложений: 1
Думаю, надо добавить то, что это просто линии, так как не показаны координатные оси с разметкой и числовыми значениями по осям Х и Y
|
Высылаю файлы JS и HTML, где построен только один график. Может быть при использовании этих файлов можно решить мою проблему: надо построить графики нескольких функций на нескольких участках: y1(x) = x+1 на участке от 0 до 2; y2(x) = x^2+4 на участке от 2 до 5;y3(x) = x^2-2*x+1 на участке от 5 до 10; Функции и интервалы выбраны совершенно произвольно. а это всё надо сделать на одной числовой оси Х.
|
К сожалению, не получилось, или я не знаю, как в сообщение вложить
файлы JS и HTML const canvasPlot = document.getElementById(`canvas_plot`); const ctx = canvasPlot.getContext(`2d`); //Рисуем сетку const canvasPlotWidth = canvasPlot.clientWidth; const canvasPlotHeight = canvasPlot.clientHeight; const scaleX = 30; //расстояние между элементами сетки по Х const scaleY = 30; //расстояние между элементами сетки по Y //Рисуем главные оси // Обычное расположение осей //const xAxis = canvasPlotWidth / 2; //const yAxis = canvasPlotHeight / 2; // Уточнённое расположение осей за счёт сдвига осей const xAxis = Math.round(canvasPlotWidth / scaleX / 2) * scaleX; const yAxis = Math.round(canvasPlotHeight / scaleY / 2) * scaleY; // Выбор шрифта и его вид, размер ctx.font = `${Math.round(scaleX / 2)}px Arial`; ctx.textAlign = `left`; ctx.textBaseline = `top`; ctx.beginPath(); ctx.strokeStyle = `#f5f0e8`; var zz = 5; //Зазор между осями и числами нумерации чисел for (let i = 0; i <= canvasPlotWidth; i = i + scaleX) { ctx.moveTo(i, 0); ctx.lineTo(i, canvasPlotHeight); // нанесение вертикальных линий разметки ctx.fillText((i - xAxis) / scaleX, i + zz, yAxis + zz); //нанесение числовых значений на ось Х } for (let i = 0; i <= canvasPlotHeight; i = i + scaleY) { ctx.moveTo(0, i); ctx.lineTo(canvasPlotWidth, i); // нанесение горизонтальных линий разметки ctx.fillText((yAxis - i) / scaleY, xAxis + zz, i + zz); //нанесение числовых значений на ось Y } ctx.stroke(); ctx.closePath(); //закрыть путь, чтобы рисовать новые линии другим цветом var zxy = 20; //Зазор между осями и обозначением этих осей x,y ctx.beginPath(); ctx.strokeStyle = `#000000`; ctx.moveTo(xAxis, 0); ctx.lineTo(xAxis, canvasPlotHeight); ctx.fillText(`y`, xAxis - zxy, 0 ); // означение оси Y ctx.moveTo(0, yAxis); ctx.lineTo(canvasPlotWidth, yAxis); ctx.fillText(`x`, canvasPlotWidth - zxy, yAxis - zxy ); // означение оси X ctx.stroke(); ctx.closePath(); //закрыть путь, чтобы рисовать новые линии другим цветом //ПРЕОБРАЗОВАНИЕ CANVAS СИСТЕМУ КООРДИНАТ В ДЕКАРТОВУ СИСТЕМУ КООРДИНАТ // Рисуем график функции ctx.fillStyle = `#ff0000`; // цвет графика чёрный //ctx.lineWidth = 0.5 //толщина линии for (let i = 0; i <= canvasPlotWidth; i++) { const x = (i - xAxis) / scaleX; const y = Math.pow(x, 2); ctx.fillRect(x * scaleX + xAxis, yAxis - scaleY * y, 4, 4); |
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link href="./Graf.css" rel="stylesheet"> </head> <body style= "margin": 0;> <canvas id="canvas_plot" width="700" height="500"></canvas> <script src="./Graf.js"></script> </body> </html> |
Ссылка на график file:///C:/Users/%D0%98%D0%97%D0%9E/Desktop/JS1/Graf.html
|
IZUM,
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Графики</title> </head> <body> <canvas id="canvas" width="400" height="200" style="border:1px solid grey"></canvas> <script> function createPath(x1, x2, y, sx, sy) { const path = new Path2D(); for (let x = x1; x <= x2; x++) { if (x == x1) { path.moveTo(x * sx, y(x) * sy); } else { path.lineTo(x * sx, y(x) * sy); } } return path; } const ctx = canvas.getContext('2d'); ctx.translate(0, 200); ctx.scale(1, -1); ctx.strokeStyle = 'red'; ctx.stroke(createPath(0, 2, x => x + 1, 30, 1)); ctx.strokeStyle = 'green'; ctx.stroke(createPath(2, 5, x => x ** 2 + 4, 30, 1)); ctx.strokeStyle = 'blue'; ctx.stroke(createPath(5, 10, x => x ** 2 + 2 * x + 1, 30, 1)); </script> </body> </html> |
Вот ссылка на график file:///C:/Users/%D0%98%D0%97%D0%9E/Desktop/JS1/Graf.html
|
Rise,
Уважаемый Rise ! Спасибо. У Вас отлично получилось решение указанной проблемы с построением графиков. Но, почему то, не показаны чиловые оси X и Y. Это же, графики, не просто линии.... |
<html><head> <script> function DrawFn() { var ctx = document.querySelector("canvas").getContext("2d"); var width = ctx.canvas.width; var height = ctx.canvas.height; var size_x = width - 40; var size_y = height - 24; var drawer; var i, x0, x1, x2, x, y, max_y, el, fn, range; var els = document.getElementsByName("Fn_X"); ctx.save(); ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.strokeStyle = "black"; ctx.fillStyle = "black"; ctx.beginPath(); ctx.translate(32, 8); ctx.rect(0, 0, size_x, size_y); // Черртим рамку for(i = 0; i <= 10; ++ i) { // Размечаем ось X ctx.moveTo(i * size_x / 10, 0); ctx.lineTo(i * size_x / 10, size_y); ctx.fillText(String(i), i * size_x / 10 - 4, size_y + 16); if(i & 1) continue; // Размечаем ось Y ctx.moveTo(0, i * size_y / 10); ctx.lineTo(size_x, i * size_y / 10); ctx.fillText(String(i * 10), -16, (10 - i) * size_y / 10 + 8); } ctx.stroke(); // Очищаем основную област графика ctx.clearRect(8, 8, size_x - 16, size_y - 16); for(i = 0; i < els.length; ++ i) { ctx.strokeStyle = els[i].style.color; // Цвет линии графика соответствует цвету input-текста fn = els[i].value.split(/:/)[1]; // Выражение функции справа от двоеточия range = els[i].value.split(/:/)[0].split(".."); // Интервал участка задаётся форматом "от..до" слева от двоеточия x1 = parseInt(range[0]); x2 = parseInt(range[1]); max_y = size_y; ctx.beginPath(); drawer = ctx.moveTo.bind(ctx); for(x0 = size_x * x1 / 10; x0 < size_x * x2 / 10; ++ x0) { x = x0 / size_x * 10; try { with(Math) { drawer(x0, y = size_y - eval(fn) * size_y / 100); max_y = Math.min(max_y, y); } } catch(err) { break; } drawer = ctx.lineTo.bind(ctx); } ctx.stroke(); ctx.beginPath(); ctx.moveTo(x0, 0); ctx.lineTo(x0, size_y); ctx.setLineDash([1, 2]); ctx.strokeStyle = "black"; ctx.stroke(); ctx.setLineDash([]); fn = fn.replace(/\*\*2/g, "\u00B2").replace(/\*\*3/g, "\u00B3").replace(/\*/g, ""); ctx.fillText(fn, size_x * (x1 + (x2 - x1) / 2) / 10, max_y); } ctx.restore(); } </script> </head> <body onload='DrawFn()'> Y2(x)=<input type=text name=Fn_X value='0..2:x+1' onchange='DrawFn()' style=color:magenta><br> Y3(x)=<input type=text name=Fn_X value='2..5:x**2+4' onchange='DrawFn()' style=color:red><br> Y4(x)=<input type=text name=Fn_X value='5..10:x**2-2*x+1' onchange='DrawFn()' style=color:orange><br> <canvas width=400px height=200px></canvas> </body> |
Вложений: 2
Замечено, что на балке, имеющей чередующиеся между собой неподвижные опоры и подвижные шарниры, при наличии участка, где если сделать подъём точки в бесшарнирном пролете, то можно получить вертикальное перемещение шарниров, как показано на картинке. Как с помощью JS описать этот процесс с выдачей необходимых результатов?
|
Вложений: 1
Вот так лучше рассмотреть рисунки
|
Вложений: 1
Rise,
Я попробовал к построенным Вами графикам пристроить оси координат, но получилось так, что все графики оказались сдвинутыми влево, в отрицательную область Х. Помогите, пожалуйста исправить этот сдвиг. [HTML]<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link href="./GrafPL.css" rel="stylesheet"> </head> <body style= "margin": 0;> <canvas id="canvas_plot" width="700" height="500"></canvas> <script src="./GrafPL.js"></script> </body> </html>[/HTML]const canvasPlot = document.getElementById(`canvas_plot`); const ctx = canvasPlot.getContext(`2d`); //Рисуем сетку const canvasPlotWidth = canvasPlot.clientWidth; const canvasPlotHeight = canvasPlot.clientHeight; const scaleX = 30; //расстояние между элементами сетки по Х const scaleY = 30; //расстояние между элементами сетки по Y //Рисуем главные оси // Обычное расположение осей //const xAxis = canvasPlotWidth / 2; //const yAxis = canvasPlotHeight / 2; // Уточнённое расположение осей за счёт сдвига осей const xAxis = Math.round(canvasPlotWidth / scaleX / 2) * scaleX; const yAxis = Math.round(canvasPlotHeight / scaleY / 2) * scaleY; // Выбор шрифта и его вид, размер ctx.font = `${Math.round(scaleX / 2)}px Arial`; ctx.textAlign = `left`; ctx.textBaseline = `top`; ctx.beginPath(); ctx.strokeStyle = `#f5f0e8`; var zz = 5; //Зазор между осями и числами нумерации чисел for (let i = 0; i <= canvasPlotWidth; i = i + scaleX) { ctx.moveTo(i, 0); ctx.lineTo(i, canvasPlotHeight); // нанесение вертикальных линий разметки ctx.fillText((i - xAxis) / scaleX, i + zz, yAxis + zz); //нанесение числовых значений на ось Х } for (let i = 0; i <= canvasPlotHeight; i = i + scaleY) { ctx.moveTo(0, i); ctx.lineTo(canvasPlotWidth, i); // нанесение горизонтальных линий разметки ctx.fillText((yAxis - i) / scaleY, xAxis + zz, i + zz); //нанесение числовых значений на ось Y } ctx.stroke(); ctx.closePath(); //закрыть путь, чтобы рисовать новые линии другим цветом var zxy = 20; //Зазор между осями и обозначением этих осей x,y ctx.beginPath(); ctx.strokeStyle = `#000000`; ctx.moveTo(xAxis, 0); ctx.lineTo(xAxis, canvasPlotHeight); ctx.fillText(`y`, xAxis - zxy, 0 ); // означение оси Y ctx.moveTo(0, yAxis); ctx.lineTo(canvasPlotWidth, yAxis); ctx.fillText(`x`, canvasPlotWidth - zxy, yAxis - zxy ); // означение оси X ctx.stroke(); ctx.closePath(); //закрыть путь, чтобы рисовать новые линии другим цветом //ПРЕОБРАЗОВАНИЕ CANVAS СИСТЕМУ КООРДИНАТ В ДЕКАРТОВУ СИСТЕМУ КООРДИНАТ // Рисуем график функции //ctx.fillStyle = `#ff0000`; // цвет графика чёрный //ctx.lineWidth = 0.5 //толщина линии //for (let i = 0; i <= canvasPlotWidth; i++) { //const x = (i - xAxis) / scaleX; //const y = Math.pow(x, 2); //степенная фукция, y=x^2 //ctx.fillRect(x * scaleX + xAxis, yAxis - scaleY * y, 4, 4); //} function createPath(x1, x2, y, sx, sy) { const path = new Path2D(); for (let x = x1; x <= x2; x++) { if (x == x1) { path.moveTo(x * sx, y(x) * sy); } else { path.lineTo(x * sx, y(x) * sy); } } return path; } ctx.translate(0, 200); ctx.scale(1, -0.5); ctx.strokeStyle = 'red'; ctx.lineWidth = 4 //толщина линии ctx.stroke(createPath(0, 2, x => x + 1, 30, 1)); ctx.strokeStyle = 'green'; ctx.stroke(createPath(2, 5, x => x ** 2 + 4, 30, 1)); ctx.strokeStyle = 'blue'; ctx.stroke(createPath(5, 10, x => x ** 2 + 2 * x + 1, 30, 1)); |
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> |
Цитата:
|
Rise, оказалось так всё просто.. Спасибо !
|
Alikberov,
Графики, получились красивые, особенно, с осями координат. Спасибо за ответ. Однако, графики не имеют своих интервалов существования на оси Х, потому что они существуют на всей числовой оси Х и сходятся в одной точке (0, 0) |
Alikberov, Только, что опробовал Ваш код, и оказалось, что Вы построили все возможные варианты построения графиков. Поэтому, очень прошу извинить меня за мою невнимательность и ещё раз большое спасибо. Ваш код не просто правильный, но совершенно полноценный.
|
Alikberov,
Было бы здорово, если бы Вы, общий код разделили на три кода: Соответственно, для одного графика, для графиков на разных интервалах, и графиков проходящих через (0,0). Сам, я боюсь чт что-нибудь не так сделаю или допушу досадную ошибку. Заранее благодарен. |
Увы! Код написан довольно быстро и местами небрежно. Имеет ряд недоработок:
Цитата:
Вот только комментарии не успел раскидать, из-за чего код слишком мутно выглядит. Вот фрагмент с пояснениями. var meine_diagramme = { min_x: 0, // Минимум по оси X на графике max_x: 10, // Максимум по оси X на графике min_y: 0, // Минимум по оси Y на графике max_y: 100, // Максимум по оси Y на графике step_x: 1, // Шаг цифровой разметки по оси X под графиком step_y: 20, // Наш цифровой разметки по оси Y слева от графика width: 390, // Ширина Canvas-области - масштаб графика height: 120, // Высота Canvas-области fn: [ // Здесь можем перечислить массивом все наши функции { x1: 0, // Начальная точка на оси X x2: 100, // Конечная точка на оси X color: "red", // Цвет линии построения графика fn: "x**2" // Ведущая функция на графике } ] }; // Создаём объект графика и передаём ему реквизиты var grafik = new Functions(meine_diagramme); // Добавляем его на страницу document.body.appendChild(grafik.domElement); // Теперь добавим вторую функцию var mein_diagramm = { x1: 2.5, // Начальная точка на оси X x2: 7.5, // Конечная точка на оси X color: "blue", // Цвет линии построения графика fn: "30*sin(10*x)+60" }; // Пауза перед добавлением второго графика setTimeout(`grafik.draw([mein_diagramm])`, 5000); // Пауза перед очищением области графика setTimeout(`grafik.clear()`, 10000); // Пауза перед отображением только второго графика`); setTimeout(`grafik.draw([mein_diagramm])`, 15000); // Пауза перед смещением оси путём коррекции минимума на сетке setTimeout(`grafik.grid.min_x = -12; grafik.clear()`, 20000); // Пауза перед отображением двух графиков setTimeout(`mein_diagramm.x1 = -10; grafik.draw([mein_diagramm, meine_diagramme.fn[0]])`, 25000); |
Alikberov,
Уважаемый Alikberov, так как, я не такой опытный, как Вы, мне так и не удалось Ваш код разделить на три кода ( три типа построения графиков) Убрал строки 152-170 с целью убрать первый тип графиков и, как и ожидалось ничего не получилось (где то ошибка). Вернее, после этого пошли ошибки за ошибкой, которые надо было исправлять. Убедительно прошу разделить общий файл на три по типам построения графиков. Если, есть возможность дайте хоть, какие нибудь главные комментарии. |
Alikberov, Извините, опять поторопился со своим последним сообщением. Мне удалось Ваш код разделить на три кода ( три типа построения графиков). Правда, потратил на это несколько часов.
|
Вот Вам Конструктор Графиков с "горячей отладкой".
(Можно изменять любые параметры как мышкой, так и JSON.) Правда, там не всё работает так, как хотелось бы мне. Но это поправимо в дальнейшем. P.S.: Класс переименовал, добавил сетку и легенду. |
Alikberov,
График не реагирует на изменения шкалы, а должен по идее. Могу подсказать, где подсмотреть можно на эту тему, если интересно. |
Вложений: 1
Alikberov, Я взял за основу Ваш код для построения графиков, но не смог нарисовать обыкновенные геометрические фигуры ромба и окружности, которые привязаны к определенной координате (См.картинку). Попробовал нарисовать обыкновенный отрезок, а он уехал, вобще, куда-то из области координат. Ваш код настолько насышен различными тегами, что я точно не смогу разобраться в чём дело. Видимо здесь более глубинные причины разрыва осей координат от геометрических фигур. Прошу, если возможно, упростить или сделать понятным высланный мной код HTML, который я выделил из общего Вашего кода. И, самое главное - нарисовать ромб и окружность, показанные на картинке. Их размеры должны быть сооизмеримы с координатными осями.
<!DOCTYPE html> <html><head> <canvas id="canvas"></canvas> <script> var canv = document.getElementById(`canvas`), ctx = canv.getContext(`2d`); // рисуем в 2d 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: 40, min_y: -8, max_y: 8, step_x: 1, step_y: 20, width: 600, height: 200, fn: [ { x1:0, x2:6, color: "red", fn: "x**2" } ] }).domElement ); } //линия 1 ctx.beginPath(); ctx.moveTo(200, 0); ctx.lineTo(300, 1000); ctx.stroke(); ctx.closePath(); </script> <style> canvas { display: block; } body { background-color: silver; } </style> </head> <body onload='Draw_Fn()'> </body> |
Цитата:
У меня в двух браузерах (Chrome и Firefox ESR) отрабатывается нормально. Цитата:
Очень буду рад помощи в этой бесконечной и бессмыленной битве с кросс-браузерностью.:thanks: Цитата:
Класс просто не расчитывался для внешего вмешательства. Цитата:
Цитата:
|
Вложений: 1
Цитата:
строки #503 // Рисуем на первом графике hChart.context.strokeStyle = "blue"; hChart.transform(); // Трансформации контекста холста под формат графика hChart.context.beginPath(); // Рисуем ромб в точке 7,0 hChart.context.moveTo(7, 1); hChart.context.lineTo(7.5, 0); hChart.context.lineTo(7, -1); hChart.context.lineTo(6.5, 0); hChart.context.closePath(); // Рисуем эллипс в точке 11,0 hChart.context.moveTo(11, 0); hChart.context.ellipse(11, 0, 0.5, 0.5, 0, 0, 2 * Math.PI); // Сбрасываем трансформацию, чтобы толшина кисти восстановилась hChart.context.setTransform(1, 0, 0, 1, 0, 0); // Отображаем ромб и эллипс hChart.context.stroke();Тaк подойдёт (смотрите изображение)? |
Изображения то, что нужно!
|
Вложений: 2
1. Если, построить ломанную линию (см.рис.1) способом построения геометрической фигуры, то , видимо, нельзя будет определить значения хc и yc в любой точке ломанной линии и площади фигуры под ломанной линией на любом отрезке xn…xk (см. рис.2). Поэтому, наверное, надо данную ломанную линию построить в виде графика функции. Координаты по X : 0, 5, 10, 16, 21, 30, 33. По Y: 0, 2.24, -1.49, 1.5, -1, 0.5, 0.
2. В точках X: 8, 13, 19, 27, 33. Надо построить ромбы, в точках Х: 5, 10, 16, 21, 30. надо построить окружности (не эллипсы). Методом копирования. Приведённые выше числовые данные могут быть произвольными значениями. Хорошо бы было, если были бы удалены теги (строки) относящиеся к остальным графикам и оставлено в коде только то, что относится к графику ломанной линии, ромбов и окружностей. Прошу помочь, так как, мне это точно не осилить…. |
Вложений: 2
высыланные в предыдущем сообщении картинки не совсем разборчивы. Высылаю ещё раз
|
Цитата:
Следуйте правилам контекста Canvas и добавляйте свои инструкции. Кликайте на график, чтобы изменения вступили в силу. Если допустите ошибку, текстовое поле поменяет цвет. |
Вложений: 1
Цитата:
Дан треугольник с длиной основания 8 пунктов. Вершина треугольника находится в пункте 5 на высоте 2.24 пункта. Опишем его переменными: Ax = 0, Bx = 8 Cx = 5, Cy = 2.24 По сути, мы имеем тут два прямоугольных треугольника: Ax = 0, Cx = 5, Cy = 2.24 // левый треугольник Cx = 5, Bx = 8, Cy = 2.24 // правый прямоугольник Так как из двух одинаковых прямоугольников можем получить прямоугольник, находим их площади через площади прямоугольников с делением пополам. Находим площадь: S_left_rect = (Cx - Ax) * Cy // площадь левого прямоугольника S_right_rect = (Bx - Cx) * Cy S_left_triangle = S_left_rect / 2 // площадь левого треугольника AxCxCy S_right_triangle = S_right_rect / 2 // площадь правого треугольника CxBxCy S_triangle = S_left_triangle + S_right_triangle // площадь целого треугольника AxBxCy Теперь нужно узнать площадь заштрихованной области xn,yn,xk,yk. Опишем переменными: xn = 3 // начало штриховки xk = 6 // конец штриховки yn = ??? // нужно найти yk = ??? // нужно найти Используя метод вычислительного построения линии, находим yn: delta_x = Cx - Ax // длина отрезка AxCx (5 пунктов) yn = (xn - Ax) / delta_x * Cy // (3 - 0) / 5 * 2.24 = 1.344 Используя метод вычислительного построения линии, находим yk: delta_x = Bx - Cx // длина отрезка CxBx (3 пункта) yk = (Bx - xk) / delta_x * Cy // (8 - 6) / 3 * 2.24 = 1.493 Теперь мы имеем: xn = 3 // начало штриховки xk = 6 // конец штриховки yn = 1.344 // минимальная высота начала штриховки yk = 1.493 // минимальная высота конца штриховки Для начала нужно разобраться, что мы видим под этой штриховкой вообще: Прямоугольник №1: xn,Cx,yn Прямоугольник №2: Cx,xk,yk Прямоугольный треугольник №1: xn,yn,Cy Прямоугольный треугольник №2: Cx,xk,Cy Площадь будем искать подобным методом: Через вычитание суммы площадей двух нештрихованных треугольников над заштрихованной областью. Находим площадь незаштрихованных треугольников и вычитаем её из общей площади: S_left_rect = (Cx - xn) * Cy // Прямоугольник xnCxCy: (5 - 3) * 2.24 = 4.48 S_right_rect = (xk - Cx) * Cy // Прямоугольник xkCxCy: (6 - 5) * 2.24 = 2.24 S_left_triangle = (Cx - xn) * (Cy - yn) / 2 // Треугольник ynCxCy: (5 - 3) * (2.24 - 1.344) / 2 = 0.896 S_right_triangle = (xk - Cx) * (Cy - yk) / 2 // Треугольник xkCxCy: (6 - 5) * (2.24 - 1.493) / 2 = 0.3735 Теперь складываем площади двух нижних заштрихованных прямоугольников с площадами треугольников над ними: S_hatching = S_left_rect + S_left_triangle + S_right_rect + S_right_triangle // 7.9895 Как видно, всё не так уж сложно и требует неких навыков программисткого мышления. Цитата:
Так как нужно всего навсего строить ломанную по координатам из массива, на оси X отмечать начало очередной линии, а вот ромбики нужно чертить в точке прохождения линий через нулевую отметку на Y. Запустите gist: Я добавил отрисовку ломанной по массиву с ромбиками и кружочками. Вoт здесь я разместил простой скрипт со всеми нужными формулами расчёта площади фигуры под ломанной линией на любом отрезке (в пределах одного треугольника). (Расчёт площади по ломанной на отрезке со смежными треугольниками требует простого сложения таких площадей с нехитрой эвристикой…) |
Часовой пояс GMT +3, время: 00:28. |