学了两天的canvas了,整理一下所学的知识,总结到一起,加深一下对canvas的理解。嗯、就这样
canvas:负责在页面中设定一个区域,然后就可以通过js动态的在这个区域中绘制图形
canvas基本用法:要使用canvas,必须先设置width和height属性,指定可以绘图的区域大小。(如果不设置,默认大小是width:300px; height:150px;)一般的写法是直接写在行间,也可以写在style样式中,但是写在style中和写在行间的结果会有一定的不同。(后面会举例说明)
要在画布上绘图,需要取得绘图上下文,而取得绘图上下文对象的引用,需要调用getContext()方法,并传入上下文的名字。传入“2d”就可以取得2d上下文对象
var oC = document.getElementById('c1');
var oGC = oC.getContext('2d');
需要注意的是,在使用<canvas>之前,要先检测getContext()方法是否存在,确定浏览器支持<canvas>元素
var oC = document.getElementById('c1');
if(oC.getContext){//确定浏览器支持<canvas>元素
var oGC = oC.getContext('2d'); }
填充和描边
2d上下文的两种基本绘图操作是填充和描边。填充,就是用指定的样式(颜色、渐变、图像)填充图形;描边,就是只在图形的边画线。操作的属性是fillStyle(填充)和strokeStyle(描边),这两个属性的值可以是字符串、渐变对象或模式对象,而且他们的默认值都是黑色
绘制矩形:
与矩形有关的方法包括:fillRect()、strokeRect()、clearRect(),这三个方法都可以接收四个参数:矩形的x坐标,y坐标,矩形的宽和高(单位都是px)
var oC = document.getElementById('c1');
if(oC.getContext){
var oGC = oC.getContext('2d');
}
oGC.fillStyle = 'red';//不写的话默认为黑色
//oGC.fillRect(50,50,100,100);
oGC.strokeRect(50.5,50.5,100,100);
写得时候,要注意顺序,样式要写在绘图的前面,否则样式显现不出来。
绘制路径
要绘制路径,首先必须要调用beginPath()方法,表示要开始绘制新的路径,然后再通过调用下列方法来实际的绘制路径
rect(x,y,w,h):从(x,y)开始绘制一个矩形,宽度和高度分别为w,h
arc(x,y,r,start,end,false/true):以(x,y)为圆心绘制一条弧线,半径为r,起始和结束角度为star和end(用弧度表示),false和true,表示按顺时针或逆时针计算,默认为false(按顺时针计算)
moveTo(x,y):将绘图图标移动到(x,y),不画线
lineTo(x,y):从上一点绘制一条直线,到(x,y)为止
arcTo(x1,y1,x2,y2,r):从上一点开始绘制一条弧线,到(x2,y2)为止,并且以给定的半径r穿过(x1,y1)
bezierCurveTo(c1x,c1y,c2x,c2,x,y):从上一点开始绘制一条曲线,到(x,,y)为止,并且以(c1x,c1y)和(c2x,c2y)为控制点
quadraticCurveTo(cx,cy,x,y):从上一点开始绘制一条二次曲线,到(x,y)为止,并且以(cx,cy)为控制点
创建了路径后,接下来,如果你想要绘制一条连接到路径起点的线条,可以调用closePath()方法。如果路径已经完成,可以调用fill()或者stroke()方法对路径进行填充或描边,也可以调用clip()在路径上创建一个剪切区域。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style>
body{ background:black;}
#c1{ background:white;}
span{ color:white;}
</style>
<script>
window.onload = function(){
var oC = document.getElementById('c1');
if(oC.getContext){
var oGC = oC.getContext('2d');
}
oGC.save();
oGC.fillStyle = 'red';
oGC.beginPath();
oGC.moveTo(100,100);
oGC.lineTo(200,200);
oGC.lineTo(300,200);
oGC.closePath();
oGC.fill();
oGC.restore();
oGC.beginPath();
oGC.moveTo(100,200);
oGC.lineTo(200,300);
oGC.lineTo(300,300);
oGC.closePath();
oGC.fill();
};
</script>
</head>
<body>
<canvas width="400" height="400">
<span>不支持canvas浏览器</span>
</canvas> <!--默认:宽300 高150-->
</body>
</html>
绘制文本:
绘制文本的方法主要有两种:fillText()和strokeText(),这两个方法都可以接收四个参数:要绘制的文本字符串,x坐标,y坐标和可选的最大像素宽度(第四个参数并未得到所有浏览器的支持,也可以不写)
三个属性:font:表示文本样式、大小及字体
textAlign:表示文本对齐方式,可能的值有start(left)、end(right)、center。(建议使用start和end代替left和right,因为前两者的意思更稳妥,能同时适合从左到右和从右到左的显示的语言)
textBaseLine:表示文本的基线:可能的值有:top、hanging、middle、alphabetical、ideographic、bottom
2d上下文还提供了辅助确定文本大小的方法measureText(),这个方法接收一个参数,即要绘制的文本,返回一个对象,该对象目前只有一个width属性
看一个实例,让文字在画布上居中显示
var oC =document.getElementById('c1');
if(oC.getConext){
var oGC = oC.getContext('2d');
}
oGC.font = '60px impact';
oGC.textBaseline = 'top'; //middle bottom
var w = oGC.measureText('妙味课堂').width;//计算文字的宽度
oGC.fillText('妙味课堂',(oC.width - w)/2,(oC.height - 60)/2);//让文字在画布上居中显示
变换:
方法有:rotate(angle):围绕原点旋转图像angle弧度
translate(x,y):将坐标原点移动到(x,y),执行这个变换后,执行这个变换后,坐标(0,0)会变成之前有(x,y)表示的点
scale(x,y)缩放图像,在x方向上乘以x,在y方向上乘以y,x和y的默认值都是1.0
看个例子,让矩形在一点放大旋转,缩小旋转
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style>
body{ background:black;}
#c1{ background:white;}
</style>
<script>
window.onload = function(){
var oC = document.getElementById('c1');
if(oC.context){
var oGC = oC.getContext('2d');
}
var num = 0;
var num2 = 0;
var value = 1;
setInterval(function(){
num++;
oGC.save();
oGC.clearRect(0,0,oC.width,oC.height);
oGC.translate(100,100);//移动坐标原点到(100,100),控制坐标原点一直在初始位置
if(num2 == 100){
value = -1;
}
else if(num2 == 0){
value = 1;
}
num2 += value;
oGC.scale( num2*1/50,num2*1/50 );//控制图像的放大和缩小
oGC.rotate(num*Math.PI/180);//控制矩形的旋转
oGC.translate(-50,-50);//变化坐标原点,让旋转围绕矩形中心点旋转
oGC.fillRect(0,0,100,100);
oGC.restore();
},30);
};
</script>
</head>
<body>
<canvas width="400" height="400"></canvas>
</body>
</html>
绘制图像
2d绘图上下文内置了对图像的支持。如果想要把一幅图像绘制画布中,可以使用drawImage()方法,。根据期望的最终结果不同,调用这个方法时,可以使用三种不同的参数组合。最简单的方式是传入一个HTML<img>元素,以及绘制该图像的起点坐标(x,y),如果想要改变绘制后图像的大小,可以再多传入两个参数,分别表示目标宽度和高度。除了上述两种方式,还可以选择把图像中的某个区域绘制到上下文中。drawImage()方法的这种调用总共需要传入9个参数(要绘制的图像、源图像的坐标,宽高目标图像的坐标和宽高)
var img = doxument.images[0];
oC.drawImage(img,0,0,40,40,0,100,40,60);
阴影:
属性有:shadowColor:用css3颜色格式表示的阴影颜色,默认为黑色
shadowOffsetX:形状或路径x轴方向的阴影偏移量,默认为0
shadowOffsetY:形状或路径y轴方向的阴影偏移量,默认为0
shadowBlur:模糊的像素数,默认为0,即不模糊
<script>
var oC = document.getElementById('c');
if(oC.getContext){
var oGc = oC.getContext('2d');
oGc.shadowColor = 'brown';
oGc.shadowOffsetX = 6;
oGc.shadowBlur = 4;
oGc.fillStyle = 'red';
oGc.fillRect(100,100,50,50);
}
</script>
渐变:
哟啊创建一个新的线性渐变,可以调用createLinearGrandient()方法。这个方法接收四个参数:起点的x坐标,起点的y坐标,终点的x坐标,终点的y坐标。调用这个方法后,它就会创建一个指定大小的渐变,并返回CanvasGradient对象实例
创建了渐变对象后,就可以使用addColorStop()方法来指定色标的颜色。这个方法接收两个参数:色标位置和CSS颜色值(色标位置是一个0-1之间的数字)(和css3中的渐变有木有很相似)
当然还可以创建径向渐变,可以使用createRaidalGradient()方法,这个方法接受六个参数,对应着两个圆的圆心和半径,前三个参数指定的是起点圆的圆心和半径,后三个指定的是终点圆的圆心和半径
var oC =document.getElementById('c1');
var oGC = oC.getContext('2d');
var obj = oGC.createRadialGradient(200,200,100,200,200,150);
obj.addColorStop(0,'red');
obj.addColorStop(0.5,'yellow');
obj.addColorStop(1,'blue');
oGC.fillStyle = obj;
oGC.fillRect(0,0,oC.width,oC.height);
模式:
模式其实就是重复的图像,可以用来填充或者描边图形。要创建一个新模式,可以调用createPattern()方法并传入两个参数:一个HTML<img>元素和一个表示如何重复图像的字符串。第二个参数的属性值有:repeat、repeat-x、repeat-y、no-repeat(该方法的第一个参数也可以是一个video)元素,或者另一个canvas元素
var oC = document.getElementById('c');
if(oC.getContext){
var oGc = oC.getContext('2d');
var Img = new Image();
Img.onload = function(){
draw(this);
}
Img.src = '2.jpg';
function draw(){
var bg = oGc.createPattern(obj,'repeat');
oGc.fillStyle = bg;
oGc.fillRect(0,0,200,200);
}
}
使用图像数据
2d上下文一个明显的长处就是,可以通过getImageDate()取得原始图像数据。这个方法接收四个参数,要去的其数据的画面区域的x和y坐标以及该区域的像素宽度和高度
var oImg = oGC.getImageData(10,5,50,50)
这里返回的对象是oImg实例,每个oImg对象都有三个属性:width、height和data.其中data属性是一个数组。保存着每一个像素。在data数组中,每一个像素用4个元素来保存,分别表示红、绿、蓝和透明度的值。数组中的每一个元素的值都介于0-255之间。能够直接访问到原始图像数据,就能够以各种方式操作这些数据
还有一个createImageData(w,h):生成新的像素矩阵,初始值是全透明的黑色。可以接收两个参数,代表宽和高
putImageData(oImg,x,y):设置新的图像数据添加到画布上,接收三个参数:图像对象,坐标
看一个例子:像素点字(这个例子我的博客上写过,此处就不再详细的说了)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style>
body{ background:black; color:white; font-size:30px;}
#c1{ background:white;}
</style>
<script>
window.onload = function(){
var oC = document.getElementById('c1');
var oGC = oC.getContext('2d');
var aLi = document.getElementsByTagName('li');
for(var i=0;i<aLi.length;i++){
aLi[i].onclick = function(){
var str = this.innerHTML;
var h = 180;
var timer = null;
clearInterval(timer);
var iNow = 0;
oGC.clearRect(0,0,oC.width,oC.height);
oGC.font = h + 'px impact';
oGC.textBaseline = 'top';
oGC.fillStyle = 'red';
var w = oGC.measureText(str).width;
oGC.fillText(str,(oC.width - w)/2,(oC.height - h)/2);
var oImg = oGC.getImageData((oC.width - w)/2,(oC.height - h)/2,w,h);
oGC.clearRect(0,0,oC.width,oC.height);
var arr = randomArr(w*h,w*h/10);
var newImg = oGC.createImageData(w,h);
timer = setInterval(function(){
for(var i=0;i<arr[iNow].length;i++){
newImg.data[4*arr[iNow][i]] = oImg.data[4*arr[iNow][i]];
newImg.data[4*arr[iNow][i]+1] = oImg.data[4*arr[iNow][i]+1];
newImg.data[4*arr[iNow][i]+2] = oImg.data[4*arr[iNow][i]+2];
newImg.data[4*arr[iNow][i]+3] = oImg.data[4*arr[iNow][i]+3];
}
oGC.putImageData(newImg,(oC.width - w)/2,(oC.height - h)/2);
if(iNow == 9){
iNow = 0;
clearInterval(timer);
}
else{
iNow++;
}
},200);
};
}
function randomArr(iAll,iNow){
var arr = [];
var allArr = [];
for(var i=0;i<iAll;i++){
arr.push(i);
}
for(var j=0;j<iAll/iNow;j++){
var newArr = [];
for(var i=0;i<iNow;i++){
newArr.push( arr.splice( Math.floor(Math.random()*arr.length) ,1) );
}
allArr.push(newArr);
}
return allArr;
}
};
</script>
</head>
<body>
<canvas width="400" height="400"></canvas>
<ul style="float:left;">
<li>妙</li>
<li>味</li>
<li>课</li>
<li>堂</li>
</ul>
</body>
</html>
合成:globalAlpha和globalCompositionOperation
globalAlpha是一个介于0和1之间的值,用于指定所有绘制的透明度。默认值为0
globalCompositionOperation表示后绘制的图形怎样与先绘制的图形结合,这个属性的值是字符串,可能的值如下:
source-over(默认值):后绘制的图形位于先绘制的图形上方
source-in:后绘制的图形与先绘制的图形重叠部分可见,两者其他部分完全透明
source-out:后绘制的图形与先绘制的图形不重叠部分可见,先绘制的图形完全透明
source-atop:后绘制的图形与先绘制的图形重叠部分可见,先绘制的图形不受影响
destination-over:后绘制的图形位于先绘制的图形下方,只有之前透明像素下的部分可见
destination-in:后绘制的图形位于先绘制的图形下方,两者不重叠的部分完全透明
destination-out:后绘制的图形擦除与先绘制的图形重叠的部分
destination-atop:后绘制的图形位于先绘制的图形下方,在两者不重叠的地方,先绘制的图形会变透明
lighter:后绘制的图形与县绘制的图形重叠部分相加,使该部分变亮
copy:后绘制的图形玩去替代与之重叠的县绘制图形
xor:后悔值的图形与先绘制的图形重叠部分执行“异或”操作。
var oImg = document.getElementById('img1');
var oC = document.getElementById('c1');
var oGC = oC.getContext('2d');
oGC.fillRect(0,0,100,100);
oGC.fillStyle = 'red';
oGC.globalCompositeOperation = 'xor';
oGC.fillRect(50,50,100,100);
//alert( oC.toDataURL() );
oImg.src = oC.toDataURL();
这里我们还用到了toDataURL()方法,可以导出canvas元素上绘制的图像,这个方法接收一个参数,即图像的MIME类型格式(默认情况下浏览器会将图像编码为png格式,但这个方法不能兼容一些低版本的浏览器),而且适合用于创建图像的任何上下文。
嗯,好像前面还有一个问题没解决,就是把canvas的宽高设置在行间和设置在style样式中有什么区别,嗯,我们先看个例子
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body{background:black;}
canvas{background:#fff;}
#c2{width:200px; height:200px;}
</style>
</head>
<body>
<canvas width="200" height="200"><span>该浏览器不支持canvas</span></canvas>
<canvas ><span>该浏览器不支持canvas</span></canvas>
<script>
var oC1 = document.getElementById('c1');
var oC2= document.getElementById('c2');
if(oC1.getContext){
var oGc1 = oC1.getContext('2d');
oGc1.fillStyle = 'red';
oGc1.fillRect(0,0,100,100);
var oGc2 = oC2.getContext('2d');
oGc2.fillStyle = 'red';
oGc2.fillRect(0,0,100,100);
}
</script>
</body>
</html>
从这段代码中,我们能看到两个画布除了一个宽高是在行间设置一个是在style中设置,其他的都一样,那我们看下面的显示效果
咿呀,为什么明明都设置的是宽200px,高200px,两个怎么就不一样呢?
其实这是因为,canvas的默认宽高为宽300px;高150px;当我们在行间设置画布宽高的时候,我们在画布上绘制图形的时候不会有任何影响,但如果我们在style中设置画布的宽高的时候,当我们去在画布上绘制图形的时候,绘制的图形会按我们在style中设置的宽高比上默认的宽高乘以自身的宽高,才是它在画布上的宽高。所以我们在对画布设置宽高的时候尽量在行间设置。
嗯,文字不好表述,直接上公式呗
图形的实际宽/高 = 我们为图形设置的宽(高) *(我们在style样式中为画布设置的宽(高)/画布的默认宽(高))
OK,终于整理完毕