Codular

HomeWriters RSS

More Beginner HTML5 Canvas

Introduction

In our first canvas introduction we covered basic drawing with lines, arcs and rectangles. Here, we'll move on to how you can put a lot of these together to firstly - build a custom shape. Then secondly working with images, that is importing them into our canvas and also exporting the canvas.

Be sure you've read the previous article first, as we'll be using a lot of the code that we already have from there, and building on some of the previous examples.

Custom Shapes

Let's throw everything together that we've used and look to make a hexagon, for this we need to look at the shape, and work out how to do it. Simply put, you keep drawing new lines using lineTo() till you reach back to the start.

A hexagon is a six sided shape, with each line having an angle of 120°ree; between it - if we start with a horizontal line of 50px long, we need to work out what other angles to do next.

The best way to do this, is to use some trigonometry - if your maths isn't that great, there's a great brief explanation on Wikipedia. We are only interested in the right angle triangle rules, and with this we can start to work out the other points that we need.

If you haven't before, it's worth taking a brief look at vetors - they are super simple, but will tell you that a diagonal vector is created by the sum of the horizontal & vertical components.

So, we need to find the horizontal and vertical components of the hexagon, let's quickly go through some maths and work out that (if we're working clockwise) with a right angle triangle made for the second line, we get a top angle of 30°rees; and a bottom right angle of 60°rees;. Luckily there are some super simple tools out there that will let you work out the lengths of the two sides. We've worked out that one is about 25px, and the other is around 43px. We will use these throughout.

Let's work out the points, take the first point at 75, 50, we will then have a 50px horizontal till 125, 50, at that point we'll use the aforementioned x/y changes to calculate the next point at 150, 93 - continue onwards till you get a series of points, you can then add them all together, and with the canvas end up with something like:

<canvas width='200' height='200' id='canvas'></canvas>
<script>
    var canvas = document.getElementById('canvas');
    var context = canvas.getContext('2d');
    context.beginPath();
    context.moveTo(75, 50);
    context.lineTo(125, 50);
    context.lineTo(150, 93);
    context.lineTo(125, 136);
    context.lineTo(75, 136);
    context.lineTo(50, 93);
    context.lineTo(75, 50);
    context.strokeStyle = '#0000ff';
    context.stroke();
</script>

You'll see that we now have a nice blue hexagon created. It is as simple as that to draw a custom shape, and you are able to merge any number of different lines, arcs, or bezier curves together if you wish.

Using External Images

If you want to use an external image within your canvas, it is super super simple. It is as easy as creating an image object, with the image URL that you want to use, and then using drawImage() to add the image. I'm going to use this awesome picture of bacon, and then position it on the canvas so that the top left corner is at the center of the canvas:

<canvas width='200' height='200' id='canvas'></canvas>
<script>
    var canvas = document.getElementById('canvas');
    var context = canvas.getContext('2d');
    var img = new Image();
    img.src = 'http://placebacn.com/150/150';
    img.onload = function(){
        context.drawImage(img, 100, 100);
    };
</script>

We have to make sure that we listen for when the image is loaded, otherwise the JavaScript will have no idea about what the image is, or contains and so won't work correctly.

Save Canvas to Image

We have the ability to save anything made on the canvas to an image - this is either through a data URL, or as raw image data. We'll be focusing on getting the image as a data URL. To do this we can call the simple method toDataURL() that is part of the canvas - not the context - which takes two parameters:

We then get the full data URL out. Taking the first example in this tutorial and exporting it:

<canvas width='200' height='200' id='canvas'></canvas>
<textarea cols='100' rows='15' id='result'></textarea>
<script>
    var canvas = document.getElementById('canvas');
    var context = canvas.getContext('2d');
    context.beginPath();
    context.moveTo(75, 50);
    context.lineTo(125, 50);
    context.lineTo(150, 93);
    context.lineTo(125, 136);
    context.lineTo(75, 136);
    context.lineTo(50, 93);
    context.lineTo(75, 50);
    context.strokeStyle = '#0000ff';
    context.stroke();

    var URL = canvas.toDataURL();
    document.getElementById('result').innerHTML = URL;
</script>

If you take the string in the textarea and put it in your browser URL bar, you should then see an image loaded that is the same as the content of the canvas. This can be super useful for an app where you're able to create, and save your own mockups or sketches.

Quick and Mini Build-It

Let's very quickly take a look at letting a user upload their own image from their machine that will then be added into a canvas, which we could then add another image on top of if we wanted.

Firstly we need to take a look at something rather awesome here, it allows us to get the image data from an image that someone has elected to upload, but without actually having to use any server side code. Let's quickly throw an example down, with comments - then a brief explanation:

<input type='file' id='upload'>
<script>
var imgData;

// Attach event listener
document.getElementById('upload').addEventListener('change', doUpload);

// Take event from file change & handle it
function doUpload(e){
    // The user might upload multiple files, we'll take the first
    var file = e.target.files[0];

    // Check that there is a file uploaded
    if(file){
        // We need to use a FileReader to actually read the file.
        var reader = new FileReader();

        // When it's loaded, we'll assign the read section to a variable (imgData);
        reader.onload = function(event){
            imgData = event.target.result;
        }

        // Pass the reader the file to read and give us the DataURL
        reader.readAsDataURL(file);
    }
}
</script>

That is the basis of the code to read a file that is chosen to be uploaded, without actually uploading it. We're using something called a FileReader() that will take a file in and run a certain method against it. Here, we're telling it to read the file as a data URL.

Add Canvas

We can use this data URL to create an image object, with the source set to the URL - and then pass that to the canvas as previously, to load the image in:

<canvas width='200' height='200' id='canvas'></canvas>
<input type='file' id='upload'>
<script>
    // Attach event listener
    document.getElementById('upload').addEventListener('change', doUpload);

    // Take event from file change & handle it
    function doUpload(e){
        // The user might upload multiple files, we'll take the first
        var file = e.target.files[0];

        // Check that there is a file uploaded
        if(file){
            // We need to use a FileReader to actually read the file.
            var reader = new FileReader();

            // When it's loaded, we'll send the image data to the canvas method
            reader.onload = function(event){
                canvasLoadImage(event.target.result);
            }

            // Pass the reader the file to read and give us the DataURL
            reader.readAsDataURL(file);
        }
    }

    // Handle the returned image data
    function canvasLoadImage(imgData){  
        // Create a New Imgae
        var img = new Image();

        // Assign the image data as the source - as we are using a data URL
        img.src = imgData;

        // Always use onload with images!
        img.onload = function(){

            // Load the Canvas & Context
            var canvas = document.getElementById('canvas');
            var context = canvas.getContext('2d');

            // Draw the image
            context.drawImage(img, 0, 0);

            // More here?
        }
    }
</script>

One thing to bare in mind with this, is that there is no validation that the image is a legitimate image, or that it is safe for work or anything. But the great thing about this is that there is no server interaction and it is all client based. So the user would only be causing hassle to themselves.

You can change the section // More here? to perhaps include some automatic features to draw on the canvas, or even overlay another image in the bottom right hand corner. Then add a button that will export the image canvas to a data URL for the person to download - or something similar.

You might also want to make the canvas size bigger so that the whole image is uploaded to the canvas, or tweak it so that the image is centered overall within the canvas.

Conclusion

That is the very basics of canvas covered, meaning that you can now go and play and abuse canvas all over. There will be an article in the future that will lead onto animation with canvas and how you successfully manage that. Animation in canvas is not solely used for videos or that, but more for games based on user input.

Tags: JavaScript, Canvas