bezierCurveTo应该是画的三次bezier曲线,那就是一共4个点 我们一般用的bezier曲线的表示形式是(x, y) = B(t),t是0-1范围内的一个数,也就是说输入一个位置,输出bezier曲线上这个位置的点的坐标,这个方程很容易根据控制点构造出来 但是你的需求是需要y = f(x)形式的,直接用数学方式去做似乎很麻烦(好像是个微分方程)。 换个思路,我们用B(t)的形式去计算一系列点,然后根据你输入的x,去取一个最接近的点,你计算的点越多,它就越精确 实现代码: // 三次bezier曲线类,参数为4个控制点坐标 function CubicBezier( p0, p1, p2, p3 ) { this.p0 = p0; this.p1 = p1; this.p2 = p2; this.p3 = p3; } CubicBezier.prototype = { cal: function( t, a, b, c, d ) { var k = 1 - t; return k * k * k * a + 3 * k * k * t * b + 3 * ( 1 - t ) * t * t * c + t * t * t * d; }, // 根据t获取曲线点坐标 get: function( t ) { return { x: this.cal( t, this.p0.x, this.p1.x, this.p2.x, this.p3.x ), y: this.cal( t, this.p0.y, this.p1.y, this.p2.y, this.p3.y ) } } } // 三次Bezier曲线查找表(lut, look up table) // count是计算点的数量,越大越精确 function CubicBezierLut( p0, p1, p2, p3, count ) { this.bezier = new CubicBezier( p0, p1, p2, p3 ); this.lut = []; count = count || 100; var step = 1 / count; var t = 0; for ( var i = 0; i < count; i++ ) { this.lut.push( this.bezier.get( t ) ); t += step; } } CubicBezierLut.prototype = { getYbyX: function( x ) { // 找一个最接近的点 for ( var i = 0; i < this.lut.length - 1; i++ ) { var point = this.lut[ i ]; var nextPoint = this.lut[ i + 1 ]; if ( Math.abs( x - point.x ) <= Math.abs( x - nextPoint.x ) ) { return point.y; } } return null; } } // 使用 var lut = new CubicBezierLut( { x: 0, y:0 }, { x: 1, y: 0.4 }, { x: 0, y: 0.6 }, { x: 1, y: 1 }, 200 ) console.log( lut.getYbyX( 0.2 ) ) // 0.09236480000000001 console.log( lut.getYbyX( 0.9 ) ) // 0.9587178500000009 刚才这几个点构造出来的bezier曲线大概长这样 看结果应该没问题 另外注意一点,三次bezier曲线需要4个点,但是canvas的bezierCurveTo只接受三个参数,那是因为默认已经将当前点作为了第一个点。
bezierCurveTo
应该是画的三次bezier曲线,那就是一共4个点我们一般用的bezier曲线的表示形式是
(x, y) = B(t)
,t是0-1范围内的一个数,也就是说输入一个位置,输出bezier曲线上这个位置的点的坐标,这个方程很容易根据控制点构造出来但是你的需求是需要
y = f(x)
形式的,直接用数学方式去做似乎很麻烦(好像是个微分方程)。换个思路,我们用
B(t)
的形式去计算一系列点,然后根据你输入的x,去取一个最接近的点,你计算的点越多,它就越精确实现代码:
刚才这几个点构造出来的bezier曲线大概长这样

看结果应该没问题
另外注意一点,三次bezier曲线需要4个点,但是canvas的bezierCurveTo只接受三个参数,那是因为默认已经将当前点作为了第一个点。