前面我整理过一篇文章canvas学习之API整理笔记(一),从这篇文章我们已经可以基本了解到常用绘图的API、简单的变换和动画。而本篇文章的主要内容包括高级动画、像素操作、性能优化等知识点,讲解每个知识点的同时还会有一些酷炫的demo,保证看官们全程在线,毫无尿点,看完不会后悔,哈哈,一个耿直的笑_

除此之外,关于canvas的一系列实例即将来袭!欢迎关注!

开始之前

var can = document.getElementById(‘canvas’);
//创建一个画布
var ctx = can.getContext(‘2d’);

下面所有的操作都在画布ctx上进行操作。

高级动画

继上一篇简单介绍了动画(主要是requestAnimationFrame方法),现在我们来一步步实现一个在画布内滚动的实例。

html代码:

<canvas id="canvas" width="400" height="200" style="background:#fff;"></canvas>

js代码:

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var ball = { //小球属性,原点位置,速度,半径等。
x: 100,
y: 100,
vx: 4,
vy: 2,
radius: 20,
color: 'blue',
draw: function() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2, true);
ctx.closePath();
ctx.fillStyle = this.color;
ctx.fill();
}
};
function draw() {
ctx.clearRect(0,0, canvas.width, canvas.height); //绘制之前清除整个画布
ball.draw(); //在画布中绘制小球
ball.x += ball.vx; //改变小球位置坐标
ball.y += ball.vy; //改变小球位置坐标
if (ball.y + ball.vy > canvas.height-15 || ball.y + ball.vy < 15) { //边界判断
ball.vy = -ball.vy;
}
if (ball.x + ball.vx > canvas.width-15 || ball.x + ball.vx < 15) { //边界判断
ball.vx = -ball.vx;
}
window.requestAnimationFrame(draw); //循环执行
}
draw();

上面代码实现的效果如下图:

代码我已经写了基本的注释,不难理解,简单概括一下这个实例的实现思想

创建一个小球对象,包含一个绘制自己的方法。在整个画布中绘制这个小球,然后在下一次绘制之前,先清除整个画布,改变小球的各个属性(包含了逻辑,比如边界的判断),然后重新绘制一遍,从而达到了动起来的效果。

如果你把上面代码中的ctx.clearRect(0,0, canvas.width, canvas.height);换成了下面这样:

ctx.fillStyle = 'rgba(255,255,255,0.3)';
ctx.fillRect(0, 0, canvas.width, canvas.height);

就可以得到渐变尾巴的效果:

像素操作

如果我们想对一个canvas画布进行如下操作:获取每一个点的信息,对每一个坐标点进行操作。那我们就需要了解一下ImageData对象了。

ImageData对象(由getImageData方法获取的)中存储着canvas对象真实的像素数据,它包含以下几个只读属性:

  • width

    图片宽度,单位是像素。

  • height

    图片高度,单位是像素。

  • data

    Uint8ClampedArray类型的一维数组,包含着RGBA格式的整型数据,范围在0至255之间(包括255)。简单讲,就是一个数组,每四个元素存储一个点的颜色信息,这四个元素分别对应为R、G、B、A的值(知道颜色取值的一眼就明白了,不知道的也没关系,后面有实例,一看就明白)。

创建ImageData对象

去创建一个新的,空白的ImageData对像,你应该会使用createImageData()方法

var myImageData = ctx.createImageData(width, height);

上面代码创建了一个新的具体特定尺寸的ImageData对像。所有像素被预设为透明黑。

获取像素数据

为了获得一个包含画布场景像素数据的ImageData对像,你可以用getImageData()方法

var myImageData = ctx.getImageData(left, top, width, height);

创建的myImageData对象就有width、height、data三个属性的值了。看下面这个实例:

html代码:

<div id="color">hover处的颜色</div>

<canvas id="myCanvas" width="300" height="150"></canvas>

js代码:

var can = document.getElementById('myCanvas');
var ctx = can.getContext('2d');
var img = new Image();
img.src = "img_the_scream.jpg";
ctx.drawImage(img, 0, 0);
var color = document.getElementById('color');
function pick(event) {
var x = event.layerX;
var y = event.layerY;
var area = ctx.getImageData(x, y, 1, 1); //创建ImageData对象
var data = area.data; //获取data属性(一个存储颜色rgba值的数组)
var rgba = 'rgba(' + data[0] + ',' + data[1] + ',' + data[2] + ',' + data[3] + ')';
color.style.color = rgba;
color.textContent = rgba;
}
can.addEventListener('mousemove', pick);

实现的效果如下图:

注意:

如果有些同学试到这里发现有这个报错内容Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.,需要检查这行代码:

img.src = "img_the_scream.jpg";

这里的图片地址不能是跨域地址。网上有一些解决办法,这里就不展开讲了。

写入像素数据

你可以用putImageData()方法去对场景进行像素数据的写入。

ctx.putImageData(myImageData, x, y);  //在画布的(x, y)点开始绘制myImageData所存储的像素信息。

所以我们可以把获取到的像素信息进行处理,然后再重新绘制,就得到了新的图形。看看下面这个实例:

html代码:

<canvas id="canvas" width="660" height="277"></canvas>

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = 'img_the_scream.jpg';
ctx.drawImage(img, 0, 0);
var imageData = ctx.getImageData(0,0,canvas.width, canvas.height); //获取ImageData
var colors = imageData.data; //获取像素信息
function invert() {
for (var i = 0; i < colors.length; i += 4) { //四个为一组
colors[i] = 225 - colors[i]; // red
colors[i+1] = 225 - colors[i+1]; // green
colors[i+2] = 225 - colors[i+2]; // blue
colors[i+3] = 255; //alpha
}
ctx.putImageData(imageData, 220, 0); //从(220, 0)开始绘制改变过的颜色
}
function toGray() {
for (var i = 0; i < colors.length; i += 4) {
var avg = (colors[i] + colors[i+1] + colors[i+2]) / 3;
colors[i] = avg; // red
colors[i+1] = avg; // green
colors[i+2] = avg; // blue
colors[i+3] = 255; //alpha
}
ctx.putImageData(imageData, 440, 0); //从(440, 0)开始绘制改变过的颜色
}
invert(); //反转色
toGray(); //变灰色

实现的效果如下图:

性能优化

坐标点尽量用整数

浏览器为了达到抗锯齿的效果会做额外的运算。为了避免这种情况,请保证使用canvas的绘制函数时,尽量用Math.floor()函数对所有的坐标点取整。比如:

ctx.drawImage(myImage, 0.3, 0.5);  //不提倡这样写,应该像下面这样处理
ctx.drawImage(myImage, Math.floor(0.3), Math.floor(0.5));

使用多个画布绘制复杂场景

比如做一个游戏,有几个层面:背景层(简单变化)、游戏层(时刻变化)。这个时候,我们就可以创建两个画布,一个专门用来绘制不变的背景(少量绘制),另一个用来绘制游戏动态部分(大量绘制),就像这样:

<canvas id="background-can" width="480" height="320"></canvas>
<canvas id="game-can" width="480" height="320"></canvas>

用CSS设置静态大图

如果有一层是永远不变的,比如一张静态的背景图,最好使用div+css的方法去替代ctx.drawimage(),这么做可以避免在每一帧在画布上绘制大图。简单讲,dom渲染肯定比canvas的操作性能更高。

尽量少操作canvas的缩放

如果要对一个画布进行缩放,如果可以的话,尽量使用CSS3的transform来实现。总之,记住一个原则,能用html+div实现的尽量不用js对canvas进行操作。

更多

  • 将画布的函数调用集合到一起(例如,画一条折线,而不要画多条分开的直线)
  • 使用不同的办法去清除画布(clearRect()、fillRect()、调整canvas大小)
  • 尽可能避免 shadowBlur特性
  • 有动画,请使用window.requestAnimationFrame() 而非window.setInterval()

结语

OK,canvas常用的API就基本总结完了,靠这些API已经足够开发一些中型游戏了。比如之前自己写的实例demo之小游戏tinyHeart,就是用这些函数画出来的。关键是这些函数的组合使用,多多联系就好了。

如果你把我之前的两篇文章都看了的话,相信你会对canvas越来越感兴趣。所以为了做一个有始有终的人,我后续还会出一系列的关于canvas的实例,注意,是一系列!敬请期待!

canvas学习之API整理笔记(二)的更多相关文章

  1. canvas学习之API整理笔记(一)

    其实canvas本身很简单,就是去学习它的API,多看实例,多自己动手练习,多总结.但是canvas的API实在是有点多,对于初学者来说,可能学到一半就止步不前了.我也有这种感觉,在学习的过程中,编写 ...

  2. Elasticsearch Java Rest Client API 整理总结 (二) —— SearchAPI

    目录 引言 Search APIs Search API Search Request 可选参数 使用 SearchSourceBuilder 构建查询条件 指定排序 高亮请求 聚合请求 建议请求 R ...

  3. HTML5 <Audio/>标签Api整理(二)

    1.实例2: 相对较完整 Html代码: <style> #volumeSlider .slider-selection { background:#bababa; } </styl ...

  4. JUC整理笔记二之聊聊volatile

    要想学好JUC,还得先了解 volatile 这个关键字.了解 volatile ,我们从一个例子开始吧. 本文不会很详细去说java内存模型,只是很简单地学习一下volatile 一个例子 pack ...

  5. Elasticsearch Java Rest Client API 整理总结 (三)——Building Queries

    目录 上篇回顾 Building Queries 匹配所有的查询 全文查询 Full Text Queries 什么是全文查询? Match 全文查询 API 列表 基于词项的查询 Term Term ...

  6. jQuery整理笔记文件夹

    jQuery整理笔记文件夹 jQuery整理笔记一----jQuery開始 jQuery整理笔记二----jQuery选择器整理 jQuery整理笔记三----jQuery过滤函数 jQuery整理笔 ...

  7. HTML5 <Audio>标签API整理(三)

    一.浏览器支持 Internet Explorer 9+, Firefox, Opera, Chrome, 和 Safari 都支持 <audio> 元素. 注意: Internet Ex ...

  8. 【canvas学习笔记二】绘制图形

    上一篇我们已经讲述了canvas的基本用法,学会了构建canvas环境.现在我们就来学习绘制一些基本图形. 坐标 canvas的坐标原点在左上角,从左到右X轴坐标增加,从上到下Y轴坐标增加.坐标的一个 ...

  9. canvas学习笔记、小函数整理

    http://bbs.csdn.net/topics/391493648 canvas实例分享 2016-3-16 http://bbs.csdn.net/topics/390582151 html5 ...

随机推荐

  1. 【初码干货】使用阿里云对Web开发中的资源文件进行CDN加速的深入研究和实践

    提示:阅读本文需提前了解的相关知识 1.阿里云(https://www.aliyun.com) 2.阿里云CDN(https://www.aliyun.com/product/cdn) 3.阿里云OS ...

  2. Linux根文件系统分析之init和busybox

    Hi,大家好!我是CrazyCatJack.今天给大家讲解Linux根文件系统的init进程和busybox的配置及编译. 先简单介绍一下,作为一个嵌入式系统,要想在硬件上正常使用的话.它的软件组成大 ...

  3. 乐乎环球WiFi

    乐乎环球WiFi招商加盟 随身WiFi设备 乐乎环球Wifi是由北京蔚蓝创智科技有限公司研发的产品,是一款可以在全球100多个国家和地区实现免漫游4G高速上网的随身WiFi设备.和普通MiFi设备相比 ...

  4. ucos实时操作系统学习笔记——任务间通信(信号量)

    ucos实时操作系统的任务间通信有好多种,本人主要学习了sem, mutex, queue, messagebox这四种.系统内核代码中,这几种任务间通信机制的实现机制相似,接下来记录一下本人对核心代 ...

  5. 2016年我们重新思考移动互联网创业的风险, 微信还是APP?

    感觉这两年前端开发又火起来了,很多做内容创业和做微电商创业的人,往往都选择了运营微信号.对于做纯技术开发的人来说,一般是看不上微信号的,感觉没什么技术含量,或者说没什么技术壁垒.也有另一批人观点相反的 ...

  6. ASP.NET MVC防范CSRF最佳实践

    XSS与CSRF 哈哈,有点标题党,但我保证这篇文章跟别的不太一样. 我认为,网站安全的基础有三块: 防范中间人攻击 防范XSS 防范CSRF 注意,我讲的是基础,如果更高级点的话可以考虑防范机器人刷 ...

  7. 用Maven部署war包到远程Tomcat服务器

    过去我们发布一个Java Web程序通常的做法就是把它打成一个war包,然后用SSH这样的工具把它上传到服务器,并放到相应的目录里,让Tomcat自动去解包,完成部署. 很显然,这样做不够方便,且我们 ...

  8. PE Checksum Algorithm的较简实现

    这篇BLOG是我很早以前写的,因为现在搬移到CNBLOGS了,经过整理后重新发出来. 工作之前的几年一直都在搞计算机安全/病毒相关的东西(纯学习,不作恶),其中PE文件格式是必须知识.有些PE文件,比 ...

  9. [翻译]AKKA笔记 - ACTOR生命周期 - 基本 -5

    原文地址:http://rerun.me/2014/10/21/akka-notes-actor-lifecycle-basic/ (请注意这了讨论的生命周期并不包括 preRestart 或者pos ...

  10. Spark 运行架构核心总结

    摘要: 1.基本术语 2.运行架构 2.1基本架构 2.2运行流程  2.3相关的UML类图  2.4调度模块: 2.4.1作业调度简介 2.4.2任务调度简介 3.运行模式 3.1 standalo ...