From our sponsor: Meco is a distraction-free space for reading and discovering newsletters, separate from the inbox.
With HTML5 gaining popularity, this tutorial outlines what is really just the tip of the iceberg that is interactive design. I will go over the development of dynamic, and generative banners to give your website that little extra wow!
If you are interested in reading more about the HTML5 spec, this is a great resource: Dive Into HTML5 by Mark Pilgrim
Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.
Markup
The HTML markup is very simple, since we will be doing all the work with JavaScript, on the canvas element:
<canvas id="banner"></canvas>
JavaScript
As expected, it will be JavaScript doing all the heavy lifting here. But first and foremost, we will need to check if our users are using a modern browser that supports the canvas element. If it’s not supported, we want to dish up the next best thing: a static image. We will be using Modernizr to check on this.
Variables
Let’s start defining some variables:
//The words to be written on the banner var keyword = "HONEY", canvas, context, bgCanvas, bgContext, density = 13, particles = [], colour = '#fff0a4', mouse = { x:0, y:0 }, isDrawing = false, canvasW, canvasH;
A little explanation: The keyword here is going to be the word which you want to display on the banner.
The canvas, is a variable which will hold the HTML canvas element. This will be assigned later. The context is what allows us to drawn and write to the canvas.
The density variable holds how many pixels we want to have (both horizontally and vertically) between each banner particle.
The particles array will store all the particles and their respective settings.
The colour variable is the colour that each particle will have.
Finally, the isDrawing variable let’s us know if we are hovering over the banner, and the canvasW and canvasH are the canvas’ width and height respectively.
Setting up the banner
The first step is to call the reload function which we will also call on window resize:
this.initialize = function( canvas_id ) { reload( canvas_id ); window.onresize = function(event) { reload( canvas_id ); } };
In the reload function we initialize the canvas and context and set the respective sizes. Then we call the prepare, setupParticles and draw functions.
var reload = function( canvas_id ) { canvas = document.getElementById( canvas_id ); if ( !window.HTMLCanvasElement ) return false; context = canvas.getContext('2d'); canvasW = window.innerWidth; canvasH = 300; canvas.width = canvasW; canvas.height = canvasH; bgCanvas = document.createElement('canvas'); bgContext = bgCanvas.getContext('2d'); bgCanvas.width = canvasW; bgCanvas.height = canvasH; prepare(); setupParticles(); draw(); };
The first thing to note here, is that the function takes a string variable, which should match the element ID in the HTML. In our case, we would pass “canvas-banner”.
As you can see, both, the background canvas and the main canvas are set to the same size. We will get into why we are using two canvas elements in the next section.
The Background Canvas
Ok, now I have some explaining to do: The reason why we have two canvases here, is more or less the core of these banners. The background canvas is where you will be printing the text, or images. Afterwards, we will scan over the image data (pixel by pixel) of the canvas. If we run into a black pixel we will know that we have drawn on this location, and hence, will create a particle in its place.
var prepare = function() { //Chose the font, and size that we want. bgContext.font = "300px 'Jockey One'"; //Fill the keyword text onto the canvas. bgContext.fillText(keyword, ( canvasW / 2 ) - ( Math.round( bgContext.measureText(keyword).width/2 ) ) , 260 ); };
The fillText command above, takes three parameters: The first being the text to write, the second and third being the x and y co-ordinates respectively.
Next, we will create our particles. These will soon be drawn onto the main canvas, but for now, we will just store them in our particles array:
var setupParticles = function() { particles = []; //Declare our local variables var imageData, image_Data, pixel, width = 0, i = 0, slide = false; //Get the image data - from (0,0) to the edges of the canvas imageData = bgContext.getImageData( 0, 0, canvasW, canvasH ); image_Data= imageData.data; for( var height = 0; height < canvasH; height += density ) { ++i; slide = ((i % 2) == 0); width = 0; if (slide == true) { width += 6; } //Iterate horizontally over the image data for( width; width < canvasW; width += density ) { //Get the pixel located at our current iteration pixel = image_Data[ ( ( width + ( height * canvasW )) * 4 ) - 1 ]; //Pixel has been drawn on. if( pixel == 255 ) { //Add the coodinates and colour to our particle array. particles.push({ colour : colour, x : width, y : height }); } } } };
Yes, that is a large chunk of code, I’ll go over the tricky parts now.
Really, all we are doing is looping over every n-th pixel, where n is the density set at the start.
getImageData takes four values, the x and y of the top left corner, as well as for the bottom right. In our case, we passed it two zeros (the very top left) and the canvas width and height, which are the coordinates of the very bottom right. It returns a very big list, containing the color data of every single pixel on the canvas. Why are we multiplying this by four? Because within this list, each pixel is represented by four values, red, green, blue and an alpha value.
By default, all the canvas imageData contains, is a long list of zeros – by drawing on this canvas (in our case, using fillText), the pixels now contain proper color data.
Finally, we have pushed the x and y coordinates into a simple dictionary, which we will now use to draw our banner.
Drawing the banner
Here, we finally pull everything together. With our list of x and y positions, stored in the particles array, we can draw out the banner.
var draw = function() { context.clearRect( 0, 0, canvasW, canvasH ); var dx, dy, sqrDist, scale = 1; for ( var i = 0, len = particles.length; i < len ; ++i ) { ... context.beginPath(); context.moveTo( x, y - height / 2 ); context.lineTo( x + width / 2, y - height / 4 ); context.lineTo( x + width / 2, y + height / 4 ); context.lineTo( x, y + height / 2 ); context.lineTo( x - width / 2, y + height / 4 ); context.lineTo( x - width / 2, y - height / 4 ); context.lineTo( x, y - height / 2 ); context.closePath(); context.fill(); } };
We loop through each of the particles we stored previously to set the color and to draw a shape on that (x,y) point.
With that, we have a very simple static banner… now for the fun part, let’s add some interactivity.
Adding Interactivity
The fun thing about this is that we can be as simple, or complex as we want. The first thing we will want to do though, is track the user’s mouse position while it is over the banner.
var mouse = {x:0, y:0, o: false};
The mouse variable will be updated by two functions, one tracking the movement, and one tracking whether the mouse has left the canvas element:
var MouseMove = function( e ) { mouse.x = e.offsetX || ( e.layerX - canvas.offsetLeft ); mouse.y = e.offsetY || ( e.layerY - canvas.offsetTop ); if( !isDrawing ) { isDrawing = true; drawTimeout = setTimeout( function() { draw(); isDrawing = false; }, 60); } }; var MouseOut = function(e) { isDrawing = false; clearTimeout( drawTimeout ); draw(); };
In order to make these work, we also need to attach JavaScript events to our canvas element. These will go right back up into our reload function.
canvas.addEventListener('mousemove', MouseMove, false); canvas.addEventListener('mouseout', MouseOut, false);
Now that we can track the mouse, we need to change up our draw function a little, based on how we want to interact with the mouse.
... var p = particles[i]; dx = p.x - mouse.x; dy = p.y - mouse.y; // distance from mouse to particle sqrDist = Math.sqrt( dx * dx + dy * dy ); ( isDrawing ) ? scale = Math.max( Math.min( 3 - ( sqrDist / 10 ), 10 ), 1 ) : scale = 1; var width = density / scale - 4, height = density, x = p.x, y = p.y; context.fillStyle = p.colour; ...
Above, we calculate the distance between the current particle and the mouse. Then we update the variable scale to fall between 1 (meaning no scaling) and the distance between the mouse and the particle (but not bigger than 10).
All that’s left now, is to tell our canvas to draw at regular intervals, rather than just once at the start. At risk of getting too complicated I’m just going to keep it simple and use setTimeouts when the user hovers over the banner – but if you are interested in looking more into canvas animations, the function you will be looking for is requestAnimationFrame
Let’s get some color
We have a neat working banner, why not add a little color. Fortunately, we have already done most of the work here, we only need to change 2 lines.
//A variable to store each of the colors we want to use var colors = ['#fff0a4', '#ffe98f', '#ffcf52', '#fbad1d', '#c48d1c']; ... //When creating the particles, we assign a color from this list. color: colors[Math.floor(Math.random() * colors.length)],
And there we have it! A unique, generative and colorful banner, made just for you. Take a look through the demos to see a few other examples, of just what you can do.
Amazing… little script and big impact !
thx a lot for this demo
Very nice indeed Tim, I may use this.
Cheers,
Jonah
this is awesome. flash dies slowly but faithfully.
Wow… that’s some clever coding. It’s really nice to see what’s possible with HTML5 and it looks to me more and more that the possibilities are endless.
WOW … Amazing, Tim !!! I’m speachless ! :-)))
Muito Louco Valeu! 🙂
Amazing! Keep ‘on rocking!
Wow! is awesome! Thank You!
really nice and fresh idea
Awesome output!!! Thanks Tim for sharing!
the output is good enough to compete with flash..
Equal to flash totally . . . great work!
Wow, didnt know html5 can go this far! Very interesting!
goodbye day flash T.T
HTML5 Will be the king (:
Wonderful. Thank You.
Mix that up with some touch events?
everything is possible…..100% proof …thnx
WOw!!! Super effect. I’ll try it for sure
What I must configure in Banner1.js to make a smaller Text-size and looks good too?
Amazing effect. Love Demo 2. Thanks for this great tutorial..
Beautiful examples. Looking forward to the demise of Flash – All hail HTML5! 🙂
I still do not know if I should still make the decision to learn flash. I know flash is still going to be around for sometime but things like this makes you confuse.
Good job Tim
Hi
I can’t change the height , when i do the word is cropped , i end up with huge padding top 🙁
Doesn’t work in Opera (latest) on Win7 (don’t stop loading), on ff no probs
Amazing effect. Thanks for sharing!
This is toooo awesome! You have an awesome creativity. I have been wanting to try out HTML5 Canvas for quite some time now and I guess I was waiting for something like this 😛
Thanks!
your marketing strategy… generating lots of buzz!
Great Job!!
Interesting ! Ty for the tutorial. 🙂
Nice!!!
jawdropper!
Awesome! I have to update my JS and Canvas Knowledge. Thanks for that!
Really nice text effects and tutorial.
Does anyone know how I could intergrate this into a WordPress site?
Completely awesome
HTML5 Rocks. Thanks for sharing.
dat ws insane !!! it is so amazing !! loved it !!
Hi, thanks for that outstanding tutorial.
I created another visual effect which got featured on my page.
See http://www.romainpetit.com