@greenfavo
2015-11-29T11:46:50.000000Z
字数 6805
阅读 1093
html5
canvas元素本身没有任何外观,但它在文档中创建了一个画布,同时还提供了很多强大的绘制客户端Javascript的API。IE9以上的主流浏览器都支持canvas。
SVG和canvas都是html5的标签,都可以用来绘图。canvas和SVG之间一个重要区别是:使用canvas绘图是同根调用它提供的方法而使用SVG绘图是通过构建一棵XML元素树来实现的。这两种方式可以互相模拟。但是,从表面上看,这两者还是不同的,并且各有优劣。比如:使用SVG来绘图,可以简单地通过移除相应的元素来编辑图片。而使用canvas来绘图,要移除图片中的元素就不得不通过简单地擦除再重新绘制。canvas的绘图API是基于javascript的,并且相对比较简洁。不像SVG那么复杂。
先在DOM中创建一个canvas元素
<canvas id='canvas'></canvas>
绘制路径
var canvas=document.getElementById('canvas');//设置画布大小,不能在css里定义canvas.width=1024;canvas.height=768;//兼容性处理if(canvas.getContext('2d')){var context=canvas.getContext('2d');//绘图上下文对象}else{alert('你的浏览器不支持canvas');}//开始绘制:一个三角形context.beginPath();context.moveTo(100,100);//状态设置context.lineTo(700,700);//路径x,ycontext.lineTo(100,700);context.lineTo(100,100);context.closePath();//终点context.lineWidth=5;//线条宽度context.strokeStyle='green';//线条颜色context.stroke();//绘制线条context.fillStyle='#3de0ad';//填充色context.fill();//内容填充
绘制矩形的3种简单方法
//绘制普通矩形边框context.rect(0,0,100,50);//起点(0,0)width=100 height=50context.stroke();//状态和路径一步完成context.strokeRect(0,0,100,50);//绘制填充色矩形context.fillStyle='green';context.fillRect(0,0,100,200);
清空矩形
context.clearRect(0,0,canvas.width,canvas.height);//清空画布
坐标轴变换
context.translate(100,500);//将x,y轴起点移到(100,50)context.rotate(Math.PI/6);//顺时针旋转30degscale(1.5,2);//缩放 x'=1.5x y'=2y//transform(a,b,c,d,e,f)综合上面3种变换/*[a,c,e] 默认: 1 0 0[b,d,f] 0 1 0[0,0,1] 0 0 1a,d水平,垂直缩放b,c水平,垂直倾斜e,f水平,垂直位移*/context.transform(2,-0.2,-0.2,1.5,50,100);context.setTransform(1,0,0,1,100,100);//清空之前所有的tranform,重新设置transform
在进行坐标轴变换时,通常会对后面其他图形的绘制产生影响。要避免这种情况可以用下面2个方法
context.save();//保存当前绘制状当前坐标系context.rotate(Math.PI/6);//坐标轴变换....context.restore();//恢复到原来的坐标系//恢复到默认坐标系context.setTransform(1,0,0,1,0,0)
绘制圆形
//圆心(300,300)半径r=200,从0绘制到2π,默认顺时针context.beginPath();context.arc(300,300,200,0,2*Math.PI,false)//逆时针;context.closePath();//自动闭合未封闭的图形context.stroke();
用贝塞尔曲线绘制曲线
//二次贝塞尔曲线绘制弧形 1个控制点context.moveTo(100,0);//起点context.quadraticCurveTo(300,150,100,300);//(300,150)是控制点 (100,300)是结束点context.stroke();//三次贝塞尔曲线绘制波浪线 2个控制点context.beginPath();context.moveTo(400,400);//起点context.bezierCurveTo(500,200,700,600,800,400);//控制点1(500,200)控制点2(700,600)终点(800,400)context.stroke();
颜色,透明度,渐变,图案
context.fillStyle='#ccc';//任何css支持的颜色格式context.globalAlpha=0.5;//设置全局透明度//图片做背景//context.createPattern(img|canvas|video,repeat-style)var img=new Image();img.src='1.jpg';img.onload=function(){var pattern=context.createPattern(img,'repeate-x');context.fillStyle=pattern;context.fillRect(0,0,400,300);}//线性渐变 createLinerGradient(xstart,ystart,xend,yend);var linearGrad=context.createLinerGradient(200,200,400,400);linearGrad.addColorStop(0.0,'#fff');linearGrad.addColorStop(0.5,'green');linearGrad.addColorStop(1.0,"#000");context.fillStyle=linearGrad;context.fillRect(200,200,600,600);//径向渐变 createRadialGradient(x0,y0,r0,x1,y1,r1)var radialGrad=context.createRadialGradient(400,400,100,400,400,500);radialGrad.addColorStop(0,"white");radialGrad.addColorStop(0.25,"yellow");radialGrad.addColorStop(0.5,"green");radialGrad.addColorStop(0.75,"blue");radialGrad.addColorStop(1,"black");context.fillStyle=radialGrad;context.fillRect(0,0,800,800);
线段绘制相关的属性
context.lineWidth=2;//线条的帽子lineCapcontext.lineCap='butt';//默认context.lineCap='square';//延续lineWidth的一半context.lineCap='round';//延长成一个半圆//线条连接的样式 lineJoincontext.lineJoin='miter';//默认 尖角context.lineJoin='round'//圆角context.lineJoin='bevel';//像把顶端折叠了一样
文本
context.fillStyle='green';//填充色//font可以使用css里全部的的字体样式属性,包括@font-facecontext.font='bold 40px Arial';context.fillText('hello,canvas',100,200);//内容,起点坐标context.lineWidth=2;context.font='italic bold 40px Arial';context.strokeStyle='blue';context.strokeText('这是描边镂空效果的文字',100,200);context.fillText('hello,canvas',100,200,100);//内容,起点坐标,最大字符长度,单位为px//度量文本宽度var textwidth=context.measureText('hello,world').width;context.fillText('hello,world的长度是'+textwidth+'px',400,600);//对齐方式context.textAlign='left'||'right'||'center';context.textBaseLine='middle';
阴影
context.fillStyle='green';context.shadowColor='gray';context.shadowOffsetX=10;//偏移量,在默认坐标系中度量context.shadowOffsetY=20;context.shadowBlur=5;//模糊度context.fillRect(0,0,300,200);
调用clip()方法定义一个裁剪区域。一旦定义了裁剪的区域,在该区域外将不会绘制任何内容。
context.save();context.beginPath();context.fillStyle="black";context.fillRect(0,0,800,800);context.beginPath();context.arc(400,400,150,0,Math.PI*2);context.fillStyle="white";context.fill();context.clip();//剪辑context.font="bold 150px Arial";context.textAlign="center";context.textBaseline="middle";context.fillStyle="blue";context.fillText("CANVAS",canvas.width/2,canvas.height/2);context.restore();
使用drawImage()将源图像的像素内容复制到画布上
var image=new Image();image.src='1.jpg';image.onload=function(){// context.drawImage(image|canvas,sx,sy,sw,sh,dx,dy,dw,dh);全部参数//sx,sy为源图像上的坐标//dx,dy为目的地起始绘制坐标,设置了dw,dh会自动缩放图像//3个参数 drawImage(image,dx,dy);会复制整个源图片//5个参数 drawImage(image,dx,dy,dw,dh);会复制整个源图片,并缩放context.draImage(image,300,200,400,300,200,200,400,400);}
图像合成方式,gloabalCompositeOperation有11种属性,都是下面三种属性的延伸
globalCompositeOperation='source-over';//默认值,表示将源像素绘制在目标像素上,对于半透明的源像素就直接合并globalCompositeOperation='copy';//关闭合并,将源像素直接复制到画布上,忽略目标像素gloabalCompositeOperation='destination-over';//将新的源像素绘制在已有目标像素下面
像素操作(先创建2个canvas对象canvasa和canvasb)
var image=new Image();image.src='1.jpg';image.onload=function(){contexta.drawImage(image,0,0,canvasa.width,canvasa.height);}//获取像素var imageData=contexta.getImageData(0,0,canvasa.width,canvasa.height);//修改像素var pixelData=imageData.data;//每个像素点有4个通道rgba,一维数组排列for(var i=0;i<canvasb.width*canvasb.height;i++){pixelData[4*i+0]=0;//RpixelData[4*i+1]=0;//GpixelData[4*i+2]=0;//BpixelData[4*i+3]=0.5;//A}//将修改后的像素复制到另一个画布上contextb.putImageData(imageData,0,0,0,0,canvasb.width,canvasb.height);
命中检测:isPointInPath()方法确定一个指定的点是否落在(或者在边界上)当前路径中,如果该方法返回true表示落在当前路径,反之则返回false。传递给该方法的点是在默认坐标系中。通常用来检测鼠标单击事件是否发生在特定的图形上。
function hit(context,event){var canvas=context.canvas;//从canvas对象中获取canvas元素//鼠标指针相当于canvas画布的位置var x=event.clientX-canvas.getBoundingClientRect().left;var y=event.clientY-canvas.getBoundingClientRect().top;context.beginPath();context.arc(100,100,50,0,2*Math.PI);if(context.isPointInPath(x,y)){alert('点中了!');}else{alert('没点中!');}}canvas.onclick=function(event){hit(context,event);}
除了进行基于路径的命中检测外,还可以使用getImageData()方法来检测鼠标点击下的像素是否已经绘制过。如果返回的像素(单个或多个)是完全透明的,则表明该像素上没有绘制任何内容,并且鼠标事件点空了。
function hitpaint(context,event){//通过转换和缩放将鼠标事件坐标转换成画布坐标var canvas=context.canvas;var bb=canvas.getBoundingClientRect();var x=(event.clientX-bb.left)*(canvas.width/bb.width);var y=(event.clientY-bb.top)*(canvas.height/bb.height);//获取像素var pixels=context.getImageData(x,y,1,1);//如果任何像素的alpha!=0,则返回true(命中)for(var i=3;i<pixels.data.length;i+=4){if(pixels.data[i]!==0)return true;}//否则,表示不命中return false;}
getImageData()方法和toDataUrl()方法都受同源安全策略的限制:它对于绘制图片(通过drawImage()方法直接绘制或者通过canvasPattern间接绘制)和画布所在文档不属于同源的画布都是无效的。不过在Firefox浏览器下没什么影响,在chrome下会被限制,将代码放在服务器就可正常运行了。