使用requestAnimationFrame和Canvas给按钮添加绕边动画

techbrood 发表于 2016-05-14 22:51:02

标签: canvas, 按钮, 绕边, 动画

- +

要给按钮添加酷炫的绕边动画,可以使用Canvas来实现。

基本的思路是创建一个和按钮大小相同的Canvas元素,内置在按钮元素中。然后在Canvas上实现边线环绕的动画。下载 (3).png

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();

这样我们就实现了一个按钮的绕边动画。

在线实例

你可以通过在线实例自己试试看,还可以基于这个简化版本添加渐变效果和鼠标悬停交互处理,乃至实现不规则形状按钮的描边动画。

possitive(3) views11590 comments0

发送私信

最新评论

请先 登录 再评论.
相关文章
  • HTML5 And Canvas 2D Specs Are Now Feature Complete, First HTML 5.1 Working Draft Published

    We’ve been writing about HTML5 for quite a while, but, until today, the actual HTML5 specs and standards were still moving targets. Now, however, the...

  • WebGL、Asm.js和WebAssembly概念简介

    随着HTML技术的发展,网页要解决的问题已经远不止是简单的文本信息,而包括了更多的高性能图像处理和3D渲染方面。这正是要引入WebGL、Asm.js和WebAssembly这些技...

  • CSS3特性查询(Feature Query: @supports)功能简介

    这是2017年不能不了解和学习的一个CSS新特性,非常实用,考虑到现实世界浏览器的复杂性,该特性本应该先于其他新特性出来。我们已经知道使用媒体查询(Media Que...

  • JavaScript语言多编程范式简介

    和C++等语言类似,JS支持多范式(paradigms)编程。我们常常混合这些范式来完成一些大型Web项目。JS支持3种编程范式:命令式、面向对象和函数式。命令式(Imperative JavaScript)命令式就是简单的从上而下完成任务,流水账过程式编码风格:function

  • 深入理解CSS3滤镜(filter)功能和实例详解

    CSS3滤镜功能源自SVG滤镜规范,SVG滤镜最早用来给矢量图添加类似PS中像素图的一些特效。
    把这个滤镜功能引入到普通HTML元素中可以带来很有趣的效果(模糊、...

  • 深入理解JS和CSS3动画性能问题和技术选择

    本文对比了JS及其框架和CSS3的动画性能,并深入剖析了其内在原因。技术结论大致如下:1. jQuery出于设计原因,在动画性能上表现最差2. CSS3由于把动画逻辑推给了...

  • 学习使用CSS制作进度条

    进度条是基础的界面控件,可用于多种场合,比如任务完成进度,手机充电状态等。本文介绍一个简单实用的进度条制作方法。预期效果如下图所示:直观上,我们可以把该进度条控件分为2个部分,外部的边界用来表示固定的目标范围,里面的条形部分用来表示当前进度。外部目标范围元素的CSS代码编写如下:.pb-scope

  • 计算WebGL中的uniforms变量使用数

    在使用Three.js为人体模型加载皮肤材料时,启用了skinning:true的参数。有时候会导致GL编译错误,提示“too many uniforms”。下面的文章有助于理解错误原因和检...

  • Three.js入门教程2 - 着色器(下)

    这是WebGL着色器教程的后半部分,如果你没看过前一篇,阅读这一篇教程可能会使你感到困惑,建议你翻阅前面的教程。

  • CSS3图片混合(Blend)效果及其参考计算公式一览表

    在Photoshop软件中,混合是将两个图层的色彩值进行合成,从而创造出大量的效果。在这些效果的背后实际是一些简单的数学公式在起作用。下面所介绍的公式仅适用于R...

  • 如何使用WebGL实现空气高温热变形动画特效

    我们在炎炎夏日,或者在火堆旁,经常会观察到热源周围空气的不稳定波动现象。本文将讲解如何通过WebGL来实现这个特效。该效果可用于热变形、波浪、水面波光等场...

  • Three.js 开发基础知识 - 绘制3D对象

    Three.js是一个用来简化WebGL开发的JavaScript库,比如绘制一个三维立方体,使用WebGL需要100多行,那Three.js只要10几行就能够完成。本文通过创建一个立方体来...

  • 如何使用纯CSS3实现一个3D泡沫

    要实现一个逼真的泡沫,涉及到比较复杂的光学/物理学知识。我们这里先简化下问题,实现一个相对简单而足够实用的泡沫元素。我们可以把基础的泡沫元素应用在很多场景中,比如水景、泡咖啡、啤酒甚至火焰特效中。泡沫首先是一个圆形元素.bubble

  • 更多...