Comics: CRUD Dev - It ain't much but it's honest work


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.
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:
imageData[0] = 128; // czerwony
imageData[1] = 64; // zielony
imageData[2] = 250; // niebieski
imageData[3] = 128; // kanał alfa
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ść.
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.
To teraz czas zebrać całą wiedzę tutaj opisaną:
Dodaj element canvas w pliku HTML:
<canvas id="canvas" width="800" height="600"></canvas>
I wreszcie kod w JavaScript:
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.
Żeby wylosować liczbę z zakresu: (1, 10) wystarczy napisać:
const randomRange = (min, max) => Math.floor(min + Math.random() * (max - min + 1));
console.log(randomRange(1, 10)); // 6
console.log(randomRange(1, 10)); // 10
console.log(randomRange(1, 10)); // 1
Funkcja, w takiej postaci może zwrócić liczbę minimum lub maksimum z podanego zakresu.
W kwietniu opublikowałem 6 wpisów:
Inne:
NodeJS:
JavaScript:
MongoDB:
Przeczytałem dwie książki:
Przesłuchałem trzy audiobooki:
Omit tworzy nowy typ danych na podstawie już istniejącego. Przydaje się szczególnie wtedy kiedy chcemy się pozbyć niektórych pól ze wzorca.
Składania wygląda następująco:
Omit<Type, Keys>
Pierwszy parametr Type to istniejący typ danych. Drugi: Keys to pole lub pola, które nie zostaną wzięte pod uwagę, w nowo stworzonym typie danych.
Jest dostępny w TypeScript od wersji 3.5
interface Book {
title: string;
author: string;
pages: number;
}
type AudioBook = Omit<Book, 'pages'>;
// AudioBook będzie wyglądać tak:
/*
AudioBook {
title: string;
author: string;
}
*/
Mamy nowy typ AudioBook bez pola pages.
Jeśli chcemy pozbyć się więcej niż jedno pole, piszemy:
interface Book {
title: string;
author: string;
pages: number;
weight: number;
}
type eBook = Omit<Book, 'pages' | 'weight'>;
// eBook będzie wyglądać tak:
/*
eBook {
title: string;
author: string;
}
*/
Za pomocą Omit możemy także rozszerzać interfejsy:
interface Book {
title: string;
author: string;
pages: number;
weight: number;
}
interface AudioBook extends Omit<Book, 'pages' | 'weight'> {
length: number;
}
// Interfejs AudioBook będzie wyglądać tak:
/*
interface AudioBook {
title: string;
author: string;
length: number;
}
*/
Dzięki Omit możemy też "nadpisać" dane pole:
interface Book {
id: string;
title: string;
author: string;
}
interface AudioBook extends Omit<Book, 'id'> {
id: number;
}
// Interfejs AudioBook będzie wyglądać tak:
/*
interface AudioBook {
id: number;
title: string;
author: string;
}
*/
W interfejsie Book mamy pole id o typie string. A w nowym typie AudioBook potrzebujemy wszystkie pola z Book tylko pole id powinno być typu number. Dzięki Omit jak widać, można to łatwo osiągnąć.