bezierCurveTo画完曲线后 怎么根据x值,计算出y的值是多少

bezierCurveTo画完曲线后 怎么根据x值,计算出y的值是多少

阅读 4.2k
1 个回答

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只接受三个参数,那是因为默认已经将当前点作为了第一个点。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题