HTML5移动开发学习笔记之Canvas基础
1.第一个Canvas程序
看的是HTML5移动开发即学即用这本书,首先学习Canvas基础,废话不多说,直接看第一个例子。
效果图为:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 </body> 18 <script type="text/javascript"> 19 //canvas对象的取得 20 var canvas=document.getElementById("c1"); 21 //取得绘图用的上下文对象 22 var ctx=canvas.getContext("2d"); 23 //绘图处理 24 ctx.fillStyle="rgb(255,0,0)"; 25 ctx.fillRect(50,50,200,200); 26 ctx.fillStyle="rgba(0,0,255,0.5)"; 27 ctx.fillRect(100,100,200,200); 28 <!--alert("hello");--> 29 </script> 30 </html>
知识点:
Canvas 的基本用法
1)取得Canvas对象
2)从Canvas对象中获取绘图用的上下文
3)使用上下文中的方法与属性进行绘图
颜色的指定方法
1)ctx.fillStyle="#FF0000";
2)ctx.fillStyle="rgb(255,0,0)";
3)ctx.fillStyle="rgba(0,0,255,0.5)"; 最后这个指透明度的。。。
2.路径
绘制一个简单的三角形,效果:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 </body> 18 <script type="text/javascript"> 19 //canvas对象的取得 20 var canvas=document.getElementById("c1"); 21 //取得绘图用的上下文对象 22 var ctx=canvas.getContext("2d"); 23 //路径绘制开始 24 ctx.beginPath(); 25 //路径的绘制 26 ctx.moveTo(0,0); 27 ctx.lineTo(0,290); 28 ctx.lineTo(290,290); 29 //路径绘制结束 30 ctx.closePath(); 31 //进行绘图处理 32 ctx.fillStyle="rgb(200,0,0)" 33 ctx.fill(); 34 <!--alert("hello");--> 35 </script> 36 </html>
知识点:
控制路径时使用的方法:
1) beginPath() 重置路径的开始
2) closePath() 关闭到现在为止的路径
3) moveTo() 指定绘图开始时的基点(x,y)
4) lineTo() 绘制从前一次绘图位置到(x,y)的直线
绘制路径时使用的方法:
1)stroke() 绘制路径
2)fill()填充路径
指定绘图样式时使用的属性
1)fillStyle 指定填充时使用的颜色与样式
2)strokeStyle 指定路径的线颜色与样式
3)lineWidth 指定路径线的粗细
下面制作一个当用户触摸屏幕时在触摸位置绘制三角形的实例程序 (书上的是用户触摸屏幕时绘制,现在改一下,鼠标移动时在移动的位置绘制三角形)效果:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <meta name="viewport" content="width=320,user-scalable=no" /> 6 <style type="text/css"> 7 canvas { 8 border-width: 5px; 9 border-style: dashed; 10 border-color: rgba(20, 126, 239, 0.50) 11 } 12 </style> 13 14 </head> 15 <body> 16 hello HTML5! 17 <canvas id="c1" width="300" height="300" ></canvas> 18 </body> 19 20 <script type="text/javascript"> 21 22 function getPointOnCanvas(canvas, x, y) { 23 var bbox = canvas.getBoundingClientRect(); 24 return { x: x - bbox.left * (canvas.width / bbox.width), 25 y: y - bbox.top * (canvas.height / bbox.height)}; 26 } 27 //canvas对象的取得 28 var canvas=document.getElementById("c1"); 29 //取得绘图用的上下文对象 30 var ctx=canvas.getContext("2d"); 31 //设置Canvas的onmouse事件 32 canvas.onmousemove=function(event) 33 { 34 //取得鼠标移动处的坐标 35 var x=event.pageX; 36 var y=event.pageY; 37 var canvas=event.target; 38 var loc=getPointOnCanvas(canvas,x,y); 39 console.log("mouse down at point(x:"+loc.x+",y:"+loc.y+")"); 40 41 var r=Math.random()*10+25; 42 //路径指定 43 44 ctx.beginPath(); 45 ctx.moveTo(loc.x,loc.y); 46 ctx.lineTo(loc.x,loc.y+r); 47 ctx.lineTo(loc.x+r,loc.y+r); 48 ctx.lineTo(loc.x,loc.y); 49 50 //绘图 51 ctx.strokeStyle="red"; 52 ctx.stroke(); 53 }; 54 </script> 55 </html>
遇到的问题,刚开始取不到鼠标移动处的坐标,借鉴了http://www.jb51.net/html5/89807.html 这里面的方法,把效果做出来了,注意console.log()的运用,看下代码运行时的效果:
3.颜色定义
这一小节感觉书上分得不太合理,我实现以下这个程序是为了熟练下JS代码
效果:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <meta name="viewport" content="width=320,user-scalable=no" /> 6 <style type="text/css"> 7 canvas { 8 border-width: 5px; 9 border-style: dashed; 10 border-color: rgba(20, 126, 239, 0.50) 11 } 12 </style> 13 <script> 14 (function(){ 15 window.addEventListener("load",function(){ 16 var ctx=document.getElementById("c1").getContext("2d"); 17 //圆1 18 ctx.beginPath(); 19 ctx.arc(150,45,35,0,Math.PI*2,false); 20 ctx.fillStyle='rgba(192,80,77,0.7)'; 21 ctx.fill(); 22 ctx.strokeStyle='rgba(192,80,77,1)'; 23 ctx.stroke(); 24 25 //圆2 26 ctx.beginPath(); 27 ctx.arc(125,95,35,0,Math.PI*2,false); 28 ctx.fillStyle='rgba(155,187,89,0.7)'; 29 ctx.fill(); 30 ctx.strokeStyle='rgba(155,187,89,1)'; 31 ctx.stroke(); 32 33 //圆3 34 ctx.beginPath(); 35 ctx.arc(175,95,35,0,Math.PI*2,false); 36 ctx.fillStyle='rgba(128,100,162,0.7)'; 37 ctx.fill(); 38 ctx.strokeStyle='rgba(128,100,162,1)'; 39 ctx.stroke();}, false); 40 })(); 41 </script> 42 </head> 43 <body> 44 hello HTML5! 45 <canvas id="c1" width="300" height="150" ></canvas> 46 </body> 47 </html>
知识点:
1)描绘轮廓线
ctx.strokeStyle="#ff0000";
2)填充轮廓
ctx.fillStyle="#0000ff";
我自己从中练习的知识点应该是
1)匿名函数 (function(){})();的使用
2)window.addEventListener("load",function(){},false);
4.绘制方法的介绍
1) 绘制圆弧的arc()方法
arc()方法的语法如下:context.arc(x,y,半径,开始角度,结束角度,是否逆时针旋转);
从指定的开始角度开始至结束角度为止,按指定方向进行圆弧绘制。最后的参数为ture时,将按逆时针旋转。角度不是“度”,而是“弧度”。
效果:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 var canvas=document.getElementById("c1"); 19 var ctx=canvas.getContext("2d"); 20 21 //使用颜色填充矩形 22 ctx.fillStyle="#f00ff0"; 23 ctx.fillRect(0,0,300,300); 24 //描绘圆弧 25 //路径开始 26 ctx.beginPath(); 27 var startAngle=0; 28 var endAngle=120*Math.PI/180; 29 ctx.arc(100,100,100,startAngle,endAngle,false); 30 31 //绘制处理 32 ctx.strokeStyle="#ff0000"; 33 ctx.lineWidth=3; 34 ctx.stroke(); 35 </script> 36 </body> 37 </html>
写完后对arc()方法了解多一点了。x,y是圆心的坐标,现在可以想象得出是怎样画出来的。。。
2)绘制圆弧的arcTo()方法
arcTo()方法的语法如下:
context.arcTo(x1,y1,x2,y2,半径);
此方法的功能是,从路径的起点和终点分别向坐标(x1,y1)、(x2,y2)绘制直线后,在绘制指定半径的圆弧。
效果:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 var canvas=document.getElementById("c1"); 19 var ctx=canvas.getContext("2d"); 20 21 //使用颜色填充矩形 22 ctx.fillStyle="#f00ff0"; 23 ctx.fillRect(0,0,300,300); 24 //描绘圆弧 25 //路径开始 26 ctx.beginPath(); 27 ctx.moveTo(20,20); 28 ctx.arcTo(290,150,100,280,100); 29 ctx.lineTo(20,280); 30 31 //绘制处理 32 ctx.strokeStyle="#ff0000"; 33 ctx.lineWidth=3; 34 ctx.stroke(); 35 </script> 36 </body> 37 </html>
自己改了下坐标,效果加深对这个方法的理解。。。
3)quadraticCurveTo()与bezierCurveTo()方法
① quadraticCurveTo()方法用于绘制二元抛物线,其语法格式如下。
context.quadraticCurveTo(cpx,cpy,x,y);
绘制由最后指定的位置开始至坐标(x,y)的曲线。此时,使用控制点为(cpx,cpy)的二元抛物线进行连接,并将位置(x,y)追加到路径中。
② bezierCurveTo()方法用于绘制三元抛物线,语法格式为:
bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y);
绘制由最后指定路径位置至指定位置的曲线。此时,使用控制点分别为(cp1x,cp1y),(cp2x,cp2y)的三元抛物线进行连接,并将位置(x,y)追加到路径中,具体示意图:(qq上对图片的修饰似乎还不够熟练。。。)
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 var canvas=document.getElementById("c1"); 19 var ctx=canvas.getContext("2d"); 20 21 //使用颜色填充矩形 22 ctx.fillStyle="#f00ff0"; 23 ctx.fillRect(0,0,300,300); 24 //描绘圆弧 25 //路径开始 26 ctx.beginPath(); 27 ctx.moveTo(20,20); 28 ctx.bezierCurveTo(100,280,180,280,280,20); 29 30 31 //绘制处理 32 ctx.strokeStyle="#ff0000"; 33 ctx.lineWidth=3; 34 ctx.stroke(); 35 </script> 36 </body> 37 </html>
4)绘制矩形的rect()方法
语法格式如下:context.rect(x,y,宽度,高度); x,y为矩形左上角坐标
除此之外,Canvas中还提供了三种特定的矩形绘制方法;
① context.strokeRect(x,y,w,h) 绘制矩形的轮廓
② context.fillRect(x,y,w,h) 填充矩形
③ context.clearRect(x,y,w,h) 清空矩形
这个比较好理解就不做效果演示及代码。
5.绘制渐变效果
线性渐变与圆形渐变
线性渐变就是从左至右(或自上而下)依次显示逐渐变化的颜色。而圆形渐变自圆心向外围逐渐显示变化的颜色。
1)线性渐变
指定线性渐变时使用createLinearGradient()方法,具体语法如下:
//先创建CanvasGradient对象: CanvasGradient=context.createLinearGradient(x1,y1,x2,y2); 表示由位置(x1,y1)至位置(x2,y2)显示渐变效果
//然后追加渐变颜色:CanvasGradient.addColorStop(颜色开始的相对位置,颜色); 指定渐变中使用的颜色,第一个参数(开始相对位置)中指定一个数字,从而决定什么位置使用什么颜色。
举个栗子:
代码为:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 var canvas=document.getElementById("c1"); 19 var ctx=canvas.getContext("2d"); 20 21 //绘图 22 var g=ctx.createLinearGradient(0,0,300,0); 23 g.addColorStop(0,"rgb(255,0,0)"); //开始位置设置为红色 24 g.addColorStop(1,"rgb(255,255,0)"); //黄色 25 ctx.fillStyle=g; 26 ctx.fillRect(20,20,260,260); 27 </script> 28 </body> 29 </html>
2)圆形渐变
绘制圆形渐变时,使用createRadialGradient()方法创建对象,同样使用addColorStop()方法追加渐变颜色。具体语法如下
//创建CanvasGradient对象 CanvasGradient=context.createRadialGradient(x1,y1,r1,x2,y2,r2); 通过参数指定以(x1,y1)为圆心,半径为r1的圆到以(x2,y2)为圆心,半径为r2的圆的渐变效果
// 追加渐变颜色 CanvasGradient.addColorStop(颜色开始的相对位置,颜色);
举个栗子
代码为:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 var canvas=document.getElementById("c1"); 19 var ctx=canvas.getContext("2d"); 20 21 //绘图 22 var g=ctx.createRadialGradient(150,150,50,150,150,100); 23 g.addColorStop(0.3,"red"); //开始位置设置为红色 24 g.addColorStop(0.7,"yellow"); 25 g.addColorStop(1.0,"blue"); //黄色 26 ctx.fillStyle=g; 27 ctx.fillRect(20,20,260,260); 28 </script> 29 </body> 30 </html>
6.绘制图像
Canvas 中的图像绘制
图像绘制的基本步骤如下:
1)读取图像文件
2)在Canvas中进行绘制
图像读取前,首先创建Image对象,在Image对象的src属性中指定图像文件所在路径后就可以读取了。读取结束后,触发onload事件,基本语法如下:
var image=new Image();
image.src="图像文件路径";
image.onload=function(){//图像读取时的处理}
使用Canvas上下文中的drawImage()方法将读取后的Image对象绘制在Canvas上,实际上是将Image对象中的图像数据输出到Canvas中。有三种drawImage()方法用于图像的绘制
①直接绘制 context.drawImage(image,dx,dy)
②尺寸修改(resize) context.drawImage(image,dx,dy,dw,dh)
③图像截取 context.drawImage()
第①种方法直接将读取的图像绘制在坐标(dx,dy)处。第②种方法按照新的宽度dw与高度dh将图像绘制在坐标(dx,dy)处。第③种方法是将原图像的一部分截取出后再按指定尺寸绘制在Canvas上,从原图像的坐标(sx,sy)开始截取宽(sw),高(sh)的部分图像,然后绘制在Canvas上的坐标(dx,dy)处,宽度为dw,高度为dh。
像素处理
Canvas与SVG以及Flash稍有不同,绘制的图形/图像并不能作为对象操作。也就是说使用stroke()或者fill()方法绘制的图形,既不能移动它也不能删除它。如果想操作绘制的图形/图像,使用SVG或者Flash实现比使用Canvas要好。
Canvas中绘制的图形/图像作为一个整体的位图保存,因此可以访问各个像素信息。也就是说,可以使用JavaScript处理Canvas上绘制的图像像素信息。这是Canvas的一个特色
1)像素处理的API
imagedata=ctx.getImageData(sx,sy,sw,sh) 返回以(sx,sy)为左上顶点,宽为sw,高为sh的矩形图像-imagedata对象。
ctx.putImageData(imagedata,dx,dy) 将imagedata所表示的图像绘制在顶点坐标为(dx,dy)处。
简述之,使用getImageData()方法取出Canvas上图像的像素数据,通过JavaScript加工过这些像素数据后,使用putImageData方法,重新绘制到Canvas中。
ImageData对象是代表图像像素数据的对象。此对象定义了三种属性:
①imagedata.width 图像数据的宽度
②imagedata.height 图像数据的高度
③imagedata.data 图像数据(CanvasPixelArray类型)
在JavaScript中进行像素数据读取,并进行加工与输出时的具体操作是,从imagedata.data中得到CanvasPixelArray类型的对象。此对象是保存像素信息的一元数组。但是与JavaScript的Array对象不同,不可对其进行与通常数组一样的操作。
举个栗子:(本例中,当用户将桌面上的图像文件拖动到浏览器中后,首先读取图像文件并在浏览器中显示,接着对图像进行黑白变换,在原图的旁边显示变换后的图像)
用户将桌面上的图像文件拖动到浏览器中的界面:
进行黑白变换后的效果:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 body{ 7 font-family:宋体,Arial,Helvetica,sans-serif; 8 font-size:80%; 9 } 10 #dp{ 11 width:200px; 12 min-height:70px; 13 border:1px solid #000000; 14 background-color:#eeeeee; 15 padding:len; 16 margin:2em; 17 } 18 #dp img{ 19 margin-right:lem; 20 } 21 </style> 22 <script> 23 (function(){ 24 25 //拖动区域的div元素 26 var dp=null; 27 //FileReader接口对象 28 var reader=null; 29 30 //页面导入时的处理 31 window.addEventListener("load",function(){ 32 //获取拖动区域的div元素 33 dp=document.getElementById("dp"); 34 //设置dragover事件的事件侦听 35 dp.addEventListener("dragover",function(evt){ 36 evt.preventDefault();},false); 37 //设置drop事件的事件侦听 38 dp.addEventListener("drop",function(evt){ 39 evt.preventDefault(); 40 file_droped(evt);},false); 41 },false); 42 43 //文件被拖入时的处理 44 function file_droped(evt) 45 { 46 //清空显示区域 47 while(dp.firstChild) 48 { 49 dp.removeChild(dp.firstChild); 50 } 51 //拖动文件的File接口对象 52 var file=evt.dataTransfer.files[0]; 53 //FileReader接口对象 54 reader=new FileReader(); 55 //非图像文件画像时报错 56 if(!/^image/.test(file.type)){alert("请拖入图像文件");} 57 //导入拖入图像 58 reader.readAsDataURL(file); 59 reader.onload=prepare_image; 60 } 61 62 //显示拖入图像文件 63 function prepare_image(evt) 64 { 65 //创建img元素,显示拖入的图像 66 var image=document.createElement("img"); 67 image.setAttribute("src",reader.result); 68 dp.appendChild(image); 69 //img元素中导入图像文档后进行后续处理 70 image.onload=function(){ 71 //获取图像的尺寸 72 var w=parseInt(image.width); 73 var h=parseInt(image.height); 74 //创建canvas对象,导入图像 75 var canvas=document.createElement("canvas"); 76 canvas.width=w; 77 canvas.height=h; 78 var ctx=canvas.getContext("2d"); 79 ctx.drawImage(image,0,0); 80 //取得canvas像素数据 81 var imagedata=ctx.getImageData(0,0,w,h); 82 83 //进行黑白转换 84 convert_image_to_gray_scale(imagedata.data); 85 86 //替换canvas中的像素数据 87 ctx.putImageData(imagedata,0,0); 88 89 //显示canvas 90 dp.appendChild(canvas); 91 } 92 } 93 94 //黑白变换函数 95 function convert_image_to_gray_scale(data) 96 { 97 var len=data.length; 98 var pixels=len/4; 99 for(var i=0;i<pixels;i++){ 100 //取出R,G,B值 101 var r=data[i*4]; 102 var g=data[i*4+1]; 103 var b=data[i*4+2]; 104 105 //进行黑白变换 106 var t=parseInt((11*r+16*g+5*b)/32); 107 //将变换后的像素数据设置到原来数组元素中 108 data[i*4]=t; 109 data[i*4+1]=t; 110 data[i*4+2]=t; 111 } 112 } 113 114 })(); 115 </script> 116 117 </head> 118 <body> 119 <div id="dp"> 120 <p>将桌面图像文件拖动到此处。</p> 121 </div> 122 </body> 123 </html>
7.绘制数据图表
1)绘制方格图
绘制方格图是为了最终绘制折线数据图表做准备的,方格将作为折线图的基准线。绘制方格图的逻辑很简单,只要在Canvas上绘制一系列的横线和竖线。
效果:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 //获取上下文 19 var canvas=document.getElementById("c1"); 20 var ctx=canvas.getContext("2d"); 21 22 //描绘背景 23 var gradient=ctx.createLinearGradient(0,0,0,300); 24 gradient.addColorStop(0,"#e0e0e0"); 25 gradient.addColorStop(1,"#ffffff"); 26 ctx.fillStyle=gradient; 27 ctx.fillRect(0,0,canvas.width,canvas.height); 28 29 //描绘边框 30 var grid_cols=10; 31 var grid_rows=10; 32 var cell_height=canvas.height/grid_rows; 33 var cell_width=canvas.width/grid_cols; 34 ctx.lineWidth=1; 35 ctx.strokeStyle="#a0a0a0"; 36 37 ctx.beginPath(); 38 39 //准备画竖线 40 for( var col=0;col<=grid_cols;col++) 41 { 42 var x=col*cell_width; 43 ctx.moveTo(x,0); 44 ctx.lineTo(x,canvas.height); 45 } 46 47 //准备画横线 48 for( var row=0;row<=grid_rows;row++) 49 { 50 var y=row*cell_height; 51 ctx.moveTo(0,y); 52 ctx.lineTo(canvas.width,y); 53 } 54 55 //完成描绘 56 ctx.stroke(); 57 </script> 58 </body> 59 </html>
接着我们在方格图中追加绘制数据图表,此处用到的数据为某种商品12个月内的销售数量,涉及的实例数据如下:
1月 | 2月 | 3月 | 4月 | 5月 | 6月 | 7月 | 8月 | 9月 | 10月 | 11月 | 12月 |
80 | 92 | 104 | 110 | 68 | 50 | 45 | 90 | 74 | 68 | 98 | 103 |
效果图为:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 //获取上下文 19 var canvas=document.getElementById("c1"); 20 var ctx=canvas.getContext("2d"); 21 22 //定义图表数据 23 var uriage=[80,92,104,110,68,50,45,90,74,68,98,103]; 24 25 //描绘背景 26 var gradient=ctx.createLinearGradient(0,0,0,300); 27 gradient.addColorStop(0,"#e0e0e0"); 28 gradient.addColorStop(1,"#ffffff"); 29 ctx.fillStyle=gradient; 30 ctx.fillRect(0,0,canvas.width,canvas.height); 31 32 //描绘边框 33 var grid_cols=uriage.length+1; 34 var grid_rows=4; 35 var cell_height=canvas.height/grid_rows; 36 var cell_width=canvas.width/grid_cols; 37 38 ctx.beginPath(); 39 40 //准备画竖线 41 for( var col=0;col<=grid_cols;col++) 42 { 43 var x=col*cell_width; 44 ctx.moveTo(x,0); 45 ctx.lineTo(x,canvas.height); 46 } 47 48 //准备画横线 49 for( var row=0;row<=grid_rows;row++) 50 { 51 var y=row*cell_height; 52 ctx.moveTo(0,y); 53 ctx.lineTo(canvas.width,y); 54 } 55 56 //完成描绘 57 ctx.lineWidth=1; 58 ctx.strokeStyle="#a0a0a0"; 59 ctx.stroke(); 60 61 //获取数据中最大值 62 var max_v=0; 63 for(var i=0;i<uriage.length;i++) 64 { 65 if(uriage[i]>max_v) 66 max_v=uriage[i]; 67 } 68 //为了能让最大值容纳在图表内,计算坐标 69 max_v=max_v*1.1; 70 //将数据换算为坐标 71 var points=[]; 72 for(var i=0;i<uriage.length;i++) 73 { 74 var v=uriage[i]; 75 var px=cell_width*(i+1); 76 var py=canvas.height-canvas.height*(v/max_v); 77 points.push({"x":px,"y":py}); 78 } 79 //描绘折线 80 ctx.beginPath(); 81 ctx.moveTo(points[0].x,points[0].y); 82 for(var i=1;i<points.length;i++) 83 { 84 ctx.lineTo(points[i].x,points[i].y); 85 } 86 ctx.lineWidth=2; 87 ctx.strokeStyle="#ee0000"; 88 ctx.stroke(); 89 90 //绘制坐标图形 91 for(var i in points) 92 { 93 var p=points[i]; 94 ctx.beginPath(); 95 ctx.arc(p.x,p.y,6,0,2*Math.PI); 96 ctx.fillStyle="#ee0000"; 97 ctx.fill(); 98 } 99 </script> 100 </body> 101 </html>
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 <script> 13 (function(){ 14 //canvas元素对象 15 var canvas=null; 16 //canvas的2D上下文 17 var ctx=null; 18 //canvas的尺寸 19 var cw=0; 20 var ch=0; 21 22 //页面导入时的事件处理 23 window.addEventListener("load",function(){ 24 //canvas元素的对象 25 canvas=document.getElementById("c1"); 26 //canvas的2D上下文 27 ctx=canvas.getContext("2d"); 28 // 获取canvas的尺寸 29 cw=parseInt(canvas.width); 30 ch=parseInt(canvas.height); 31 //将坐标平面向右下移动 32 ctx.translate(cw/2,ch/2); 33 //绘制时钟 34 draw_watch(); 35 } 36 ,false); 37 38 function draw_watch() 39 { 40 //清空Canvas 41 ctx.clearRect(-cw/2,-ch/2,cw,ch); 42 //计算针的最大长度 43 var len=Math.min(cw,ch)/2; 44 //绘制刻度盘 45 var tlen=len*0.85; 46 ctx.font="14px 'Arial'"; 47 ctx.fillStyle="black"; 48 ctx.textAlign="center"; 49 ctx.textBaseline="middle"; 50 for(var i=0;i<12;i++) 51 { 52 var tag1=Math.PI*2*(3-i)/12; 53 var tx=tlen*Math.cos(tag1); 54 var ty=-tlen*Math.sin(tag1); 55 ctx.fillText(i,tx,ty); 56 } 57 58 //获取当前时刻的时,分,秒 59 var d=new Date(); 60 var h=d.getHours(); 61 var m=d.getMinutes(); 62 var s=d.getSeconds(); 63 if(h>12) 64 {h=h-12;} 65 //绘制时针,短 66 var angle1=Math.PI*2*(3-(h+m/60))/12; 67 var length1=len*0.5; 68 var width1=5; 69 var color1="#000000"; 70 drawhand(angle1,length1,width1,color1); 71 //绘制分针,长 72 var angle2=Math.PI*2*(15-(m+s/60))/60; 73 var length2=len*0.5; 74 var width2=5; 75 var color2="#000000"; 76 drawhand(angle2,length2,width2,color2); 77 //绘制秒针 78 var angle3=Math.PI*2*(15-s)/60; 79 var length3=len*0.5; 80 var width3=5; 81 var color3="#000000"; 82 drawhand(angle3,length3,width3,color3); 83 84 //设置timer 85 setTimeout(draw_watch,1000); 86 } 87 88 //针绘制函数 89 function drawhand(angle,len,width,color) 90 { 91 //计算针端的坐标 92 var x=len*Math.cos(angle); 93 var y=-len*Math.sin(angle); 94 95 //绘制针 96 ctx.strokeStyle=color; //设置颜色 97 ctx.lineWidth=width; //设置线的粗细 98 ctx.lineCap="round";//将针尖设置为圆形 99 ctx.beginPath(); 100 ctx.moveTo(0,0); 101 ctx.lineTo(x,y); 102 ctx.stroke(); 103 } 104 })(); 105 </script> 106 </head> 107 <body> 108 hello HTML5! 109 <canvas id="c1" width="300" height="300" ></canvas> 110 </body> 111 </html>
代码解释: 首先看页面导入时的事件处理代码: window.addEventListener("load",function() { ... //将坐标平面向右下移动 ctx.translate(cw/2,ch/2); //绘制时钟 draw_watch(); },false); 上述代码中,使用translate()方法将绘图基点移动到Canvas的中心(向右移动一半宽度距离,向下移动一半高度距离)。后面进行绘图处理时,坐标(0,0)就变成Canvas的中心,将大大简化时钟坐标的计算。(巧妙之处) 再看下draw_watch()函数 第一行是清空Canvas区域,因为程序中将每隔1秒钟重新绘制整个模拟时针,以实现动态时针的动画效果,如果不清空,上次的秒针将一直被保留 ctx.clearRect(-cw/2,-ch/2,cw,ch); clearRect()方法的参数依次为区域左上角x,y坐标,区域宽度,区域高度。因为坐标平面已经移动,所以作为基点的左上角的坐标变成(-cw/2,-ch/2) 然后是,绘制刻度盘的代码 for(var i=0;i<12;i++) { var tag1=Math.PI*2*(3-i)/12; var tx=tlen*Math.cos(tag1); var ty=-tlen*Math.sin(tag1); ctx.fillText(i,tx,ty); } 从0时到11时的时刻数字由fillText()完成绘制 这里终点关注坐标的计算,因中心坐标是(0,0),所以只要确定好角度和半径,就可以计算出各个时刻的坐标来(注意在刻度盘数字3的位置的角度是0度) 所以这个计算公式 var angle1=Math.PI*2*(3-(h+m/60))/12;也就好理解了。同理分针和秒针也一样。 然后要完成没过1秒要更新的效果,这时用到定时函数setTimeout(draw_watch,1000);表示每过一秒钟循环调用draw_watch函数自身。
2)变形的保存于恢复
① 变形的保存与恢复的方法save()与restore()的语法格式如下
context.save();
context.restore();
这两种方法都是基于同一堆栈(stack)构造。调用save()方法后,将变形结果保存于堆栈顶端,调用restore()方法后,从堆栈顶端取出上次保存的结果用于恢复。
看一个栗子,结合了save(),restore(),及rotate()方法
效果:
代码如下:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 //获取上下文 19 var canvas=document.getElementById("c1"); 20 var ctx=canvas.getContext("2d"); 21 22 23 //定义绘制矩形的方法 24 function drawRect(context,color) 25 { 26 context.fillStyle=color; 27 context.fillRect(0,0,100,30); 28 } 29 30 //定义旋转函数 31 function rorateDeg(context,deg) 32 { 33 alert(context); 34 alert(deg); 35 var rad=deg*Math.PI/180; 36 context.rotate(rad); 37 } 38 39 //绘制普通的矩形 ---1 画出第一个矩形 40 drawRect(ctx,"red"); 41 42 //指定移动、旋转后绘图 43 ctx.save(); 44 ctx.translate(100,30);//旋转基点 45 rorateDeg(ctx,45);//旋转45度 46 drawRect(ctx,"blue"); //---2 画出第二个矩形 47 ctx.restore();//恢复状态 48 49 //指定移动,旋转后绘图 50 ctx.save(); 51 ctx.translate(200,50);//旋转基点 52 rorateDeg(ctx,90);//旋转45度 53 drawRect(ctx,"green");//---3 画出第三个矩形 54 ctx.restore();//恢复状态 55 </script> 56 </body> 57 </html>
②变形矩阵
与变形矩阵相关的方法有两个,即transform()与setTransform()方法。
语法为:
setTransform(m11,m12,m21,m22,dx,dy) 变形矩阵的指定(清空先前的指定)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <img src="XiaoKeAi.jpg" width="200" height="200" alt="小可爱" id="xka"/> 17 <script type="text/javascript"> 18 (function(){ 19 //不支持window.addEventListener的浏览器不执行代码 20 if(!window.addEventListener) 21 { 22 return; 23 } 24 //Canvas对象 25 var canvas=null; 26 //canvas的上下文对象 27 var ctx=null; 28 //动画的帧率 29 var fps=60; 30 //图像对象 31 var image=null; 32 //旋转角度 33 var deg=0; 34 35 //页面导入时的事件处理 36 window.addEventListener("load",function(){ 37 //img元素 38 image=document.getElementById("xka"); 39 //图像尺寸 40 var w=parseInt(image.width); 41 var h=parseInt(image.height); 42 //创建canvas对象 43 canvas=document.createElement("canvas"); 44 canvas.width=w; 45 canvas.height=h; 46 //canvas的上下文对象 47 ctx=canvas.getContext("2d"); 48 //不支持canvas的浏览器返回 49 if(!ctx) 50 { 51 return; 52 } 53 //将图像绘制入canvas中 54 ctx.drawImage(image,0,0); 55 //用canvas替换img元素 56 image.parentNode.replaceChild(canvas,image); 57 //canvas的动画开始 58 move(); 59 } 60 ,false); 61 function move() 62 { 63 //canvas尺寸 64 var cw=parseInt(canvas.width); 65 var ch=parseInt(canvas.height); 66 //初始化变形矩阵 67 ctx.setTransform(1,0,0,1,0,0); 68 //清空canvas 69 ctx.clearRect(0,0,cw,ch); 70 //计算变形矩阵 71 var m11=Math.cos(deg*Math.PI/180); 72 var dx=(cw/2)-(cw*m11/2); 73 //变形矩阵设置 74 ctx.setTransform(m11,0,0,1,dx,0); 75 //将变形后的图像绘制入canvas中 76 ctx.drawImage(image,0,0); 77 //旋转角度递增 78 deg++; 79 deg=deg%360; 80 //使用timer定时绘制下一副图 81 setTimeout(move,1000/fps); 82 } 83 })(); 84 </script> 85 </body> 86 </html>
代码解释:
//页面导入时的事件处理
window.addEventListener("load",function(){
...
//将图像绘制入canvas中
ctx.drawImage(image,0,0);
//用canvas替换img元素
image.parentNode.replaceChild(canvas,image);
//canvas的动画开始
move();
}
,false);
首先将显示图标的img元素的根对象作为参数传递给drawImage()方法,将图像粘贴到canvas上,随后调用repalceChild()方法将img元素替换为Canvas元素。此时img元素并没有从文档中消失,img元素的跟对象可以用于绘制各桢,可以无限多次使用。
然后再看下move()函数
//初始化变形矩阵
ctx.setTransform(1,0,0,1,0,0);
//清空canvas
ctx.clearRect(0,0,cw,ch);
首先将变形矩阵恢复为默认值,這是为了下一个清空Canvas区域时便于坐标计算。
接着计算将向setTransform()方法中传入的各参数值。为了Canvas坐标平面看起来像在立体的旋转,只需要变动m11和dx即可。
var m11=Math.cos(deg*Math.PI/180);
var dx=(cw/2)-(cw*m11/2);
然后再设置
ctx.setTransform(0,1,m11,0,dx,0);
最后
//将变形后的图像绘制入canvas中
ctx.drawImage(image,0,0);
就OK啦。。。
需要连续处理所以又借助了setTimeout函数。。这个不解释了。。。
方法 | 说明 |
context.fillText(text,x,y) | 描绘文本,参数text是将要描绘的文本,参数x与y指定了描绘位置的坐标。默认情况下以描绘对象文本的左下为基准 |
context.fillText(text,x,y,maxWidth) | 描绘文本,参数maxWidth是可选的,指定数值后,文本将显示在指定的宽度内,可缩小显示。 |
context.strokeText(text,x,y) | 描绘文件的轮廓 |
context.strokeText(text,x,y,maxWidth) | 描绘文件的轮廓 |
属性 | 说明 |
context.font | 定义文本的样式。与CSS的font属性设置的内容相同 |
context.textAlign | 定义文本的对齐方式,可指定start,end,left,right,center等,水平方向的基准 |
context.textBaseline | 定义文件的基准线。可指定top,hanging(罗马字上缘),middle,alphabetic(罗马字基线),bottom,ideographic(罗马字下缘)等,垂直方向的基准 |
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="400" height="300" ></canvas> 17 <table id="tb1"> 18 <caption>会员数的变化</caption> 19 <thead> 20 <tr> 21 <th>公元</th> 22 <th>2003年</th> 23 <th>2004年</th> 24 <th>2005年</th> 25 <th>2006年</th> 26 <th>2007年</th> 27 <th>2008年</th> 28 <th>2009年</th> 29 </tr> 30 </thead> 31 <tbody> 32 <tr> 33 <th>会员数</th> 34 <th>230</th> 35 <th>360</th> 36 <th>459</th> 37 <th>654</th> 38 <th>834</th> 39 <th>956</th> 40 <th>1,085</th> 41 </tr> 42 </tbody> 43 </table> 44 45 <script type="text/javascript"> 46 (function(){ 47 //不支持window.addEventListener的浏览器不执行代码 48 if(!window.addEventListener) 49 { 50 return; 51 } 52 //Canvas对象 53 var canvas=null; 54 //canvas的上下文对象 55 var ctx=null; 56 57 //页面导入时的事件处理 58 add_event_listener(window,"load",function(){ 59 //取得canvas对象 60 var canvas=document.getElementById("c1"); 61 62 //取得table元素的根对象 63 var mytb=document.getElementById("tb1"); 64 65 //绘制图表 66 draw_graph(mytb,canvas); 67 } 68 ); 69 70 //图表绘制 71 function draw_graph(tb,canvas) 72 { 73 //获取canvas的上下文 74 var ctx=canvas.getContext("2d"); 75 76 //取得横轴的显示文字 77 var head_cells=tb.tHead.rows[0].cells; 78 79 var heads=[]; 80 for(var i=1;i<head_cells.length;i++) 81 { 82 heads.push(head_cells[i].innerHTML); 83 } 84 //取得值,计算最大值 85 var max=0; 86 var value_cells=tb.tBodies[0].rows[0].cells; 87 var values=[]; 88 for( var i=1;i<head_cells.length;i++) 89 { 90 var v=value_cells[i].innerHTML; 91 v=parseInt(v.replace(/[^\d]/g,"")); //正则表达式,将非数字的字符替换为空格 92 values.push(v); 93 if(v>max) 94 { 95 max=v; 96 97 } 98 } 99 //定义图表原点 100 var basex=parseInt(canvas.width*0.1); 101 var basey=parseInt(canvas.height*0.8); 102 //计算图表的宽度与高度 103 var gw=parseInt(canvas.width*0.8); 104 var gh=parseInt(canvas.height*0.7); 105 //绘制图表区域的背景 106 ctx.fillStyle="#eeeeee"; 107 ctx.fillRect(basex,basey-gh,gw,gh); 108 //显示轴 109 ctx.beginPath(); 110 ctx.moveTo(basex,basey-gh); 111 ctx.lineTo(basex,basey); 112 ctx.lineTo(basex+gw,basey); 113 ctx.strokeStyle="#666666"; 114 ctx.stroke(); 115 //定义文字的字型 116 ctx.font="12px '黑体'"; 117 //描绘图表 118 for(var i=0;i<heads.length;i++) 119 { 120 //取得图表的值 121 var v=values[i]; 122 //竖线中心x坐标 123 var x=basex+(gw/heads.length)*i+((gw/heads.length)/2); 124 //定义竖线的宽度 125 var barw=(gw/heads.length)*0.7; 126 //定义竖线的高度 127 var barh=gh*0.9*(v/max); 128 //绘制竖线 129 ctx.fillStyle="green"; 130 ctx.fillRect(x-barw/2,basey-barh,barw,barh); 131 //检查fillText()方法是否存在 132 if(!ctx.fillText) 133 { 134 continue; 135 } 136 //间隔与值显示宽度的最大值 137 var tw=(gw/heads.length)*0.9; 138 //将文本的坐标基准设置为center 139 ctx.textAlign="center"; 140 //绘制X轴 141 ctx.textBaseline="top"; 142 ctx.fillStyle="black"; 143 ctx.fillText(heads[i],x,basey+3,tw); 144 //绘制值 145 ctx.textBaseline="ideographic"; 146 ctx.fillStyle="black"; 147 ctx.fillText(v,x,basey-barh-3,tw); 148 } 149 } 150 function add_event_listener(elm,type,func) 151 { 152 if(!elm) 153 { 154 return false; 155 } 156 if(elm.addEventListener) 157 { 158 elm.addEventListener(type,func,false); 159 } 160 else if(elm.attachEvent) 161 { 162 elm.attachEvent('on'+type,func); 163 } 164 else 165 { 166 return false; 167 } 168 return true; 169 } 170 })(); 171 </script> 172 </body> 173 </html>
10.动画效果
介绍两种动画的实现实例
1)圆球跳动的动画
效果:
代码:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 //获取上下文 19 var canvas=document.getElementById("c1"); 20 var ctx=canvas.getContext("2d"); 21 22 //记录圆球的状态 23 var ball={x:10,y:100,dir_x:5,dir_y:5}; 24 //动画 25 setInterval(drawBall,100);//每个100毫秒调用一次drawBall()函数 26 function drawBall() 27 { 28 //绘制背景 29 ctx.fillStyle="yellow"; 30 ctx.fillRect(0,0,300,300); 31 //绘制圆球 32 ctx.beginPath(); 33 ctx.arc(ball.x,ball.y,15,0,2*Math.PI,true); 34 ctx.fillStyle="red"; 35 ctx.fill(); 36 //让圆球运动起来 37 ball.x+=ball.dir_x; 38 ball.y+=ball.dir_y; 39 if(ball.x<0||ball.x>300) 40 { 41 ball.dir_x*=-1; 42 } 43 if(ball.y<0||ball.y>300) 44 { 45 ball.dir_y*=-1; 46 } 47 } 48 </script> 49 </body> 50 </html>
2)待机动画
效果:
代码:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8" /> 5 <style type="text/css"> 6 canvas { 7 border-width: 5px; 8 border-style: dashed; 9 border-color: rgba(20, 126, 239, 0.50) 10 } 11 </style> 12 13 </head> 14 <body> 15 hello HTML5! 16 <canvas id="c1" width="300" height="300" ></canvas> 17 <script type="text/javascript"> 18 //获取上下文 19 var canvas=document.getElementById("c1"); 20 var ctx=canvas.getContext("2d"); 21 22 //动画绘制开始 23 var ci=0; 24 anim(); 25 //定义动画函数 26 function anim() 27 { 28 ctx.clearRect(0,0,300,300);//清空Canvas 29 //循环绘制36根长方形棒棒 30 for(var i=0;i<36;i++) 31 { 32 ctx.save(); 33 //旋转 34 var r=(i*10)*Math.PI/180; 35 ctx.translate(150,150);//移动中心点 36 ctx.rotate(r); 37 //绘制细长方形 38 if(i==ci) 39 { 40 ctx.globalAlpha=1.0;//半透明效果 41 } 42 else 43 { 44 ctx.globalAlpha=0.3 45 } 46 ctx.beginPath(); 47 ctx.fillStyle="red"; 48 ctx.rect(0,0,50,6); 49 ctx.fill(); 50 ctx.restore(); 51 } 52 ci=(ci+1)%36; 53 setTimeout(anim,20);//每隔20微秒调用anim函数,实现动画效果 54 } 55 </script> 56 </body> 57 </html>
结语:终于将Canvas这章知识点学完,HTML5很好,很强大,很好玩~~