马黑PHP整站系统

在canvas画布中绘制二次贝塞尔曲线

位置: 首页 > 代码集锦[ 发布时间: 2024.4.14  作者: 马黑  阅读: 106 ]

二次贝塞尔曲线需要三个点的坐标数据:曲线起始点坐标(x1,y1)、曲线控制点坐标(cpx,cpy)和曲线终点坐标(x2,y2)。在 canvas 画布中,起始点坐标默认使用上一次绘制图形的路径终点坐标,没有路径终点坐标时起始点坐标为(0,0),也可以使用 moveTo(x,y) 指令重新定义。canvas 绘制二次贝塞尔曲线有专门的指令,quadraticCurseTo(cpx, cpy, endX, endY), 其中,cpx 和 cpy 为曲线控制点坐标,endX 和 endY 为曲线终点坐标,曲线起点坐标取上一回路径终点坐标或通过 moveTo(x,y) 指令定义。假设画笔标识为 ctx,我们来绘制一条二次贝塞尔曲线:

ctx.moveTo(50, 100);
ctx.quadraticCurveTo(120, 0, 250, 100);

这表示,曲线从(50,100)出发,到(250,100)停车,曲线的控制点是(120, 10),效果如下示例所示(小圆点用于标识三个点的位置):

影响二次贝塞尔曲线的外观主要是控制点,上例中的小绿点就是控制点。控制点可以在曲线上,若此,绘制出来的将不是曲线而是一条直线;控制点可以为正负数、可以超出画布的范围,不同的数值将直接影响曲线的曲率和最终外观。

单纯使用二次贝塞尔曲线,我们就可以绘制出奇妙的动态图案。以下代码,我们仅来回改变控制点(cpx,cpy)中的cpy值,作出的动态图案十分令人惊艳,它还有无限可能:

<canvas id="canv" width="300" height="200"></canvas>   <script> let ctx = canv.getContext('2d'); let ww = canv.width, hh = canv.height;
/* 全局变量 ctrY :控制点Y坐标 step :控制点Y坐标变化幅度 total :曲线总数 raf :关键帧动画标识 */
let ctrY = hh / 2, step = 0.25, total = 20, raf = null;   //函数 :生成随机rgb颜色 let mkRgba = (opacity=0.5) => { let ar = [256,256,256].map((item) => Math.floor(Math.random() * item)); ar.push( opacity || (.5 + Math.random() * .5).toFixed(1)); return 'rgba(' + ar.join(',') + ')'; }   //创建一个曲线类 class curveLine {     //类构造     constructor(x1, y1, cpx, cpy, x2, y2) {         this.x1 = x1;         this.y1 = y1;         this.cpx = cpx;         this.cpy = cpy;         this.x2 = x2;         this.y2 = y2;         this.color = 'green';         this.lineWidth = 4;     };     //类的绘制行为     draw(ctx) {         ctx.save();         ctx.strokeStyle = this.color;         ctx.lineCap = 'round';         ctx.lineWidth = this.lineWidth;         ctx.beginPath();         ctx.moveTo(this.x1, this.y1);         ctx.quadraticCurveTo(this.cpx, this.cpy, this.x2, this.y2);         ctx.stroke();         ctx.closePath();         ctx.restore();     }; };   //批量绘制曲线 let draw = () => {     ctx.clearRect(0, 0, ww, hh);     let add = ww - 20;     for(let i = 0; i < total; i ++) {         let cl = new curveLine(); //创建曲线类实例         cl.x1 = ww / 2;         cl.y1 = hh - 5;         cl.cpx = (ww + add) / total * i - add / 2 + 5;         cl.cpy = ctrY;         cl.x2 = ww / 2;         cl.y2 = 5;         cl.color = mkRgba(0.7);         cl.lineWidth = 4;         cl.draw(ctx);        } };   //渲染效果 let render = () => {     ctrY += step;     if(ctrY > hh || ctrY < 0) step = -step;     draw();     raf = requestAnimationFrame(render); //调用关键帧动画接口 };   render();   //画布单击事件 :暂停或启用动画 canv.onclick = () => {     raf = raf ? cancelAnimationFrame(raf) : requestAnimationFrame(render); }; </script>

以上代码,可以保存为本地 .html 文档或将代码拿到 pencil code 运行以查看效果,提醒一下,动画是可以暂停和继续运行的,方法是单击画布。

前一篇: canvas画布中小球碰撞简单处理
下一篇: 在canvas画布中绘制三次贝塞尔曲线

发表评论:

       

评论列表 [2条]

#2 | 马黑 于 2024-4-14 17:56 发布: 小球使用 fill() 方法填充颜色,如果只画一个小球,填充前定义 ctx.fillStyle 就可以了。不同的代码环境,设置的位置不同,你找找哪里用上了随机十六进制颜色,用 mkRgba(0.5) 之类的替代 `井${Math.random()....}` 就好。

#1 | 了了 于 2024-4-14 17:48 发布: 这个也太好看了吧。有时候像钻石,有时候像灯笼。每条线的颜色都在不停的变幻~。mkRgba(0.7)看到透明度设置了。。但是这个透明度怎么用到小球里面还不知道。。

Copyright © 2023 All Right Reserved 马黑PHP文章管理整站系统v1.8
联系我们: gxblk@163.com