The fade out effect is one the easiest things you can do with a bitmap and it's a great introduction to pixel manipulation on the HTML5 Canvas.
In fact, the 'fade to black' effect is so great that Metallica wrote a song about it.
A bitmap image is a picture composed of pixels - small, colorful dots. The color is defined as a combination of three basic colors: Red, Green and Blue (RGB). We will gradually decrease the value of each component of each pixel, which will result in the image fading out to black.
Let's take a look at this piece of art which I painstakingly created:
You're not seeing anything? Take a closer look! There are actually four pixels (just above the word 'You're'): black, white, green and gray.
Take a look at how this image information is stored in memory:
I zoomed in on the four pixels (which are now large squares) and showed the corresponding array below.
Each pixel is defined by four values (bytes - unsigned integers of 8 bits, but you don't have to remember that). The first three values correspond to the three RGB components. The fourth one is the alpha (transparency) and we'll ignore it for now.
So the first pixel's RGB values are 0,0,0 - it's completely black. The second pixel is 255,255,255 - maximum values for each component, which results in white. The third pixel has a high value of Green (177), but lower values of R and B, resulting in a shade of green. The fourth pixel has equal values of each component, resulting in gray.
You can access the values of the Canvas pixels using the getImageData function.
Now let's look at our code snippet:
<html> |
<body> |
<img id="source" src="image.jpg"> |
<canvas id="myCanvas" width="600" height="373"></canvas> |
|
<script> |
window.onload = function() { |
let canvas = document.getElementById("myCanvas"); |
let context = canvas.getContext("2d"); |
let img = document.getElementById("source"); |
context.drawImage(img, 0, 0); |
let imgData = context.getImageData(0, 0,canvas.width,canvas.height); |
window.requestAnimationFrame(fade); |
|
function fade(){ |
for (let i = 0; i < imgData.data.length; i += 4) { |
r=imgData.data[i]; |
g=imgData.data[i+1]; |
b=imgData.data[i+2]; |
if(r>0)r--; |
imgData.data[i]=r; |
if(g>0)g--; |
imgData.data[i+1]=g; |
if(b>0)b--; |
imgData.data[i+2]=b; |
} |
context.putImageData(imgData, 0, 0); |
window.requestAnimationFrame(fade); |
} |
} |
</script> |
</body></html> |
Code in action (click on the right-side/black image to reset the image):
Code explanation:
[8-9]: setup the Canvas and its Context.
[10-11]: copy the image from the "img" element to the Canvas. (In real life you probably want to hide the img element, so that only the fading picture will be visible.)
[12]: get the pixels to the imgData object
[15-30]: this is the function where the actual fading occurs:
In each animation frame, we cycle through the data, one pixel (four bytes) at a time [16]. We get each component [17-19] and decrease it if it hasn't reached zero already [20-25].
Finally we draw the updated image [27] and request another animation frame [28].
If you replace [20-25] with the lines below, you'll fade the image to white instead of black:
if(r<255)r++; |
imgData.data[i]=r; |
if(g<255)g++; |
imgData.data[i+1]=g; |
if(b<255)b++; |
imgData.data[i+2]=b;*/ |
Once you get the hang of it, here are a couple of things you might want to try:
- stop after 255 iterations
- try increasing one component while decreasing the other ones
- image fade in
- fade out at the end of each level in your game
- get a $200k/year job as a JS developer
Good luck!
Check out these programming tutorials:
JavaScript:
Oldschool fire effect (20 lines)
Animated fractal (32 lines)
Physics engine for beginners
Starfield (21 lines)
Yin Yang with a twist (4 circles and 20 lines)
Optical illusion (18 lines)
Tutorial - interactive, animated sprites
Your first program in JavaScript: you need 5 minutes and a notepad
Fractals in Excel
Python in Blender 3d:
Domino effect (10 lines)
Wrecking ball effect (14 lines)
3d fractal in Blender Python