Canvas 画贝塞尔曲线(二阶曲线和三阶曲线)

分类:Javascript     发布:2020-01-06     来源:本站     浏览:352 次
在线预览:
二阶:http://qingshanboke.com/demo/quadratic.htm
三阶:http://qingshanboke.com/demo/bezier.htm

一、实现思路:
1.用两个canvas实现,一个绘制曲线,一个绘制运动圆点。
2.绘制曲线:可以通过canvas提供的API方法绘制。
二阶:quadraticCurveTo(controlX, controlY, endingPointX, endingPointY) 1个控制点。
三阶:bezierCurveTo(controlX1, controlY1, controlX2, controlY2, endPointX, endPointY),2个控制点。
3.绘制圆点:根据贝塞尔曲线公式,计算出不同时刻圆点坐标,然后绘制到canvas上。

二、实现过程:
1.二阶曲线:
核心公式:
实现代码:
<html>
<title>二阶贝塞尔曲线</title>
<style type="text/css">
    body {
        background: black;
    }
    
    #canvas {
        position: absolute;
        top: 0;
        left: 0;
        width: 600px;
        height: 600px;
    }
    
    #line {
        position: absolute;
        top: 0;
        left: 0;
        width: 600px;
        height: 600px;
    }
</style>
 
<body>
    <canvas id="canvas" width="600" height="600"></canvas>
    <canvas id="line" width="600" height="600"></canvas>
    <script type="text/javascript">
        var point = {
            begin: {
                x: 20,
                y: 20
            },
            control: {
                x: 40,
                y: 400
            },
            end: {
                x: 600,
                y: 600
            },
        };
 
        function drawline() {
            let canvas = document.getElementById("canvas");
            let ctx = canvas.getContext("2d");
            ctx.beginPath();
 
            ctx.moveTo(point.begin.x, point.begin.y);
            ctx.quadraticCurveTo(point.control.x, point.control.y, point.end.x, point.end.y);
 
            ctx.strokeStyle = "#2578b0";
            ctx.lineWidth = 2;
            ctx.stroke();
 
        }
        drawline();
 
        let t = 0;
 
        function drawPoint() {
            //根据二次贝塞尔曲线的公式,获取某时刻t[0-1]的贝塞尔曲线上的点            
            let x = Math.pow((1 - t), 2) * point.begin.x + 2 * t * (1 - t) * point.control.x + Math.pow(t, 2) * point.end.x;
            let y = Math.pow((1 - t), 2) * point.begin.y + 2 * t * (1 - t) * point.control.y + Math.pow(t, 2) * point.end.y;
 
            //移出画布后,重新开始
            if (x > 600) {
                t = 0;
                x = point.begin.x;
                y = point.begin.y;
            }
 
            let canvas = document.getElementById("line");
            let ctx = canvas.getContext("2d");
 
            //清除上一次的点
            ctx.clearRect(0, 0, 600, 600);
            ctx.beginPath();
 
            //画小圆点
            ctx.moveTo(point.begin.x, point.begin.y);
            ctx.arc(x, y, 4, 0, 2 * Math.PI, false);
            ctx.fillStyle = "white";
            ctx.fill();
 
            //显示坐标
            ctx.font = 'bold 12px Arial';
            ctx.textAlign = 'left';
            ctx.textBaseline = 'bottom';
            ctx.fillStyle = 'white';
            ctx.fillText("x:" + parseInt(x), x, y - 24);
            ctx.fillText("y:" + parseInt(y), x, y - 12);
            ctx.closePath();
            t += 0.006;
        }
 
        setInterval(drawPoint, 60);
    </script>
</body> 
</html> 


2.三阶曲线:
核心公式:
实现代码:
<html>
<title>三阶贝塞尔曲线</title>
<style type="text/css">
    body {
        background: black;
    }
    
    #canvas {
        position: absolute;
        top: 0;
        left: 0;
        width: 600px;
        height: 600px;
    }
    
    #line {
        position: absolute;
        top: 0;
        left: 0;
        width: 600px;
        height: 600px;
    }
</style>
 
<body>
    <canvas id="canvas" width="600" height="600"></canvas>
    <canvas id="line" width="600" height="600"></canvas>
    <script type="text/javascript">
        var point = {
            begin: {
                x: 0,
                y: 600
            },
            control1: {
                x: 500,
                y: 500
            },
            control2: {
                x: 400,
                y: 40
            },
            end: {
                x: 600,
                y: 0
            },
        };
 
        function drawline() {
            let canvas = document.getElementById("canvas");
            let ctx = canvas.getContext("2d");
            ctx.beginPath();
 
            ctx.moveTo(point.begin.x, point.begin.y);
            ctx.bezierCurveTo(point.control1.x, point.control1.y, point.control2.x, point.control2.y, point.end.x, point.end.y);
            ctx.strokeStyle = "#2578b0";
            ctx.lineWidth = 2;
            ctx.stroke();
 
        }
        drawline();
 
        let t = 0;
 
        function drawPoint() {
            //根据三次贝塞尔曲线的公式,获取某时刻t[0-1]的贝塞尔曲线上的点            
            let x = point.begin.x * Math.pow((1 - t), 3) + 3 * t * point.control1.x * Math.pow((1 - t), 2) + 3 * point.control2.x * Math.pow(t, 2) * (1 - t) + point.end.x * Math.pow(t, 3);
            let y = point.begin.y * Math.pow((1 - t), 3) + 3 * t * point.control1.y * Math.pow((1 - t), 2) + 3 * point.control2.y * Math.pow(t, 2) * (1 - t) + point.end.y * Math.pow(t, 3);
 
            //移出画布后,重新开始
            if (x > 600) {
                t = 0;
                x = point.begin.x;
                y = point.begin.y;
            }
 
            let canvas = document.getElementById("line");
            let ctx = canvas.getContext("2d");
 
            //清除上一次的点
            ctx.clearRect(0, 0, 600, 600);
            ctx.beginPath();
 
            //画小圆点
            ctx.moveTo(point.begin.x, point.begin.y);
            ctx.arc(x, y, 4, 0, 2 * Math.PI, false);
            ctx.fillStyle = "white";
            ctx.fill();
 
            //显示坐标
            ctx.font = 'bold 12px Arial';
            ctx.textAlign = 'left';
            ctx.textBaseline = 'bottom';
            ctx.fillStyle = 'white';
            ctx.fillText("x:" + parseInt(x), x, y - 24);
            ctx.fillText("y:" + parseInt(y), x, y - 12);
            ctx.closePath();
            t += 0.006;
        }
 
        setInterval(drawPoint, 60);
    </script>
</body>
 
</html>

在线预览:http://qingshanboke.com/demo/bezier.htm

 

参考资料:
https://www.w3school.com.cn/tags/canvas_quadraticcurveto.asp
https://www.w3school.com.cn/tags/canvas_beziercurveto.asp
https://baike.baidu.com/item/%E8%B4%9D%E5%A1%9E%E5%B0%94%E6%9B%B2%E7%BA%BF/1091769?fr=aladdin
https://blog.csdn.net/ixygj197875/article/details/80043658

如果觉得文章对您有帮助,您可以对我进行打赏 ¥1.71 元(金额随机^_^,每次刷新金额不同)。

请使用支付宝扫码支付

留言评论

*称  呼:
*联系方式: 方便与您取得联系,推荐使用邮箱。
*内  容:

已有评论

勿忘初心 2020-01-08 00:32:05
三阶,能不能算出 t值兄台
t是取0-1之间的值,变化量 2020-01-30 17:14:52

上一篇:Android 自定义Radiobutton样式

下一篇:没有了