使用requestAnimationFrame和Canvas給按鈕添加繞邊動畫

要給按鈕添加酷炫的繞邊動畫,可以使用Canvas來實現。

基本的思路是創建一個和按鈕大小相同的Canvas元素,內置在按鈕元素中。然後在Canvas上實現邊線環繞的動畫。


requestAnimationFrame接口

我們使用requestAnimationFrame接口來實現動畫幀的繪製,該接口告訴瀏覽器在重畫(repaint)之前先執行一個動畫回調函數。

通過這樣的回調機制,瀏覽器可以把多個動畫函數執行完成後再統一繪製,提高動畫渲染性能。

(function() {
    for (var d = 0, a = ["webkit", "moz"], b = 0; b < a.length && !window.requestAnimationFrame; ++b) window.requestAnimationFrame = window[a[b] + "RequestAnimationFrame"], window.cancelAnimationFrame = window[a[b] + "CancelAnimationFrame"] || window[a[b] + "CancelRequestAnimationFrame"];
    window.requestAnimationFrame || (window.requestAnimationFrame = function(b) {
        var a = (new Date).getTime(),
            c = Math.max(0, 16 - (a - d)),
            e = window.setTimeout(function() {
                b(a + c)
            }, c);
        d = a + c;
        return e
    });
    window.cancelAnimationFrame || (window.cancelAnimationFrame =
        function(a) {
            clearTimeout(a)
        })
})();
上面實現的是一個兼容各瀏覽器並可以安全降級的requestAnimationFrame版本,當瀏覽器不支持時,回退到setTimeout/clearTimeout定時函數。

Border對象

現在我們需要創建一個Border對象,用來表示繞邊的那個動畫對象。該Border對象的寬高和按鈕元素接近,幷包含一個canvas對象。

function Border(opt) { // 參數opt即爲傳入的button元素
    this.elem = opt.elem;
    this.active = false;
    this.canvas = document.createElement('canvas');//創建畫布
    this.ctx = this.canvas.getContext('2d');//獲取畫布上下文
    this.width = this.canvas.width = this.elem.outerWidth();//設置寬
    this.height = this.canvas.height = this.elem.outerHeight();//設置高
    this.borderSize = parseInt(this.elem.css('border-left-width'), 10);//設置邊寬
    this.waypoints = [
        [0, 0],
        [this.width - this.borderSize, 0],
        [this.width - this.borderSize, this.height - this.borderSize],
        [0, this.height - this.borderSize]
    ];//設置路標數組
    this.tracer = {
        x: 0,
        y: 0,
        color: opt.color,
        speed: opt.speed,
        waypoint: 0
    };//設置路徑對象
    this.canvas.style.top = -this.borderSize + 'px';
    this.canvas.style.left = -this.borderSize + 'px';
    this.elem.append($(this.canvas));//把canvas內置到button元素中。
}

然後我們實現循環繞邊的函數,由於這是Border對象的一個行爲,我們把它實現爲其原型對象的一個方法:

Border.prototype.loop = function() {
  requestAnimationFrame($.proxy(this.loop, this));//定時調用自身
  this.ctx.globalCompositeOperation = 'source-over';//源覆蓋目標的合成模式
  this.ctx.fillStyle = this.tracer.color;
  this.ctx.fillRect(this.tracer.x, this.tracer.y, this.borderSize, this.borderSize);//在當前路徑上繪製小方塊(本例是4*4px)
   //下面這段代碼是通用算法,用來計算某段路徑上x/y方向上的速度分量,同時判斷下一步是否需要拐彎(在路標處)
  var previousWaypoint = (this.tracer.waypoint == 0) ? this.waypoints[this.waypoints.length - 1] : this.waypoints[this.tracer.waypoint - 1],
      dxTotal = previousWaypoint[0] - this.waypoints[this.tracer.waypoint][0],
      dyTotal = previousWaypoint[1] - this.waypoints[this.tracer.waypoint][1],
      distanceTotal = Math.sqrt(dxTotal * dxTotal + dyTotal * dyTotal),//該段路徑總長度
      angle = Math.atan2(this.waypoints[this.tracer.waypoint][1] - this.tracer.y, this.waypoints[this.tracer.waypoint][0] - this.tracer.x),
      vx = Math.cos(angle) * this.tracer.speed,
      vy = Math.sin(angle) * this.tracer.speed,
      dxFuture = previousWaypoint[0] - (this.tracer.x + vx),
      dyFuture = previousWaypoint[1] - (this.tracer.y + vy),
      distanceFuture = Math.sqrt(dxFuture * dxFuture + dyFuture * dyFuture);//在該路徑上的總移動距離


  if (distanceFuture >= distanceTotal) {//已移動距離超過路徑長度,則需要拐彎,即更新路標
      this.tracer.x = this.waypoints[this.tracer.waypoint][0];
      this.tracer.y = this.waypoints[this.tracer.waypoint][1];
      this.tracer.waypoint = (this.tracer.waypoint == this.waypoints.length - 1) ? 0 : this.tracer.waypoint + 1;
  } else {//否則,在當前路徑上移動位置
      this.tracer.x += vx;
      this.tracer.y += vy;
  }
}

有了Border對象後,我們來實際使用它。(在C++等面嚮對象語言中,我們通常稱上面定義了一個類Class,在實際使用時,需要創建類的實例,即對象Object)。

var button = $("#your_button_id")[0];
$this = $(button);
var border = new Border({
    elem: $this,
    color: $this.data('color'),
    speed: $this.data('speed')
});

$(border.canvas).stop(true).animate({
    'opacity': 1
}, 400);

border.loop();
這樣我們就實現了一個按鈕的繞邊動畫。
在線實例

你可以通過在線實例自己試試看,還可以基於這個簡化版本添加漸變效果和鼠標懸停交互處理,乃至實現不規則形狀按鈕的描邊動畫。

by iefreer
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章