Na samym początku animacji będziemy mieć pełną przeźroczystość (wartość równa zero lub bliska zeru). Wraz z upływem czasu przeźroczystość będzie maleć.
Jeśli chcemy uzyskać efekt odwrotny: czyli najpierw brak przeźroczystości, a na końcu pełna wystarczy napisać:
Więc mamy funkcję render. Posiada ona jeden parametr: timestamp. To znacznik czasu, który będzie przekazany poprzez wywołanie funkcji requestAnimationFrame.
Przy pierwszym wywołaniu przypisujemy zmiennej start wartość. Jest to znacznik czasu pierwszego wywołania animacji. A później w zmiennej elapsed zapisujemy, ile czasu upłynęło od startu. Ponieważ znacznik czasu jest podany w milisekundach więc żeby wiedzieć ile to sekund, dzielimy różnicę między znacznikami przez 1000. 1 sekunda = 1000 milisekund.
Restart animacji
Załóżmy, że chcemy, żeby nasza animacji trwała 3 sekundy. Po upływie tego czasu chcemy zacząć wszystko od nowa. Oto przykład:
Została dodana nowa zmienna animationTime, która przechowuje liczbę, mówiącą ile czasu ma trwać animacja. Sprawdzamy warunek: elapsed >= animationTime jeśli jest spełniony, to znaczy, że czas animacji się skończył, więc resetujemy znacznik czasu.
Tak na marginesie: nie tworzymy tutaj żadnej animacji. Ale możemy wykorzystać czas, jaki upłynął do stworzenia ciekawych efektów.
Canvas API udostępnia zbiór funkcji do manipulowania danymi obrazu na poziomie pikseli.
Dostęp do danych tak niskiego poziomu sprawia, że możemy zaimplementować wiele ciekawych efektów.
Pobieranie danych o pikselach
Do pobrania danych o pikselach wystarczy wywołać metodę getImageData:
getImageData(sx, sy, sw, sh)
Wywołujemy ją z kontekstu Canvas. Przyjmuje cztery parametry:
Dwa pierwsze parametry: sx i sy określają lewy-górny punkt startowy, od którego ma pobrać dane o pikselach. Dwa ostatnie parametry sw i sh to odpowiednio szerokość i wysokość obszaru, z którego mają zostać pobrane dane o pikselach.
Metoda getImageData zwraca obiekt o nazwie: ImageData, który posiada takie właściwości:
width - Szerokość obszaru, dla którego zostały pobrane piksele.
height - Wysokość obszaru, dla którego zostały pobrane piksele.
data - Tutaj znajduje się to, co nas interesuje. Czyli tablica wszystkich pikseli.
data jest to jednowymiarowa tablica. Każdy piksel jest opisany przez cztery wartości: RGBA: R - red (czerwony), G - green (zielony), B - blue (niebieski), i A - aplha dla kanału alfa.
Inaczej mówiąc jeśli chcemy mieć dostęp do pierwszego piksela, piszemy:
Każdy element z data przyjmuje wartość z przedziału: 0 - 255. W przypadku kanału alfa 255 oznacza brak przezroczystości a 0 pełną przezroczystość.
Zapis zmodyfikowanych pikseli
Skoro już wiem, jak pobrać piksele to czas nauczyć się, jak zastosować wprowadzone przez nas zmiany na płótnie.
Służy do tego metoda putImageData:
putImageData(imageData, dx, dy)
W pierwszym parametrze imageData przekazujemy tablicę pikseli, które chcemy zastosować. Ostatnie dwa parametry to punkt startowy, od którego mają zostać zapisane zmiany.
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const randomRange = (min, max) =>Math.floor(min + Math.random() * (max - min + 1));
const draw = () => {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const width = imageData.width;
const height = imageData.height;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const index = (y * width + x) * 4;
const color = randomRange(0, 255);
// Ustaw wartości dla pojedynczego piksela
imageData.data[index] = color; // R
imageData.data[index + 1] = color; // G
imageData.data[index + 2] = color; // B
imageData.data[index + 3] = 255; // A
}
}
ctx.putImageData(imageData, 0, 0);
}
const render = () => {
draw();
requestAnimationFrame(render);
}
render();
Ten kod tworzy animację szumu. Zmieniamy każdy piksel obrazu.
Zapis:
const index = (y * width + x) * 4;
Daje nam dostęp do pojedynczego piksela. Następnie ustawiamy wartości dla każdego piksela. Po modyfikacji całej tablicy zapisujemy zmiany dla pierwszej klatki animacji.