zoukankan      html  css  js  c++  java
  • HTML5之Canvas

    感性认识

    canvas元素是HTML5中新增的一个重要元素,专门用来绘制图形,它就像页面的一个画布,利用canvas绘图的步骤很简单:

    1. 页面放置canvas;
    2. 获取canvas的context;
    3. 通过context的api用JavaScript来进行绘画;
    4. 绘制路径(矩形不需要),设置样式,使用stroke或fill来填充;

    首先我们了解canvas的坐标是这样的

    先来看下示例

    <script type="text/javascript">
    	var canvas=document.getElementById("mycanvas");
    	//获取context
    	var ctx=canvas.getContext("2d");
    	//设置样式
    	ctx.strokeStyle="green";
    	ctx.lineWidth=2;
    	//绘制矩形(不需要绘制路径)
    	ctx.strokeRect(10,10,180,60);
    	
    	//绘制直线
    	ctx.moveTo(200,30);
    	ctx.lineTo(280,60);
    	ctx.stroke();
    	
    	//绘制圆形
    	ctx.beginPath();
    	ctx.fillStyle="blue";
    	ctx.arc(60,130,50,0,Math.PI*2,true);
    	ctx.fill();
    	
    	//绘制三角形	
    	ctx.beginPath();
    	ctx.moveTo(120,130);
    	ctx.lineTo(190,190);
    	ctx.lineTo(280,150);
    	ctx.closePath();
    	ctx.stroke();
    </script>

    绘制的图形如下:

    绘制简单图形

    1. 绘制矩形
      fillRect(x, y, width, height) //绘制实心矩形,被填充
      strokeRect(x, y, width, height)//绘制空心矩形,只是边框
      它的四个参数分别为矩形左上角顶点的x坐标、y坐标,以及矩形的宽和高。
    2. 绘制圆形
      矩形不用绘制路径,直接fill或stroke,而其他的图形需要先绘制路径,然后在fill或stroke。
      context.arc(x,y,r,sAngle,eAngle,counterclockwise);
      • x:圆的中心的 x 坐标。
      • y:圆的中心的 y 坐标。
      • r:圆的半径。
      • sAngle:起始角,以弧度计。(弧的圆形的三点钟位置是 0 度)。
      • eAngle:结束角,以弧度计。
      • counterclockwise:可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。
      如需通过 arc() 来创建圆,请把起始角设置为 0,结束角设置为 2*Math.PI

    3. 绘制直线
      ctx.moveTo(200,30); //设置路径的起点
      ctx.lineTo(280,60); //设置路径的终点
      ctx.stroke(); //给路径着色
      如果上面示例,我们并没有使用beginPath,因为这是第一次绘图,所以不用,但如上例中绘制圆形,如果不用beginPath,你绘制出的图如

      这是因为没有使用beginPath来重置路径,而且这还牵涉到另一个API:closePath,它的作用是把起点终点链接起来,如绘制三角形,如果你注释掉closePath,将不会绘制成三角形只是折线而已。
      这里需要强调的是使用fill时会自动把起点和终点链接起来,就类似隐含先执行了closePath一样。这一点可以这样验证,把示例中的绘制圆形注释掉beginPath,而且只绘半圆,代码如下
      <!--放置canvas-->
      <canvas id="mycanvas" width="300" height="200" style="border:1px solid #ccc;"></canvas>
      <script type="text/javascript">
      	var canvas=document.getElementById("mycanvas");
      	//获取context
      	var ctx=canvas.getContext("2d");
      	//设置样式
      	ctx.strokeStyle="green";
      	ctx.lineWidth=2;
      	//绘制矩形(不需要绘制路径)
      	ctx.strokeRect(10,10,180,60);
      	
      	//绘制直线
      	ctx.moveTo(200,30);
      	ctx.lineTo(280,60);
      	ctx.stroke();
      	
      	//绘制圆形
      	//ctx.beginPath();
      	ctx.fillStyle="blue";
      	ctx.arc(60,130,50,0,Math.PI,true);
      	ctx.fill();
      	
      	//绘制三角形	
      	ctx.beginPath();
      	ctx.moveTo(120,130);
      	ctx.lineTo(190,190);
      	ctx.lineTo(280,150);
      	ctx.closePath();
      	ctx.stroke();
      </script>
      绘制的图形如下

      是不是感觉奇怪,如果把绘制圆形使用closePath,再把fill改成stroke,你就会发现路径是这样的

      所以beginPath和closePath需要要搞懂,会用慎用!

    绘制渐变

    1. 线性渐变
      示例:
      var canvas=document.getElementById("mycanvas");
      //获取context
      var ctx=canvas.getContext("2d");
      //设置样式
      ctx.lineWidth=20;
      var g=ctx.createLinearGradient(0,0,0,100);
      g.addColorStop(0,'green');
      g.addColorStop(0.5,'blue');
      g.addColorStop(1,'red');
      ctx.strokeStyle=g;
      
      ctx.moveTo(0,0);
      ctx.lineTo(0,100);
      ctx.stroke();
      绘图如

      绘制线性渐变需要使用createLinearGradient和addColorStop方法
      context.createLinearGradient(x0,y0,x1,y1);
      • x0:渐变开始点的 x 坐标
      • y0:渐变开始点的 y 坐标
      • x1:渐变结束点的 x 坐标
      • y1:渐变结束点的 y 坐标
      gradient.addColorStop(stop,color);
      • stop:介于 0.0 与 1.0 之间的值,表示渐变中开始与结束之间的位置。
      • color:在结束位置显示的 CSS 颜色值
    2. 径向渐变
      示例
      <!--放置canvas-->
      <canvas id="mycanvas" width="300" height="200" style="border:1px solid #ccc;"></canvas>
      <script type="text/javascript">
      var canvas=document.getElementById("mycanvas");
      //获取context
      var ctx=canvas.getContext("2d");
      //设置样式
      var g=ctx.createRadialGradient(100,100,5,100,100,30);
      g.addColorStop(0,'green');
      g.addColorStop(0.5,'blue');
      g.addColorStop(1,'red');
      ctx.fillStyle=g;
      ctx.arc(100,100,50,0,Math.PI*2,true);
      ctx.fill();
      </script>
      使用的径向渐变方法
      context.createRadialGradient(x0,y0,r0,x1,y1,r1);
      • x0:渐变的开始圆的 x 坐标
      • y0:渐变的开始圆的 y 坐标
      • r0:开始圆的半径
      • x1:渐变的结束圆的 x 坐标
      • y1:渐变的结束圆的 y 坐标
      • r1:结束圆的半径

    绘制变形图

    1. 坐标变换
      可以通过变化canvas坐标来达到变换图形的效果,坐标有三种变换方式:
      • 平移:重新映射画布上的 (0,0) 位置
        context.translate(x,y);
        x和y分别表示把坐标原点向x和y方向移动多少个单位,默认的单位是像素;
      • 缩放:缩放当前绘图至更大或更小
        context.scale(x,y);
        x和y分别表示把x和y方向放大或缩小的倍数;
      • 旋转:旋转当前绘图
        context.rotate(angle);
        angle表示旋转角度,以弧度计。如需将角度转换为弧度,请使用 degrees*Math.PI/180 公式进行计算。
      示例
      <!--放置canvas-->
      <canvas id="mycanvas" width="300" height="200" style="border:1px solid #ccc;"></canvas>
      <script type="text/javascript">
      var canvas=document.getElementById("mycanvas");
      //获取context
      var ctx=canvas.getContext("2d");
      ctx.strokeStyle="green";
      ctx.strokeRect(0,0,50,50);
      //移动坐标
      ctx.translate(10,10);
      ctx.strokeRect(0,0,50,50);
      //缩放2倍
      ctx.scale(2,2);
      ctx.strokeRect(10,10,50,50);
      //旋转10度
      ctx.rotate(10*Math.PI/180);
      ctx.strokeRect(10,10,50,50);
      </script>
      绘制的图形

    2. 坐标变换和路径结合的使用
      路径一旦绘制好后是不会随着坐标变换而变换的,如
      var canvas=document.getElementById("mycanvas");
      //获取context
      var ctx=canvas.getContext("2d");
      //坐标变换前的路径
      ctx.moveTo(0,0);
      ctx.lineTo(100,20);
      ctx.lineTo(20,80);
      //变换坐标
      ctx.rotate(20*Math.PI/180);
      //为路径填色
      ctx.strokeStyle="green";
      ctx.stroke();
      
      //坐标变换后绘制的图像,路径与上一路径相同
      ctx.strokeStyle="red";
      ctx.beginPath();
      ctx.moveTo(0,0);
      ctx.lineTo(100,20);
      ctx.lineTo(20,80);
      ctx.stroke();
      绘制的图像

      可见坐标变换对路径是没影响的,一般这种情况我们会把绘图操作封装成一个函数,方便坐标变换后操作。
      var canvas=document.getElementById("mycanvas");
      //获取context
      var ctx=canvas.getContext("2d");
      
      doPic(ctx,"green");
      ctx.rotate(20*Math.PI/180);
      doPic(ctx,"red");
      ctx.rotate(20*Math.PI/180);
      doPic(ctx,"blue");
      
      function doPic(ctx,color){	
      	ctx.beginPath();
      	ctx.moveTo(0,0);
      	ctx.lineTo(100,20);
      	ctx.lineTo(20,80);
      	ctx.strokeStyle=color;
      	ctx.stroke();	
      }
    3. 矩阵变换
      如果上述都不能满足需求,HTML5还提供一种更复杂的变化:矩阵变换,这块牵涉到矩阵的数学知识,稍后单一节示例。

    图像组合

    通常当绘制的图像重叠时将以绘制的先后顺序来处理重叠的部分,但HTML5提供了globalCompositeOperation 选项来设置如何处理重叠。

    <canvas id="mycanvas" width="300" height="200" style="border:1px solid #ccc;"></canvas>
    <script type="text/javascript">
    var canvas=document.getElementById("mycanvas");
    //获取context
    var ctx=canvas.getContext("2d");
    
    ctx.fillStyle="red";
    ctx.fillRect(20,20,75,50);
    ctx.fillStyle="blue";	
    ctx.globalCompositeOperation="source-over";
    ctx.fillRect(50,50,75,50);	
    ctx.fillStyle="red";
    
    ctx.fillRect(150,20,75,50);
    ctx.fillStyle="blue";
    ctx.globalCompositeOperation="destination-over";
    ctx.fillRect(180,50,75,50);	
    </script>

    绘制的图像

    globalCompositeOperation 属性设置或返回如何将一个源(新的)图像绘制到目标(已有)的图像上。

    • 源图像 = 您打算放置到画布上的绘图。
    • 目标图像 = 您已经放置在画布上的绘图。

    属性值和描述

    • source-over:默认。在目标图像上显示源图像。
    • source-atop:在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的。
    • source-in:在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的。
    • source-out:在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的。
    • destination-over:在源图像上方显示目标图像。
    • destination-atop:在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示。
    • destination-in:在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的。
    • destination-out:在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的。
    • lighter:显示源图像 + 目标图像。
    • copy:显示源图像。忽略目标图像。
    • source-over:使用异或操作对源图像与目标图像进行组合。

    绘制阴影

    HTML5给添加阴影也非常简单,主要涉及到下面几个属性:

    • shadowColor:设置或返回用于阴影的颜色,如果取消只需设置为rgba(0,0,0,0);
    • shadowBlur:设置或返回用于阴影的模糊级别,一般设置在0-10之间;
    • shadowOffsetX:设置或返回阴影距形状的水平距离;
    • shadowOffsetY:设置或返回阴影距形状的垂直距离;
    ctx.fillStyle="blue";
    ctx.shadowColor="#ccc";
    ctx.shadowBlur=5;
    ctx.shadowOffsetX=10;
    ctx.shadowOffsetY=10;
    ctx.fillRect(10,10,60,60);
    ctx.fillRect(80,80,60,60);

    使用图片

      1. 绘制图片
        插入图片的方法只有一个,但是有三个重载方法,具体如下:
        context.drawImage (image, dx, dy)
        context.drawImage (image, dx, dy, dw, dh)
        context.drawImage (image, sx, sy, sw, sh, dx, dy, dw, dh)
        image是一个Image对象,用来装载图像文件,而其他参数参考下图:

        示例
        <canvas id="mycanvas" width="300" height="200" style="border:1px solid #ccc;">不支持canvas.</canvas>
        <script type="text/javascript">
        var mycanvas=document.getElementById("mycanvas");
        var ctx=mycanvas.getContext("2d");
        var img=new Image();
        img.src="p.jpg";
        ctx.drawImage(img,0,0);
        </script>
        但这样有时可能并不能绘制出图片,因为当image的src设置好后,但由于网络或图片过大导致不能及时加载,所以一般我们会在image的onload事件中操作
        <canvas id="mycanvas" width="300" height="200" style="border:1px solid #ccc;">不支持canvas.</canvas>
        <script type="text/javascript">
        var mycanvas=document.getElementById("mycanvas");
        var ctx=mycanvas.getContext("2d");
        var img=new Image();
        img.src="p.jpg";
        img.onload=function(){
        	ctx.drawImage(img,0,0); 
        	ctx.drawImage(img,10,10,50,50,250,0,50,50);
        }
        绘制的图片如:
      2. 图像平铺 HTML5提供了一个非常方便的方法
    createPattern(image, repetitionStyle)
        创建并返回一个 CanvasPattern 对象,该对象表示一个贴图图像所定义的模式。要使用一个模式来勾勒线条或填充区域,可以把一个 CanvasPattern 对象用作 strokeStyle 属性或 fillStyle 属性的值。repetitionStyle 说明图像如何贴图。可能的值如下所示:
        • "repeat" - 在各个方向上都对图像贴图。默认值。
        • "repeat-x" - 只在 X 方向上贴图。
        • "repeat-y" - 只在 Y 方向上贴图。
        • "no-repeat" - 不贴图,只使用它一次。
        示例
    img.onload=function(){
    	var ptt=ctx.createPattern(img,'repeat');
    	ctx.fillStyle=ptt;
    	ctx.fillRect(0,0,300,200);
    }

    1. 裁剪
      clip() 方法从原始画布中剪切出任意形状和尺寸。
      一旦再勾画出路径后调用clip方法,则所有只有的绘图都会被限制在这个路径区域,从而达到裁剪的效果,可以结合save和restore方法。
      img.onload=function(){	
      	ctx.beginPath();
      	ctx.arc(60,60,50,0,Math.PI*2,true);	
      	ctx.clip();
      	ctx.drawImage(img,0,0);
      }
    2. 像素
      html5还有一个令人赞叹的技术就是可以处理像素,这设计到两个API:
      var imgData=context.getImageData(x,y,width,height);
      • x - 开始复制的左上角位置的 x 坐标。
      • y - 开始复制的左上角位置的 y 坐标。
      • width - 将要复制的矩形区域的宽度。
      • height - 将要复制的矩形区域的高度。
      getImageData() 方法返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。对于 ImageData 对象中的每个像素,都存在着四方面的信息,即rgba 值:
      • r - 红色 (0-255)
      • g - 绿色 (0-255)
      • b - 蓝色 (0-255)
      • a - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
      color/alpha 以数组形式存在储于 ImageData对象的 data 属性中,形式如[r1,g1,b1,a1,r2,g2,b2,a2,....]。
      context.putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight);
      • imgData - 规定要放回画布的 ImageData 对象。
      • x - ImageData 对象左上角的 x 坐标,以像素计。
      • y - ImageData 对象左上角的 y 坐标,以像素计。
      • dirtyX - 可选。水平值(x),以像素计,在画布上放置图像的位置。
      • dirtyY - 可选。水平值(y),以像素计,在画布上放置图像的位置。
      • dirtyWidth - 可选。在画布上绘制图像所使用的宽度。
      • dirtyHeight - 可选。在画布上绘制图像所使用的高度。
      putImageData() 方法将图像数据(从指定的 ImageData 对象)放回画布上。
      示例:我们把图片上的一部分颜色取反,并把透明度降到60%:
      img.onload=function(){	
      	ctx.drawImage(img,0,0);
      	var imgData=ctx.getImageData(10,10,80,80);
      	for(var i=0;i<imgData.data.length;i+=4){
      		imgData.data[i]=255-imgData.data[i+2];
      		imgData.data[i+1]=255-imgData.data[i+1];
      		imgData.data[i+2]=255-imgData.data[i];
      		imgData.data[i+3]=imgData.data[i+3]*0.6;
      	}
      	ctx.putImageData(imgData,150,100);
      }

      PS:在chrome等浏览器中这个API函数设计到跨域的问题,因此不能通过本地浏览(即file:///),需要通过webserver(即http://)才能看到效果,否则报类似下面的异常:

      但firefox是好用的。

    绘制文字

    在canvas中也可以绘制文字,这涉及到两个API:

    context.fillText(text,x,y,maxWidth);
    context.strokeText(text,x,y,maxWidth);
    • text - 规定在画布上输出的文本。
    • x - 开始绘制文本的 x 坐标位置(相对于画布)。
    • y - 开始绘制文本的 y 坐标位置(相对于画布)。
    • maxWidth - 可选。允许的最大文本宽度,以像素计。

    在绘制之前可以先设置文字的相关属性:

    • font属性:设置文字的字体,语法与 CSS font 属性相同,可以按顺序设置font-style、font-variant、font-weight、font-size/line-height、font-family;
    • textAlign属性:设置文字的水平对齐方式,可选值start、end、left、right、center,默认是start;
    • textBaseline属性:设置文字的垂直对齐方式,可选值top、hanging、middle、alphabetic、ideographic、bottom,默认是alphabetic;

    有时为了方便定位,需要获取文字的宽度,html5提供了一个API:

    context.measureText(text)

    返回的TextMetrics对象的width属性表示使用当前指定的字体后文字的总长度。

    ctx.font="italic 30px sans-serif";
    ctx.textBaseline="top";
    ctx.fillStyle="red";
    var txt='爱我中华';
    ctx.fillText(txt,0,0);
    var tml = ctx.measureText(txt);
    ctx.strokeStyle="green";
    ctx.strokeText(txt,tml.width+20,0);

    善后工作

    1. 保存及恢复状态
      在绘制过程中,可能临时要改变一下属性设置,当临时绘制结束又想回到之前的状态,这就涉及到恢复,涉及到两个API:
      save() //把当前环境的状态压入栈
      restore() //状态出栈
      示例
      ctx.fillText(txt,0,0);
      ctx.save();//状态入栈
      ctx.fillStyle="green";
      ctx.textBaseline="bottom";
      ctx.fillText(txt,0,80);
      ctx.restore();//状态出栈
      ctx.fillText(txt,0,120);
    2. 保存文件
      在canvas绘制后可以使用toDataURL方法把它保存成浏览器能识别的data URL数据
      ctx.font="italic 30px sans-serif";
      ctx.textBaseline="top";
      ctx.fillStyle="red";
      var txt='爱我中华';
      ctx.fillText(txt,0,0);
      
      document.getElementById("img").src=mycanvas.toDataURL("image/jpeg");
      data URL是目前大多数浏览器能够识别的一种base64编码的URL,主要用于小型的、可以在网页中直接嵌入的数据,格式类似“data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAADICAYAAA....”
    3. 简单动画
      可以在canvas重复绘制、擦除、绘制的动作来实现动画,这其中涉及到一个擦除的API
      context.clearRect(x,y,width,height);
      setInterval函数
      setInterval(code,millisec[,"lang"])
      setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。
      例如我们来绘制一个运动的小圆:
      var i=0;
      var intervalId=setInterval(doarc,1000);
      
      function doarc(){
      	ctx.clearRect(0,0,mycanvas.width,mycanvas.height);
      	ctx.beginPath();
      	ctx.arc(i,i,20,20,Math.PI*2,true);
      	ctx.fillStyle="blue";
      	ctx.fill();
      	i+=30;
      	if(i>200){clearInterval(intervalId);}
      }

  • 相关阅读:
    Part 11 Search filter in AngularJS
    Part 10 AngularJS sort rows by table header
    Part 9 Sorting data in AngularJS
    Part 8 AngularJS filters
    Part 7Handling events in AngularJS
    Part 6 AngularJS ng repeat directive
    PHP单一入口应用程序概述
    SVN
    跨平台的.NET集成开发环境:MonoDevelop
    PHP中使用KindEditor
  • 原文地址:https://www.cnblogs.com/zhaiqianfeng/p/4621670.html
Copyright © 2011-2022 走看看