I came across a situation where I needed to, essentially, take an image and slap it into a canvas element. It turned out to be pretty simple code to accomplish, but I ran into a few sticking points so I thought I would share the code.
The Template
The template is straight forward. An input to select the image, and a canvas element to put the image into.
<template> <div class="journey"> <input type="file" id="imageLoader" @change="updateCanvasImage"/> <canvas id="imageCanvas" ref="imageCanvas"></canvas> </div> </template>
There are two notable things here. First, the @change syntax for handling the onChange event. This will call our updateCanvasImage method any time the image changes. Second, the ref= property on our canvas. We’ll use this in our method to tell the image where it will be written to.
The script
The real meat of this, the script, is fairly straight forward too. The only thing that really tripped me up was in the img.onload function, I was originally trying to call this.$refs.imageCanvas there and was getting the beloved “undefined” error in the console.
After Googling around finding all different explanations for why this wasn’t working, I finally decided to log this to see what was going on in there… which was when I realized this was referencing the event, instead of the Vue instance.
Enter var self = this; . Once I set this and changed from this.$refs to self.$refs , everything worked beautifully. Then I went ahead and cleaned up the code a little more and moved the canvas drawing itself to a separate method.
Below is the final product.
<script> export default { methods: { updateCanvasImage(e) { var self = this; var reader, files = e.target.files; var reader = new FileReader(); reader.onload = (e) => { var img = new Image(); img.onload = function() { self.drawCanvasImage(img) } img.src = event.target.result; }; reader.readAsDataURL(files[0]); }, drawCanvasImage(img) { var canvas = this.$refs.imageCanvas; canvas.width = img.width; canvas.height = img.height; var ctx = canvas.getContext('2d'); ctx.drawImage(img,0,0); } } } </script>