Mouse Move Glitch Collage Using HTML Canvas

Published

April 30th 2019

Difficulty

Intermediate

Posted by

Rik Lomas

As seen on the Azab site (or when you win at Solitaire), it's fairly straight forward to create a glitch-style collage that draws the image again and again whenever your user moves their mouse. In this video, we build up how to make a site that has a HTML canvas slideshow that reveals each image on click and has a tweening movement.

View demo

Transcript

(upbeat music)- [Rik] Today we're going to be talking aboutthis effect on the Azab website.So when I move my mouse around the page,we get this drawing effect so you can see as I move around,the image gets drawn again and again and again.So it almost looks like it layers up.Now this might remind you of the winning solitairestyle thing from Microsoft in the 90s,so we have this kind of same style effect,we're drawing lots of things over each other.Now, our site is gonna look something like this.So when I move my mouse around the page,it draws multiple times.Now we're gonna add in some different styleof effects as well, so if I click on the page,we'll change the image as well.Now I'm using some photos by Pawel Czerwinski,using from Unsplash so you can just grab them,any of your own, you can even use your own in this project.We're gonna talk about this in three different parts.The first part is we'll set up a canvas tag,which is how we draw these imagesand just draw one image whenever we move the mouse.So this image will be hooked exactlyto the mouse to begin with.Our number two, what we'll talk about is howwe click to change, so when I click,the image changes to a different onethat we're trying to draw.And the third one is we'll add this kind of movementin as well so it doesn't go instantly to the mouse,we kind of get this effect where it movestowards the mouse over time.So we'll talk about this in this project.(upbeat music)

So I've just set up a quick projectthat looks something like this.At the moment, if I move my mouseon the page, nothing happens.So let's just talk about what I've done to set this page up.So quickly, all I've done is added a h1 tagwith Oil paintings in here and then a link to our Instagramand if I look at our style sheet,what we have is basically a web font in here,and we've got some basic styling,black background, white text.My h1 is fixed to the top left corner.My a tag with my Instagram is in the top rightcorner and at the bottom,I just kinda wanna have this mix blend mode different,which we'll talk about a little bit later.I've also added in all of my images.Each of my images is sized to 800 by 1200and that's because I want to make them retina friendly.We're gonna do this at half the size,we're gonna do it at 400 by 600 when we draw,so at the moment we've just doubled itand exported it in that way.So the first thing we're gonna do is actually add a canvastag to my HTML because I want to basically draw on my page.So in my index.html, I'm gonna add in a canvas tag.

Now at the moment, nothing goes inside of this,it just exists as a tagand if we look at the page right now,it kinda looks the same.Now what I want to do is style this to beacross the entire page itself.How do I do that?I need to add some code that tells canvas what to do,what do we want to draw on the page,where do we want to draw on the page,how should this even work.So this is what I need to do with a JavaScript file.Now I'm gonna make a new script tag hereand I'm gonna call it something like drawer.So you can call this whatever you'd like,something that draws things is a drawer.js file.

It just needs to be something that kinda makes sense to you.At the moment I've got an empty file.I need to add this to my index.html.Where do I do this?I'm gonna do this below my canvas tag.So I'm gonna add a script tag first of all.Script, and I need to pull in my drawer.js file.So in here, I'm gonna pull in using the source, src,this is gonna be equal to something quotes,what do I want this to be equal to?Well I just made a file called drawer.js, drawer.js.

Now currently my drawer.js is currently blank,there's nothing in there.So nothing will happen at the moment.So if I go back to my page,move on the page, obviously nothing happens.But let's start to think about whatwe need to add into my JavaScript.Well the first thing I need to do is addsome code that sets up my canvas.So the first thing I need to do is grabthis canvas tag and set it up.Now I want to set it up for both retina and non-retinaas well, so I need to think about that as we start.So the first thing we're going to do is grab our canvas tag.So I'm gonna save this to a constant,a constant called canvasTag.Now we've just made that name up,it doesn't mean anything, I can call it whatever I want.It could be called canvas,it could be called potato, it's up to us.This is going to be equal to something.

What do we want to pick out of our page?Well, we need to pick something out of our page.So on the page in JavaScript it's called a documentand what do we want to use?What do we want to grab off the shelfwithin JavaScript, to grab tags?So here what we want to grab is the query selector,so we're gonna use .querySelector.

Now this is just a tool built into JavaScript,but we want to use this.So to use this, we use round brackets.What do we want to use?Well, we want to grab a certain tag.Which tag?Well, canvas.Canvas isn't a special word in JavaScript,so we're gonna put it in quotes, canvas.So this just basically holds onto one thing, a canvas tag.So at the moment, nothing happens in here.

The next thing we want to do is set this up,we want to give it a certain width and height.Now this is going to be acrossthe entire page but we could tell itto be a certain number instead, it's up to us.We don't know the certain number because we don't knowwhat our user is looking at the project on.They could be looking at it on a mobile device,a tablet or a live screen like this.So we need to set it up for that user.To do that, the first thing we're going to dois we're gonna set up a canvas.widthand this is gonna be equal to, oops sorry, canvasTag.width,and this is gonna be equal to how wide the screen is,window.innerWidth.

We also want to set up a height for this as well,so canvasTag.width and height,and this one is going to be equal to the window.innerHeight.

Now one thing we need to do is setthis up for retina as well,so what I'm gonna do is justmultiply both by two, so times two, times two.

But the downside of doing thisis it makes our canvas tag really big.You can see these scroll bars startto appear up and down the page.So how do we fix that?So to fix this, what we're gonna do is saythe CSS style of this canvas, not the canvas drawing area,is gonna be half the size.So our canvasTag is going to have a style.width,so this one is our CSS and the one aboveis just our drawing area.This one is going to be exactly the window width plus in px,because obviously it's CSS, it needs some unit with this.And also, similar, what we need is a height as well,and this one is innerHeight plus px.

Now what we'll get at the moment is this sets up our pagewithout any scroll bars which is kind of what we want.There is a tiny little scroll bar thatyou might notice down here and the reasonfor that is our canvas element is an inline tagwhich means there's a little bit of space at the bottom.So to get rid of that, we're going to go to our style sheetand in our style sheet, we're just gonna say, canvas,a vertical alignment on our inline tagis right at the bottom.So it doesn't sit on the baseline of text,it sits right at the bottom, so there's no underneath space.So now we should see that if we scroll in either way,our canvas is set up.The next thing we want to do is set up our canvas' context.Now what do I mean by that?Canvas can have multiply ways of doing things.It can do things in 3D, it can do things in 2D,and there's a lot of different wayswe can actually draw in a canvas.So the next thing we're gonna do is set upa new constant based on this canvas tag.So what I'm gonna do is a new constant called context.Now this is a common thing that you'll seein any kind of canvas documentation.Which context are we drawing things in?Are we doing it in two-dimensions,three-dimensions, four-dimensions?Which doesn't exist,but we could have that in 2030, let's say.So what we're gonna say hereis we want to draw our canvasTag,we want to get the context in brackets, in a 2D way,so we want to draw in a 2D canvas tag.Now with this, we also want to say a certain scale,like we're gonna do things based on retina,which is in double, the pixel density,so our context also has a scale two across and two down.

So basically this is the coordinatesthat we're setting up here.We've got a double, so we're saying to our context,this is already double so we kind ofget retina friendly canvases.Now this is just basic setup that we would dofor any canvas tag that we want to draw inside of.If you want to draw lines or circlesor squares or rectangles, this is how we do the same thing.Now what do we want to draw in here instead?Well we want to draw in our whole canvas tag, an image.Which image do we want to draw?Well we want image1 to start with,or image2, or image3 or image4.So let's get one of these to start with.So my images aren't tied up with my index.htmlor my drawer.js at the moment.So what do we want to do?Well in my JavaScript,I want to make a new image tag from scratch.So to do that, we're gonna make a new constant called imageand this is gonna be equal to, well it's not justgoing to be image1.jpg, we want to make an image tag.So to do that, in our page, in our document,we want to get something from the shelf, using a dot,and we want to make something,want to do something using JavaScript.Now a part of JavaScript we can use is a createElement.

What do we want to do with createElement?Well we want to run it,so we want to run it using round brackets.And then what do we want to put in here,what kind of tag is this?Well if we did an image tag in HTML, we would use img,so we need this in quotes, img isn't a special word.Now this is gonna create an image thing that we're holding,an image constant, an image variablethat we can do stuff with.Now what do we want to do with this image?Well, at the moment it's just an empty image tag.We want to tell it what source it should be.So just like we did with our script tag,our image has an src, a source, that's equal to something.

We want it to be equal to the first image for now.So in quotes, we're gonna say, image1.jpg.

So we've got our canvas set up,we've got our context set up,we've got our image set up.Now how do we actually draw things on the page?

What I want to do is when I move my mouse aroundthe entire document or the entire page,I want to draw on my canvas tag.But in which context?In the 2D context.So that's the next thing I'm gonna think about.So, on my document I want to move my cursor,so I want to listen out for any mouse movements.So to do that, I'm gonna do on my documentand addEventListener,and I wanna do two things in here.I want to run this and say listen out for in quotes,mousemove, and when you listen to a mousemove,as soon as it does move, do something.So after this quote we're gonna do comma functionround brackets, curly brackets.So just watch out for the curly bracketsand round brackets here.There should just be one round brackets, one curly brackets.This one here is just attached to that one.Now we're gonna give ourselves a little bitmore room to breath in here and what we want to dois just draw this on our canvas.Now how do we do that?Well the first thing we need to listen outfor is has the image been loaded yet.If this is quite a large image,it may not even be able to be drawn yet.So we're also gonna add in here an if statement.If, round brackets, curly brackets.What do we want to do in our if statement?So we want to check for if this image tag up herehas been completed, has it been loaded yet.So, our image.complete, has it been loaded yet.

Now at the moment, it's complaining, but don't worry,we're just gonna open these curly brackets outand the next thing we want to do is draw itin a certain place on the page.So for now we're just gonna draw it inmaybe about 100 by 100.So for now we're just gonna say on our 2D context,'cause we got the context in 2D,what we want to do is something,we want to do something to this drawing,we want to draw an image.In this image there's a few things that go in here.We want to draw in our context,this image that we've loaded.

Where do we want to draw this image though?Well for now what we'll do is a comma, 100 by 100,and we're also going to give it a certain size and width.So the width is 600 and the height is 400 at the moment.So what we should see now is justone image that's always in the same place.So soon as I move this, it pops out, there we go.Now obviously what we want is this to be drawnin a certain place at certain times.What do we need to listen out for?Well, with this whole function thatwe have from here to here, this gives us some moreinformation that passes along from the browser.So it gives us coordinates, where is the mouse right now.So what we can do is pass those extra bits of information inin these round brackets, so in these round brackets,I'm gonna make a variable called event.Now this could be called whatever you like,it doesn't need to be called event,it could be called anything.But what I can get as part of this event is two things,where the mouse is across the pageand where the mouse is up and down the page.So instead of this being always at 100 by 100,what I can do instead is replace 100 with event,or whatever this is called,dot pagex and for this one, I can do event.pagey.

So what we'll get on the page right now,is if I move around,this suddenly starts to draw it in the right place.Now this is always in the top left cornerbecause I always draw from that top left corner.So how do I shift this over?Well all I need to do is remove some values from this.So here what I'm gonna do in pagexis just remove 200, half the width.In page y, I'm gonna remove 300.So what we'll get from here is just this mouse follows usin the middle of the page like this.(upbeat music)

So at the moment it's always going to be one image.But what happens if you want to show multiple images,how do we even think about this?Well the idea of what I want to do is when I click,I want to replace this image.So at the moment,everything is currently fixed to this single image.So how do we go about changing this?Well at the moment, there is only one image that's beenloaded on this page and we wantmultiple images to be loaded.So what we're gonna do just quicklyis we're gonna get rid of two things.Now there might be some complaints,you might see some JavaScript complaints coming up,but what we want to replace it with is what?Well we want to replace it with a list of images.So how do we do that?We're gonna make a new constant called images,which is plural, and this is going to be equal toa list of something, or an array of things.Now in my array, what I'm gonna put in is quote,image1.jpg and then a comma, with image2.jpg,and I'm gonna fill this out into all four of these.Now at the moment what this will do is it willjust make some strings, some list of characters basicallyand this actually doesn't load any images into our pageso at the moment, this code will not work.So how do we actually load these images in?So we want to turn this listof just sources into real images.So to do that, we're gonna use another JavaScript tool,especially for lists in this case, called .map.A map basically takes the inputand turns it into something new,so we're gonna do something to each image one by one.In our map, what we're gonna say is each of these srcs,which is image1, image2, image3, image4.jpg does something.

So we're gonna take the original and turn it into something.Now I'm just gonna add some space,just to make this a little bit easier to read.But what I wanna do in here is basically make an image.Now this code will only run between these curly brackets,it won't be able to get it from outside.So what I'm gonna do is a constant within herefor each one called image and this is gonna be equalto document.createElement.

We want to create a new image tag.And just like before, each image tag has a source,and this usually equals something like image1.jpg,but we know what image1.jpg is because it's passed ineach time using this src which is what we've just made up.So we don't want to do this 'cause this is hard codedfor images which are all image1.jpg.We want to replace this with the source each time.And the last thing we want to do is we wantto turn the input and send it back out.We want to return back the original image.So this is gonna make an image tagfor each one of these four things.Now at the moment, this is gonna do something.But it will still break when we try and do the mouse'cause we don't know which of these imagesthat we're talking about at the moment.So we need to keep track of something,we need to keep track of which image is the current one.So above this, what I'm gonna dois hold the the current image.Now I'm gonna do this using a variable, not a constant.We want something that's gonna change.These images don't change,we can't do any code that changes this.But we want to do code that changeswhich one we're talking about on a click.So we want to do let something equal something,just like constant equals something.We're gonna do i, i just means the index thatwe're talking about, the number in the listthat we're currently talking about, equal to zero.Now it's zero because lists count from zero,not one like humans.But what we're trying to talk aboutis the first image in here.Now what I wanna do in here is not talk about image,because image doesn't exist outside of this whole box.Image exists in this box, but we can't get to that box.So what we wanna do is imagesand then find which one we're talking about in here.To do that, we're just gonna change if images,square brackets because we're talking about a list now,which one of this list are we talking about,the index in this list.Now this is just finding this image,this image, this image, or this image at the moment,and we want to draw that image in the same way.So I'm gonna take that code and replace it with this.Now at the moment what we'll see on our page is basicallythe same thing as what we had from before.We have things that move, but nothing happening on click.Well that kind of makes sense because at the moment,nothing happens on click.So what do we want to do on click?Well what I'm gonna do is on anypart of the canvas tag, if we click it,then we want to change which image that we're talking about.So underneath it, we want to make a new addEventListener.

What do we want to attach it to?We want to attach it to the canvas tag.Now the reason for doing it on the canvas tagand not the document is I still want to clickthe Instagram link to go to Instagram.I just want to do it on this bit instead.So on this canvasTag I'm gonna add an event listener.What do I want to listen out for?A click.What do I do when I've clicked?Well I want to run some code.I want to run a function, round brackets, curly brackets.What do I want to do?Well what I want to do is I want to justincrease that value of i.The new value of i is going to be equalto the old value of i plus one.So zero becomes one, as soon as I click,which talks about a different one, it talks about image2.If I click again, it talks about image3.If I click again, it talks about image4.So let's see this in action.

There we go, we can see this changing.But as soon as I get to the fourth one and click again,it breaks and that's because there isn't an image fivethat we're talking about.So what we wanna do is add a little bit more code in herethat says if we run out of numbers, go back to the start.So how do we do that?Well I know that there's four things in this list,so if this i gets bigger thanthe amount of things in the list,go to the start.So if brackets, curly brackets.So on the round brackets, what we're gonna say is if iis bigger or equal to images.length,so if we wanted to add a fifth image,this code would still work.And if it is, then what?I goes back to zero.So it's gonna do some calculation in here each time.So let's just see if this works.

One, two, three, and there we go, back to the start.

So we're basically making something that loops around now.And as you can see, it doesn't really matterhow many images that we put in here,the only thing that we need to changein our code now is this list.So if we add a fifth, this is the only placethat we need to go because we've set up our codeto only listen out for certain numbers like how longis this list that we're talking about.(upbeat music)

So at the moment you might notice thatas soon as I move my mouse,it draws instantly and I can almost shake this off as well,it just sticks to the mouse at all points.Now I've kind of covered this in a previous videocalled Smooth moments with JavaScriptand the idea behind that is we have this kind of effectthat moves as we kind of move the mouse.So we're gonna be using similar code to that in this projectand the idea of what we want to dois not move this exactly to the mouse,now what we want to do is kind of trendthis towards the mouse,almost like tween it towards the mouse instead.So this needs a little bit of re-engineering.Now it's not too much, it's not too bad.But basically the issue that we haveis we only do things on mouse move.So if I move my cursor really, really quickly,then I'm only doing this next drawing.But we want to have the states in between there as well.So how do we have those states in between that?So I'm gonna add in some more code.I'm gonna do this above the let i is zeroand we're gonna add four things in here.What we wanna do is hold an aim for the x.Now when we load the page,we might not even have our cursor on the page.So we're just gonna say null, which is empty, nothing.

It's kinda like zero without it being anything at all.And then we're gonna have an aim for y.Where is this meant to go to?But what we have is where our cursor currently was,so we kinda want to hold where the cursorwas to trend it towards the aim.So here we're gonna do a current x of nulland a current y of null.Now I've kept them all as lets rather than constantbecause they're going to change if I move my mouse,this wants to change.Now what I'm gonna do to start withis I'm gonna get rid of this thing that draws.So I'm just gonna get rid of this.Now the idea of y is because I want my aimto be where this mouse movement is.So in here, what I'm gonna do is say my aim xis exactly where the event pagex is.So if I move my mouse really quickly,I want to trend towards my new mouse movement.And the same thing for y.I want this in two directions.Now I'm also going to sayif the current x position is empty,just make the current x the same thing.So if current x is equal to null,then that should be the same as well.We want to have a starting point as well.But if it's not then we want to tween it,or transition it between the two.So for now this is just in an if statement.Now how do we draw on the page itself?Well at the moment we draw, or we did draw,on any mouse movement.But we kind of want to draw between mouse movements as well,so we've got a problem.How do we draw things betweenanything happening on the page,any event happening on the page completely?So we need to think about this in a different way.What we're gonna do is we're gonna use this commentedout code a little bit later but for nowwhat we're gonna say is I basically wantto make some kind of drawing loop.So I'm gonna make a constant called draw.Now constants and lets don't have to be equalto numbers or lists or strings,they can also be equal to things that do stuff, functions.Function, round bracket, curly bracket.And what I'm gonna do in here is basicallydraw the image where is it currently.So I need to have some current value first of all,so if current x is a thing,so we'll just leave it as if current xand add curly brackets after that.So if there is a current x that isn't null,then what do we want to do?Well we want to draw stuff.How do we draw stuff?We use the code from up here.So I'm just gonna grab this commented out bit of code,I'm gonna take it and put it between hereand I'm gonna un-comment it.There we go.Now again, you can just remove those little commentsin the SuperHi Editor it's command and forward slash,and what I've got here is not event pagex,but instead I want it to be the current x positionand the current y position.

The thing is, this draw function never runs.We've set it up, but we never ever run it.Where do we want to run this?Well we want to run this on page load,but we also want to keep running this,we want to run this in a loop thathappens over and over and over again.So the first thing we're gonna dois we're gonna run it on page load.Now to run things on page load,we just don't go inside any boxes,so no boxes like addEventListener for instance,we're just gonna keep it outside everything.We're just gonna write draw.So this will run this draw function just once.But we want to run this on every single frame.So in my draw function,I'm gonna create a loop that runs and runs and runson every single frame.To do that we're gonna use a JavaScript call tool calledrequestAnimationFrame and here what we're gonna doin animation frame is draw.So this will draw it first time 'round,and then it will do this bit of work,and then go, wait for the next frame,and then do this again.And then on the next frame,do it again and on the frame after that, do it again.So what we'll see right now on the page is if I move,it just happens the once.And the reason for that is wenever updated the aim position,it's just always the current position.Now how do we change the current position?Well basically I want to trend it towards the aim.So what I want to do in my if statement,and notice I'm still with if current x'cause I still want to update things,well what do I want to do in here?Well this depends on the current x position.So my current x, and what I want to dois change this to be something.I want to change this to be equalto the old version of current xand some distance between where the current x positionis and the new aim position is.So in brackets, I'm gonna put in aim x minus current x.

So aim x plus current x is just the distance,so this plus, minus this, plus aim x, is equal to aim x.

But we don't want to just go straight there.We want to have some distance between them,so what I'm gonna do is timesthis last bit by some small number.The small number I'm gonna use is 0.1.

So we'll have this is just the one direction at the moment.So if I just see it right now,what we'll get, is this will draw in one way.Now notice how this does it based on the speed now,the speed is 0.1.I could change that to be slower if I wanted.So for instance, 0.01 will make this even slower,and there we go, it's kinda trending towards the mousevery, very slowly now.Now of course we want to do it in the y direction too.So in the y direction, we're gonna do current yis the old version plus the difference betweenthe aim y minus the current y,so how far is that gap,but we don't want all of the gap straight away,we kind of want to have some kind of padding,or tweening, between the two.So we're gonna just add this last little bit in hereand what we'll get on the pageis this is the kind of slow version,and there we go, it starts to tween between,and if I click again, it will change these images.So if I want to change the speed of this,all I need to do is change these two numbers.Maybe I just want to make it 10 times quicker, so now...

It should go a lot quicker.So this is how we can makesomething that looks really, really good.It's only a short amount of JavaScript.There is some complex JavaScripts in here,but we've basically got 55 lines of JavaScript in total.We're setting up the canvas tag,setting up the context we want to draw in,setting up our images,when we move our mouse, we want to go to a certain place.If I click, we want to change the image.And I'm gonna keep drawing a loop wheneverwe want to draw the next frame and thenwe're gonna do some calculations to work outwhere the next current position should be.And there we have it, it's a few bits of JavaScript.It's not too complex, it's you know,a little bit of thinking,but once we kind of build these techniques up together,we can build very powerful sites very, very quickly.

If you're interested in learningmore about these kinds of techniques,join our JavaScript for Designers coursewhere we talk about six different projects,all very similar using lots of fun techniquesjust like the ones that we've been teaching.(upbeat music)

Want more? Sign up for our newsletter for more articles, resources, and fresh inspiration