资讯专栏INFORMATION COLUMN

n阶贝塞尔曲线(bezier)javascript 实现解析

EastWoodYang / 1502人阅读

摘要:最近学习,看到曲线,所以补充了下知识,另外相关的数学定律都忘光了需要了解的前期需要了解相关的知识,可以看下维基百科什么是贝塞尔曲线什么是线性插值绘制本身只提供了二次和三次的绘制函数,如果更高阶级的怎么办呢要对起进行降阶拆分。

最近学习canvas,看到bezier曲线,所以补充了下知识,另外相关的数学定律都忘光了~

需要了解的

前期需要了解相关的知识,可以看下维基百科

什么是贝塞尔曲线?

什么是线性插值?

绘制

canvas本身只提供了二次和三次的绘制函数,如果更高阶级的怎么办呢~要对起进行降阶拆分。

网上有个很牛掰的案例 bezier curve

我们来看下这个案例的js,这个demo并没有像我们的方程式写的那样来进行计算,但是它用了递归的操作,递归调用draw方法,来实现层层的绘制

var input = document.getElementsByTagName("input")[0]
var span = document.getElementsByTagName("span")[0]
var div = document.getElementsByTagName("div")[0]
var ctx1 = document.getElementsByTagName("canvas")[0].getContext("2d")
var ctx2 = document.getElementsByTagName("canvas")[1].getContext("2d")
var ctx3 = document.getElementsByTagName("canvas")[2].getContext("2d")

var points = [], colors = [], running = true, steps = 200, interval = 16, num

ctx1.font = "16px consolas"
ctx1.fillStyle = ctx1.strokeStyle = "hsl(0, 0%, 50%)"
ctx1.lineWidth = ctx2.lineWidth = 2
ctx3.strokeStyle = "hsl(0, 90%, 70%)"

function count() {
  num = parseInt(input.value)
  span.innerHTML = num
}

function toggle() {
  input.disabled = running = !running
}

function draw(per, arr, color) {
  var ary = []
  var node

  ctx2.strokeStyle = ctx2.fillStyle = colors[color]

  node = arr.reduce(function(previous, current, index) {
    // 从第二个元素开始,第二个点,这时候index为1,计算得到p点,index为1的时候,p点为bezier开始点到第一个控制点的插值
    // 第三个元素的时候,第三个点,index为2,计算得到p点,index为2的时候,p点为第一个控制点向第二个控制点移动的插值
    var p = {x: arr[index - 1].x + (arr[index].x - arr[index - 1].x) * per, y: arr[index - 1].y + (arr[index].y - arr[index - 1].y) * per}

    if(index > 1) {
      // 当达到第二个控制点的时候,获取从开始点到第一个控制点的p,进行line
      ctx2.beginPath()
      ctx2.moveTo(previous.x, previous.y)
      ctx2.lineTo(p.x, p.y)
      ctx2.stroke()
      ctx2.closePath()
    }
    // 绘制当前的插值点
    ctx2.beginPath()
    ctx2.arc(p.x, p.y, 3, 0, Math.PI * 2, true)
    ctx2.fill()
    ctx2.closePath()
    // 将坐标点push到新的坐标数组中
    ary.push(p)
    return p
  })

  if(ary.length > 1) {
    // 将插值作为新的开始点和控制点进行绘制,就这样递归下去
    draw(per, ary, color + 1)
  } else {
    // 如果插值的数组只有1个值,绘制的就是bezier曲线上的点,从起点一点一点连到结束点
    ctx3.lineTo(node.x, node.y)
    ctx3.stroke()
  }
}

var drawAsync = eval(Wind.compile("async", function () {
  toggle()
  ctx3.beginPath()
  ctx3.moveTo(points[0].x, points[0].y)
  for(var i = 0; i <= steps; i++) {
    draw(i / steps, points, 0)
    $await(Wind.Async.sleep(interval))
    ctx2.clearRect(0, 0, 800, 600)
  }
  ctx3.closePath()
  points = []
  toggle()
}))

div.addEventListener("click", function(e) {
  if(running) {
    return
  }

  var point = {x: e.pageX - div.offsetLeft, y: e.pageY - div.offsetTop}

  if(points.length == 0) {
    ctx1.clearRect(0, 0, 800, 600)
    ctx2.clearRect(0, 0, 800, 600)
    ctx3.clearRect(0, 0, 800, 600)
  } else {
    ctx1.beginPath()
    ctx1.moveTo(point.x, point.y)
    ctx1.lineTo(points[points.length - 1].x, points[points.length - 1].y)
    ctx1.stroke()
    ctx1.closePath()
  }

  ctx1.beginPath()
  ctx1.fillText("[" + point.x + ", " + point.y + "]", 15, 25 * (points.length + 1))
  ctx1.arc(point.x, point.y, 4, 0, Math.PI * 2, true)
  ctx1.fill()
  ctx1.closePath()

  points.push(point)

  if(points.length == num) {
    drawAsync().start()
  }
}, false)

input.addEventListener("change", count, false)

window.addEventListener("load", function() {
  for(var i = 0; i < parseInt(input.max); i++) {
    colors[i] = "hsl(" + 60*(i + 1) + ", 60%, 60%)"
  }
  count()
  toggle()
}, false)
总结

让我自己写还真写不出来。。。对array.reduce的用法真的炉火纯青了

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91353.html

相关文章

  • n塞尔曲线bezierjavascript 实现解析

    摘要:最近学习,看到曲线,所以补充了下知识,另外相关的数学定律都忘光了需要了解的前期需要了解相关的知识,可以看下维基百科什么是贝塞尔曲线什么是线性插值绘制本身只提供了二次和三次的绘制函数,如果更高阶级的怎么办呢要对起进行降阶拆分。 最近学习canvas,看到bezier曲线,所以补充了下知识,另外相关的数学定律都忘光了~ 需要了解的 前期需要了解相关的知识,可以看下维基百科 什么是贝塞尔曲...

    Labradors 评论0 收藏0
  • 如何理解并应用塞尔曲线

    摘要:动画曲线的应用了解了如何用贝塞尔曲线来指定动画曲线后,很多动画涉及到速度方面的效果就可以实现了,例如小车加速刹车,弹簧动画等速度轨迹都可以根据自己的需要来进行定制。 贝塞尔曲线又叫贝兹曲线,在大学高数中一度让我非常头疼。前阵子练手写动画的时候,发现贝塞尔曲线可以应用于轨迹的绘制以及定义动画曲线。 本文就来探究一下,贝塞尔曲线到底是个什么样的存在。 贝塞尔曲线原理 贝塞尔曲线由n个点来决...

    余学文 评论0 收藏0
  • 塞尔曲线算法之JS获取点

    摘要:什么是贝塞尔曲线贝塞尔曲线,又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。这个是三阶贝塞尔曲线,同理,绿点有个,点与点之间都是按百分比运动,最终得到一个小黑点。同理,还有四阶贝塞尔。我们看看中阶贝塞尔曲线上获取点的效果的地址 什么是贝塞尔曲线? 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。 showImg(htt...

    SQC 评论0 收藏0
  • 【前端优化】动画几种实现方式总结和性能分析

    摘要:备注没整理格式,抱歉动画实现的几种方式性能排序实现方式自身调用调用的定时器值推荐最小使用的原因即每秒帧为什么倒计时动画一定要用而避免使用两者区别及引发的线程讨论线程讨论为什么单线程是的一大特性。 备注:没整理格式,抱歉 动画实现的几种方式:性能排序js < requestAnimationFrame 3->4->2. 那么在来看你这段代码。 var t = true; window...

    IamDLY 评论0 收藏0

发表评论

0条评论

EastWoodYang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<