bezierMaker.js——N阶贝塞尔曲线生成器

写在最前

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

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

若是你喜欢这个做品欢迎Star,毕竟star来之不易。。git

项目地址:这里✨✨✨github

欢迎关注个人博客,不按期更新中——canvas

为何须要一个试验场?

在绘制复杂的高阶贝塞尔曲线时没法知道本身须要的曲线的控制点的精确位置。在试验场中进行模拟,能够实时获得控制点的坐标值,将获得的点坐标变为对象数组传递进BezierMaker类就能够生成目标曲线数组

效果图

功能

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

引入

<script src="./bezierMaker.js"></script>
复制代码

绘制

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

/**
 * 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()
复制代码

绘制结果

image

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

核心原理

绘制贝塞尔曲线

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

7460499-2603066c32c19ba9
这个公式中的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中大可能是安卓的实现,前端领域中还有不少地方能够更多的展开,欢迎讨论~ 多多批评!

其余canvas相关文章

最后

项目地址:这里✨✨

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

惯例po做者的博客,不定时更新中——

有问题欢迎在issues下交流。

相关文章
相关标签/搜索