最近學習canvas,看到bezier曲線,因此補充了下知識,另外相關的數學定律都忘光了~node
前期須要瞭解相關的知識,能夠看下維基百科git
canvas自己只提供了二次和三次的繪製函數,若是更高階級的怎麼辦呢~要對起進行降階拆分。數組
網上有個很牛掰的案例 bezier curveasync
咱們來看下這個案例的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
的用法真的爐火純青了學習