Build A Drawing App with Vuejs and Html5 Canvas
In this tutorial, we will be building a simple drawing app with Vuejs and Html5 Canvas.
Basically the HTML <canvas>
element is used to draw graphics on a web page. Vuejs is a progressive Javascript framework for building user interfaces.
Here’s the demo of our app!
Prerequisites
- Familiarity with HTML, CSS, and JavaScript (ES6+).
- Vs code or any code editor installed on your development machine.
- Basic knowledge of vuejs
Before we kick off
Learn Vue.js and modern, cutting-edge front-end technologies from core-team members and industry experts with our premium tutorials and video courses on VueSchool.io.
Building the file structure
Let’s start by creating a file structure for the application. We will basically need just 3 files:index.html
,main.css
and app.js
file(s).To create this files open up the terminal and type the following code:
cd desktop
mkdir drawing-app && cd drawing-app
touch index.html && touch app.js && main.css
After creating these files, lets setup our index.html file and bring in vue into the project. Let’s define a simple boilerplate and then link the CSS stylesheet and the javascript to the index.html file and also initialize vue by adding the vue development CDN. Open up the terminal and add the following code to your index.html
file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Drawing App</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<div id="app">
<h1>{{ message }}</h1>
<canvas id="canvas"></canvas>
</div>
https://cdn.jsdelivr.net/npm/vue/dist/vue.js
http://app.js
</body>
</html>
And then to set up vue, let’s also add the following to the app.js
file. We start by storing the vue instance in a variable app then we define the root div.:
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
in our main.css
file lets add borders to the canvas:
html body {
padding: 0px;
margin: 0px;
}
#canvas {
border: 3px solid black;
height: 100px;
width: 100px
}
We can run our application by using live-server
.If you don’t have live-server installed on you local machine, then install it by running npm i live-server -g
.The -g flag will install the package globally in our local machine. After installing it, you can now move into your development project using the terminal by using the cd
command followed by the location of your application. To run our application using live-server open up the terminal and run the following commands:
cd desktop
cd drawing-app && live-server --port=4040
This will open up our application on a live-server running on port 4040.
Let’s continue building our application.
Let’s continue by defining the canvas instance in the mounted life cycle hook in our app.js:
mounted() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
this.vueCanvas = ctx;
}
And then add vueCanvas
in our data property:
data: {
message: 'Hello Vue!',
vueCanvas:null
},
Now we want to programmatically define the width and height of our canvas. So to do that we will leverage on window.innerHeight
and window.innerWidth
.Let’s add the codes in the mounted life cycle hook:
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
Drawing basic shapes
Drawing a Simple Square
Let see how to draw simple shapes using canvas.Let’s start by drawing a simple square shape. There are a lot of properties that we could use with the ctx
instance that we defined earlier. To draw a simple square shape we will use the fillRect
property which takes in four parameters. The first parameter will be the X position
, the second parameter is the Y position
,the third parameter will be the width
of the shape and the forth parameter will be the height
of the shape. For e.g ctx.fillRect(x,y,width,height);
ctx.fillRect(100,100,300,300)
This means that the shape will take the position of 100 at the X axis
, 100 at y axis
and will take 300 for the height and then 300 for the width of the shape. By default, the shape will come with a black background. To have a transparent background you could use the strokeRect
property. You could change the color by setting strokeStyle
to any color of your choice.
Note that the strokeStyle
should always be above the shape you are trying to style. Meaning that it should always take this format:
ctx.strokeStyle = "red"
ctx.strokeRect(100,100,300,300)
And not this:
ctx.strokeRect(100,100,300,300)
ctx.strokeStyle = "red"
Drawing A Simple Triangle
To draw a simple triangle, we will use the beginPath
property. The ctx.beginPath
property is called before beginning each line. Then the next thing is to use the ctx.moveTo
property. The moveTo
property begins a new sub-path at the point specified. This actually means that we have to specify the x and y parameter. So picture this as picking up your pen and placing it on a notebook without writing:
ctx.moveTo(x, y);
Now to actually draw a line we will use the lineTo property which adds a straight line to the current sub-path by connecting the sub-paths last point to the specified (x, y)
coordinates which is passed as a parameter.
ctx.lineTo(200,100)
This method does not directly render anything until you use the stroke property.
ctx.stroke()
With this, we just drew a straight line. To add a vertical line at the end of the line we just drew we will add :
ctx.lineTo(200,150)
Now to join the lines together will use the closePath
property.
The code for drawing a triangle will look like this:
ctx.beginPath();
ctx.moveTo(100,100)
ctx.lineTo(200,100)
ctx.lineTo(200,150)
ctx.closePath()
ctx.stroke()
Implementing the Drawing App
Let’s start writing functions for the drawing app. The first thing we will do it to define a variable painting and then set it to false. This is to take note of if we are drawing or not. We will define that in the data property:
painting:false
After doing this let’s define some functions in the methods object that will mutate the value of painting:
methods: {
startPainting() {
this.painting = true;
console.log(this.painting)
},
finishedPainting() {
this.painting = false;
console.log(this.painting)
}
},
Now we want a situation when the mouse is down we set the value of painting to true and when the mouse is up we then set the value of painting to false. So we add event listeners to the canvas tag in the index.html
file:
<canvas @mousedown="startPainting" @mouseup="finishedPainting" id="canvas"></canvas>
Ensure you test that this is working by opening up the console and then press the button on your mouse, doing this will output true on the console and when you leave the button it will output false on the console.
Now, will add an event listener on the canvas to listen to when the mouse is moving. Let’s define another method called paint. This is where we will implement the actual painting.
<canvas @mousedown="startPainting" @mouseup="finishedPainting" @mousemove="draw" id="canvas"></canvas>
and define the paint method in the methods object:
draw(e) {
console.log("Hello...Event is Working")
}
Now move your mouse around on the canvas and then you will notice that Hello…The event is Working is logged on the console…this means that the event listener is working.
Let’s start by writing a condition that if we aren’t holding down the mouse the function shouldn’t be called:
draw(e) {
if(!this.painting) return
console.log("Hello...Event is Working")
}
This is to ensure that the user is actually holding down the mouse.
Now let’s make the canvas and ctx variable global so that we can access it from anywhere. Let’s define canvas and ctx in the data object and set it to null.
canvas:null,
ctx:null
Now instead of using var canvas
and var ctx
in the mounted life cycle hook we will be using this.canvas
and this.ctx
.
this.canvas = document.getElementById("canvas");
this.ctx = canvas.getContext("2d");
// Resize canvas
this.canvas.height = window.innerHeight;
this.canvas.width = window.innerWidth;
After doing this, lets set up some styles to our pen.By adding some lineWidth
,lineCap
:
draw(e) {
if(!this.painting) return
this.ctx.lineWidth = 10;
this.ctx.lineCap ="round"
}
Now we will use the lineTo method to start drawing the line. Recall the lineTo
property adds a straight line to the current sub-path by connecting the sub-paths last point to the specified (x, y)
coordinates.We can use the e.clientX
for the X-axis
and e.clientY
for the Y-axis
. And also recall that this won’t work until we add the stroke property.
So now our draw method will now be:
draw(e) {
if(!this.painting) return
this.ctx.lineWidth = 10;
this.ctx.lineCap ="round"
this.ctx.lineTo(e.clientX,e.clientY)
this.ctx.stroke()
// console.log(e.clientX); // x coordinate
// console.log(e. clientY); // y coordinate
}
Yea….we just built our paint app…But there is still an issue…
After drawing and our mouse is lifted, and then we want to continue drawing, it continues from where we stopped…which isn’t supposed to be so.
so we need to add some more codes the draw function:
draw(e) {
if(!this.painting) return
this.ctx.lineWidth = 10;
this.ctx.lineCap ="round"
this.ctx.lineTo(e.clientX,e.clientY)
this.ctx.stroke()
this.ctx.beginPath()
this.ctx.moveTo(e.clientX,e.clientY)
}
And then we will also modify the finishedPainting
method to:
finishedPainting() {
this.painting = false;
console.log(this.painting);
this.ctx.beginPath()
},
And also modify the startPainting
method to :
startPainting(e) {
this.painting = true;
console.log(this.painting)
this.draw(e)
},
And that’s basically it..we fixed the problem. We just used the canvas api to build a simple painting app.
Conclusion
We have seen how simple it is to build a simple application with the canvas API and vuejs. We also learned how to use some mouse event listeners in vuejs.
We could build more applications using the canvas API or we could add more features to the application like changing of the pen color or even changing the canvas background color. Click here for source code.