### Summary of Background

It is believed that when you study canvas or use canvas in project development, you should meet the requirement of realizing a writing Sketchpad widget.

Well, I believe it’s only a matter of dozens of lines of code for canvas to use more sophisticated children’s shoes. Here’s a simple example of demo:

```
<!DOCTYPE html>
<html>
<head>
<title>Sketchpad demo</title>
<style type="text/css">
canvas {
border: 1px blue solid;
}
</style>
</head>
<body>
<canvas id="canvas" width="800" height="500"></canvas>
<script type="text/javascript">
let isDown = false;
let beginPoint = null;
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
// Setting Line Colors
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
canvas.addEventListener('mousedown', down, false);
canvas.addEventListener('mousemove', move, false);
canvas.addEventListener('mouseup', up, false);
canvas.addEventListener('mouseout', up, false);
function down(evt) {
isDown = true;
beginPoint = getPos(evt);
}
function move(evt) {
if (!isDown) return;
const endPoint = getPos(evt);
drawLine(beginPoint, endPoint);
beginPoint = endPoint;
}
function up(evt) {
if (!isDown) return;
const endPoint = getPos(evt);
drawLine(beginPoint, endPoint);
beginPoint = null;
isDown = false;
}
function getPos(evt) {
return {
x: evt.clientX,
y: evt.clientY
}
}
function drawLine(beginPoint, endPoint) {
ctx.beginPath();
ctx.moveTo(beginPoint.x, beginPoint.y);
ctx.lineTo(endPoint.x, endPoint.y);
ctx.stroke();
ctx.closePath();
}
</script>
</body>
</html>
```

Its implementation logic is also simple:

- We monitored three major events on the canvas canvas canvas:
`mousedown`

、`mouseup`

and`mousemove`

At the same time, we also created a`isDown`

Variables; - When the user presses the mouse（
`mousedown`

When you start writing, you will`isDown`

Set as`true`

Put down the mouse（`mouseup`

) When you do, set it to ____________`false`

The advantage of this method is that it can judge whether the user is currently in the painting state. - adopt
`mousemove`

Events continuously collect coordinate points of the mouse, if and only if`isDown`

by`true`

Pass the current point through the canvas`lineTo`

The method connects and draws the points in front of it.

Through the above steps we can achieve the basic Sketchpad function, but things are not so simple. Careful children’s shoes may find a very serious problem – the lines drawn in this way are jagged, not smooth enough, and the faster you draw, the stronger the sense of broken lines. As shown in the following figure:

Why?

### problem analysis

The main reasons for this phenomenon are:

- We are based on canvas.
`lineTo`

Method Connecting points, connecting adjacent two points is a straight line, non-curve, so it is a broken line drawn by this way.

- Restricted browser pairs
`mousemove`

The frequency of events is known to all.`mousemove`

The browser collects the coordinates of the current mouse every little time, so the faster the mouse moves, the farther the two adjacent points are collected, so “the more obvious the sense of broken lines”;

### How can we draw a smooth curve?

There are ways to draw a smooth curve.`lineTo`

If you can’t depend on it, we can use another drawing API of canvas.——`quadraticCurveTo `

It is used to draw quadratic Bessel curves.

#### quadratic Bezier curve

`quadraticCurveTo(cp1x, cp1y, x, y)`

call`quadraticCurveTo`

The method requires four parameters.`cp1x`

、`cp1y`

It describes control points, and`x`

、`y`

It is the end of the curve:

More detailed information to move to MDN

Since we are going to use the Bessel curve, it is clear that our data is not enough.**To fully describe a quadratic Bessel curve, we need to: start point, control point and end point.**How do these data come about?

There’s a very clever algorithm that can help us get this information.

#### Algorithms for Obtaining Quadratic Bessel Key Points

This algorithm is not difficult to understand. Let me give you an example.

- Suppose we collected six mouse coordinates in a painting, which are
`A, B, C, D, E, F`

； - Take the front one.
`A, B, C`

Three points, calculate`B`

and`C`

Midpoint`B1`

In order to`A`

As a starting point,`B`

For the control point,`B1`

For the end, use`quadraticCurveTo`

Draw a line segment of quadratic Bessel curve.

- Next, calculate it.
`C`

and`D`

The midpoint of a point`C1`

In order to`B1`

As a starting point,`C`

For control points,`C1`

Continue to draw the curve for the end point.

- Continue drawing by analogy until the last point.
`F`

When`D`

and`E`

Midpoint`D1`

Starting with`E`

For the control point,`F`

End the Bessel curve for the end point.

OK, that’s how the algorithm works. Then we upgrade the existing code based on the algorithm.

```
let isDown = false;
let points = [];
let beginPoint = null;
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
// Setting Line Colors
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
canvas.addEventListener('mousedown', down, false);
canvas.addEventListener('mousemove', move, false);
canvas.addEventListener('mouseup', up, false);
canvas.addEventListener('mouseout', up, false);
function down(evt) {
isDown = true;
const { x, y } = getPos(evt);
points.push({x, y});
beginPoint = {x, y};
}
function move(evt) {
if (!isDown) return;
const { x, y } = getPos(evt);
points.push({x, y});
if (points.length > 3) {
const lastTwoPoints = points.slice(-2);
const controlPoint = lastTwoPoints[0];
const endPoint = {
x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2,
y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2,
}
drawLine(beginPoint, controlPoint, endPoint);
beginPoint = endPoint;
}
}
function up(evt) {
if (!isDown) return;
const { x, y } = getPos(evt);
points.push({x, y});
if (points.length > 3) {
const lastTwoPoints = points.slice(-2);
const controlPoint = lastTwoPoints[0];
const endPoint = lastTwoPoints[1];
drawLine(beginPoint, controlPoint, endPoint);
}
beginPoint = null;
isDown = false;
points = [];
}
function getPos(evt) {
return {
x: evt.clientX,
y: evt.clientY
}
}
function drawLine(beginPoint, controlPoint, endPoint) {
ctx.beginPath();
ctx.moveTo(beginPoint.x, beginPoint.y);
ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y);
ctx.stroke();
ctx.closePath();
}
```

On the original basis, we created a variable.`points`

Prior to storage`mousemove`

According to this algorithm, we can know that it takes at least three points to draw a quadratic Bessel curve, so we only have one point.`points`

Drawing begins when the number of points in the plot is greater than 3. The next step is the same as the algorithm, which will not be discussed here.

After code updates, our curves have become much smoother, as shown in the following figure:

This is the end of this article. I hope you have a good time painting on the canvas drawing board. ~See you next time.

Interested children’s shoes can be stamped here to pay attention to my blog, any fresh and interesting blog will be shared here for the first time.~