Miłosz Orzeł

.net, js, html, arduino, java... no rants or clickbaits.

Układ współrzędnych HTML5 Canvas, rysowanie z wartością y rosnącą ku górze ekranu

Układ współrzędnych w HTML 5 Canvas jest ustalony w taki sposób, że za punkt początkowy (0, 0) przyjęty jest lewy-górny róg canvas. To rozwiązanie nie jest niczym niezwykłym w świecie grafiki ekranowej (tak samo jest np. w Windows Forms czy SVG). Popularne kiedyś monitory CRT wyświetlały linie obrazu w kolejności od góry do dołu a obraz w linii tworzony był od lewej do prawej. Umieszczenie punktu (0,0) w lewym-górnym rogu było więc intuicyjne i ułatwiało budowanie sprzętu i oprogramowania do obsługi grafiki… 

Niestety czasem domyślny układ współrzędnych na canvas jest mało praktyczny. Przyjmijmy, że chcesz wykonać animację lotu pocisku. Naturalnie wydaje się, że dla wznoszącego się pocisku wartość współrzędnej y powinna rosnąć. Da to jednak dziwaczny efekt odwróconej trajektorii:

Domyślny układ współrzędnych (y rośnie ku dołowi ekranu)

Można temu zaradzić poprzez modyfikację wartości y przekazywanej do funkcji rysującej:

context.fillRect(x, offsetY - y, size, size);

Dla y = 0, pocisk zostanie umieszczony w miejscu wyznaczonym przez offsetY (by y = 0 oznaczało sam spód canvas ustaw offset na wartość równą wysokości canvas). Im większa będzie wartość y tym wyżej pocisk zostanie narysowany. Problem w tym, że możesz mieć w kodzie setki miejsc, w których wykorzystywana będzie współrzędna y. Wystarczy, że raz zapomnisz uwzględnić offsetY i cały obraz może zostać uszkodzony.

Na szczęście canvas umożliwia wprowadzenie zmian w układzie współrzędnych za pomocą transformacji. Nam przydadzą się dwie metody transformujące: translate(x, y) i scale(x, y). Pierwsza z nich umożliwia przesunięcie początku układu współrzędnych. Druga służy do zmiany wielkości rysowanych obiektów, jednak może też zostać użyta do odwrócenia współrzędnych.

Pojedyncze wykonanie tego kodu sprawi, że początek układu współrzędnych znajdzie się w punkcie (0, offsetY) a wartość y będzie wyższa u góry ekranu:

context.translate(0, offsetY);
context.scale(1, -1);

Przesunięcie i skalowanie układu współrzędnych

Od tej pory możemy wywoływać metody rysujące bez konieczności modyfikacji współrzędnych!

Jest jednak pewien problem: podanie -1 jako wartości drugiego parametru metody scale powoduje, że cały obraz tworzony jest dla odwróconej współrzędnej y. Dotyczy to także tekstu (wywołanie fillText sprawi, że tekst pojawi się „do góry nogami”). Przed wypisaniem tekstu należy więc przywrócić domyślny układ osi y. Ponieważ ręczne przywracanie stanu canvas byłoby bardzo kłopotliwe, istnieją metody save() i restore(), które umożliwiają odpowiednio: odłożenie stanu na stosie i przywrócenie stanu ze stosu. Zaleca się użycie metody save przed dokonaniem transformacji. W stan canvas wchodzą nie tylko użyte transformacje ale też wartości takie jak styl wypełnienia czy grubość linii...

context.save();

context.fillStyle = 'red';
context.scale(2, 2);
context.fillRect(0, 0, 10, 10);

context.restore();

context.fillRect(0, 0, 10, 10);

Powyższy kod sprawi, że zostaną narysowane 2 kwadraty:

Pierwszy z nich ma kolor czerwony i narysowany jest w skali 2x. Drugi jest rysowany w ustawieniach domyślnych canvas (kolor czarny i skala 1x). Dzieje się tak dlatego, że przed zmianami skali i koloru, stan canvas został odłożony na stosie po czym został przywrócony przed narysowaniem drugiego kwadratu.