canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器)


Posted in HTML / CSS onJanuary 10, 2018

写在最前

由于原生的Canvas最高只支持到三阶贝塞尔曲线,那么我想添加多个控制点怎么办呢?(即便大部分复杂曲线都可以用3阶贝塞尔来模拟)与此同时,关于贝塞尔控制点的位置我们很难非常直观的清楚到底将控制点设置为多少可以形成我们想要的曲线。本着解决以上两个痛点同时社区内好像并没有N阶的解决方案(js版)故这次作者非常认真的开源了bezierMaker.js!

bezierMaker.js理论上支持N阶贝塞尔曲线的生成,同时提供了试验场供开发者可以自行添加并拖拽控制点最终生成一组绘制动画。非常直观的让开发者知道不同位置的控制点所对应的不同生成曲线。

如果你喜欢这个作品欢迎Star,毕竟star来之不易。。

项目地址:这里✨✨✨

为什么需要一个试验场?

在绘制复杂的高阶贝塞尔曲线时无法知道自己需要的曲线的控制点的精确位置。在试验场中进行模拟,可以实时得到控制点的坐标值,将得到的点坐标变为对象数组传递进BezierMaker类就可以生成目标曲线

效果图

canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器) 
 

canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器)

功能

  1. [x] 试验场可添加任意数量控制点
  2. [x] 试验场支持展示曲线绘制的形成动画
  3. [x] 控制点可自由拖拽
  4. [x] 支持显示贝塞尔曲线形成过程的切线
  5. [x] 3阶及以下贝塞尔曲线的绘制采用原生API

引入

<script src="./bezierMaker.js"></script>

绘制

上面的效果图为试验场的使用,当你通过试验场获得控制点的准确坐标之后,就可以调用bezierMaker.js进行曲线的直接绘制。

/**
 * canvas canvas的dom对象
 * bezierCtrlNodesArr 控制点数组,包含x,y坐标
 * color 曲线颜色
 */
var canvas = document.getElementById('canvas')
//3阶之前采用原生方法实现
var arr0 = [{x:70,y:25},{x:24,y:51}]
var arr1 = [{x:233,y:225},{x:170,y:279},{x:240,y:51}]
var arr2 = [{x:23,y:225},{x:70,y:79},{x:40,y:51},{x:300, y:44}]
var arr3 = [{x:333,y:15},{x:70,y:79},{x:40,y:551},{x:170,y:279},{x:17,y:239}]
var arr4 = [{x:53,y:85},{x:170,y:279},{x:240,y:551},{x:70,y:79},{x:40,y:551},{x:170,y:279}]
var bezier0 = new BezierMaker(canvas, arr0, 'black')
var bezier1 = new BezierMaker(canvas, arr1, 'red')
var bezier2 = new BezierMaker(canvas, arr2, 'blue')
var bezier3 = new BezierMaker(canvas, arr3, 'yellow')
var bezier4 = new BezierMaker(canvas, arr4, 'green')
bezier0.drawBezier()
bezier1.drawBezier()
bezier2.drawBezier()
bezier3.drawBezier()
bezier4.drawBezier()

绘制结果

canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器)

当控制点少于3个时,会适配使用原生的API接口。当控制点多于2个后,由我们自己实现的函数进行描点绘制。

核心原理

绘制贝塞尔曲线

绘制贝塞尔曲线的核心点在于贝塞尔公式的运用:
 

canvas实现高阶贝塞尔曲线(N阶贝塞尔曲线生成器) 
 

这个公式中的P0-Pn代表了从起点到各个控制点再到终点的各点与占比t的各种幂运算。

BezierMaker.prototype.bezier = function(t) { //贝塞尔公式调用
    var x = 0,
        y = 0,
        bezierCtrlNodesArr = this.bezierCtrlNodesArr,
        //控制点数组
        n = bezierCtrlNodesArr.length - 1,
        self = this
    bezierCtrlNodesArr.forEach(function(item, index) {
        if(!index) {
            x += item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) 
            y += item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) 
        } else {
        //factorial为阶乘函数
            x += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) 
            y += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) 
        }
    })
    return {
        x: x,
        y: y
    }
}

对所有点进行遍历同时根据当前占比t的值(0<=t<=1),计算出当前在贝塞尔曲线上的点坐标x,y。t的取值作者分成了1000份,即每次运算t+=0.01。此时算出的x,y即所求的贝塞尔曲线分成了1000份之后的某一点。当t值从0~1遍历1000次后生成1000个x,y对应坐标,依次描点画线即可模拟出高阶贝塞尔曲线。

对于贝塞尔公式的推导作者会在之后的文章中专门说明,现在你只需要知道我们通过贝塞尔公式计算出实际贝塞尔曲线被等分成了1000份的各点,用直线连接各点后即可模拟出类曲线。

对于模拟场贝塞尔曲线生成动画的实现

这个部分相关代码可以参考这里

整体思路是用递归的方式来将每个一层控制点当做1阶贝塞尔函数来计算下一层控制点并对应连线。具体逻辑作者会留到深入讲解贝塞尔曲线公式原理的时候一起梳理一下试验场的动画生成原理~

小结

作者一直想开源一些东西(但是菜,也没啥能写的),然而平时会用到的都被人写了,再造轮子也没别人写得好。这次也算是发现了一个貌似空白一些的区域。所以非常郑重的决定开源。贝塞尔的高级运用在gayhub中大多是安卓的实现,前端领域中还有很多地方可以更多的展开,欢迎讨论~ 多多批评!

最后

项目地址:这里✨✨

试验场地址:一定进来玩✨✨✨

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
CSS3实现精美横向滚动菜单按钮
Apr 14 HTML / CSS
纯CSS3实现给头像加个光芒四射且旋转的背景动画效果
May 07 HTML / CSS
CSS3属性background-size使用指南
Dec 09 HTML / CSS
CSS3的column-fill属性对齐列内容高度的用法详解
Jul 01 HTML / CSS
html5 canvas 画图教程案例分析
Nov 23 HTML / CSS
仿酷狗html5手机音乐播放器主要部分代码
May 15 HTML / CSS
HTML5语音识别标签写法附图
Nov 18 HTML / CSS
用HTML5实现鼠标滚轮事件放大缩小图片的功能
Jun 25 HTML / CSS
解析HTML5的存储功能和web SQL的相关操作方法
Feb 19 HTML / CSS
HTML5 Canvas玩转酷炫大波浪进度图效果实例(附demo)
Dec 14 HTML / CSS
浅析canvas元素的html尺寸和css尺寸对元素视觉的影响
Jul 22 HTML / CSS
详解CSS不定宽溢出文本适配滚动
May 24 HTML / CSS
H5混合开发app如何升级的方法
Jan 10 #HTML / CSS
浅谈关于html5中图片抛物线运动的一些心得
Jan 09 #HTML / CSS
详解快速开发基于 HTML5 网络拓扑图应用
Jan 08 #HTML / CSS
浅谈HTML5 Web Worker的使用
Jan 05 #HTML / CSS
详解基于canvas的视频遮罩插件
Jan 04 #HTML / CSS
详解HTML5中的picture元素响应式处理图片
Jan 03 #HTML / CSS
canvas 阴影和图形变换的示例代码
Jan 02 #HTML / CSS
You might like
php+mysqli实现将数据库中一张表信息打印到表格里的方法
2015/01/28 PHP
php实现上传图片保存到数据库的方法
2015/02/11 PHP
PHP数组操作类实例
2015/07/11 PHP
无需数据库在线投票调查php代码
2016/07/20 PHP
PHP使用curl_multi_select解决curl_multi网页假死问题的方法
2018/08/15 PHP
JS实多级联动下拉菜单类,简单实现省市区联动菜单!
2007/05/03 Javascript
JS小框架 fly javascript framework
2009/11/26 Javascript
JavaScript 学习笔记(六)
2009/12/31 Javascript
js模拟点击事件实现代码
2012/11/06 Javascript
IE6浏览器下resize事件被执行了多次解决方法
2012/12/11 Javascript
兼容IE和FF的图片上传前预览js代码
2013/05/28 Javascript
jquery实现两个图片渐变切换效果的方法
2015/06/25 Javascript
Bootstrap每天必学之缩略图与警示窗
2015/11/29 Javascript
论JavaScript模块化编程
2016/03/07 Javascript
js基于myFocus实现轮播图效果
2017/02/14 Javascript
使用JavaScript实现alert的实例代码
2017/07/06 Javascript
fetch 使用及如何接收JS传值
2017/11/11 Javascript
element-ui table span-method(行合并)的实现代码
2018/12/20 Javascript
关于ES6尾调用优化的使用
2020/09/11 Javascript
解决Vue-cli无法编译es6的问题
2020/10/30 Javascript
[01:00:14]2018DOTA2亚洲邀请赛 4.6 淘汰赛 VP vs TNC 第三场
2018/04/10 DOTA
python监控网卡流量并使用graphite绘图的示例
2014/04/27 Python
Python Web框架Flask中使用百度云存储BCS实例
2015/02/08 Python
Windows下安装Django框架的方法简明教程
2018/03/28 Python
Python利用lxml模块爬取豆瓣读书排行榜的方法与分析
2019/04/15 Python
Django项目使用CircleCI的方法示例
2019/07/14 Python
HTML5 Canvas+JS控制电脑或手机上的摄像头实例
2014/05/03 HTML / CSS
Html5页面上如何禁止手机虚拟键盘弹出
2020/03/19 HTML / CSS
Original Penguin美国官网:布拉德皮特、强尼德普喜爱的服装品牌
2016/10/25 全球购物
什么是表空间(tablespace)和系统表空间(System tablespace)
2013/02/25 面试题
历史学专业大学生找工作的自我评价
2013/10/16 职场文书
中国文明网签名寄语
2014/01/18 职场文书
村庄绿化方案
2014/05/07 职场文书
班主任高考寄语
2015/02/26 职场文书
风雨哈佛路观后感
2015/06/03 职场文书
用Python提取PDF表格的方法
2021/04/11 Python