canvas基础第二节
一、图形的组合方式
globalAlpha是一个介于0和1之间的值(包括0和1),用于指定所有绘制的透明度。默认值为0。如果所有后续操作都要基于相同的透明度,就可以先把globalAlpha设置为适当值,然后绘制,最后在把它设置回默认值0.
//绘制一个红色的矩形
context.fillStyle="red";
context.fillRect(10,10,50,50);
//修改全局透明度
context.globalAlpha=0.5;
//绘制蓝色矩形
context.fillStyle="blue";
context.fillRect(30,30,50,50);
//重置全局透明度
context.globalAlpha=0;
//这个例子中蓝色矩形会呈现半透明效果,透过它可以看到下面的红色矩形。
globalCompositionOperation表示绘制后的图形怎样与先绘制的图形结合。这个属性的值是字符串,可能的值如下:
source-over(默认值):后绘制的图形位于先绘制的图形上方。
source-in:后绘制的图形与先绘制的图形重叠的部分可见,两者其他部分完全透明。
source-out:后绘制的图形与先绘制的图形不重叠的部分可见,先绘制的图形完全透明。
source-atop:后绘制的图形与先绘制的图形重叠的部分可见,先绘制图形不受影响。
destination-over:后绘制的图形位于先绘制的图形下方,后绘制的图形只有之前透明像素下的部分才可见,被遮挡的部分不可见。
destination-in:后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明。就是显示重叠的部分的形状,显示先绘制的图形的颜色。
destination-out:后绘制的图形擦除与先绘制的图形重叠的部分。
destination-atop:后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形会变透明。
lighter:后绘制的图形与先绘制的图形重叠部分的值相加,使该部分变亮。(叠加的是颜色额)
copy:后绘制的图形完全替代与之重叠的先绘制图形。
xor:后绘制的图形与先绘制的图形重叠的部分执行“异或”操作;图像异或,相异为1,相同为0.即重叠部分不显示,不重叠部分显示。
//画目标图
context.beginPath();
context.fillStyle="red";
context.fillRect(100,50,100,300);
//画源图
context.beginPath();
context.globalCompositeOperation="destination-out";
//context.globalCompositeOperation="xor";
context.fillStyle="blue";
context.arc(250,200,100,0, Math.PI*2);
目标图像:已经放到画布中的绘图
源图像:打算放置到画布中的绘图
在使用globalCompositionOperation的情况下一定要多测一些浏览器,因为不同的浏览器对这个属性的实现仍然存在较大的差别。
二、使用图片
//第一种写法:第一个参数:图片对象;第二个参数是开始画的x坐标;第三个参数:开始画的y的坐标;
//context.drawImage(img,0,0);
//第二种写法:第一个参数:图片对象;第二个参数:是开始画的x坐标;第三个参数:开始画的y的坐标;第四个参数:图片绘制到canvas上的宽度;第五个参数:图片绘制到canvas上的高度;
//context.drawImage(img,0,0,200,200);
//第三种写法(裁剪):第一个参数:图片对象;第二三个参数在原图上要裁剪的起始x、y的坐标;第四、五个参数:在原图上要裁剪的宽和高;第六、七个参数:要放到canvas画布上的起始x、y坐标;第八九个参数:要到canvas画布上的宽和高;
context.drawImage(img,100,100,100,100,50,50,300,300);
var canvas=document.getElementById("myCanvas");
var context=canvas.getContext("2d");
var img= newImage();
img.src="img/20150821130732_anQeR.jpeg";
img.onload=function(){
context.drawImage(img,100,100,100,100,50,50,300,300);
}
综合使用drawImage( )和其他方法,可以对图像进行各种基本操作。而操作的结果可以通过toDataURL( )方法获得。不过有一个例外,即图像不能来自其他域。如果图像来自其它域,调用toDataURL( )会抛出错误。
canvas提供了toDataURL的接口,可以方便的将canvas画布转化成base64编码的image。目前支持的最好的是png格式,jpeg格式的现代浏览器基本也支持,但是支持的不是很好。
//我们创建一个画布,在上面做一些绘图,然后试着把它保存为本地图片。
var can = document.getElementById('canvas');
var ctx = can.getContext('2d');
var imgA = new Image();
imgA.src ='http://www.html5party.com/wp-content
/uploads/2013/09/css_yangshijiance.png';
imgA.onload = function() {
ctx.drawImage(imgA, -25, 0, imgA.width, imgA.height);
ctx.restore();
};
var imgB = new Image();
imgB.src = 'http://www.html5party.com/wp-content
/uploads/2013/09/canvas_chroma.png';
imgB.onload = function() {
ctx.globalAlpha = 0.1
ctx.drawImage(imgB, -100, -75, imgB.width, imgB.height);
ctx.restore();
};
function toImage(returnType) {
var dataURL = document.getElementById('canvas').toDataURL("image/png");
// The returnType argument specifies how to get the
// the image. 'obj' will set the source to an image element.
// 'window' will open a new window and display the image.
// 'download' will prompt the user to save the image.
switch(returnType) {
case 'obj':
var imgObj = new Image();
imgObj.src = dataURL;
document.getElementById('graphics').appendChild(imgObj);
break;
case 'window':
window.open(dataURL, "Canvas Image");
break;
case 'download':
dataURL = dataURL.replace("image/png", "image/octet-stream");
document.location.href = dataURL;
break;
}
}
理想的状态是页面上有三个点击链接:
1、Image Tag
点击会有一张图片插入在网页中。
2、New Window
打开一个新的窗口,并显示一个PNG格式的图片
3、Download
下载保存一张PNG个格式的图片
很不幸,点击并没有反映,为什么呢?笔者做了许多试验,原因出在图片渲染上,canvas上如果添加图片,toDataURL()将失效,获取不到canvas信息。通过简单几步来验证这个问题。
把js脚本中图片渲染的部分去除,A和B图。为了便于观察,在画布上画一个简单的矩形,填充颜色:
ctx.fillStyle = 'Red';
ctx.strokeStyle = 'Green';
ctx.beginPath();
ctx.rect(20, 20, 100, 100);
ctx.stroke();
ctx.fill();
这样画布上便显示为一个红色矩形,格式为PNG
三、裁剪
var canvas=document.getElementById("myCanvas");
var context=canvas.getContext("2d");
//绘制一个三角形
context.beginPath();
context.moveTo(200,200);
context.lineTo(250,200);
context.lineTo(225,150);
context.closePath();
context.stroke();
//调用裁剪
context.clip();
var img= newImage();
img.src="img/20150821130732_anQeR.jpeg";
img.onload=function() {
context.drawImage(img,0,0);
}
//你上面画的是什么形状,裁剪出来的就是什么形状
四、使用图像数据
var canvas=document.getElementById("myCanvas");
var context=canvas.getContext("2d");
//getImageData()取的原始图像数据
//有四个参数:第一二个参数,开始获取像素的x,y坐标,第三四个参数,获取像素点的宽高。
//var ImageData=context.getImageData(0,0, img.width, img.height);
这里返回的对象是getImageData()的实例,每个getImageData()对象都有三个属性:width、height、data。
width和height表示访问像素区域大小
//其中data属性是一个数组,保存着图像中每一个像素的数据。
//在data数据中,每一个像素用4个元素来保存,分别代表红、绿、蓝和透明度。
//数组中的每个元素都是介于0和255之间的,能够直接访问到原始图像数据,
//就能够以各种方式来操作这些数据。
var img= newImage();
img.src="img/20150821130732_anQeR.jpeg";
img.onload=function() {
context.drawImage(img,0,0);
var ImageData=context.getImageData(0,0, img.width, img.height);
var data=ImageData.data;
//注意:每次循环控制变量i都递增4,在取得每个像素的红、绿、蓝颜色值后,
//计算出他们的平均值,再把这个平均值设置为每个颜色的值,
//结果就是去掉了每个像素的颜色,只保留了亮度接近的灰度值.(用彩色变黑白)
for(var i=0; i<data.length; i+=4){
var r=data[i];
var g=data[i+1];
var b=data[i+2];
//求rgb的平均值,
var gray=(r+g+b)/2;
//设置颜色值
data[i]=gray;
data[i+1]=gray;
data[i+2]=gray;
}
//putImageData()方法把图像数据绘制到画布上,有三个参数
//第一个参数,获取ImageData,第二三个参数,要放到画布上的x,y坐标
context.putImageData(ImageData,0,0);
}
五、canvas视频处理
function animation( ){
//video.ended 属性返回音频/视频是否已结束。返回值:布尔值true|false。如果播放已结束,则返回 true。否则返回 false。
if(!video.ended){
//将视频的每一帧,绘制在canvas上
context.drawImage(video,0,0,canvas.width,canvas.height);
window.requestAnimationFrame(animate);
}
}
//当视频可以播放时,进行播放调用循环
//video的oncanplay事件类似于图像的onload,加载完成之后
//oncanplay 事件在用户可以开始播放视频/音频(audio/video)时触发。
//object.oncanplay=function(){myScript};
//object.addEventListener("canplay",myScript);
video.oncanplay=function(e){
video.play( );
window.requestAnimationFrame(animate);
}
六、canvas动画
最原始的你还可以使用window.setTimout()或者window.setInterval()通过不断更新元素的状态位置等来实现动画,前提是画面的更新频率要达到每秒60次才能让肉眼看到流畅的动画效果。
window.requestAnimationFrame()通过递归调用同一方法来不断更新画面以达到动起来的效果,但它优于setTimeout/setInterval的地方在于它是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销。
取消该次动画:可以直接调用,也可以通过window来调用,接收一个函数作为回调,返回一个ID值,通过把这个ID值传给window.cancelAnimationFrame()可以取消该次动画。
window.requestAnimationFrame()方法用于告诉浏览器,你想在浏览器的下个重绘 之前来执行一个动画或者执行浏览器通过调用一个特定的函数来更新动画的请求。该方法会在下次重回之前执行一个作为参数的回调函数。
window.requestAnimationFrame 是专门为实现高性能的帧动画而设计的一个API,目前已在多个浏览器得到了支持,包括IE10+,Firefox,Chrome,Safari,Opera等,在移动设备上,ios6以上版本以及IE mobile 10以上也支持requestAnimationFrame,唯一比较遗憾的是目前安卓上的原生浏览器并不支持requestAnimationFrame,不过对requestAnimationFrame的支持应该是大势所趋了,安卓版本的chrome 16+也是支持requestAnimationFrame的。
例子window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame ||window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
七、实现多个小球随机运动,用面向对象的方法
var canvas=document.getElementById("myCanvas");
var context=canvas.getContext("2d");
//圆是一个类,就是对象只有一个,就是圆
functionCircle(x,y,r,speedX,speedY,color) {
//所有的属性
this.r=r;
this.x=x;
this.speedX=speedX;
this.speedY=speedY;
this.y=y;
this.color=color;
}
//在原型上写方法,
//第一个方法,画圆
Circle.prototype.draw=function() {
context.beginPath();
context.fillStyle=this.color;
context.arc(this.x, this.y, this.r,0, Math.PI*2);
context.fill();
}
//第二个方法,运动
Circle.prototype.move=function() {
//这里改变x递加的值,可以改变运动速度
this.x+=this.speedX;
this.y+=this.speedY;
if(this.x>=canvas.width-this.r||this.x<=this.r) {
this.speedX*= -1;
}
if(this.y>=canvas.height-this.r||this.y<=this.r) {
this.speedY*= -1;
}
}
//进行实例化操作
//实现同时出现多个小球,需要同时实例化出多个对象
//储存new出来的实例化对象数组
var arr=[ ];
//来很多个小球
for(var i=0; i<100; i++) {
//设置一个随机的半径
var R=randomNum(30,5);
//随机位置
var X=randomNum(canvas.width-R, R);
var Y=randomNum(canvas.height-R, R);
//随机速度
var speedX=randomNum(8,1);
var speedY=randomNum(8,1);
//随机颜色
var COLOR="rgb("+randomNum(255,0)+","+randomNum(255,0)+","+randomNum(255,0)+")";
//将对像实例化
var newCircle= newCircle(X, Y, R, speedX, speedY, COLOR);
arr.push(newCircle)
}
moveCircle();
//定义一个执行动画的函数
function moveCircle() {
//先清理画布
context.clearRect(0,0, canvas.width, canvas.height);
//循环执行实例化对象的数组
for(var i=0; i<arr.length;i++){
arr[i].draw();
arr[i].move();
}
//执行动画
window.requestAnimationFrame(moveCircle);
}
//定义一个随机数的函数
functionrandomNum(max,min) {
returnparseInt(Math.random()*(max-min+1)+min);
}