@greenfavo
2015-11-29T19:46:50.000000Z
字数 6805
阅读 1018
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,y
context.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=50
context.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);//顺时针旋转30deg
scale(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 1
a,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;
//线条的帽子lineCap
context.lineCap='butt';//默认
context.lineCap='square';//延续lineWidth的一半
context.lineCap='round';//延长成一个半圆
//线条连接的样式 lineJoin
context.lineJoin='miter';//默认 尖角
context.lineJoin='round'//圆角
context.lineJoin='bevel';//像把顶端折叠了一样
文本
context.fillStyle='green';//填充色
//font可以使用css里全部的的字体样式属性,包括@font-face
context.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;//R
pixelData[4*i+1]=0;//G
pixelData[4*i+2]=0;//B
pixelData[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下会被限制,将代码放在服务器就可正常运行了。