How to use HTML Canvas with Vue
Tags: vue, tutorial, beginners
Published: 2020-05-01 13:26:23

HTML 5's Canvas API is an amazing tool for creating graphics on a page. From drawing basic shapes and animation to data visualization and on-the-fly video processing, Canvas API turns your dreams to reality using JavaScript. Let's learn how to integrate it with Vue. 

### :unicorn: What we're building :unicorn:
![4_mousedown_mouseup](https://dev-to-uploads.s3.amazonaws.com/i/pcuiqdtqidyfdoalp5hs.gif)

### 1. Create a canvas
Start off by creating a canvas in your DOM. Let's add a little CSS to keep the canvas' boundaries visible.
```vue
<template>
  <div id="app">
    <h1>Drawing with mousemove event</h1>
    <canvas id="myCanvas" width="560" height="360" />
  </div>
</template>

<style>
#myCanvas {
  border: 1px solid grey;
}
</style>
```
Instantiate a Vue class and hook it up to you DOM.
```javascript
new Vue({
  el: '#app'
})
```
![1_setup_canvas](https://dev-to-uploads.s3.amazonaws.com/i/a4b187fq28y0yrcrihb5.png)

The trick to managing the canvas is by making it accessible to Vue by declaring a state and passing it the canvas' 2d context. We just need to make sure to do this after Vue and DOM have finished initialization. Enter `mounted()` lifecycle hook.
```javascript
new Vue({
  el: '#app',
  data: {
    canvas: null,
  },
  mounted() {
    var c = document.getElementById("myCanvas");
    this.canvas = c.getContext('2d');
  }
})
```
### 2. Reading mouse coordinates from `mousemove`
Using the `mousemove` event, we can identify the exact location of the cursor in the screen. Create an event handler called `showCoordinates` and pass it to the corresponding Vue directive.

The event handler will read the x- and y-coordinates from the **MouseEvent** interface. Use the properties `offsetX` and `offsetY` to take into consideration the (x,y) offset from the edge of the canvas. Make sure not to confuse these with `clientX` and `clientY` because they start from the top left corner of the visible screen.

```vue
<template>
  <div id="app">
    <span>{{x}}, {{y}}</span>
    <h1>Drawing with mousemove event</h1>
    <canvas id="myCanvas" width="560" height="360" @mousemove="showCoordinates"/>
  </div>
</template>
```
```javascript
new Vue({
  // ...
  data: {
    canvas: null,
    x: 0,
    y: 0
  },
  methods: {
    showCoordinates(e) {
      this.x = e.offsetX;
      this.y = e.offsetY;
    }
  },
  // ...
})
```
![2_reading_coordinates](https://dev-to-uploads.s3.amazonaws.com/i/o3jma45ffn70l8w1u5vi.gif)

### 3. Draw!
So far, so good. Knowing the exact coordinates of the cursor helps us determine where to draw on the canvas. Let's create a new function to draw a line and rename `showCoordinates` to `draw`. Inside `draw`, call the function to draw a line.
```javascript
new Vue({
  // ...
  methods: {
    // ...
    drawLine(x1, y1, x2, y2) {
      let ctx = this.canvas;
      ctx.beginPath();
      ctx.strokeStyle = 'black';
      ctx.lineWidth = 1;
      ctx.moveTo(x1, y1);
      ctx.lineTo(x2, y2);
      ctx.stroke();
      ctx.closePath();
    },
    draw(e) {
      this.drawLine(this.x, this.y, e.offsetX, e.offsetY);
      this.x = e.offsetX;
      this.y = e.offsetY;
    }
  },
  // ...
})
```
Don't forget to update the Vue directive `mousemove` to use `draw`: `<canvas id="myCanvas" width="560" height="360" @mousemove="draw"/>`

![3_mousemove_draw](https://dev-to-uploads.s3.amazonaws.com/i/w0gr13nh2y84qv2no95q.gif)

Now we're getting somewhere! While your cursor is within the canvas boundaries, Vue keeps creating a line from old x- and y-coordinates to the next location.

But did you notice the ugly line from the top left corner? That's because we set the default (x,y) coordinates to be (0,0). We want to fix it but not by modifying the default coordinates. Instead, we need to tell Vue when to start and stop drawing. Just like how a pen shouldn't be able to transfer ink to paper just by hovering, the mouse shouldn't be able to draw just by moving over the canvas.

### 4. `mousedown`, `mouseup`
Create a new state called `isDrawing` and set the default value to false. Then define two methods to handle `mousedown` and `mouseup` events. Update `draw` to use the `isDrawing` flag. It looks like we added a lot of stuff but we're simply telling Vue to draw if and only if the left mouse button is pressed.
```javascript
new Vue({
  // ...
  data: {
    canvas: null,
    x: 0,
    y: 0,
    isDrawing: false
  },
  methods: {
    // ...
    draw(e) {
      if(this.isDrawing) {
        this.drawLine(this.x, this.y, e.offsetX, e.offsetY);
        this.x = e.offsetX;
        this.y = e.offsetY;
      }
    },
    beginDrawing(e) {
      this.x = e.offsetX;
      this.y = e.offsetY;
      this.isDrawing = true;
    },
    stopDrawing(e) {
      if (this.isDrawing) {
        this.drawLine(this.x, this.y, e.offsetX, e.offsetY);
        this.x = 0;
        this.y = 0;
        this.isDrawing = false;
      }
    }
  },
  // ...
})
```
Pass the new functions to the appropriate Vue directives: `<canvas id="myCanvas" width="560" height="360" @mousemove="draw" @mousedown="beginDrawing" @mouseup="stopDrawing" />`. Then remove the coordinates from the dom to finish your project!

[Clik here for the complete code.](https://codepen.io/reiallenramos/pen/MWaEmpw)