HTML5中CANVAS

1.  HTML5 Canvas历史

Canvas的概念最初是由苹果公司提出的,用于在Mac OS X WebKit中创建控制板部件(dashboard widget)。在Canvas出现之前,开发人员若要在浏览器中使用绘图API,只能使用Adobe的Flash和SVG(Scalable Vector Graphics,可伸缩矢量图形)插件,或者只有IE才支持的VML(Vector Markup Language,矢量标记语言),以及其他一些稀奇古怪的JavaScript技巧。

假设我们要在没有canvas元素的条件下绘制一条对角线--听起来似乎很简单,但实际上如果没有一套二维绘图API的话,这会是一项相当复杂的工作。HTML5 Canvas能够提供这样的功能,对浏览器端来说此功能非常有用,因此Canvas被纳入了HTML5规范。

起初,苹果公司曾暗示可能会为WHATWG(Web Hypertext Application Technology Working Group,Web超文本应用技术工作组)草案中的Canvas规范申请知识产权,这在当时引起了一些Web标准化追随者的关注。不过,苹果公司最终还是按照W3C的免版税专利权许可条款公开了其专利。

"Canvas本质上是一个位图画布,其上绘制的图形是不可缩放的,不能像SVG图像那样可以被放大缩小。此外,用Canvas绘制出来的对象不属于页面DOM结构或者任何命名空间--这点被认为是一个缺陷。SVG图像却可以在不同的分辨率下流畅地缩放,并且支持点击检测(能检测到鼠标点击了图像上的哪个点)。

既然如此,为什么WHATWG的HTML5规范不使用SVG呢?尽管Canvas有明显的不足,但HTML Canvas API有两方面优势可以弥补:首先,不需要将所绘制图像中的每个图元当做对象存储,因此执行性能非常好;其次,在其他编程语言现有的优秀二维绘图API的基础上实现Canvas API相对来说比较简单。毕竟,二鸟在林不如一鸟在手。

2.  Canvas到底是什么

在网页上使用canvas元素时,它会创建一块矩形区域。默认情况下该矩形区域宽为300像素,高为150像素,但也可以自定义具体的大小或者设置canvas元素的其他特性。一下代码是可放到HTML页面中的最基本的canvas元素。

<canvas></canvas> 

  在页面中加入了canvas元素后,我们便可以通过JavaScript来自由地控制它。可以在其中添加图片、线条以及文字,也可以在里面绘图,甚至还可以加入高级动画。

  大多数主流操作系统和框架支持的二维绘制操作,HTML5 Canvas API都支持。如果你在近年来曾经有过二维图像编程的经验,那么会对HTML5 Canvas API感觉非常顺手,因为这个API就是参照既有系统设计的。如果没有这方面经验,则会发现与这么多年来一直使用的图片加CSS开发Web图形的方式比起来,Canvas的渲染系统有多么强大。

  使用canvas编程,首先要获取其上下文(context)。接着在上下文中执行动作,最后将这些动作应用到上下文中。可以将canvas的这种编辑方式想象成为数据库事务:开发人员先发起一个事务,然后执行某些操作,最后提交事务。

3.  什么情况下不用Canvas

尽管canvas元素功能非常强大,用处也很多,但在某些情况下,如果其他元素已经够用了,就不应该再使用canvas元素。例如,用canvas元素在HTML页面中动态绘制所有不同的标题,就不如直接使用标题样式标签(H1、H2等),它们所实现的效果是一样的。

 

提示:以下所有实验请使用的浏览器为Google Chrome 33.0.1701.0

4.  开发工具HBuilder

HBuilder是DCloud推出的一款支持HTML5的Web开发IDE。快,是HBuilder的最大优势,通过完整的语法提示和代码输入法、代码块等,大幅提升HTML、js、css的开发效率。同时,它还包括最全面的语法库和浏览器兼容性数据。

5.  基础知识

context:一直觉得这个翻译成“上下文”,context是一个封装了很多绘图功能的对象,获取这个对象的方法是

var context = canvas.getContext("2d");

注:html5暂时不支持3d功能。

 

canvas元素绘制图像的时候有两种方法,分别是

context.fill()//填充

context.stroke()//绘制边框

 

style:在进行图形绘制前,要设置好绘图的样式

      context.fillStyle//填充的样式

      context.strokeStyle//边框样式

context.lineWidth //图形边框宽度

 

颜色的表示方式:

       直接用颜色名称:"red" "green" "blue"

       十六进制颜色值: "#EEEEFF"

       rgb(1-255,1-255,1-255)

       rgba(1-255,1-255,1-255,透明度)

1.  Canvas绘图

6.1绘制矩形

语法:

fillRect(x,y,width,height) 

strokeRect(x,y,width,height)

参数说明:

x:矩形起点横坐标

y:矩形起点纵坐标

width:矩形长度

height:矩形高度

代码:

function drawRect() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null)
        return false;
    var context = canvas.getContext("2d");
    
    //实践表明在不设施fillStyle下的默认fillStyle=black
    context.fillRect(0, 0, 100, 100);
    
    //实践表明在不设施strokeStyle下的默认strokeStyle=black
    context.strokeRect(120, 0, 100, 100);

    //设置纯色
    context.fillStyle = "red";
    context.strokeStyle = "blue";
    context.fillRect(0, 120, 100, 100);
    context.strokeRect(120, 120, 100, 100);

    //设置透明度实践证明透明度值>0,<1值越低,越透明,值>=1时为纯色,值<=0时为完全透明
    context.fillStyle = "rgba(255,0,0,0.2)";
    context.strokeStyle = "rgba(255,0,0,0.2)";
    context.fillRect(240,0 , 100, 100);
    context.strokeRect(240, 120, 100, 100);
}


 

6.2清除矩形区域

语法:

clearRect(x,y,width,height) 

参数说明:

x:清除矩形起点横坐标

y:清除矩形起点纵坐标

width:清除矩形长度

height:清除矩形高度

代码:

function clearRect() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null)
        return false;
    var context = canvas.getContext("2d");
    
    //实践表明在不设施fillStyle下的默认fillStyle=black
    context.fillRect(0, 0, 100, 100);
    //实践表明在不设施strokeStyle下的默认strokeStyle=black
    context.strokeRect(120, 0, 100, 100);

    //设置纯色
    context.fillStyle = "red";
    context.strokeStyle = "blue";
    context.fillRect(0, 120, 100, 100);
    context.strokeRect(120, 120, 100, 100);

    //设置透明度实践证明透明度值>0,<1值越低,越透明,值>=1时为纯色,值<=0时为完全透明
    context.fillStyle = "rgba(255,0,0,0.2)";
    context.strokeStyle = "rgba(255,0,0,0.2)";
    context.fillRect(240, 0, 100, 100);
    context.strokeRect(240, 120, 100, 100);
    // 清除矩形
    context.clearRect(50, 50, 240, 120);
}


 

6.3圆弧

语法:

arc(x, y, radius, starAngle,endAngle, anticlockwise)

参数说明:

x:圆心的x坐标

y:圆心的y坐标

radius:圆半径

straAngle:开始角度

endAngle:结束角度

anticlockwise:是否逆时针(true)为逆时针,(false)为顺时针

代码:

function drawArc() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext('2d');
    context.beginPath();
    context.arc(200, 150, 100, 0, Math.PI * 2, true);
    context.closePath();
    context.fillStyle = 'rgba(0,255,0,0.25)';
    context.fill();
}


 

6.4路径

语法:

beginPath()   //绘制路径的开始点

closePath()   //绘制路径的结束点

代码:

function drawPath() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext('2d');
    var n = 0;
   
    //左侧1/4圆弧
    context.beginPath();
    context.arc(100, 150, 50, 0, Math.PI/2 , false);
    context.fillStyle = 'rgba(255,0,0,0.25)';
    context.fill();
    context.strokeStyle = 'rgba(255,0,0,0.25)'
    context.closePath();
    context.stroke();

    //右侧1/4圆弧
    context.beginPath();
    context.arc(300, 150, 50, 0, Math.PI*1.5 , true);
    context.fillStyle = 'rgba(0,255,0,0.25)';
    context.fill();
    context.strokeStyle = 'rgba(0,255,0,0.25)';
    context.closePath();
    context.stroke();
}


 

6.5 绘制线段

语法:

moveTo(x,y)

lineTo(x,y)

参数说明:

x:x坐标

y:y坐标

每次画线都从moveTo的点到lineTo的点,如果没有moveTo那么第一次lineTo的效果和moveTo一样,每次lineTo后如果没有moveTo,那么下次lineTo的开始点为前一次lineTo的结束点。

代码:

function drawLine() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null)
        return false;
    var context = canvas.getContext("2d");
    
    context.strokeStyle = "rgb(250,0,0)";
    context.fillStyle = "rgb(250,0,0)"
    
    //实验证明第一次lineTo的时候和moveTo功能一样
    context.lineTo(100, 100);
    
    //之后的lineTo会以上次lineTo的节点为开始
    context.lineTo(200, 200);
    context.lineTo(200, 100);
    context.moveTo(200, 50);
    context.lineTo(100,50);
    context.stroke();
}


 

6.6 贝塞尔曲线

语法:

bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)

参数说明:

cp1x:第一个控制点x坐标

cp1y:第一个控制点y坐标

cp2x:第二个控制点x坐标

cp2y:第二个控制点y坐标

x:终点x坐标

y:终点y坐标

代码:

function drawBezier() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext("2d");

    context.moveTo(50, 50);
    context.bezierCurveTo(50, 50,150, 50, 150, 150);
    context.stroke();
    
    context.moveTo(50, 50);
    context.lineTo(150, 50);
    context.lineTo(150, 150);
    context.stroke();
}


 

6.7 贝塞尔二次曲线

语法:

quadraticCurveTo(qcpx,qcpy,qx,qy)

参数说明:

qcpx:二次样条曲线控制点x坐标

qcpy:二次样条曲线控制点y坐标

qx:二次样条曲线终点x坐标

qy:二次样条曲线终点y坐标

代码:

function drawQuadratic() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext("2d");

    context.moveTo(150, 150);
    context.quadraticCurveTo(150, 250, 250, 250);
    context.stroke();
    
    context.moveTo(150, 150);
    context.lineTo(150, 250);
	context.lineTo(250, 250);
	context.stroke();
}


 

6.8 线性渐变

语法:

createLinearGradient(xStart,yStart,xEnd,yEnd)

addColorStop(offset,color)

参数说明:

xstart:渐变开始点x坐标

ystart:渐变开始点y坐标

xEnd:渐变结束点x坐标

yEnd:渐变结束点y坐标

 

offset:设定的颜色离渐变结束点的偏移量(0~1)

color:绘制时要使用的颜色

技术分享

代码:

function drawLinear() {
      var canvas = document.getElementById("mycanvas");
      if (canvas == null) {
          return false;
      }
      var context = canvas.getContext('2d');
    	  var g1 = context.createLinearGradient(0, 0, 0, 300);

      g1.addColorStop(0, 'rgb(255,0,0)'); //红  
      g1.addColorStop(0.5, 'rgb(0,255,0)');//绿
      g1.addColorStop(1, 'rgb(0,0,255)'); //蓝

      //可以把lg对象理解成GDI中线性brush
      context.fillStyle = g1;
      //再用这个brush来画正方形
      context.fillRect(0, 0, 400, 300);  
}


 

6.9 径向渐变

语法:

createRadialGradient(xStart,yStart,radiusStart,xEnd,yEnd,radiusEnd)

addColorStop(offset,color)

参数说明:

xStart:发散开始圆心x坐标

yStart:发散开始圆心y坐标

radiusStart:发散开始圆的半径

xEnd:发散结束圆心的x坐标

yEnd:发散结束圆心的y坐标

radiusEnd:发散结束圆的半径

 

offset:设定的颜色离渐变结束点的偏移量(0~1)

color:绘制时要使用的颜色

代码:

function drawRadial() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext('2d');
    
    var g1 = context.createRadialGradient(200, 150, 0, 200, 150, 100);
    g1.addColorStop(0.1, 'rgb(255,0,0)');  
    g1.addColorStop(1, 'rgb(50,0,0)');
    context.fillStyle = g1;
    context.beginPath();
    context.arc(200, 150, 100, 0, Math.PI * 2, true);
    context.closePath();
    context.fill();

  	var g1 = context.createRadialGradient(100, 150, 10, 300, 150, 50);

    g1.addColorStop(0.1, 'rgb(255,0,0)');
    g1.addColorStop(0.5, 'rgb(0,255,0)');
    g1.addColorStop(1, 'rgb(0,0,255)');
    context.fillStyle = g1;
    context.fillRect(0, 0, 400, 300);
}


 

6.10 图形变形

语法:

    平移 translate(x,y)

参数说明:

x:坐标原点向x轴方向平移x

y:坐标原点向y轴方向平移y

语法:

缩放 scale(x,y)

参数说明:

x:x坐标轴按x比例缩放

y:y坐标轴按y比例缩放

语法:

旋转 rotate(angle)

参数说明:

angle:坐标轴旋转x角度(角度变化模型和画圆的模型一样)

代码:

function changeGraph() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext('2d');
  	context.save(); //保存了当前context的状态
    context.fillStyle = "#EEEEFF";
    context.fillRect(0, 0, 400, 300);

    context.fillStyle = "rgba(255,0,0,0.1)";
    //平移 缩放 旋转  1 2 3        
    context.translate(100, 100);
    context.scale(0.5, 0.5);
    context.rotate(Math.PI / 4);
    context.fillRect(0, 0, 100, 100);
    context.restore(); //恢复到刚刚保存的状态,保存恢复只能使用一次
  	context.save(); //保存了当前context的状态

    //实验表明应该移动的是坐标轴
    //实验表明缩放的是坐标轴比例
    //实验表明旋转的是坐标轴
    //综合上述,因此平移 缩放 旋转 三者的顺序不同都将画出不同的结果
}


 

6.11 图形阴影

语法:

shadowOffsetX :阴影的横向位移量(默认值为0)
shadowOffsetY :阴影的纵向位移量(默认值为0)
shadowColor :阴影的颜色
shadowBlur :阴影的模糊范围(值越大越模糊)

代码:

function drawShadow() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext('2d');
  	
    context.shadowOffsetX = 20;
    context.shadowOffsetY = 20;
    context.shadowColor = 'rgba(100,100,100,0.5)';
    context.shadowBlur = 2.5;
    context.fillStyle = 'rgba(255,0,0,0.5)';
    context.fillRect(100, 100, 200, 100);
}


 

6.12 绘制文字

语法:

填充文字:fillText(text,x,y)  

绘制文字轮廓: strokeText(text,x,y)

计算字体长度(px): measureText(text)

参数说明:

text:要绘制的文字

    x:文字起点的x坐标轴

    y:文字起点的y坐标轴

代码:

function drawText() {
      var canvas = document.getElementById("mycanvas");
      if (canvas == null) {
          return false;
      }
      var context = canvas.getContext('2d');
    	
      context.fillStyle = "#EEEEFF";
    	  context.fillRect(0,0,400,300);
	  context.fillStyle = "#00f";
    	  context.font = "italic 30px sans-serif";

	  //填充字符串
    	  var txt="fill示例文字";
	  context.fillText(txt, 0, 30);
	  var length=context.measureText(txt);
      context.fillText("长" + length.width + "px", 0, 80);

	  context.font = "bolid 30px sans-serif";
    	  txt = "stroke示例文字";
    	  length = context.measureText(txt);
    	  context.strokeText(txt,0,130);
	  context.fillText("长" + length.width + "px", 0, 180);
}


 

6.13 保存和恢复状态

语法:

保存save()

恢复restore()

使用说明:

save()调用该方法,会保存当前context的状态、属性(把他理解成游戏存档);restore()调用该方法就能恢复到save时候context的状态、属性(游戏回档)

代码:

function saveAndRestore() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext('2d');
  	
  	context.fillStyle = "red";
    context.save(); //保存了当前context的状态
    context.fillStyle = "black";
    context.fillRect(0, 0, 100, 100);
    context.restore();//恢复到刚刚保存的状态
    context.fillRect(0,120,100,100);
}


 

6.14 保存文件

语法:

toDataURL(MIME)

使用说明:

在canvas中绘出的图片只是canvas标签而已,并非是真正的图片,是不能右键,另存为的,我们可以利用canvas.toDataURL()这个方法把canvas绘制的图形生成一幅图片,生成图片后,就能对图片进行相应的操作了。

代码:

function saveFile() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext('2d');
  	
  	context.fillStyle = "rgb(0,0,225)";
  	context.fillRect(0, 0, canvas.width, canvas.height);
  	context.fillStyle = "rgb(255,255,0)";
  	context.fillRect(10, 20, 50, 50);
  	
  	//把图像保存到新的窗口
var w = window.open(canvas.toDataURL("image/jpeg"),"smallwin","width=400,height=350");
}


 

6.15 图形组合

语法:

globalCompositeOperation=type

使用说明:

source-over(默认值):在原有图形上绘制新图形

destination-over:在原有图形下绘制新图形

source-in:显示原有图形和新图形的交集,新图形在上,所以颜色为新图形的颜色

destination-in:显示原有图形和新图形的交集,原有图形在上,所以颜色为原有图形的颜色

source-out:只显示新图形非交集部分

destination-out:只显示原有图形非交集部分

source-atop:显示原有图形和交集部分,新图形在上,所以交集部分的颜色为新图形的颜色

destination-atop:显示新图形和交集部分,新图形在下,所以交集部分的颜色为原有图形的颜色

lighter:原有图形和新图形都显示,交集部分做颜色叠加

xor:重叠飞部分不现实

copy:只显示新图形

技术分享

代码:

function graphComb() {
    var canvas = document.getElementById("mycanvas");
    if (canvas == null) {
        return false;
    }
    var context = canvas.getContext('2d');
  	var oprtns = new Array(
      "source-over",
      "destination-over",
      "source-in",
      "destination-in",
      "source-out",
      "destination-out",
      "source-atop",
      "destination-atop",
      "lighter",
      "xor",         
      "copy"
      );
   var i = 0;//组合效果编号

   //结合setinterval动态显示组合
   var interal = setInterval(function () {
       if (i == 10) {
           i=0;
       }
       else {
           i++;
       }
       //蓝色矩形
       context.fillStyle = "blue";
       context.fillRect(10, 10, 60, 60);
       //设置组合方式 
       context.globalCompositeOperation = oprtns[i];
       //设置新图形(红色圆形)
       context.beginPath();
       context.fillStyle = "red";
       context.arc(60, 60, 30, 0, Math.PI * 2, false);
       context.fill();
  }, 5000);
}


 

6.16 绘制图像

语法:

绘图drawImage

    图形平铺createPattern(image,type)

    图形裁剪 clip()

像素处理getImageData(sx,sy,sw,sh)

参数说明:

drawImage(image,x,y)

image:Image对象var img=new Image(); img.src="url(...)";

x:绘制图像的x坐标

y:绘制图像的y坐标

drawImage(image,x,y,w,h)

image:Image对象var img=new Image(); img.src="url(...)";

x:绘制图像的x坐标

y:绘制图像的y坐标

w:绘制图像的宽度

h:绘制图像的高度

drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh):选取图像的一部分矩形区域进行绘制

image:Image对象var img=new Image(); img.src="url(...)";

sx:图像上的x坐标

sy:图像上的y坐标

sw:矩形区域的宽度

sh:矩形区域的高度

dx:画在canvas的x坐标

dy:画在canvas的y坐标

dw:画出来的宽度

dh:画出来的高度

createPattern(image,type)

image:Image对象var img=new Image(); img.src="url(...)";

no-repeat:不平铺

repeat-x:横方向平铺

repeat-y:纵方向平铺

repeat:全方向平铺

clip()只绘制封闭路径区域内的图像,不绘制路径外部图像,用的时候先创建裁剪区域,再绘制图像。

getImageData(sx,sy,sw,sh)

    sx:cavas的x轴坐标点

    sy:canvas的y轴坐标点

    sw:距离x的宽度

    sh:距离y的高度

    可以利用context.getImageData返回的一个像素颜色数组,顺序是所取像素范围的从左到右,从上到下,数组的元素是(所有图形,包括图片,和绘制的图形)每个像素的rgba。

 

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。