[关闭]
@greenfavo 2015-11-29T19:46:50.000000Z 字数 6805 阅读 1018

canvas API详解

html5

canvas介绍

canvas元素本身没有任何外观,但它在文档中创建了一个画布,同时还提供了很多强大的绘制客户端Javascript的API。IE9以上的主流浏览器都支持canvas。

和SVG的区别

SVG和canvas都是html5的标签,都可以用来绘图。canvas和SVG之间一个重要区别是:使用canvas绘图是同根调用它提供的方法而使用SVG绘图是通过构建一棵XML元素树来实现的。这两种方式可以互相模拟。但是,从表面上看,这两者还是不同的,并且各有优劣。比如:使用SVG来绘图,可以简单地通过移除相应的元素来编辑图片。而使用canvas来绘图,要移除图片中的元素就不得不通过简单地擦除再重新绘制。canvas的绘图API是基于javascript的,并且相对比较简洁。不像SVG那么复杂。

基础API

先在DOM中创建一个canvas元素

  1. <canvas id='canvas'></canvas>

绘制路径

  1. var canvas=document.getElementById('canvas');
  2. //设置画布大小,不能在css里定义
  3. canvas.width=1024;
  4. canvas.height=768;
  5. //兼容性处理
  6. if(canvas.getContext('2d')){
  7. var context=canvas.getContext('2d');//绘图上下文对象
  8. }else{
  9. alert('你的浏览器不支持canvas');
  10. }
  11. //开始绘制:一个三角形
  12. context.beginPath();
  13. context.moveTo(100,100);//状态设置
  14. context.lineTo(700,700);//路径x,y
  15. context.lineTo(100,700);
  16. context.lineTo(100,100);
  17. context.closePath();//终点
  18. context.lineWidth=5;//线条宽度
  19. context.strokeStyle='green';//线条颜色
  20. context.stroke();//绘制线条
  21. context.fillStyle='#3de0ad';//填充色
  22. context.fill();//内容填充

绘制矩形的3种简单方法

  1. //绘制普通矩形边框
  2. context.rect(0,0,100,50);//起点(0,0)width=100 height=50
  3. context.stroke();
  4. //状态和路径一步完成
  5. context.strokeRect(0,0,100,50);
  6. //绘制填充色矩形
  7. context.fillStyle='green';
  8. context.fillRect(0,0,100,200);

清空矩形

  1. context.clearRect(0,0,canvas.width,canvas.height);//清空画布

坐标轴变换

  1. context.translate(100,500);//将x,y轴起点移到(100,50)
  2. context.rotate(Math.PI/6);//顺时针旋转30deg
  3. scale(1.5,2);//缩放 x'=1.5x y'=2y
  4. //transform(a,b,c,d,e,f)综合上面3种变换
  5. /*
  6. [a,c,e] 默认: 1 0 0
  7. [b,d,f] 0 1 0
  8. [0,0,1] 0 0 1
  9. a,d水平,垂直缩放
  10. b,c水平,垂直倾斜
  11. e,f水平,垂直位移
  12. */
  13. context.transform(2,-0.2,-0.2,1.5,50,100);
  14. context.setTransform(1,0,0,1,100,100);//清空之前所有的tranform,重新设置transform

在进行坐标轴变换时,通常会对后面其他图形的绘制产生影响。要避免这种情况可以用下面2个方法

  1. context.save();//保存当前绘制状当前坐标系
  2. context.rotate(Math.PI/6);//坐标轴变换
  3. ....
  4. context.restore();//恢复到原来的坐标系
  5. //恢复到默认坐标系
  6. context.setTransform(1,0,0,1,0,0)

绘制圆形

  1. //圆心(300,300)半径r=200,从0绘制到2π,默认顺时针
  2. context.beginPath();
  3. context.arc(300,300,200,0,2*Math.PI,false)//逆时针;
  4. context.closePath();//自动闭合未封闭的图形
  5. context.stroke();

用贝塞尔曲线绘制曲线

  1. //二次贝塞尔曲线绘制弧形 1个控制点
  2. context.moveTo(100,0);//起点
  3. context.quadraticCurveTo(300,150,100,300);//(300,150)是控制点 (100,300)是结束点
  4. context.stroke();
  5. //三次贝塞尔曲线绘制波浪线 2个控制点
  6. context.beginPath();
  7. context.moveTo(400,400);//起点
  8. context.bezierCurveTo(500,200,700,600,800,400);//控制点1(500,200)控制点2(700,600)终点(800,400)
  9. context.stroke();

二次贝塞尔曲线在线演示
三次贝塞尔曲线在线演示

颜色,透明度,渐变,图案

  1. context.fillStyle='#ccc';//任何css支持的颜色格式
  2. context.globalAlpha=0.5;//设置全局透明度
  3. //图片做背景
  4. //context.createPattern(img|canvas|video,repeat-style)
  5. var img=new Image();
  6. img.src='1.jpg';
  7. img.onload=function(){
  8. var pattern=context.createPattern(img,'repeate-x');
  9. context.fillStyle=pattern;
  10. context.fillRect(0,0,400,300);
  11. }
  12. //线性渐变 createLinerGradient(xstart,ystart,xend,yend);
  13. var linearGrad=context.createLinerGradient(200,200,400,400);
  14. linearGrad.addColorStop(0.0,'#fff');
  15. linearGrad.addColorStop(0.5,'green');
  16. linearGrad.addColorStop(1.0,"#000");
  17. context.fillStyle=linearGrad;
  18. context.fillRect(200,200,600,600);
  19. //径向渐变 createRadialGradient(x0,y0,r0,x1,y1,r1)
  20. var radialGrad=context.createRadialGradient(400,400,100,400,400,500);
  21. radialGrad.addColorStop(0,"white");
  22. radialGrad.addColorStop(0.25,"yellow");
  23. radialGrad.addColorStop(0.5,"green");
  24. radialGrad.addColorStop(0.75,"blue");
  25. radialGrad.addColorStop(1,"black");
  26. context.fillStyle=radialGrad;
  27. context.fillRect(0,0,800,800);

线段绘制相关的属性

  1. context.lineWidth=2;
  2. //线条的帽子lineCap
  3. context.lineCap='butt';//默认
  4. context.lineCap='square';//延续lineWidth的一半
  5. context.lineCap='round';//延长成一个半圆
  6. //线条连接的样式 lineJoin
  7. context.lineJoin='miter';//默认 尖角
  8. context.lineJoin='round'//圆角
  9. context.lineJoin='bevel';//像把顶端折叠了一样

文本

  1. context.fillStyle='green';//填充色
  2. //font可以使用css里全部的的字体样式属性,包括@font-face
  3. context.font='bold 40px Arial';
  4. context.fillText('hello,canvas',100,200);//内容,起点坐标
  5. context.lineWidth=2;
  6. context.font='italic bold 40px Arial';
  7. context.strokeStyle='blue';
  8. context.strokeText('这是描边镂空效果的文字',100,200);
  9. context.fillText('hello,canvas',100,200,100);//内容,起点坐标,最大字符长度,单位为px
  10. //度量文本宽度
  11. var textwidth=context.measureText('hello,world').width;
  12. context.fillText('hello,world的长度是'+textwidth+'px',400,600);
  13. //对齐方式
  14. context.textAlign='left'||'right'||'center';
  15. context.textBaseLine='middle';

阴影

  1. context.fillStyle='green';
  2. context.shadowColor='gray';
  3. context.shadowOffsetX=10;//偏移量,在默认坐标系中度量
  4. context.shadowOffsetY=20;
  5. context.shadowBlur=5;//模糊度
  6. context.fillRect(0,0,300,200);

高级API

调用clip()方法定义一个裁剪区域。一旦定义了裁剪的区域,在该区域外将不会绘制任何内容。

  1. context.save();
  2. context.beginPath();
  3. context.fillStyle="black";
  4. context.fillRect(0,0,800,800);
  5. context.beginPath();
  6. context.arc(400,400,150,0,Math.PI*2);
  7. context.fillStyle="white";
  8. context.fill();
  9. context.clip();//剪辑
  10. context.font="bold 150px Arial";
  11. context.textAlign="center";
  12. context.textBaseline="middle";
  13. context.fillStyle="blue";
  14. context.fillText("CANVAS",canvas.width/2,canvas.height/2);
  15. context.restore();

使用drawImage()将源图像的像素内容复制到画布上

  1. var image=new Image();
  2. image.src='1.jpg';
  3. image.onload=function(){
  4. // context.drawImage(image|canvas,sx,sy,sw,sh,dx,dy,dw,dh);全部参数
  5. //sx,sy为源图像上的坐标
  6. //dx,dy为目的地起始绘制坐标,设置了dw,dh会自动缩放图像
  7. //3个参数 drawImage(image,dx,dy);会复制整个源图片
  8. //5个参数 drawImage(image,dx,dy,dw,dh);会复制整个源图片,并缩放
  9. context.draImage(image,300,200,400,300,200,200,400,400);
  10. }

图像合成方式,gloabalCompositeOperation有11种属性,都是下面三种属性的延伸

  1. globalCompositeOperation='source-over';//默认值,表示将源像素绘制在目标像素上,对于半透明的源像素就直接合并
  2. globalCompositeOperation='copy';//关闭合并,将源像素直接复制到画布上,忽略目标像素
  3. gloabalCompositeOperation='destination-over';//将新的源像素绘制在已有目标像素下面

像素操作(先创建2个canvas对象canvasa和canvasb)

  1. var image=new Image();
  2. image.src='1.jpg';
  3. image.onload=function(){
  4. contexta.drawImage(image,0,0,canvasa.width,canvasa.height);
  5. }
  6. //获取像素
  7. var imageData=contexta.getImageData(0,0,canvasa.width,canvasa.height);
  8. //修改像素
  9. var pixelData=imageData.data;
  10. //每个像素点有4个通道rgba,一维数组排列
  11. for(var i=0;i<canvasb.width*canvasb.height;i++){
  12. pixelData[4*i+0]=0;//R
  13. pixelData[4*i+1]=0;//G
  14. pixelData[4*i+2]=0;//B
  15. pixelData[4*i+3]=0.5;//A
  16. }
  17. //将修改后的像素复制到另一个画布上
  18. contextb.putImageData(imageData,0,0,0,0,canvasb.width,canvasb.height);

命中检测:isPointInPath()方法确定一个指定的点是否落在(或者在边界上)当前路径中,如果该方法返回true表示落在当前路径,反之则返回false。传递给该方法的点是在默认坐标系中。通常用来检测鼠标单击事件是否发生在特定的图形上。

  1. function hit(context,event){
  2. var canvas=context.canvas;//从canvas对象中获取canvas元素
  3. //鼠标指针相当于canvas画布的位置
  4. var x=event.clientX-canvas.getBoundingClientRect().left;
  5. var y=event.clientY-canvas.getBoundingClientRect().top;
  6. context.beginPath();
  7. context.arc(100,100,50,0,2*Math.PI);
  8. if(context.isPointInPath(x,y)){
  9. alert('点中了!');
  10. }else{
  11. alert('没点中!');
  12. }
  13. }
  14. canvas.onclick=function(event){
  15. hit(context,event);
  16. }

除了进行基于路径的命中检测外,还可以使用getImageData()方法来检测鼠标点击下的像素是否已经绘制过。如果返回的像素(单个或多个)是完全透明的,则表明该像素上没有绘制任何内容,并且鼠标事件点空了。

  1. function hitpaint(context,event){
  2. //通过转换和缩放将鼠标事件坐标转换成画布坐标
  3. var canvas=context.canvas;
  4. var bb=canvas.getBoundingClientRect();
  5. var x=(event.clientX-bb.left)*(canvas.width/bb.width);
  6. var y=(event.clientY-bb.top)*(canvas.height/bb.height);
  7. //获取像素
  8. var pixels=context.getImageData(x,y,1,1);
  9. //如果任何像素的alpha!=0,则返回true(命中)
  10. for(var i=3;i<pixels.data.length;i+=4){
  11. if(pixels.data[i]!==0)return true;
  12. }
  13. //否则,表示不命中
  14. return false;
  15. }

注意

getImageData()方法和toDataUrl()方法都受同源安全策略的限制:它对于绘制图片(通过drawImage()方法直接绘制或者通过canvasPattern间接绘制)和画布所在文档不属于同源的画布都是无效的。不过在Firefox浏览器下没什么影响,在chrome下会被限制,将代码放在服务器就可正常运行了。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注