Home >Web Front-end >H5 Tutorial >How to draw smooth curves using canvas? (code)

How to draw smooth curves using canvas? (code)

不言
不言forward
2018-10-15 13:55:214352browse

The content of this article is about how to use canvas to draw smooth curves? (code). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

Background Summary

I believe that everyone should have encountered such a need when learning canvas or using canvas in project development: to implement a small drawing board that can be written tool.

Well, I believe that for children who are more familiar with canvas, this can be done with just a few dozen lines of code. The following demo is a simple example:

nbsp;html>


    <title>Sketchpad demo</title>
    <style>
        canvas {
            border: 1px blue solid; 
        }
    </style>


    <canvas></canvas>
    <script>
        let isDown = false;
        let beginPoint = null;
        const canvas = document.querySelector(&#39;#canvas&#39;);
        const ctx = canvas.getContext(&#39;2d&#39;);

        // 设置线条颜色
        ctx.strokeStyle = &#39;red&#39;;
        ctx.lineWidth = 1;
        ctx.lineJoin = &#39;round&#39;;
        ctx.lineCap = &#39;round&#39;;

        canvas.addEventListener(&#39;mousedown&#39;, down, false);
        canvas.addEventListener(&#39;mousemove&#39;, move, false);
        canvas.addEventListener(&#39;mouseup&#39;, up, false);
        canvas.addEventListener(&#39;mouseout&#39;, 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>

Its implementation logic is also very simple:

  1. We mainly listen to three events on the canvas canvas: mousedown, mouseup and mousemove, and we also create an isDown variable;

  2. When the user presses the mouse (mousedown), set isDown to true, and when the user puts down the mouse (mouseup), set it to false. The advantage of this is It can be judged whether the user is currently in the drawing state;

  3. Continuously collects the coordinate points that the mouse passes through through the mousemove event. If and only if isDown is true (that is, in the writing state), it will The current point is connected and drawn with the previous point through the lineTo method of canvas;

Through the above steps, we can realize the basic drawing board function, but things don’t work. It's not that simple. Careful children's shoes may find a very serious problem - the lines drawn in this way are jagged and not smooth enough, and the faster you draw, the stronger the sense of folding. The performance is as shown in the figure below:

How to draw smooth curves using canvas? (code)

# Why is this happening?

Problem Analysis

The main reason for this phenomenon is:

  • We use the lineTo method of canvas to connect the points , connecting two adjacent points is a straight line, not a curve, so what is drawn in this way is a polyline;

    How to draw smooth curves using canvas? (code)

  • ##Limited by the browser's collection frequency of mousemove events, everyone knows that during mousemove, the browser collects the coordinates of the current mouse every short period of time, so the faster the mouse moves , the farther the distance between the two adjacent points collected, the more obvious the "broken line feeling";


How can we draw a smooth curve?

There are actually ways to draw smooth curves. If lineTo is unreliable, we can use another drawing API of canvas - quadraticCurveTo, which is used to draw quadratic Bezier curves.

Quadratic Bezier Curve

quadraticCurveTo(cp1x, cp1y, x, y)

Calling the quadraticCurveTo method requires four parameters. cp1x and cp1y describe the control points , and x and y are the end points of the curve:

How to draw smooth curves using canvas? (code)

More detailed information can be found on MDN

Since you want to use Bezier curve, obviously our data is not enough.

To completely describe a quadratic Bezier curve, we need: starting point, control point and end point, how do these data come from?

There is a very clever algorithm that can help us obtain this information

Algorithm for obtaining quadratic Bezier key points

This algorithm is not difficult to understand, here I will directly Let’s give an example:

  1. Suppose we collect a total of 6 mouse coordinates in a painting, namely A, B, C, D, E, F;


  2. Take the previous three points A, B, and C, calculate the midpoint B1 between B and C, take A as the starting point, B as the control point, and B1 as the end point, and use quadraticCurveTo to draw a quadratic shell Searle curve segment;


    How to draw smooth curves using canvas? (code)

  3. ##Next, calculate the center of points C and D Point C1, continue to draw the curve with B1 as the starting point, C as the control point, and C1 as the end point;

  4. How to draw smooth curves using canvas? (code)

    ##The drawing continues by analogy. When it reaches the last point F, the Bezier curve ends with D1, the midpoint of D and E, as the starting point, E as the control point, and F as the end point.

  5. How to draw smooth curves using canvas? (code)

OK,算法就是这样,那我们基于该算法再对现有代码进行一次升级改造:

let isDown = false;
let points = [];
let beginPoint = null;
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');

// 设置线条颜色
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();
}

在原有的基础上,我们创建了一个变量points用于保存之前mousemove事件中鼠标经过的点,根据该算法可知要绘制二次贝塞尔曲线起码需要3个点以上,因此我们只有在points中的点数大于3时才开始绘制。接下来的处理就跟该算法一毛一样了,这里不再赘述。

代码更新后我们的曲线也变得平滑了许多,如下图所示:

How to draw smooth curves using canvas? (code)

本文到这里就结束了,希望大家在canvas画板中“画”得愉快~我们下次再见:)


The above is the detailed content of How to draw smooth curves using canvas? (code). For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:segmentfault.com. If there is any infringement, please contact admin@php.cn delete