Podstawy pracy z canvas API

Canvas (z języka angielskiego – płótno) pojawił się wraz ze standardem HTML5. Rozwiązanie to umożliwia nam na “rysowanie” po naszej stronie www. Nie mam na myśli tu tylko rysowania w znaczeniu tradycyjnym (co jest jak najbardziej możliwe, o czym przekonasz się w dalszej części tego wpisu), ale mam na myśli rysowanie za pomocą JavaScriptu skomplikowanych struktur i kształtów, a nawet tworzenie gier!

Tworzenie elementu canvas

Dodanie elementu canvas do naszego projektu jest banalne i odbywa się to poprzez najzwyklejsze dodanie znacznika HTML do struktury strony:


<canvas id="canvas"></canvas>

Należy pamiętać o nadaniu wymiarów dla elementu canvas. Możemy to zrobić podając width i height do znacznika HTML, za pomocą CSS’a lub JS’a – wybór należy do nas. Domyślnie nasz canvas przyjmuje wymiary 300×150 (w pikselach). Oczywiście możemy również stworzyć sam znacznik canvas za pomocą JS’a i dołączyć go do struktury strony dynamicznie:


const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 500;
document.getElementById('exampleId').appendChild(canvas);

Mając już stworzony element canvas należy mu nadać kontekst – to właśnie do niego będziemy się odwoływać podczas rysowania po płótnie. Do naszego zastosowania wystarczy nam kontekst 2d. O innych kontekstach dowiesz się więcej z wpisu na MDN, do którego link znajdziesz w źródłach na końcu wpisu.


const canvas = document.getElementById('canvas');
const ctx = canvas.getContext("2d");

Teraz, gdy posiadamy już płótno i kontekst nie pozostaje nam nic tylko rysować!

Canvas - tworzymy aplikację paint

Tworzymy aplikację paint

Nasza aplikacja będzie bardzo prosta – będzie umożliwiała narysowanie za pomocą kursora dowolnego kształtu na ekranie – zupełnie jak aplikacja paint.

Do napisania takiej aplikacji wykorzystamy stworzony już wcześniej element canvas oraz kontekst. Na samym początku napiszmy sobie funkcję pomocniczą, do odczytywania i aktualizowania koordynatów kursora myszy:


const pos = {x: 0, y: 0};

function setPosition(e, pos) {
    pos.x = e.clientX;
    pos.y = e.clientY;
}

Funkcja ta będzie wywoływana za każdym razem, gdy zajdzie potrzeba zmiany współrzędnych kursora. Jako parametry przekazujemy event, który uzyskujemy w trakcie uchwycenia wydarzenia na stronie (tj. click, mousemove, etc.) z którego odczytujemy współrzędne, oraz obiekt pos, który przechowuje pobrane przez nas wartości.

Kolejnym krokiem będzie napisanie funkcji odpowiedzialnej za rysowanie. Na samym początku musimy skonfigurować “ołówek”, którym będziemy rysować. Nadajemy mu właściwości tj. grubość, kolor czy zmiękczenie linii. Odbywa się to poprzez zmianę właściwości kontekstu. Potem należy skorzystać z metody beginPath() wywołanej na kontekście, aby “dać znać” kontekstowi o tym, że zaczynamy rysować. Potem podajemy punkty początkowe i końcowe między którymi ma zostać narysowana linia – służą do tego metody moveTo() oraz lineTo(). Między wywołaniem jednej a drugiej metody aktualizuję pozycję kursora za pomocą wcześniej stworzonej funkcji. Ostatnim krokiem jest wywołanie metody stroke() w celu narysowania kształtu. Finalnie nasza funkcja prezentuje się tak:


function draw(e, ctx, pos) {

    ctx.lineJoin = 'round';
    ctx.lineWidth = 3;
    ctx.lineCap = 'round';
    ctx.strokeStyle = "#000000";

    ctx.beginPath();
    ctx.moveTo(pos.x, pos.y);
    setPosition(e, pos);
    ctx.lineTo(pos.x, pos.y);
    ctx.stroke();
}

Gdy mamy już stworzone funkcje pozostaje nam podpięcie ich pod nasłuchy zdarzeń:


canvas.addEventListener("mousedown", function (e) {
    setPosition(e, pos);
    draw(e, ctx, pos);
});
canvas.addEventListener("mouseenter", function (e) {
    setPosition(e, pos);
});
canvas.addEventListener("mousemove", function (e) {
    draw(e, ctx, pos);
});

Tym sposobem stworzyliśmy bardzo prostą aplikację do rysowania kształtów. Kod wykorzystany w tym wpisie jest fragmentem projektu, którego źródła znajdziesz w źródłach i materiałach dodatkowych na końcu tego artykułu. Znajdziesz tam też link do kodu gry Snake – również opartej na canvasie. Zdaję sobie sprawę, że projekty te nie są idealne, lecz uważam, że w całkiem ciekawy, prosty i przystępny sposób pokazują możliwości canvas.

Inne możliwości canvas

Wraz z canvas otrzymaliśmy zestaw metod do rysowania z góry zdefiniowanych kształtów. Możemy narysować takie kształty jak koło czy prostokąt. Nic nie stoi też na przeszkodzie, aby narysować dowolny kształt – tu posłużymy się poznanymi wcześniej metodami: moveTo() oraz lineTo(). Takie figury i kształty możemy rysować jako wypełnione figury lub jako kontur.


/*
Pierwsze dwa parametry odpowiadają za współrzędne, 
zaś kolejne dwa za wymiary X i Y
*/
ctx.rect(200, 200, 50, 50);

//Kwadrat wypełniony
ctx.fill();

//Obramowanie kwadratu
ctx.stroke();

/*
Pierwsze dwa parametry odpowiadają za współrzędne, kolejny to promień, 
zaś dwa ostatnie to punkty startowe i końcowe na obwodzie koła.
W tym wypadku rysujemy pełny okrąg (360°).
*/
ctx.arc(200, 200, 30, 0, 2 * Math.PI);

//Koło
ctx.fill();

//Okrąg
ctx.stroke();

/*
Dowolny kształt - podajemy kolejne współrzędne wierzchołków.
W naszym wypadku tworzymy trójkąt.
*/
ctx.moveTo(50, 50);
ctx.lineTo(100, 100);
ctx.lineTo(100, 50);
ctx.fill();

To co przedstawiłem w tym wpisie to jest tak naprawdę ułamek możliwości canvasa. Myślę jednak, że jest to dobry punkt wyjściowy byrozpocząć przygodę z canvasem i poznać go w pełni. Jak zwykle zachęcam Cię do zajrzenia w linki w źródłach i materiałach dodatkowych. Znajdziesz tam dwa projekty mojego autorstwa wraz z demami. Oprócz tego znajdziesz przykłady gier tworzonych w canvas, dzięki którym zobaczysz wachlarz możliwości tego rozwiązania! Jeśli artykuł przyniósł Ci jakąś wartość to proszę Cię o zostawienie oceny, a najlepiej oceny i komentarza – będę bardzo wdzięczny! 🙂

Źródła i materiały dodatkowe: