translate, rotate, scale — i kolejność, która zmienia wszystko
Do tej pory każdy kształt rysowaliśmy tam, gdzie miał być. Transformacje pozwalają zrobić inaczej: narysować kształt w wygodnym miejscu, a potem przesunąć go, obrócić albo przeskalować — bez ruszania choćby jednej współrzędnej w środku.
Służy do tego jeden atrybut:
html
<g transform="translate(70 90) rotate(45)">
Można go postawić na pojedynczym kształcie albo — częściej i sensowniej — na grupie <g>, żeby objął wszystko w środku.
Cztery funkcje
translate(x y) przesuwa. Druga liczba jest opcjonalna; translate(40) przesuwa tylko w poziomie.
rotate(kąt) obraca. Kąt w stopniach, dodatni zgodnie ze wskazówkami zegara — bo oś Y rośnie w dół, o czym była lekcja pierwsza.
scale(x y) skaluje. Jedna liczba skaluje proporcjonalnie. Wartości ujemne odbijają lustrzanie: scale(-1 1) to odbicie w poziomie.
skewX(kąt) i skewY(kąt) pochylają. Rzadko potrzebne, ale to one dają efekt kursywy albo rzutu izometrycznego.
Środek, którego nie ma
Największa niespodzianka jest przy obrocie. Domyślnie wszystkie transformacje odnoszą się do punktu 0,0 — czyli lewego górnego rogu układu współrzędnych, a nie do środka figury.
Niebieska kropka pokazuje realną oś obrotu. Przesuń ją na środek kwadratu i obrót zacznie wyglądać tak, jak intuicyjnie oczekujesz. Zostaw w rogu — kwadrat zatoczy koło wokół punktu, którego nawet nie widać na figurze.
rotate przyjmuje na szczęście dwa dodatkowe argumenty:
html
rotate(45 100 100)
Kąt, a po nim współrzędne punktu, wokół którego ma się kręcić. To najprostszy sposób na obrót wokół środka i w praktyce używa się go częściej niż wersji z jednym argumentem.
scale takiej wygody nie ma. Skaluje zawsze względem 0,0, więc żeby powiększyć figurę „w miejscu", trzeba ją najpierw przesunąć do zera, przeskalować i odsunąć z powrotem. Albo — prościej — rysować kształt wokół punktu 0,0 od początku i dopiero potem przesuwać go na miejsce. Tak właśnie zbudowane są oba widgety w tej lekcji.
Kolejność ma znaczenie
Teraz rzecz najważniejsza, na której ludzie potykają się latami.
Funkcje w atrybucie transform wykonują się po kolei, a każda kolejna działa w układzie współrzędnych ustawionym przez poprzednią. To nie jest lista niezależnych poleceń. To ciąg zagnieżdżonych układów.
Po lewej
translatea potemrotate: kwadrat odjeżdża w bok i kręci się wokół własnego środka. Po prawejrotatea potemtranslate: obrót przekręca cały układ współrzędnych, więc kolejne przesunięcie idzie już wzdłuż obróconej osi — i kwadrat krąży po orbicie. Te same dwie liczby, dwa zupełnie inne zachowania.
Jeśli szukasz reguły do zapamiętania: czytaj od lewej jako „ustaw się", a nie jako „przesuń obiekt". Pierwsza funkcja ustawia nowy układ, druga działa już w nim. Dlatego translate na początku to zwykle „gdzie to jest", a wszystko po nim to „co się z tym dzieje".
Skalowanie skaluje wszystko
Ostatnia pułapka i pewnie ta, która najczęściej psuje prawdziwe projekty.
scale() nie powiększa tylko geometrii. Powiększa też grubość obrysu, wzór kreskowania, rozmiar tekstu — wszystko.Ikona konturowa przeskalowana dwukrotnie ma obrys dwa razy grubszy, więc przestaje pasować do reszty zestawu.
Ten sam kwadrat i ta sama skala. Po lewej obrys puchnie razem z figurą, po prawej trzyma stałą grubość dzięki
vector-effect="non-scaling-stroke".
vector-effect to właściwość stworzona dokładnie do tego problemu i warto o niej pamiętać przy mapach, wykresach i wszystkim, co można przybliżać — linia siatki ma zostać cienka niezależnie od zoomu.
Transformacje w CSS
Wszystkie te funkcje można też zapisać w CSS zamiast w atrybucie:
css
.ikona { transform: rotate(45deg); transform-origin: center; }
To ma dwie zalety: transform-origin: center załatwia problem osi obrotu bez liczenia współrzędnych, a transformacje w CSS można animować i wyzwalać na :hover.
Ma też dwie pułapki. Po pierwsze, w CSS kąt wymaga jednostki — rotate(45deg), nie rotate(45). Po drugie, wartości translatew CSS są interpretowane jako piksele, a w atrybucie jako jednostki użytkownika. Przy viewBox innym niż rozmiar wyświetlania to nie jest to samo.
Jest jeszcze matrix(a b c d e f), która zapisuje dowolną kombinację powyższych w sześciu liczbach. Nie pisze się jej ręcznie — pojawia się w plikach z programów graficznych i wystarczy wiedzieć, że to skrót, a nie coś nowego.
Podsumowanie
transformprzyjmuje listę funkcji; najczęściej stawia się go na grupie<g>.- Domyślnym punktem odniesienia jest 0,0, a nie środek figury.
rotatemoże przyjąć oś obrotu jako dwa dodatkowe argumenty;scalenie.- Funkcje wykonują się po kolei, a każda działa w układzie ustawionym przez poprzednią —
translate rotateto nie to samo corotate translate. scalepowiększa również grubość obrysu; ratunkiem jestvector-effect="non-scaling-stroke".- W CSS te same funkcje wymagają jednostek i inaczej traktują
translate, ale dajątransform-origini animacje.
W następnej lekcji kolory przestają być pojedynczą wartością — wchodzą gradienty i wzory, czyli wypełnienia, które są osobnymi obiektami.
Do wypróbowania: w presecie transform · kolejność ustaw przesunięcie na 0. Oba kwadraty zaczną zachowywać się identycznie — bo bez przesunięcia nie ma różnicy między obrotem wokół siebie a orbitą o promieniu zero. To najprostszy dowód, że kolejność ma znaczenie tylko wtedy, gdy obie operacje faktycznie coś robią.