一般来说,在H5开发中,使用canvas往往只是为了展示一些简单的图表或者简单短小的动画,很少考虑到有闪烁的问题。
最近,在手机QQ魔法表情的项目中,就遇到了奇葩的闪烁问题。
这里说的闪烁,是指动画刚开始播放,突然出现瞬间空白(大概1帧到2帧的时间)。

闪烁分析

这个魔法表情,实际是html5版本的动画,使用Fanvas(即将腾讯开源),从swf转化为canvas 2d动画。
在iOS体系下,无论哪个机型还是哪个系统版本,都没有出现问题。
但是,在部分Android机器上则出现了很奇葩的闪烁,包括小米note,小米4,三星,魅族。奇怪的是,小米同体系的红米note则完全正常。

翻阅H5 api的资料,我们知道requestAnimationFrame在Android 4.4后才支持,而动画的机制是,如果该接口不可用,则采用setInterval取代。

那么貌似有点眉目了,红米note也是4.4系统,而iOS全系都ok,也许问题就在这。
重温一下FPS和浏览器重绘的知识。浏览器保持一个帧频(一般60fps)刷新画面,这就包括页面中的canvas。而动画的绘制过程,包括几个步骤:
1、擦除整个canvas;
2、计算所有元件/图元的位置颜色;
3、逐个逐个,绘制所有元件到canvas上。
这个过程,由不精准的setInterval驱动,这个时钟无法跟浏览器重绘的频率同步。

那么,就可能出现这样的时序情况:
1、擦除整个canvas;
2、浏览器到达重绘时间点,此时canvas为空白,浏览器绘制空白的canvas;
3、50ms后,这一帧动画所有元件绘制完成(可能会因为动画复杂, 而消耗长时间,超过16ms)
关键点就在这里了。

好招不怕旧

双缓冲,只要对图形图象处理编程有稍稍一些了解,都应该听过这个术语,即使不知道这玩意是什么。这个技术非常非常古老,也非常非常简单,但效果却非常非常好。
来看看百度百科的说明,可能没有wikipedia专业,但我觉得足够解释问题了。

闪烁是图形编程的一个常见问题。需要多重复杂绘制操作的图形操作会导致呈现的图像闪烁或具有其他不可接受的外观。双缓冲的使用解决这些问题。双缓冲使用内存缓冲区来解决由多重绘制操作造成的闪烁问题。当启用双缓冲时,所有绘制操作首先呈现到内存缓冲区,而不是屏幕上的绘图图面。所有绘制操作完成后,内存缓冲区直接复制到与其关联的绘图图面。因为在屏幕上只执行一个图形操作,所以消除了由复杂绘制操作造成的图像闪烁。

回到我们的动画中,发现异曲同工,闪烁、掉帧的问题根源就是因为部分机型下没有自动实现cnavas的双缓冲(一般这些都是底层实现的),而canvas每一帧动画过程又比较漫长,擦除上一帧动画后,要过几十毫秒才能绘制完成下一帧,而这段时间内就会出现明显的空白。
解决办法就是:
创建一个临时canvas,先把下一帧动画绘制到临时canvas上。在每次真正绘制的时候,擦除正式canvas后,马上drawImage把临时canvas的内容copy过去,而这个copy过程是非常非常高效的,所以基本可以杜绝闪烁。

具体代码
    p.update = function() {
if (!this.cacheCanvas) {
this.cacheCanvas = document.createElement("canvas");
this.cacheCanvas.width = this.canvas.width;
this.cacheCanvas.height = this.canvas.height;
} updateMovieClip(); //图形变换 var ctx = this.cacheCanvas.getContext("2d");
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.save();
ctx.clearRect(0, 0, this.canvas.width + 1, this.canvas.height + 1); //部分Android机器很奇葩,如果局部刷新会出现空白的情况
drawMovieclip(ctx); //绘制
ctx.restore(); //双缓冲,先画到临时canvas,再转到正式canvas
ctx = this.canvas.getContext("2d");
ctx.clearRect(0, 0, this.canvas.width + 1, this.canvas.height + 1);
ctx.drawImage(this.cacheCanvas, 0, 0, this.canvas.width, this.canvas.height); };

【H5动画】谈谈canvas动画的闪烁问题的更多相关文章

  1. HTML动画分类 HTML5动画 SVG库 SVG工具 Canvas动画工具

     1.js配合传统css属性控制,可以使用setTimeout或者高级的requestAnimationFrame 2.css3 3.svg 4.canvas(当然,这个还是要配合js)   也许这么 ...

  2. 【30分钟学完】canvas动画|游戏基础(1):理论先行

    前言 本文虽说是基础教程,但这是相对动画/游戏领域来说,在前端领域算是中级教程了,不适合前端小白或萌新.阅读前请确保自己对前端三大件(JavaScript+CSS+HTML)的基础已经十分熟悉,而且有 ...

  3. 2015.4.23 贪吃蛇、canvas动画,各种上传工具,url信息匹配以及最全前端面试题等

    1.面向对象贪吃蛇   2.css中:hover 改变图片 页面加载完 第一次鼠标移入会闪一下 这是为啥? 解决方法:你把两张图合成一张图或者是先把图片加载到页面上,然后再hover出来. 解析:图片 ...

  4. 7 个顶级的 HTML5 Canvas 动画赏析

    HTML5确实是一项改革浏览器乃至整个软件行业的新技术,它可以帮助我们Web开发者很方便地在网页上实现动画特效,而无需臃肿的Flash作为支撑.本文分享7个顶级的HTML5 Canvas 动画,都有非 ...

  5. 8个经典炫酷的HTML5 Canvas动画欣赏

    HTML5非常强大,尤其是Canvas技术的应用,让HTML5几乎可以完成所有Flash能完成的效果.本文精选了8个经典炫酷的HTML5 Canvas动画欣赏,每一个都提供全部的源代码,希望对你有所帮 ...

  6. 7个惊艳的HTML5 Canvas动画效果及源码

    HTML5非常强大,尤其是现在大部分浏览器都支持HTML5和CSS3,用HTML5制作的动画也多了起来.另外,Canvas上绘制图形非常简单,本文就分享了一些强大的HTML5 Cnavas动画,一起来 ...

  7. 《FLASH CC 2015 CANVAS 中文教程》——1、导出canvas动画,文件结构浅析

    注::如果你对 FLASH 这个软件操作不够熟悉,建议你可以先看看FLASH动画之类的书. :FLASH CC 在文中直接简称为CC. :以下所以文章中所说的快捷键 如果你按了不起作用,请检查是否有其 ...

  8. Html5 Canvas动画旋转的小方块;

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  9. 【原创】测试不同浏览器播放canvas动画的平滑程度

    Canvas无疑是HTML5开放式网络平台最激动人心的技术之一.目前,除了IE8以外,各类浏览器的新版本都支持HTML5 Canvas. 程序员需要通过Javascript调用Canvas API.基 ...

随机推荐

  1. python 全栈开发,Day60(MySQL的前戏,数据库概述,MySQL安装和基本管理,初识MySQL语句)

    一.MySQL的前戏 在学习Mysql之前,我们先来想一下一开始做的登录注册案例,当时我们把用户的信息保存到一个文件中: #用户名 |密码 root|123321 alex|123123 上面文件内容 ...

  2. Ubuntu 8.04嵌入式交叉编译环境arm-linux-gcc搭建过程图解

    Linux版本:Ubuntu8.04 内核版本:Linux 2.6.24 交叉编译器版本:arm-linux-gcc-3.4.1 交叉编译器下载链接: https://share.weiyun.com ...

  3. git merge简介

    git merge的基本用法为把一个分支或或某个commit的修改合并到现在的分支上.我们可以运行git merge -h和git merge --help查看其命令,后者会直接转到一个网页(git的 ...

  4. Django的auto_now=True没有自动更新

    auto_now=True自动更新,有一个条件,就是要通过django的model层. 如create或是save方法. 如果是filter之后update方法,则直接调用的是sql,不会通过mode ...

  5. visual studio 2015百度云下载

    visual studio 2015百度云下载 https://pan.baidu.com/s/1b198Zo3mX5_zA2VX3xRRfw 提取码: 关注公众号[GitHubCN]回复2015获取

  6. CentOS6.8安装360 pika

    1.安装依赖包 yum install snappy-devel bz2 libzip-dev libsnappy-dev libprotobuf-dev libevent-dev protobuf- ...

  7. MySQL和Java数据类型对应

    Java MySQL数据类型对照 类型名称 显示长度 数据库类型 JAVA类型 JDBC类型索引(int) 描述             VARCHAR L+N VARCHAR java.lang.S ...

  8. JdbcType类型和Java类型的对应关系

    在Oracle中有些字段不是必填时在用户使用的时候会出现数据null的情况.这个时候在Oracle中是无法进行插入的. JDBC Type Java Type CHAR String VARCHAR ...

  9. java技术第二次作业

    (一)学习总结 1.什么是构造方法?什么是构造方法的重载? 构造方法是用于对对象初始化的方法,当新对象被创建的时候,构造函数会被调用. 每一个类都有构造函数.在程序员没有给类提供构造函数的情况下,Ja ...

  10. Ubuntu18.04更换国内源

    Ubuntu18.04更换国内源 Ubuntu本身的源使用的是国内的源,下载速度比较慢,不像CentOS一样yum安装的时候对镜像站点进项选择, 所以选择了更换成国内的源. 以下内容整合自网络 备份/ ...