In this article we pull together some of the things we learned in our HTML5 canvas tutorial to build a simple HTML5 meme-generator web-app. First we present the app, and after we detail how it was built. So, here it is – load an image below, manipulate it, add some text, and download or save and share!
Scale
Rotate
Load image:
Download image OR
How we built it
Our aim here is to build a simple meme-generator using HTML5 canvas. Our application should support the following:
- Image loading
- Simple image transformations
- Addition of custom text
- Saving on the web, for sharing/bookmarking
- Downloading
For more detailed explanation of the canvas functions we are using here, please see this introduction to canvas tutorial.
Setting up the canvas
First of all, we’ll start by setting up our canvas. We set it up as we outlined here:
1 2 3 |
<canvas id="memecanvas"> Sorry, canvas not supported </canvas> |
And the JavaScript to set up the canvas to extend to near the dimensions of the screen looks like this:
1 2 3 4 5 6 7 8 9 |
var canvas = document.getElementById('memecanvas'); ctx = canvas.getContext('2d'); var deviceWidth = window.innerWidth;; canvasWidth = Math.min(600, deviceWidth-20); canvasHeight = Math.min(480, deviceWidth-20); canvas.width = canvasWidth; canvas.height = canvasHeight; |
Draw image on canvas
We’ll add an initial image to the canvas, so it’s not blank when we begin. We make use of what we learned about images and canvas earlier. First we have an image in markup:
1 |
<img style="display: none;" src="/files/lenna.png" alt="" /> |
And then we draw it centered on the canvas with:
1 2 3 4 5 6 7 8 9 10 11 12 |
// Grab the image var img = document.getElementById('start-image'); // When the image has loaded... img.onload = function() { // Work out where to center it x = canvas.width/2 - img.width/2; y = canvas.height/2 - img.height/2; // Draw it ctx.drawImage(img, x, y); } |
Scale and rotate transformations
Next we want to add some simple transformation controls, namely rotation and scaling. We’ll use HTML5 range (slider) inputs for each, with appropriate range and step for each:
1 2 |
Scale: <input id="scale" max="4" min="0.1" step="0.01" type="range" value="1" /> Rotate: <input id="rotate" max="180" min="-180" step="1" type="range" value="0" /> |
When either of these are changed, we want to trigger a function to perform the necessary transform. So we attach a listener to the change
event.
1 2 3 4 5 |
scale = document.getElementById('scale'); scale.addEventListener('change', doTransform, false); rotate = document.getElementById('rotate'); rotate.addEventListener('change', doTransform, false); |
The function, doTransform()
will take the values from our slider inputs and apply the appropriate transforms:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
function doTransform() { ctx.save(); // Clear canvas ctx.clearRect(0, 0, canvas.width, canvas.height); // Translate to center so transformations will apply around this point ctx.translate(canvas.width/2, canvas.height/2); // Perform scale var val = document.getElementById('scale').value; ctx.scale(val, val); // Perform rotation val = document.getElementById('rotate').value; ctx.rotate(val*Math.PI/180); // Reverse the earlier translation ctx.translate(-canvas.width/2, -canvas.height/2); // Finally, draw the image ctx.drawImage(img, x, y); ctx.restore(); } |
Load custom image into canvas
This thing would be much more useful if you could use your own custom image with it. So, let’s do just that! First we need a file input element in the HTML:
1 |
<input id="fileInput" type="file" /> |
When the value of this input changes we trigger a function loadImage()
to handle the image data, and load it into the canvas:
1 2 3 |
// Trigger the imageLoader function when a file has been selected var fileInput = document.getElementById('fileInput'); fileInput.addEventListener('change', imageLoader(), false); |
And the imageLoader()
function uses the HTML5 FileAPI to load the image:
1 2 3 4 5 6 7 8 9 10 11 |
function imageLoader() { var reader = new FileReader(); reader.onload = function(event) { img = new Image(); img.onload = function(){ ctx.drawImage(img,0,0); } img.src = reader.result; } reader.readAsDataURL(fileInput.files[0]); } |
A word of warning: A peculiar issue exists on Chrome for mobile devices, which causes the page to spontaneoulsy reload when a file is chosen. Discussed in more detail here.
Add some custom text to the canvas
No meme-generator would be complete without being able to add some text. To achieve this, we add a simple text input:
1 |
<input id="custom-text" type="text" value="enter some text" /> |
When this changes, we draw the text onto the canvas. We’ll add this code to the doTransform()
function. The new code is
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// Set the text style to that to which we are accustomed ctx.lineWidth = 5; ctx.font = '20pt sans-serif'; ctx.strokeStyle = 'black'; ctx.fillStyle = 'white'; ctx.textAlign = 'center'; ctx.lineJoin = 'round'; // Draw the text var text = document.getElementById('custom-text').value; text = text.toUpperCase(); x = canvas.width/2; y = canvas.height - canvas.height/4.5; ctx.strokeText(text, x, y); ctx.fillText(text, x, y); |
This will center the text on one line toward the bottom of the image.
Save the canvas image
To save the image online, we convert the canvas to a dataURL using the toDataURL()
function, and then we post this data via AJAX request to a PHP script that decodes the data and writes the image to disk
Download the canvas image
Finally, when we’re done playing with the image and text, we’d like to be able to download it. In the HTML, we’ll add a simple Download link:
1 |
<a id="img-download" download="mobiforge-canvas.png"></a>Download image |
In JavaScript we handle the download when the link is clicked by triggering a function prepareDownload()
. We saw how to convert a canvas to an image in the previous article.
1 2 3 4 5 6 7 |
var download = document.getElementById('img-download'); download.addEventListener('click', prepareDownload, false); function prepareDownload() { var data = canvas.toDataURL(); download.href = data; } |
And that’s it! Happy meme-generating.
Leave a Reply