吕小鸣 • Canvas制作点赞送心动画

919 阅读1分钟
原文链接: www.nihaoshijie.com.cn

先看看效果



实现原理

1.动画中每颗心都有自己的透明度,位移,角度,缩放的变化动画,针对这些动画,可以分别调用canvas的相关API:


ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.scale(this.scale, this.scale);
ctx.globalAlpha = this.opacity;

2.在有大于1颗心的情况时,针对每颗心,在实现角度,缩放时必须要保存上一次canvas的状态,改变完成之后在恢复:


ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.angle);
ctx.scale(this.scale, this.scale);
ctx.globalAlpha = this.opacity;
ctx.restore();

3.计算心位移路径(3次被塞尔曲线)
公式:
转换成js代码计算心的x,y方向上的位移:


    /**
     * 获得贝塞尔曲线路径
     * 一共4个点
     */
     function getBezierLine(heart){
         var obj = heart.bezierPoint;
         var p0 = obj.p0;
         var p1 = obj.p1;
         var p2 = obj.p2;
         var p3 = obj.p3;
         var t = heart.bezierDis;
         var cx = 3 * (p1.x - p0.x),
         bx = 3 * (p2.x - p1.x) - cx,
         ax = p3.x - p0.x - cx - bx,

    cy = 3 * (p1.y - p0.y),
    by = 3 * (p2.y - p1.y) - cy,
    ay = p3.y - p0.y - cy - by,

    xt = ax * (t * t * t) + bx * (t * t) + cx * t + p0.x,
    yt = ay * (t * t * t) + by * (t * t) + cy * t + p0.y;

    heart.bezierDis += heart.speed;

    return {
    xt: xt,
    yt: yt
    }
}

路径如图所示:

根据曲线路径方法可以实现心的运动轨迹:

4.针对每一帧需要动态修改,心的位移,角度,和缩放:


/**
* 计算缩放角度的方法
*/
function getFScale(heart){
    let _scale = heart.scale;

    // 随着距离起始点的距离增加,scale不断变大
    let dis = heart.orignY - heart.y;
    _scale = (dis / heart.scaleDis);

    // 当大于设置的阈值时变成1
    if (dis >= heart.scaleDis) {
        _scale = 1;
    }

    return _scale;
}

5.计算心角度变化


/**
* 计算心左右摇摆的方法
*/
function rangeAngle(heart) {
    let _angle = heart.angle;
    // 心介于[start, end]之间不断变化角度
    if(_angle >= heart.angelEnd) {
    // 角度不断变小,向左摇摆
    heart.angleLeft = false;
    } else if (_angle <= heart.angelBegin){
    // 角度不断变大,向又摇摆
    heart.angleLeft = true;
    }
    // 动态改变角度
    if (heart.angleLeft) {
    _angle = _angle + 1;
    } else {
    _angle = _angle - 1;
    }
    return _angle;
}

组件化

整个组件代码不超过200行,相较于使用css3实现更加轻便,dom少,性能更好。
组件地址:github.com/lvming68160…