Rysowanie wykresów funkcji w html5 canvas 

{
24.07.2011
}
WebdevJavascriptHtml5
W tym artykule napiszemy program rysujący wykresy funkcji 2d. Zanim rozpoczniesz czytanie tego tutoriala warto zapoznać się z artykułem podstawy html5 canvas. Zaczniemy od stworzenia bazowego dokumentu html, na którym będziemy opierać skrypty. Najważniejszym elementem jest tu canvas o id obrazek. To na nim będziemy rysować.
<!doctype html>
<html><head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Rysowanie wykresów funkcji 2d</title>
</head>
	<body>
		<canvas style="border:1px solid black;" id="obrazek" width="800" height="600"></canvas>
		<input type="text" name="function" id="function" value="" />
		<input type="submit" name="button" id="button" value="Rysuj" />
		<button id="clear">czyść</button><br />
		Kolor linii: <select id="color">
		<option value="green">Zielony</option>
		<option value="red">Czerwony</option>
		<option value="blue">Niebieski</option>
		</select><br/>
		<script type="text/javascript" src="jquery-1.4.2.js"></script>
		<script type="text/javascript" src="main.js"></script>
	</body>
</html> 
  1. <!doctype html>
  2. <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
  3. <title>Rysowanie wykresów funkcji 2d</title>
  4. </head>
  5.         <body>
  6.                 <canvas style="border:1px solid black;" id="obrazek" width="800" height="600"></canvas>
  7.                 <input type="text" name="function" id="function" value="" />
  8.                 <input type="submit" name="button" id="button" value="Rysuj" />
  9.                 <button id="clear">czyść</button><br />
  10.                 Kolor linii: <select id="color">
  11.                 <option value="green">Zielony</option>
  12.                 <option value="red">Czerwony</option>
  13.                 <option value="blue">Niebieski</option>
  14.                 </select><br/>
  15.                 <script type="text/javascript" src="jquery-1.4.2.js"></script>
  16.                 <script type="text/javascript" src="main.js"></script>
  17.         </body>
  18. </html>
Teraz stwórzmy plik main.js, w którym będzie się znajdował skrypt rysujący. Na początku określmy w nim kilka zmiennych. Poz zmienną canvas zapisujemy nasz element canvas, następnie łapiemy context. Kolejne zmienne to zmienne pomocnicze takie jak szerokość i wysokość canvasa, zakres (range) - oznacza ile pikseli na ekranie będzie miała rzeczywista jedna jednostka.
var canvas = document.getElementById('obrazek');
var ctx = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
var range = 100;
var bl = 1;
var rangex = w/range;
var rangey = h/range;
var color = "green";
  1. var canvas = document.getElementById('obrazek');
  2. var ctx = canvas.getContext('2d');
  3. var w = canvas.width;
  4. var h = canvas.height;
  5. var range = 100;
  6. var bl = 1;
  7. var rangex = w/range;
  8. var rangey = h/range;
  9. var color = "green";
Najpierw stworzymy funkcję grid, rysującą siatkę czyli układ współrzędnych.
function grid()
{
	ctx.strokeStyle = "black";
	for(i=1;i<=Math.floor(rangex*2);i++)
	{
		ctx.lineWidth = 1/6;
		ctx.beginPath();
		ctx.moveTo((range/2)*i,0);
		ctx.lineTo((range/2)*i,h);
		ctx.closePath();
		ctx.stroke();
	}
	for(i=1;i<=Math.floor(rangey*2);i++)
	{
		ctx.lineWidth = 1/6;
		ctx.beginPath();
		ctx.moveTo(0,(range/2)*i);
		ctx.lineTo(w,(range/2)*i);
		ctx.closePath();
		ctx.stroke();
	}
	ctx.lineWidth = 1;
	ctx.beginPath();
	ctx.moveTo(0,h/2);
	ctx.lineTo(w,h/2);
	ctx.closePath();
	ctx.stroke();

	ctx.beginPath();
	ctx.moveTo(w/2,0);
	ctx.lineTo(w/2,h);
	ctx.closePath();
	ctx.stroke();
	for(i=-(rangex/2);i<=(rangex/2);i++)
	{
		ctx.fillText(i,(i+(rangex/2))*range,h/2);
	}
	ctx.save();
}
grid();
  1. function grid()
  2. {
  3.         ctx.strokeStyle = "black";
  4.         for(i=1;i<=Math.floor(rangex*2);i++)
  5.         {
  6.                 ctx.lineWidth = 1/6;
  7.                 ctx.beginPath();
  8.                 ctx.moveTo((range/2)*i,0);
  9.                 ctx.lineTo((range/2)*i,h);
  10.                 ctx.closePath();
  11.                 ctx.stroke();
  12.         }
  13.         for(i=1;i<=Math.floor(rangey*2);i++)
  14.         {
  15.                 ctx.lineWidth = 1/6;
  16.                 ctx.beginPath();
  17.                 ctx.moveTo(0,(range/2)*i);
  18.                 ctx.lineTo(w,(range/2)*i);
  19.                 ctx.closePath();
  20.                 ctx.stroke();
  21.         }
  22.         ctx.lineWidth = 1;
  23.         ctx.beginPath();
  24.         ctx.moveTo(0,h/2);
  25.         ctx.lineTo(w,h/2);
  26.         ctx.closePath();
  27.         ctx.stroke();
  28.  
  29.         ctx.beginPath();
  30.         ctx.moveTo(w/2,0);
  31.         ctx.lineTo(w/2,h);
  32.         ctx.closePath();
  33.         ctx.stroke();
  34.         for(i=-(rangex/2);i<=(rangex/2);i++)
  35.         {
  36.                 ctx.fillText(i,(i+(rangex/2))*range,h/2);
  37.         }
  38.         ctx.save();
  39. }
  40. grid();
Ustawiamy kolor linii na czarny. Kolejne dwie pętle for odpowiedzialne są za narysowanie siatki. Pierwszy for rysuje tylko pionowe linie, drugi poziome. Omówię tylko pierwszy for. Wykonujemy pętlę od 1 do Math.floor(rangex*2). Ustawiamy szerokość linii i rozpoczynamy ścieżkę. Na początek określamy punkt początkowy rysowania na ((range/2)*i,0) i prowadzimy od niego linię do (range/2)*i,h). W celu zakończenia rysowania danej linii musimy jeszcze dopisać
ctx.closePath();
ctx.stroke();
  1. ctx.closePath();
  2. ctx.stroke();
Najlepiej przedstawi to rysunek: siatka z uwzględnieniem zakresów Po pętlach rysujemy dwie linie (pionową i poziomą) o grubości 1 biegnące przez środek canvasa. Będą to osie układu współrzędnych. Ostatnia pętla dodaje podpisy jednostek do osi x. Na koniec zapisujemy stan canvas metodą save. W kolejnej funkcji, którą napiszemy określimy ustawienia startowe.
function start_settings()
{
	ctx.translate(w/2, h/2);
	ctx.scale(range,range);
}
start_settings();
  1. function start_settings()
  2. {
  3.         ctx.translate(w/2, h/2);
  4.         ctx.scale(range,range);
  5. }
  6. start_settings();
Funkcją translate przesuwamy punkt (0,0) na środek naszego canvasa. Jest to bardziej intuicyjne z matematycznego punktu widzenia. Funkcją scale powiększamy nasz rysunek stukrotnie. Robimy tak ponieważ chcemy odwzorować nie rzeczywiste jednostki canvasa lecz stworzoną przez nas skalę (100px = 1 jednostka). Pozostała już tylko funkcja rysująca wykres. Przedstawia się następująco.
function plot()
{
	ctx.strokeStyle = color;
	ctx.lineWidth = 1/50;
	var f = document.getElementById("function").value;
	var fun1 = new Function("x", "return "+f);
	ctx.beginPath();
	for(x=-rangex;x<=rangex;x+=0.01)
	{
		y = fun1(x);
		if(y!='')
		{
			if (isNaN(y) || (y == Number.NEGATIVE_INFINITY) ||
			(y == Number.POSITIVE_INFINITY) || (Math.abs(y) > 2e5)) {
			bl = 2;
			y = 0.0;
			}
			if (bl > 0)
			{
				if (bl == 1)
				{
					ctx.moveTo(x, -y);
				}
				--bl;
			}
			else {
				ctx.lineTo(x, -y);
			}
		}

	}
	ctx.stroke();
}
  1. function plot()
  2. {
  3.         ctx.strokeStyle = color;
  4.         ctx.lineWidth = 1/50;
  5.         var f = document.getElementById("function").value;
  6.         var fun1 = new Function("x", "return "+f);
  7.         ctx.beginPath();
  8.         for(x=-rangex;x<=rangex;x+=0.01)
  9.         {
  10.                 y = fun1(x);
  11.                 if(y!='')
  12.                 {
  13.                         if (isNaN(y) || (y == Number.NEGATIVE_INFINITY) ||
  14.                         (y == Number.POSITIVE_INFINITY) || (Math.abs(y) > 2e5)) {
  15.                         bl = 2;
  16.                         y = 0.0;
  17.                         }
  18.                         if (bl > 0)
  19.                         {
  20.                                 if (bl == 1)
  21.                                 {
  22.                                         ctx.moveTo(x, -y);
  23.                                 }
  24.                                 --bl;
  25.                         }
  26.                         else {
  27.                                 ctx.lineTo(x, -y);
  28.                         }
  29.                 }
  30.  
  31.         }
  32.         ctx.stroke();
  33. }
Ustawiamy kolor i grubośc linii. Zapisujemy w zmiennej f funkcję wpisaną do inputa o id function. Funkcje muszą być wpisywane w postaci: Math.sin(x) + x*x, czyli korzystając z obiektu Math i dostępnych w javascripcie operatotów. Natomiast pod zmienną fun1 tą samą funkcję evalowaną jako funkcja zmiennej x. Rozpoczynamy rysowanie ścieżki (beginPath). Pętlą for przechodzimy przez x. Do zmiennej y zapisujemy wartość funkcji dla określonego x. Następnie wykonujemy ifa czy y jest różne od pustego ciągu znaków i dopiero wtedy wykonujemy właściwe rysowanie. Sprawdzamy w kolejnym warunku czy obliczona wartość y jest liczbą, jest równa nieskończoności itd. Jeśli tak nie jest ustawiamy zmienną bl na 2 i zmiennej y przypisujemy wartość 0. Następnie w zależności od wartości bl rysujemy linię za pomocą lineTo lub ustawiamy punkt startowy rysowania (moveTo). W obu metodach mamy znak minusa przed y, ponieważ układ współrzędnych w przeglądarce jest odwrócony (wartości na osi y rosną do dołu) w stosunku do tego znanego ze szkoły. Funkcję plot kończymy wywołaniem metody stroke. Musimy jeszcze przypisać wykonanie funkcji plot do zdarzenie kliknięcia na przycisku.
document.getElementById("button").onclick = plot;
  1. document.getElementById("button").onclick = plot;
Działanie skryptu rysującego wykresy możesz zobaczyć tutaj.
Dodaj do:
Brak komentarzy

Dodaj komentarz