Rozdział 5. Rysowanie na kanwie w HTML5 (element canvas)

> Dodaj do ulubionych

Do rzeczy

W j─Özyku HTML5 dost─Öpny jest element canvas o nast─Öpuj─ůcej definicji: „zale┼╝na od rozdzielczo┼Ťci mapa bitowa stanowi─ůca kanw─Ö rysunku, kt├│rej mo┼╝na u┼╝ywa─ç do renderowania na bie┼╝─ůco wykres├│w, obraz├│w w grach i innych rodzaj├│w grafiki”. Kanwa to prostok─ůtny obszar na stronie, w kt├│rym mo┼╝na rysowa─ç dowolne obrazy za pomoc─ů JavaScriptu.

Obs┼éuga elementu canvas przez przegl─ůdarki
IEFirefoxSafariChromeOperaiPhoneAndroid
7.0+*3.0+3.0+3.0+10.0+1.0+1.0+
* Internet Explorer 7 i 8 wymagaj─ů dodatku zewn─Ötrznej biblioteki explorercanvas. Internet Explorer 9 standardowo obs┼éuguje element <canvas>.

Jak wygl─ůda kanwa? Tak naprawd─Ö to w og├│le nie wygl─ůda. Element canvas nie ma tre┼Ťci ani obramowania.

Niewidoczna kanwa

Kod ┼║r├│d┼éowy tego elementu jest nast─Öpuj─ůcy:

<canvas width="300" height="225"></canvas>

Dodamy przerywane obramowanie, aby było widać o czym jest mowa.

Kanwa z obramowaniem

Na jednej stronie mo┼╝e znajdowa─ç si─Ö wiele element├│w canvas. Ka┼╝dy z nich jest uwzgl─Ödniony w drzewie DOM i ma sw├│j w┼éasny stan. Je┼Ťli ka┼╝dej kanwie przypisze si─Ö identyfikator, to mo┼╝na si─Ö do nich odwo┼éywa─ç w taki sam spos├│b, jak do innych element├│w.

Dodamy do przedstawionego przykładu atrybut id:

<canvas id="a" width="300" height="225"></canvas>

Teraz bez trudu mo┼╝na znale┼║─ç ten element w drzewie DOM.

var a_canvas = document.getElementById("a");

Proste kształty

IEFirefoxSafariChromeOperaiPhoneAndroid
7.0+*3.0+3.0+3.0+10.0+1.0+1.0+
* Internet Explorer 7 i 8 wymagaj─ů dodatku zewn─Ötrznej biblioteki explorercanvas. Internet Explorer 9 standardowo obs┼éuguje kszta┼éty w elemencie canvas.

Ka┼╝da kanwa jest na pocz─ůtku pusta. Nic ciekawego! Dlatego trzeba co┼Ť na niej narysowa─ç.

Procedura obs┼éugi zdarzenia onclick wywo┼éuje poni┼╝sz─ů funkcj─Ö:

function draw_b() {
  var b_canvas = document.getElementById("b");
  var b_context = b_canvas.getContext("2d");
  b_context.fillRect(50, 25, 150, 100);
}

Pierwszy wiersz tej funkcji nie zawiera niczego niezwykłego. Znajduje tylko element canvas w strukturze DOM.

Ale za nim znajduje si─Ö ten wyr├│┼╝niony wiersz.

function draw_b() {
  var b_canvas = document.getElementById("b");
  var b_context = b_canvas.getContext("2d");
  b_context.fillRect(50, 25, 150, 100);
}

Każda kanwa ma kontekst rysunku, w którym wszystko sie odbywa. Po znalezieniu elementu canvas w drzewie DOM (przy użyciu metody document.getElementById() albo dowolnej innej), wywołuje się jego metodę getContext(). Metodzie tej musimy przekazać łańcuch "2d".

P: Czy istnieje kanwa 3D?
O: Na razie nie. Tw├│rcy przegl─ůdarek eksperymentuj─ů z w┼éasnymi API tr├│jwymiarowych kanw, ale ┼╝adne z nich nie doczeka┼éo si─Ö standardu. W specyfikacji HTML5 zaznaczono, ┼╝e „w przysz┼éo┼Ťci prawdopodobnie zostanie zdefiniowany kontekst 3D”.

Mamy wi─Öc ju┼╝ element canvas i jego kontekst rysunku. W kontek┼Ťcie rysunku zdefiniowane s─ů wszystkie metody i w┼éasno┼Ťci dotycz─ůce rysowania. Istnieje ca┼éa grupa w┼éasno┼Ťci i metod do rysowania prostok─ůt├│w:

  • Warto┼Ťci─ů w┼éasno┼Ťci fillStyle mo┼╝e by─ç kolor w formacie CSS, wz├│r albo gradient. (Wi─Öcej o gradientach dowiesz sie wkr├│tce). Domy┼Ťlnie w┼éasno┼Ť─ç fillStyle definiuje jednolity czarny kolor, ale mo┼╝na to zmieni─ç. Ka┼╝dy kontekst rysunkowy pami─Öta swoje w┼éasno┼Ťci przez ca┼éy okres otwarcia strony, chyba ┼╝e si─Ö je jako┼Ť zresetuje.
  • Wywo┼éanie fillRect(x, y, width, height) powoduje narysowanie prostok─ůta wype┼énionego bie┼╝─ůcym kolorem wype┼énienia.
  • W┼éasno┼Ť─ç strokeStyle jest podobna do fillStyle — jej warto┼Ťci─ů mo┼╝e by─ç kolor w formacie CSS, wz├│r lub gradient.
  • Wywo┼éanie strokeRect(x, y, width, height) powoduje narysowanie prostok─ůta z obrysem o bie┼╝─ůcym stylu. Metoda strokeRect nie wype┼énia wn─Ötrza figury, tylko rysuje jej kraw─Ödzie.
  • Metoda clearRect(x, y, width, height) kasuje ustawienia pikseli w okre┼Ťlonym prostok─ůcie.

Pytanie do profesora Kodeckiego

P: Czy mo┼╝na „zresetowa─ç” kanw─Ö?
O: Tak. Ustawienie szeroko┼Ťci lub wysoko┼Ťci elementu <canvas> powoduje skasowanie jego zawarto┼Ťci oraz przywr├│cenie domy┼Ťlnych warto┼Ťci wszystkich w┼éasno┼Ťci jego kontekstu rysunkowego. Nie trzeba nawet zmienia─ç szeroko┼Ťci. Wystarczy ustawi─ç j─ů jeszcze raz na tak─ů sam─ů warto┼Ť─ç, np.:

var b_canvas = document.getElementById("b");
b_canvas.width = b_canvas.width;

Wr├│cimy do poprzedniego przyk┼éadu kodu…

Rysowanie prostok─ůta:

var b_canvas = document.getElementById("b");
var b_context = b_canvas.getContext("2d");
b_context.fillRect(50, 25, 150, 100);

Metoda fillRect() rysuje prostok─ůt i wype┼énia go bie┼╝─ůcym stylem wype┼énienia, kt├│re je┼Ťli nie zostanie zmienione jest czarne. Wymiary prostok─ůta okre┼Ťlaj─ů po┼éo┼╝enie jego lewego g├│rnego rogu (50, 25), szeroko┼Ť─ç (150) oraz wysoko┼Ť─ç (100). Aby to lepiej zrozumie─ç, przyjrzymy si─Ö dok┼éadniej uk┼éadowi wsp├│┼érz─Ödnych kanwy.

Współrzędne na kanwie

Kanwa jest dwuwymiarowym uk┼éadem wsp├│┼érz─Ödnych. Punkt o wsp├│┼érz─Ödnych (0, 0) znajduje si─Ö w lewym g├│rnym rogu kanwy. Na osi x warto┼Ťci zwi─Ökszaj─ů si─Ö w prawo. Na osi y warto┼Ťci zwi─Ökszaj─ů si─Ö w d├│┼é.

Schemat układu współrzędnych

Schemat układu współrzędnych

Ten układ współrzędnych został narysowany przy użyciu elementu canvas. Rysunek ten zawiera:

  • zestaw poziomych linii w kolorze z┼éamanej bieli,
  • zestaw pionowych linii w kolorze z┼éamanej bieli,
  • dwie czarne poziome linie,
  • dwie ma┼ée sko┼Ťne linie tworz─ůce grot strza┼éki,
  • dwie czarne pionowe linie,
  • dwie ma┼ée sko┼Ťne linie tworz─ůce drugi grot strza┼éki,
  • liter─Ö x,
  • liter─Ö y,
  • tekst „(0, 0)” umiejscowiony w pobli┼╝u lewego g├│rnego rogu,
  • tekst „(500, 375)” umiejscowiony w pobli┼╝u prawego dolnego rogu,
  • dwie kropki: w lewym g├│rnym i prawym dolnym rogu.

Najpierw trzeba zdefiniowa─ç sam element canvas. W naszym elemencie zdefiniowali┼Ťmy atrybuty width i height oraz id, dzi─Öki kt├│remu b─Ödziemy mogli go p├│┼║niej odnale┼║─ç.

<canvas id="c" width="500" height="375"></canvas>

Kolejn─ů potrzebn─ů nam rzecz─ů jest skrypt, kt├│ry znajdzie element canvas w drzewie DOM i pozwoli nam uzyska─ç dost─Öp do jego kontekstu rysunkowego.

var c_canvas = document.getElementById("c");
var context = c_canvas.getContext("2d");

Teraz mo┼╝emy rozpocz─ů─ç rysowanie linii.

Ścieżki

IEFirefoxSafariChromeOperaiPhoneAndroid
7.0+*3.0+3.0+3.0+10.0+1.0+1.0+
* Internet Explorer 7 i 8 wymagaj─ů dodatku zewn─Ötrznej biblioteki explorercanvas. Internet Explorer 9 standardowo obs┼éuguje ┼Ťcie┼╝ki elementu <canvas>.

Wyobra┼║ sobie, ┼╝e rysujesz co┼Ť atramentem. Raczej nie zaczniesz od razu tak po prostu rysowa─ç, bo mo┼╝esz pope┼éni─ç b┼é─ůd. Najpierw pewnie zrobisz szkic o┼é├│wkiem, a gdy osi─ůgniesz zadowalaj─ůcy efekt poprawisz linie atramentem.

Kanwy maj─ů ┼Ťcie┼╝ki. Definiowanie ┼Ťcie┼╝ki jest odpowiednikiem rysowania szkicu o┼é├│wkiem. Mo┼╝na narysowa─ç co si─Ö chce, ale dop├│ki nie poprawi si─Ö linii atramentem nie b─Ödzie tego wida─ç na gotowym rysunku.

Aby narysowa─ç prost─ů lini─Ö za pomoc─ů o┼é├│wka, nale┼╝y u┼╝y─ç dw├│ch metod:

  1. moveTo(x, y) — przenosi o┼é├│wek w wyznaczone miejsce.
  2. lineTo(x, y) — rysuje lini─Ö do okre┼Ťlonego punktu.

Im wi─Öcej wywo┼éa┼ä metod moveTo() i lineTo(), tym wi─Öksza ┼Ťcie┼╝ka. To s─ů metody „o┼é├│wkowe”, tzn. mo┼╝na je wywo┼éywa─ç do woli, ale dop├│ki nie u┼╝yje si─Ö jednej z metod „atramentowych” nie b─Ödzie wida─ç ┼╝adnego efektu.

Najpierw narysujemy siatk─Ö.

Rysowanie pionowych linii

for (var x = 0.5; x < 500; x += 10) {
  context.moveTo(x, 0);
  context.lineTo(x, 375);
}

Rysowanie poziomych linii

for (var y = 0.5; y < 375; y += 10) {
  context.moveTo(0, y);
  context.lineTo(500, y);
}

To by┼éy metody „o┼é├│wkowe”. Na kanwie nie wida─ç jeszcze ┼╝adnego rysunku. ┼╗eby sta┼é si─Ö widoczny, musimy u┼╝y─ç metody „atramentowej”.

context.strokeStyle = "#eee";
context.stroke();

stroke() jest jedn─ů z metod „atramentowych”. Pobiera skomplikowan─ů ┼Ťcie┼╝k─Ö zdefiniowan─ů przy u┼╝yciu metod moveTo() i lineTo() i tworzy rysunek na kanwie. Metoda strokeStyle s┼éu┼╝y do ustawiania koloru linii. Oto wynik dzia┼éania przedstawionego skryptu:

Kanwa

Pytanie do profesora Kodeckiego

P: Dlaczego zmienne x i y maj─ů warto┼Ť─ç pocz─ůtkow─ů 0.5? Dlaczego nie 0?
O: Wyobra┼║ sobie, ┼╝e ka┼╝dy piksel jest du┼╝ym kwadratem. Wsp├│┼érz─Ödne ca┼ékowitoliczbowe (0, 1, 2…) s─ů kraw─Ödziami tych kwadrat├│w. Je┼Ťli mi─Ödzy wsp├│┼érz─Ödnymi ca┼ékowitoliczbowymi narysujesz lini─Ö o szeroko┼Ťci jeden, najdzie ona na przeciwne strony kwadratu piksela i powstanie linia o szeroko┼Ťci dw├│ch pikseli. Aby narysowa─ç lini─Ö o szeroko┼Ťci tylko jednego piksela, nale┼╝y przesun─ů─ç wsp├│┼érz─Ödne o 0.5 prostopadle do linii.

Przyk┼éadowo, je┼Ťli narysujesz lini─Ö od punktu (1, 0) do (1, 3), przegl─ůdarka narysuje lini─Ö okrywaj─ůc─ů 0,5 piksela ekranu po ka┼╝dej stronie x=1. Na ekranie nie da si─Ö wy┼Ťwietli─ç tylko po┼éowy piksela, wi─Öc linia zostanie rozci─ůgni─Öta na dwa piksele:

Ale je┼Ťli spr├│bujesz narysowa─ç lini─Ö od punktu (1.5, 0) do (1.5, 3), przegl─ůdarka narysuje lini─Ö pokrywaj─ůc─ů po 0,5 piksela po ka┼╝dej stronie x=1.5, co daje w wyniku lini─Ö o szeroko┼Ťci jednego piksela:

Dzi─Ökuj─Ö Jasonowi Johnsonowi za te schematy.

Teraz narysujemy poziom─ů strza┼ék─Ö. Wszystkie proste i krzywe na ┼Ťcie┼╝ce s─ů w tym samym kolorze (albo maj─ů gradient, o czym zaraz b─Ödzie mowa). Jako ┼╝e strza┼éka ma mie─ç inny kolor — czarny, nie bia┼éy — musimy utworzy─ç now─ů ┼Ťcie┼╝k─Ö.

Nowa ┼Ťcie┼╝ka

context.beginPath();
context.moveTo(0, 40);
context.lineTo(240, 40);
context.moveTo(260, 40);
context.lineTo(500, 40);
context.moveTo(495, 35);
context.lineTo(500, 40);
context.lineTo(495, 45);

Pionowa strza┼éka jest bardzo podobna. Poniewa┼╝ ma taki sam kolor, jak pozioma strza┼éka, nie musimy dla niej tworzy─ç nowej ┼Ťcie┼╝ki. Obie strza┼éki b─Öd─ů nale┼╝a┼éy do jednej ┼Ťcie┼╝ki.

Nie nowa ┼Ťcie┼╝ka

context.moveTo(60, 0);
context.lineTo(60, 153);
context.moveTo(60, 173);
context.lineTo(60, 375);
context.moveTo(65, 370);
context.lineTo(60, 375);
context.lineTo(55, 370);

Napisa┼éem, ┼╝e strza┼éki maj─ů by─ç czarne, ale w┼éasno┼Ť─ç strokeStyle ma nadal kolor z┼éamanej bieli. (Ustawienia w┼éasno┼Ťci fillStyle i strokeStyle nie s─ů kasowane po utworzeniu nowej ┼Ťcie┼╝ki.) Na razie to nie przeszkadza, bo wykonali┼Ťmy tylko kilka wywo┼éa┼ä metod „o┼é├│wkowych”. Zanim jednak utrwalimy rysunek atramentem, musimy ustawi─ç w┼éasno┼Ť─ç strokeStyle na czer┼ä. W przeciwnym razie strza┼éki b─Öd─ů bia┼éawe i ledwie b─Ödzie je wida─ç! Poni┼╝sze wiersze kodu zmieniaj─ů kolor na czarny i rysuj─ů linie na kanwie:

context.strokeStyle = "#000";
context.stroke();

Oto wynik działania przedstawionego skryptu:

Kanwa2

Tekst

IEFirefoxSafariChromeOperaiPhoneAndroid
7.0+*3.0+3.0+3.0+10.0+1.0+1.0+
* Internet Explorer 7 i 8 wymagaj─ů dodatku zewn─Ötrznej biblioteki explorercanvas. Internet Explorer 9 standardowo obs┼éuguje tekst na kanwie.
† Mozilla Firefox 3.0 wymaga dodatku.

Opr├│cz linii na kanwie mo┼╝na te┼╝ rysowa─ç tekst. W odr├│┼╝nieniu od strony internetowej zawieraj─ůcej kanw─Ö, na kanwie nie ma czego┼Ť takiego, jak model polowy. To znaczy, ┼╝e nie mo┼╝na u┼╝ywa─ç ┼╝adnej z technik CSS komponowania uk┼éad├│w element├│w: nie ma element├│w p┼éywaj─ůcych, margines├│w, dope┼énienia ani w┼éasno┼Ťci zawijania tekstu. (Mo┼╝e niekt├│rzy pomy┼Ťl─ů, ┼╝e to bardzo dobrze!) Na kanwie ustawia si─Ö kilka w┼éasno┼Ťci czcionki, a nast─Öpnie okre┼Ťla punkt, w kt├│rym ma zosta─ç narysowany tekst.

W kontek┼Ťcie rysunku dost─Öpne s─ů nast─Öpuj─ůce atrybuty czcionki:

  • font: pozwala ustawi─ç wszystko to, co mo┼╝na zdefiniowa─ç przy u┼╝yciu w┼éasno┼Ťci CSS font. Mo┼╝na ustawi─ç styl pisma, wariant czcionki, grubo┼Ť─ç tekstu, rozmiar czcionki, wysoko┼Ť─ç linii oraz rodzin─Ö czcionek.
  • textAlign: s┼éu┼╝y do okre┼Ťlania wyr├│wnania tekstu. Ma podobne dzia┼éanie do w┼éasno┼Ťci CSS text-align. Dost─Öpne warto┼Ťci to start, end, left, right oraz center.
  • textBaseline: umo┼╝liwia okre┼Ťlanie miejsca rysowania tekstu w odniesieniu do punktu pocz─ůtkowego. Dost─Öpne warto┼Ťci to top, hanging, middle, alphabetic, ideographic oraz bottom.

W┼éasno┼Ť─ç textBaseline jest problematyczna, poniewa┼╝ tekst sam w sobie sprawia trudno┼Ťci (zwykle litery ┼éaci┼äskie nie, ale na kanwie mo┼╝na narysowa─ç ka┼╝dy znak Unicode, a Unicode jest skomplikowany). W specyfikacji HTML5 znajduje si─Ö obja┼Ťnienie r├│┼╝nych linii bazowych pisma:

G├│rna kraw─Öd┼║ prostok─ůta em mniej wi─Öcej pokrywa si─Ö z g├│rn─ů kraw─Ödzi─ů glif├│w fontu. Linia bazowa biegnie u nasady niekt├│rych glif├│w, jak np. आ. Linia ┼Ťrodkowa znajduje si─Ö po┼Ťrodku mi─Ödzy g├│rn─ů a doln─ů kraw─Ödzi─ů prostok─ůta em. Alfabetyczna linia bazowa biegnie u nasady takich znak├│w, jak Ã┬ü, ÿ, f oraz Ω. Ideograficzna linia bazowa biegnie u podstawy takich glif├│w, jak ç§┬ü i é┬ü”. Natomiast linia dolna prostok─ůta em pokrywa si─Ö z grubsza z doln─ů ko┼äc├│wk─ů glif├│w fontu. G├│rna i dolna kraw─Öd┼║ otaczaj─ůcego pola mog─ů znajdowa─ç si─Ö daleko od tych linii bazowych ze wzgl─Ödu na to, ┼╝e niekt├│re glify mog─ů wychodzi─ç daleko poza prostok─ůt em.

W przypadku prostych alfabetów, jak języka polskiego można bezpiecznie używać tylko ustawień top, middle oraz bottom.

Narysujmy jaki┼Ť tekst! Tekst rysowany na kanwie dziedziczy ustawienia rozmiaru i stylu po elemencie <canvas>, ale mo┼╝na je zmieni─ç za pomoc─ů w┼éasno┼Ťci font kontekstu rysunkowego.

Zmiana stylu pisma

context.font = "bold 12px sans-serif";
context.fillText("x", 248, 43);
context.fillText("y", 58, 165);

Metoda fillText() rysuje tekst.

context.font = "bold 12px sans-serif";
context.fillText("x", 248, 43);
context.fillText("y", 58, 165);

Pytanie do profesora Kodeckiego

P: Czy mo┼╝na ustawia─ç rozmiar tekstu na kanwie przy u┼╝yciu jednostek wzgl─Ödnych?
O: Tak. Podobnie jak wszystkie inne elementy na stronie HTML, element <canvas> ma rozmiar pisma obliczony na podstawie regu┼é CSS zastosowanych do tej strony. Je┼Ťli w┼éasno┼Ť─ç context.font zostanie ustawiona na warto┼Ť─ç wzgl─Ödn─ů typu 1.5em albo 150%, przegl─ůdarka pomno┼╝y t─Ö warto┼Ť─ç przez obliczony rozmiar pisma elementu <canvas>.

Je┼Ťli chodzi o tekst znajduj─ůcy si─Ö w lewym g├│rnym rogu, to powiedzmy, ┼╝e chcemy, aby jego g├│rna kraw─Öd┼║ znajdowa┼éa si─Ö w punkcie y=5. Ale ja jestem leniwy i nie chce mi si─Ö mierzy─ç wysoko┼Ťci tekstu, aby obliczy─ç jego lini─Ö bazow─ů. Zamiast to robi─ç mog─Ö ustawi─ç w┼éasno┼Ť─ç textBaseline na top i przekaza─ç wsp├│┼érz─Ödn─ů lewego g├│rnego rogu pola zawieraj─ůcego tekst.

context.textBaseline = "top";
context.fillText("( 0 , 0 )", 8, 5);

Teraz zajmiemy si─Ö tekstem w prawym dolnym rogu. Powiedzmy, ┼╝e chcemy, aby dolny prawy r├│g tekstu znajdowa┼é si─Ö w punkcie o wsp├│┼érz─Ödnych (492,370) — tylko kilka pikseli od prawego dolnego rogu kanwy — ale nie chcemy mierzy─ç szeroko┼Ťci ani wysoko┼Ťci tekstu. Mo┼╝emy ustawi─ç w┼éasno┼Ť─ç textAlign na right i textBaseline na bottom, a nast─Öpnie wywo┼éa─ç metod─Ö fillText() ze wsp├│┼érz─Ödnymi prawego dolnego rogu pola zawieraj─ůcego tekstu.

context.textAlign = "right";
context.textBaseline = "bottom";
context.fillText("( 500 , 375 )", 492, 370);

Otrzymujemy taki wynik:

Kanwa3

Ups! Zapomnia┼éem o kropkach w rogach. Rysowaniem k├│┼é zajmiemy si─Ö p├│┼║niej. Teraz troch─Ö pooszukujemy i narysujemy prostok─ůty.

context.fillRect(0, 0, 3, 3);
context.fillRect(497, 372, 3, 3);

To wszystko! Oto finalny efekt naszej pracy:

Canvas4

Gradienty

IEFirefoxSafariChromeOperaiPhoneAndroid
gradienty liniowe7.0+*3.0+3.0+3.0+10.0+1.0+1.0+
gradienty promieniste9.0+3.0+3.0+3.0+10.0+1.0+1.0+
* Internet Explorer 7 i 8 wymagaj─ů dodatku zewn─Ötrznej biblioteki explorercanvas. Internet Explorer 9 standardowo obs┼éuguje gradienty w elemencie <canvas>.

W poprzednich cz─Ö┼Ťciach tego rozdzia┼éu nauczy┼ée┼Ť si─Ö rysowa─ç prostok─ůty wype┼énione jednolitym kolorem oraz jednokolorowe linie. Ale to nie znaczy, ┼╝e kolory zawsze musz─ů by─ç jednolite. Zamiast nich mo┼╝na te┼╝ tworzy─ç gradienty. Sp├│jrzmy na przyk┼éad.

Canvas gradient

Kod HTML to zwykły element kanwy.

<canvas id="d" width="300" height="225"></canvas>

Najpierw musimy znale┼║─ç interesuj─ůcy nas element <canvas> i podpi─ů─ç si─Ö do jego kontekstu rysunkowego.

var d_canvas = document.getElementById("d");
var context = d_canvas.getContext("2d");

Maj─ůc kontekst rysunkowy mo┼╝emy rozpocz─ů─ç rysowanie gradientu. Gradient to p┼éynne przej┼Ťcie mi─Ödzy dwoma lub wi─Öksz─ů liczb─ů kolor├│w. Kontekst rysunku kanwy obs┼éuguje dwa rodzaje gradient├│w:

  1. createLinearGradient(x0, y0, x1, y1): rysuje gradient wzd┼éu┼╝ linii ┼é─ůcz─ůcej punkty (x0, y0) i (x1, y1).
  2. createRadialGradient(x0, y0, r0, x1, y1, r1): rysuje gradient w kszta┼écie sto┼╝ka ┼é─ůcz─ůcy dwa okr─Ögi. Trzy pierwsze parametry definiuj─ů okr─ůg wyznaczaj─ůcy pocz─ůtek gradientu, ze ┼Ťrodkiem w punkcie (x0, y0) i o promieniu r0. Trzy ostatnie parametry definiuj─ů okr─ůg wyznaczaj─ůcy koniec gradientu, ze ┼Ťrodkiem w punkcie (x1, y1) i o promieniu r1.

Narysujemy gradient liniowy. Gradient mo┼╝e mie─ç dowolny rozmiar, a w tym przyk┼éadzie narysujemy gradient o szeroko┼Ťci 300 pikseli, czyli takiej samej, jak kanwa.

Utworzenie obiektu gradientu

var my_gradient = context.createLinearGradient(0, 0, 300, 0);

Jako ┼╝e warto┼Ťci y (drugi i czwarty parametr) maj─ů warto┼Ť─ç 0, ten gradient b─Ödzie si─Ö jednolicie rozk┼éada┼é od lewej do prawej.

Maj─ůc obiekt gradientu mo┼╝na definiowa─ç jego kolory. Ka┼╝dy gradient ma przynajmniej dwa stopnie kolor├│w. Stopnie te mo┼╝na umieszcza─ç w dowolnych miejscach. Aby doda─ç stopie┼ä koloru, nale┼╝y okre┼Ťli─ç jego po┼éo┼╝enie na gradiencie. Po┼éo┼╝enie na gradiencie mo┼╝na definiowa─ç przy u┼╝yciu warto┼Ťci z przedzia┼éu od 0 do 1.

Zdefiniujemy gradient przechodz─ůcy od czerni do bieli.

my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(1, "white");

Samo zdefiniowanie gradientu nie powoduje narysowania czegokolwiek na kanwie. Jest to tylko obiekt zapisany gdzie┼Ť w pami─Öci. Aby narysowa─ç gradient, trzeba ustawi─ç na niego w┼éasno┼Ť─ç fillStyle oraz narysowa─ç jak─ů┼Ť figur─Ö, np. prostok─ůt albo lini─Ö.

W┼éasno┼Ť─ç fillStyle jest gradientem

context.fillStyle = my_gradient;
context.fillRect(0, 0, 300, 225);

Otrzymujemy taki wynik:

Powiedzmy, ┼╝e chcemy aby gradient bieg┼é z g├│ry na d├│┼é. Przy tworzeniu obiektu takiego gradientu nale┼╝y warto┼Ťci x (pierwszy i trzeci parametr) pozostawi─ç niezmienne, a warto┼Ťci y (drugi i czwarty parametr) zmieni─ç w zakresie od 0 do wysoko┼Ťci kanwy.

Warto┼Ťci x wynosz─ů 0, warto┼Ťci y zmieniaj─ů si─Ö

var my_gradient = context.createLinearGradient(0, 0, 0, 225);
my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(1, "white");
context.fillStyle = my_gradient;
context.fillRect(0, 0, 300, 225);

Otrzymujemy taki wynik:

Mo┼╝na te┼╝ tworzy─ç gradienty biegn─ůce po skosie.

Zmieniaj─ů si─Ö warto┼Ťci x i y

var my_gradient = context.createLinearGradient(0, 0, 300, 225);
my_gradient.addColorStop(0, "black");
my_gradient.addColorStop(1, "white");
context.fillStyle = my_gradient;
context.fillRect(0, 0, 300, 225);

Otrzymujemy taki wynik:

Obrazy

IEFirefoxSafariChromeOperaiPhoneAndroid
7.0+*3.0+3.0+3.0+10.0+1.0+1.0+
* Internet Explorer 7 i 8 wymagaj─ů dodatku zewn─Ötrznej biblioteki explorercanvas. Internet Explorer 9 standardowo obs┼éuguje obrazy w elemencie <canvas>.

Oto rysunek kota:

Kontekst rysunkowy kanwy ma metod─Ö drawImage() s┼éu┼╝─ůc─ů do rysowania obraz├│w na kanwie. Metoda ta pobiera trzy, pi─Ö─ç lub dziewi─Ö─ç argument├│w.

  • Metoda drawImage(image, dx, dy) pobiera obraz i rysuje go na kanwie. Wsp├│┼érz─Ödne (dx, dy) okre┼Ťlaj─ů po┼éo┼╝enie lewego g├│rnego rogu tego rysunku. Gdyby podano wsp├│┼érz─Ödne (0, 0), to pocz─ůtek obrazu znajdowa┼éby si─Ö w lewym g├│rnym rogu kanwy.
  • Metoda drawImage(image, dx, dy, dw, dh) pobiera obraz, skaluje go do szeroko┼Ťci dw i wysoko┼Ťci dh a nast─Öpnie rysuje go na kanwie zaczynaj─ůc w punkcie o wsp├│┼érz─Ödnych (dx, dy).
  • Metoda drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh) pobiera obraz, wycina z niego prostok─ůt (sx, sy, sw, sh), skaluje go do rozmiar├│w (dw, dh), a nast─Öpnie rysuje go na kanwie zaczynaj─ůc w punkcie o wsp├│┼érz─Ödnych (dx, dy).

W specyfikacji HTML5 znajduje si─Ö obja┼Ťnienie parametr├│w metody drawImage():

Prostok─ůt ┼║r├│d┼éowy to prostok─ůt [w obr─Öbie obrazu ┼║r├│d┼éowego], kt├│rego rogi wyznaczaj─ů punkty (sx, sy), (sx+sw, sy), (sx+sw, sy+sh) oraz (sx, sy+sh).

Prostok─ůt docelowy to prostok─ůt [w obr─Öbie kanwy], kt├│rego rogi wyznaczaj─ů punkty (dx, dy), (dx+dw, dy), (dx+dw, dy+dh) oraz (dx, dy+dh).

Aby narysowa─ç obraz na kanwie, trzeba mie─ç jaki┼Ť obraz. Mo┼╝e to by─ç istniej─ůcy ju┼╝ element <img>, ale mo┼╝na te┼╝ utworzy─ç obiekt Image() przy u┼╝yciu JavaScript. W obu przypadkach rysowanie obrazu na kanwie mo┼╝na rozpocz─ů─ç dopiero po jego ca┼ékowitym wczytaniu.

Istniej─ůcy element <img> mo┼╝na bezpiecznie narysowa─ç na kanwie podczas zdarzenia window.onload.

U┼╝ycie elementu img

<img id="cat" src="images/cat.png" alt="sleeping cat" width="177" height="113">
<canvas id="e" width="177" height="113"></canvas>
<script>
window.onload = function() {
  var canvas = document.getElementById("e");
  var context = canvas.getContext("2d");
  var cat = document.getElementById("cat");
  context.drawImage(cat, 0, 0);
};
</script>

Je┼Ťli tworzony jest obiekt obrazu przy u┼╝yciu JavaScriptu, mo┼╝na bezpiecznie go narysowa─ç na kanwie podczas zdarzenia Image.onload.

U┼╝ycie obiektu Image()

<canvas id="e" width="177" height="113"></canvas>
<script>
  var canvas = document.getElementById("e");
  var context = canvas.getContext("2d");
  var cat = new Image();
  cat.src = "images/cat.png";
  cat.onload = function() {
    context.drawImage(cat, 0, 0);
  };
</script>

Trzeci i czwarty parametr metody drawImage() s┼éu┼╝─ů do skalowania obrazu.

Poniżej znajduje się kod źródłowy tego skryptu:

cat.onload = function() {
  for (var x = 0, y = 0;
       x < 500 && y < 375;
       x += 50, y += 37) {
    context.drawImage(cat, x, y, 88, 56);
  }
};

W tym momencie nasuwa si─Ö ciekawe pytanie: po co w og├│le mieliby┼Ťmy rysowa─ç jakiekolwiek obrazy na kanwie? Jakie korzy┼Ťci w por├│wnaniu z u┼╝yciem elementu <img> i regu┼é CSS mamy ze stosowania tej bardziej skomplikowanej techniki? Nawet efekt „multikota” mo┼╝na by by┼éo uzyska─ç przy u┼╝yciu 10 nak┼éadaj─ůcych si─Ö na siebie element├│w <img>.

Najkr├│cej m├│wi─ůc pow├│d jest taki sam, jak ten dla kt├│rego rysujemy tekst na kanwie. Uk┼éad wsp├│┼érz─Ödnych kanwy zawiera tekst, linie i figury geometryczne. Tekst jest po prostu tylko cz─Ö┼Ťci─ů wi─Ökszego dzie┼éa. Na bardziej z┼éo┼╝onym schemacie mo┼╝na by by┼éo u┼╝y─ç metody drawImage() do narysowania ikon, sprite’├│w i innych grafik.

Kanwa a przegl─ůdarka Internet Explorer

Internet Explorer do wersji 8.0 w┼é─ůcznie nie obs┼éuguje API kanwy. (Natomiast IE 9 obs┼éuguje je ju┼╝ w pe┼éni.) Starsze wersje Internet Explorera obs┼éuguj─ů natomiast technologi─Ö Microsoftu o nazwie VML, za pomoc─ů kt├│rej mo┼╝na zrobi─ç wiele tych samych rzeczy, co przy u┼╝yciu elementu <canvas>. Dlatego powsta┼é skrypt excanvas.js.

Skrypt Explorercanvas (excanvas.js) to otwarta dost─Öpna na licencji Apache biblioteka JavaScript implementuj─ůca API kanwy w Internet Explorerze. Aby z niej skorzysta─ç, nale┼╝y na pocz─ůtku strony umie┼Ťci─ç poni┼╝szy element <script>.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Dive Into HTML5</title>
  <!--[if lt IE 9]>
    <script src="excanvas.js"></script>
<![endif]-->
</head>
<body>
  ...
</body>
</html>

Cz─Ö┼Ťci <!--[if lt IE 9]> i <![endif]--> to komentarze warunkowe. Internet Explorer interpretuje je jak instrukcj─Ö if: „je┼Ťli bie┼╝─ůca przegl─ůdarka jest Internet Explorerem w wersji starszej od 9, to wykonaj ten blok kodu”. Dla wszystkich innych przegl─ůdarek ca┼éy ten blok jest komentarzem HTML. W efekcie Internet Explorer 7 i 8 pobior─ů skrypt excanvas.js i wykonaj─ů go, a inne przegl─ůdarki zignoruj─ů ten kod (nie pobior─ů skryptu i go nie wykonaj─ů). Dzi─Öki temu w przegl─ůdarkach obs┼éuguj─ůcych API kanwy strona b─Ödzie si─Ö szybciej wczytywa┼éa.

Do┼é─ůczeniu skryptu excanvas.js w elemencie <head> strony to wszystko, co trzeba zrobi─ç, aby nam├│wi─ç Internet Explorera do wsp├│┼épracy. Potem wystarczy doda─ç elementy <canvas> normalnie w kodzie HTML albo utworzy─ç je dynamicznie za pomoc─ů JavaScriptu. Aby rysowa─ç figury geometryczne tekst i wzory na elemencie <canvas>, post─Öpuj zgodnie ze wskaz├│wkami opisanymi w tym rozdziale.

No… mo┼╝e niezupe┼énie. Jest kilka trudno┼Ťci:

  1. Gradienty mog─ů by─ç tylko liniowe. Gradienty promieniste nie s─ů obs┼éugiwane.
  2. Wzory musz─ů by─ç zwielokrotniane w obu kierunkach.
  3. Wycinki nie s─ů obs┼éugiwane.
  4. Niejednolite skalowanie powoduje niepoprawne skalowanie linii.
  5. Jest powolne. Chocia┼╝ to nikogo nie powinno dziwi─ç, bo wszyscy wiedz─ů, ┼╝e parser JavaScriptu w Internet Explorerze dzia┼éa wolniej ni┼╝ w innych przegl─ůdarkach. Gdy zaczniesz rysowa─ç skomplikowane kszta┼éty przy u┼╝yciu biblioteki JavaScript zamieniaj─ůcej instrukcje na polecenia ca┼ékiem innej technologii, co┼Ť w ko┼äcu musi si─Ö popsu─ç. Obni┼╝ki wydajno┼Ťci nie zauwa┼╝ysz w prostych rysunkach, jak kilka kresek i przekszta┼écenie obrazu, ale od razu je dostrze┼╝esz, gdy zaczniesz tworzy─ç animacje i robi─ç inne szalone rzeczy.

Z bibliotek─Ö excanvas.js wi─ů┼╝e si─Ö jeszcze jeden problem, na kt├│ry natkn─ů┼éem si─Ö tworz─ůc przyk┼éady do tego rozdzia┼éu. ExplorerCanvas inicjuje w┼éasn─ů atrap─Ö interfejsu kanwy na ka┼╝dej stronie HTML, do kt├│rej do┼é─ůczony jest skrypt excanvas.js. Ale to nie znaczy, ┼╝e Internet Explorer mo┼╝e z niego od razu korzysta─ç. W niekt├│rych przypadkach mo┼╝e si─Ö zdarzy─ç, ┼╝e ta atrapa interfejsu kanwy b─Ödzie prawie, ale jednak nie ca┼ékiem, gotowa do u┼╝ytku. Naj┼éatwiej rozpozna─ç to po tym, ┼╝e Internet Explorer zg┼éasza b┼é─ůd „Obiekt nie obs┼éuguje tej w┼éa┼Ťciwo┼Ťci lub metody”, gry pr├│bujemy cokolwiek zrobi─ç z elementem <canvas>, np. utworzy─ç uchwyt do jego kontekstu rysunkowego.

Naj┼éatwiej problem ten jest rozwi─ůza─ç czekaj─ůc z operowaniem na kanwie do zdarzenia onload. To mo┼╝e troch─Ö potrwa─ç — jego wyst─ůpienie op├│┼║niaj─ů np. znajduj─ůce si─Ö na stronie obrazy i filmy wideo — ale w ten spos├│b damy narz─Ödziu ExplorerCanvas czas na wykonanie swojej pracy.

Kompletny realny przyk┼éad — gra Halma

Halma to bardzo stara gra planszowa. Istnieje wiele jej odmian. Ten przyk┼éad dotyczy wersji dla jednego gracza z plansz─ů o wymiarach 9 × 9 p├│l. Na pocz─ůtku gry pionki s─ů ustawione w kwadrat 3 × 3 w lewym dolnym rogu planszy. Celem gracza jest przeniesienie tego kwadratu do prawgo g├│rnego rogu przy u┼╝yciu jak najmniejszej liczby ruch├│w.

W grze Halma dozwolone s─ů dwa rodzaje ruchu:

  • przesuni─Öcie pionka w dowolnym kierunku na s─ůsiednie puste pole. Puste pole to takie, na kt├│rym aktualnie nie znajduje si─Ö ┼╝aden pionek. S─ůsiednie pole to pole znajduj─ůce si─Ö na lewo, prawo, nad, pod lub po skosie wzgl─Ödem aktualnego pola. (Nie ma mo┼╝liwo┼Ťci wychodzenia poza kraw─Öd┼║ planszy, tzn. je┼Ťli pionek znajduje si─Ö przy lewej kraw─Ödzi, to nie mo┼╝na go przesun─ů─ç w lewo, a je┼Ťli pionek znajduje si─Ö przy dolnej kraw─Ödzi, to nie mo┼╝na go przesun─ů─ç w d├│┼é).
  • Pionki mog─ů te┼╝ przeskakiwa─ç inne pionki i mo┼╝na to robi─ç seriami. To znaczy, ┼╝e mo┼╝na przeskoczy─ç jeden s─ůsiedni pionek, a po nim nast─Öpny i liczy si─Ö to jako jeden ruch. Taki seryjny skok liczy si─Ö jako jeden ruch, bez wzgl─Ödu na liczb─Ö przeskoczonych w nim pionk├│w. (Jako ┼╝e celem gry jest przeniesienie pionk├│w na drug─ů stron─Ö planszy przy u┼╝yciu jak najmniejszej liczby ruch├│w, najlepsz─ů strategi─ů jest konstruowanie d┼éugich ┼éa┼äcuch├│w zajmuj─ůcych co drugie pole pionk├│w, aby potem je przeskoczy─ç innymi pionkami).

Gra jest inicjowana podczas ładowania strony poprzez ustawienie wymiarów elementu <canvas> i zapisanie referencji do jego kontekstu rysunkowego.

gCanvasElement.width = kPixelWidth;
gCanvasElement.height = kPixelHeight;
gDrawingContext = gCanvasElement.getContext("2d");

Potem robione jest co┼Ť, o czym jescze nie pisa┼éem: do elementu <canvas> dodawana jest procedura nas┼éuchu zdarze┼ä klikni─Öcia mysz─ů.

gCanvasElement.addEventListener("click", halmaOnClick, false);

Funkcja halmaOnClick() jest wywo┼éywana, gdy u┼╝ytkownik kliknie gdziekolwiek w obr─Öbie kanwy. Jej argumentem jest obiekt MouseEvent zawieraj─ůcy informacje o miejscu, w kt├│rym nast─ůpi┼éo klikni─Öcie.

function halmaOnClick(e) {
    var cell = getCursorPosition(e);

    // Reszta kodu to logika gry HTML5
    for (var i = 0; i < gNumPieces; i++) {
	if ((gPieces[i].row == cell.row) &&
	    (gPieces[i].column == cell.column)) {
	    clickOnPiece(i);
	    return;
	}
    }
    clickOnEmptyCell(cell);
}

Kolejn─ů czynno┼Ťci─ů jest pobranie obiektu MouseEvent i obliczenie, kt├│ry kwadrat na planszy zosta┼é klikni─Öty. Jako ┼╝e plansza zajmuje ca┼éy obszar kanwy, ka┼╝de klikni─Öcie jest gdzie┼Ť na niej. Musimy tylko dowiedzie─ç si─Ö gdzie. Jest to trudne ze wzgl─Ödu na to, ┼╝e zdarzenia myszy w ka┼╝dej przegl─ůdarce s─ů zaimplementowane nieco inaczej.

function getCursorPosition(e) {
    var x;
    var y;
    if (e.pageX != undefined && e.pageY != undefined) {
	x = e.pageX;
	y = e.pageY;
    }
    else {
	x = e.clientX + document.body.scrollLeft +
            document.documentElement.scrollLeft;
	y = e.clientY + document.body.scrollTop +
            document.documentElement.scrollTop;
    }

Teraz mamy współrzędne x i y względne w odniesieniu do dokumentu (czyli całej strony HTML). Na razie niewiele mamy z nich pożytku. Potrzebujemy współrzędnych względnych w odniesieniu do kanwy.

    x -= gCanvasElement.offsetLeft;
    y -= gCanvasElement.offsetTop;

Teraz mamy ju┼╝ wsp├│┼érz─Ödne x i y wzgl─Ödne w odniesieniu do kanwy. To znaczy, je┼Ťli w tym momencie warto┼Ťci x i y wynosz─ů 0, wiemy, ┼╝e u┼╝ytkownik klikn─ů┼é piksel znajduj─ůcy si─Ö w lewym g├│rnym rogu kanwy.

Dzięki tym informacjom możemy obliczyć, który kwadrat planszy został kliknięty i odpowiednio na to zareagować.

    var cell = new Cell(Math.floor(y/kPieceHeight),
                        Math.floor(x/kPieceWidth));
    return cell;
}

Uff! Zdarzenia myszy to rzecz dla prawdziwych twardzieli. Ale teraz ju┼╝ tego samego kodu mo┼╝esz u┼╝y─ç we wszystkich swoich aplikacjach. Zapami─Ötaj: klikni─Öcie mysz─ů → wsp├│┼érz─Ödne dokumentu → wsp├│┼érz─Ödne kanwy → logika aplikacji.

Teraz przyjrzymy si─Ö g┼é├│wnej procedurze rysuj─ůcej. Jako ┼╝e grafika jest w tym przypadku bardzo prosta, postanowi┼éem, ┼╝e za ka┼╝dym razem gdy co┼Ť si─Ö mzienia na planszy rysowa─ç j─ů od nowa w ca┼éo┼Ťci. Nie jest to konieczne. Kontekst rysunkowy kanwy zachowa wszystko, co zosta┼éy w nim narysowane, nawet gdy u┼╝ytkownik przewinie stron─Ö albo przejdzie na inn─ů kart─Ö w przegl─ůdarce, a potem wr├│ci do gry. Je┼Ťli b─Ödziesz przy u┼╝yciu kanwy tworzy─ç aplikacj─Ö o bardziej skomplikowanej grafice (np. gr─Ö arcade), mo┼╝esz zoptymalizowa─ç jej dzia┼éanie od┼Ťwie┼╝aj─ůc tylko te obszary, w kt├│rych co┼Ť si─Ö zmieni┼éo. Ale to nie jest tematem tego podr─Öcznika.

gDrawingContext.clearRect(0, 0, kPixelWidth, kPixelHeight);

Procedura rysuj─ůca plansz─Ö powinna wygl─ůda─ç znajomo. Jest podobna do uk┼éadu wsp├│┼érz─Ödnych kanwy, kt├│ry narysowali┼Ťmy wcze┼Ťniej.

gDrawingContext.beginPath();

/* pionowe linie */
for (var x = 0; x <= kPixelWidth; x += kPieceWidth) {
    gDrawingContext.moveTo(0.5 + x, 0);
    gDrawingContext.lineTo(0.5 + x, kPixelHeight);
}

/* poziome linie */
for (var y = 0; y <= kPixelHeight; y += kPieceHeight) {
    gDrawingContext.moveTo(0, 0.5 + y);
    gDrawingContext.lineTo(kPixelWidth, 0.5 +  y);
}

/* Rysowanie! */
gDrawingContext.strokeStyle = "#ccc";
gDrawingContext.stroke();

Najlepsza zabawa jest przy rysowaniu pionk├│w. W tej grze pionki s─ů okr─ůg┼ée, a my jeszcze nie wiemy, jak rysowa─ç ko┼éa. Ponadto, gdy u┼╝ytkownik kliknie pionek z zamiarem przesuni─Öcia go na inne miejsce, t┼éo tego pionka powinno si─Ö zabarwi─ç. W poni┼╝szym kodzie argument p reprezentuje pionek, kt├│ry ma w┼éasno┼Ťci row i column okre┼Ťlaj─ůce jego bie┼╝─ůce po┼éo┼╝enie na planszy. Przy u┼╝yciu kilku sta┼éych gry zamieniamy wsp├│┼érzdne (column, row) na wsp├│┼érz─Ödne (x, y) kanwy, potem rysujemy ko┼éo, a p├│┼║niej (je┼Ťli pionek jest klikni─Öty) wype┼éniamy te ko┼éo jednolitym kolorem.

function drawPiece(p, selected) {
    var column = p.column;
    var row = p.row;
    var x = (column * kPieceWidth) + (kPieceWidth/2);
    var y = (row * kPieceHeight) + (kPieceHeight/2);
    var radius = (kPieceWidth/2) - (kPieceWidth/10);

To koniec logiki gry HTML5. Mamy ju┼╝ wsp├│┼érz─Ödne (x, y) na kanwie ┼Ťrodka ko┼éa, kt├│re chcemy narysowa─ç. W API kanwy nie ma metody o nazwie circle(), ale jest metoda arc(). S┼éu┼╝y ona do tworzenia ┼éuk├│w, a czym jest okr─ůg, jak nie ┼éukiem z po┼é─ůczonymi ko┼äcami? Pami─Ötasz podstawy geometrii? Metoda arc() jako argumenty pobiera wsp├│┼érz─Ödne ┼Ťrodka (x, y), promie┼ä, k─ůt pocz─ůtkowy i ko┼äcowy (w radianach) oraz kierunkowskaz (false oznacza w prawo, true oznacza w lewo). Do wykonywania oblicze┼ä w radianach mo┼╝na wykorzysta─ç modu┼é Math j─Özyka JavaScript.

gDrawingContext.beginPath();
gDrawingContext.arc(x, y, radius, 0, Math.PI * 2, false);
gDrawingContext.closePath();

Chwileczk─Ö! Nic jeszcze nie zosta┼éo narysowane. Metoda arc() , podobnie jak moveTo() i lineTo, jest metod─ů „o┼é├│wkow─ů”. Aby narysowa─ç ko┼éo, musimy ustawi─ç w┼éasno┼Ť─ç strokeStyle i wywo┼éa─ç metod─Ö stroke().

gDrawingContext.strokeStyle = "#000";
gDrawingContext.stroke();

A co z sytuacj─ů, gdy pionek jest klikni─Öty? Mo┼╝na wykorzysta─ç t─Ö sam─ů ┼Ťcie┼╝k─Ö, co do narysowania obrysu pionka i wype┼éni─ç tworzony przez ni─ů okr─ůg kolorem.

if (selected) {
    gDrawingContext.fillStyle = "#000";
    gDrawingContext.fill();
}

I to by by┼éo na tyle. Reszta programu to logika gry — rozr├│┼╝nianie dozwolonych i niedozwolonych ruch├│w, liczenie liczby ruch├│w, sprawdzanie czy gry dobieg┼éa ko┼äca itp. U┼╝yli┼Ťmy elementu <canvas>, na kt├│rym narysowali┼Ťmy 9 okr─Ög├│w i kilka prostych kresek oraz zdefiniowali┼Ťmy jedn─ů procedur─Ö obs┼éugi zdarzenia onclick, aby utworzy─ç ciekaw─ů planszow─ů gr─Ö logiczn─ů. Hurrra!

Lektura uzupe┼éniaj─ůca

Autor: Mark Pilgrim

Źródło: http://diveintohtml5.info/

Tłumaczenie: Łukasz Piwko

Tre┼Ť─ç tej strony jest dost─Öpna na zasadach licencji CC BY 3.0