zoukankan      html  css  js  c++  java
  • 突袭HTML5之Canvas 2D入门2 Canvas绘制图形

      canvas只支持一种基本形状——矩形,所有其它形状都是通过一个或多个路径组合而成,甚至是基本的矩形也可以通过路径组合成。
    一、设置画笔属性
      设想我们生活中画图的样子,我们首先是选取合适的颜料和笔,一样的道理,在canvas中画图同样也是根据需要,不断的去设置当前使用的颜色和线条类型。
    设置当前使用的颜色
      
    任何封闭的图形都是有轮廓部分和填充部分组成。设置当前的颜色也是分两部分设置:

    • 设置填充色:context.fillStyle = color
    • 设置轮廓色:context.strokeStyle = color

      参数color可以是表示CSS颜色值的字符串,渐变对象或者图案对象。默认情况下,线条和填充颜色都是黑色(CSS颜色值#000000)。
    颜色的字符串表示
      下面都是正确的值:

    // 这些 fillStyle 的值均为 '橙色'  
    ctx.fillStyle = "orange";  
    ctx.fillStyle = "#FFA500";  
    ctx.fillStyle = "rgb(255,165,0)";  
    ctx.fillStyle = "rgba(255,165,0,1)";  

    如果你要给每个图形上不同的颜色,你需要重新设置 fillStyle或strokeStyle 的值,就像我们画画时需要不断换不同颜色的颜料一样。
    设置透明度
    1.设置全局透明度:context.globalAlpha = transparency value。
      这个属性影响到 canvas 里所有图形的透明度,有效的值范围是 0.0 (完全透明)到 1.0(完全不透明),默认是 1.0。例子如下所示:

    function draw2() {  
      var ctx = document.getElementById('lesson01').getContext('2d');  
      // draw background  
      ctx.fillStyle = '#FD0';  
      ctx.fillRect(0,0,75,75);  
      ctx.fillStyle = '#6C0';  
      ctx.fillRect(75,0,75,75);  
      ctx.fillStyle = '#09F';  
      ctx.fillRect(0,75,75,75);  
      ctx.fillStyle = '#F30';  
      ctx.fillRect(75,75,75,75);  
      ctx.fillStyle = '#FFF';  
      
      // set transparency value  
      ctx.globalAlpha = 0.2;  
      
      // Draw semi transparent circles  
      for (var i=0;i<7;i++){  
          ctx.beginPath();  
          ctx.arc(75,75,10+10*i,0,Math.PI*2,true);  
          ctx.fill();  
      }  
    }  

    2.设置单个图形的透明度

      很简单,把rgba格式的字符串赋给fillStyle或者strokeStyle就可以了。
    创建渐变色
      canvas中我们也可以用线性或者径向的渐变来填充或描边。创建渐变色要经过下面几个步骤:
    1.创建渐变对象:

    • 线性渐变:context.createLinearGradient(x1,y1,x2,y2)
      方法接受4个参数,表示渐变的起点(x1,y1) 与终点(x2,y2)。
    • 径向渐变:context.createRadialGradient(x1,y1,r1,x2,y2,r2)
      方法接受6个参数,前三个定义一个以(x1,y1)为原点,半径为r1的圆,后三个参数则定义另一个以(x2,y2)为原点,半径为r2的圆。

      两个方法返回响应的渐变对象,下面就可以给这个对象添加渐变颜色了。

    2.给渐变对象上色:
      上色:gradientObject.addColorStop(position, color)
      方法接受2个参数,position 参数必须是一个 0.0 与 1.0 之间的数值,表示渐变中颜色所在的相对位置。例如,0.5 表示颜色会出现在正中间;如果第一个色标的该参数值不是0.0,则渐变会默认认为从起点到第一个色标之间都是黑色。

      color 参数必须是一个有效的 CSS 颜色值(如 #FFF, rgba(0,0,0,1),等等)。
      可以根据需要添加任意多个色标(color stops),也就是说渐变的色彩数目是任意的。但是要注意保持色标定义顺序和它理想的顺序一致,特别是当色标的位置重叠的时候。
    3.把渐变对象赋给图形的fillStyle或strokeStyle属性。

    例子如下所示:

    function draw() {  
      var ctx = document.getElementById('lesson01').getContext('2d');  
      
      // Create gradients  
      var radgrad = ctx.createRadialGradient(45,45,10,52,50,30);  
      radgrad.addColorStop(0, '#A7D30C');  
      radgrad.addColorStop(0.9, '#019F62');  
      radgrad.addColorStop(1, 'rgba(1,159,98,0)');  
        
      var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50);  
      radgrad2.addColorStop(0, '#FF5F98');  
      radgrad2.addColorStop(0.75, '#FF0188');  
      radgrad2.addColorStop(1, 'rgba(255,1,136,0)');  
      
      var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40);  
      radgrad3.addColorStop(0, '#00C9FF');  
      radgrad3.addColorStop(0.8, '#00B5E2');  
      radgrad3.addColorStop(1, 'rgba(0,201,255,0)');  
      
      var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90);  
      radgrad4.addColorStop(0, '#F4F201');  
      radgrad4.addColorStop(0.8, '#E4C700');  
      radgrad4.addColorStop(1, 'rgba(228,199,0,0)');  
        
      // draw shapes  
      ctx.fillStyle = radgrad4;  
      ctx.fillRect(0,0,150,150);  
      ctx.fillStyle = radgrad3;  
      ctx.fillRect(0,0,150,150);  
      ctx.fillStyle = radgrad2;  
      ctx.fillRect(0,0,150,150);  
      ctx.fillStyle = radgrad;  
      ctx.fillRect(0,0,150,150);  
    }  

    创建图案填充效果
    简单两步即搞定。
    1.创建图案pattern:context.createPattern(image,type)
      该方法接受两个参数。Image 可以是一个 Image 对象的引用,或者另一个 canvas 对象。Type 必须是下面的字符串值之一:repeat,repeat-x,repeat-y 和 no-repeat。

    2.pattern赋给fillStyle或strokeStyle属性。

    function draw() {  
      var ctx = document.getElementById('lesson01').getContext('2d');  
      
      // create new image object to use as pattern  
      var img = new Image();  
      img.src = 'Penguins.jpg';  
      img.onload = function(){  
      
        // create pattern  
        var ptrn = ctx.createPattern(img,'repeat');  
        ctx.fillStyle = ptrn;  
        ctx.fillRect(0,0,150,150);  
      
      }  

    创建阴影效果(目前Google Chrome 16.0.912.75还是不支持的)
      主要是设置一下阴影效果的相关属性值:

    context.shadowOffsetX = float
    context.shadowOffsetY = float
    context.shadowBlur = float
    context.shadowColor = color

    shadowOffsetX和shadowOffsetY用来设定阴影在X和Y轴的延伸距离,它们是不受变换矩阵所影响的。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,他们默认都是0。
    shadowBlur用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵的影响,默认为0。
    shadowColor用于设定阴影效果的延伸,值可以是标准的CSS颜色值,默认是全透明的黑色。

    function draw3() {  
      var ctx = document.getElementById('lesson01').getContext('2d');  
      
      ctx.shadowOffsetX = 3;  
      ctx.shadowOffsetY = 3;  
      ctx.shadowBlur = 3;  
      ctx.shadowColor = "rgba(100, 100, 0, 0.5)";  
       
      ctx.font = "20px Times New Roman";  
      ctx.fillStyle = "Black";  
      ctx.fillText("Sample String", 5, 30);  
    }  

    设置画笔的类型
    画笔粗细:context.lineWidth = value
      这个属性设置当前绘线的粗细。属性值必须为正数。默认值是1.0。

      线宽是指给定路径的中心到两边的粗细。换句话说就是在路径的两边各绘制线宽的一半。因为画布的坐标并不和像素直接对应,当需要获得精确的水平或垂直线的时候要特别注意。
    端点样式:context.lineCap = type
      属性 lineCap 的指决定了线段端点显示的样子。它可以为下面的三种的其中之一:butt,round 和 square。默认是 butt。每种设置完的效果如下图lineCap部分从左到右所示。
    连接点样式:context.lineJoin = type
      lineJoin 的属性值决定了图形中两线段连接处所显示的样子。它可以是这三种之一:round, bevel 和 miter。默认是 miter。每种设置完的效果如下图lineJoin部分从上到下所示。
    斜面连接限制:context.miterLimit = value
      当应用miter效果时,线段的外侧边缘会延伸交汇于一点上。线段直接夹角比较大的,交点不会太远,但当夹角减少时,交点距离会呈指数级增大。这时可以用miterLimit属性设定外延交点与连接点的最大距离,如果交点距离大于此值,连接效果会变成了 bevel。

     

    例子如下:

    function draw6() {  
      var ctx = document.getElementById('lesson01').getContext('2d');  
      var lineCap = ['butt','round','square'];  
      
      // Draw guides  
      ctx.strokeStyle = '#09f';  
      ctx.beginPath();  
      ctx.moveTo(10,10);  
      ctx.lineTo(140,10);  
      ctx.moveTo(10,140);  
      ctx.lineTo(140,140);  
      ctx.stroke();  
      
      // Draw lines  
      ctx.strokeStyle = 'black';  
      for (var i=0;i<lineCap.length;i++){  
        ctx.lineWidth = 15;  
        ctx.lineCap = lineCap[i];  
        ctx.beginPath();  
        ctx.moveTo(25+i*50,10);  
        ctx.lineTo(25+i*50,140);  
        ctx.stroke();  
      }  
    }  
    function draw() {  
      var ctx = document.getElementById('lesson01').getContext('2d');  
      var lineJoin = ['round','bevel','miter'];  
      ctx.lineWidth = 10;  
      for (var i=0;i<lineJoin.length;i++){  
        ctx.lineJoin = lineJoin[i];  
        ctx.beginPath();  
        ctx.moveTo(-5,5+i*40);  
        ctx.lineTo(35,45+i*40);  
        ctx.lineTo(75,5+i*40);  
        ctx.lineTo(115,45+i*40);  
        ctx.lineTo(155,5+i*40);  
        ctx.stroke();  
      }  
    }  

    二、绘制简单矩形
      矩形是唯一的基本图形,canvas提供了直接的API支持。

    • context.fillRect(x,y,width,height) : 绘制带填充色的矩形。
    • context.strokeRect(x,y,width,height) : 绘制矩形外框。
    • context.clearRect(x,y,width,height) : 清空指定的矩形区域,并设置该区域是透明的(Transparent)。
      它们都接受四个参数, x 和 y 指定矩形左上角(相对于原点)的位置,width 和 height 是矩形的宽和高。

      除了这种方式,还可以使用绘制路径的方式绘制矩形,这个参看路径绘图部分。

    绘制矩形的例子如下:

    function draw(){
      var canvas = document.getElementById('tutorial');
      if (canvas.getContext){
        var ctx = canvas.getContext('2d');

        ctx.fillRect(25,25,100,100);
        ctx.clearRect(45,45,60,60);
        ctx.strokeRect(50,50,50,50);
      }
    }

    三、路径绘图

      cavas只提供了绘制矩形的API,其他的图形都是靠路径绘制。

    绘制一个图形主要的过程如下:
    1.启动路径
    方法:使用context.beginPath()启动路径绘图。
      在内存里,路径是以一组子路径(直线,弧线等)的形式储存的,它们共同构成一个图形。每次调用 beginPath,子路径组都会被重置,然后可以绘制新的图形。
    2.移动画笔到起点
    方法:使用moveTo(x, y)移动画笔。
      虽然大多数画图的时候,用不到这个方法。我们也不能用这个方法来画什么,但是你可以把它想象成是把笔提起,并从一个点移动到另一个点的过程。当你绘制不联系的路径的时候,你就会有这个动作了。
    当 canvas 初始化或者调用 beginPath 的时候,起始坐标设置就是原点(0,0)。有时候,我们需要moveTo方法将起始坐标移至其它地方,用于绘制不连续的路径。
    3.内存中绘制线段
    画直线:lineTo(x, y)
      该方法接受终点的坐标(x,y)作为参数。起始坐标取决于前一路径,前一路径的终点即当前路径的起点,起始坐标通常也可以通过moveTo方法来设置。
    画圆弧:arc(x, y, radius, startAngle, endAngle, anticlockwise)
      我们用 arc 方法来绘制弧线或圆,方法接受五个参数:x,y 是圆心坐标,radius 是半径,startAngle 和 endAngle 分别是起末弧度(以 x 轴为基准),anticlockwise 为 true 表示逆时针,反之顺时针。
    注意:arc 方法里用到的角度是以弧度为单位而不是度。度和弧度直接的转换可以用这个表达式:var radians = (Math.PI/180)*degrees;
    画二次贝塞尔曲线:quadraticCurveTo(cp1x, cp1y, x, y)
    画三次贝塞尔曲线:bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
      贝塞尔曲线 ,它可以是二次和三次方的形式,一般用于绘制复杂而有规律的形状。它们都有一个起点一个终点(下图中的蓝点),但二次方贝塞尔曲线只有一个(红色)控制点点)而三次方贝塞尔曲线有两个。
      参数x和y是终点坐标,cp1x和 cp1y是第一个控制点的坐标,cp2x和cp2y是第二个的。
      使用二次方和三次方的贝塞尔曲线是相当有挑战的,因为缺少直观性。理论上只要有耐心,再复杂的图形都可以绘制出来的。


     

    绘制矩形路径:context.rect(x, y, width, height)
      当rect方法被调用时,moveTo方法会自动被调用,参数为(0,0),于是起始坐标又恢复成初始原点了。
    4.关闭路径
    方法:使用context.closePath()关闭路径。

      该方法它会尝试用直线连接当前端点与起始端点来关闭路径,但如果图形已经关闭或者只有一个点,它会什么都不做,这一步在某些情况并不是必须的,比如使用fill()绘制实际图形的时候,就不需要先调用closePath。
    5.绘制路径到canvas
    画图形边框:context.stroke()
    填充实心图形:context.fill()

    最后这一步是调用 stroke或 fill方法,这时,图形才是实际的绘制到 canvas 上去。

    调用stroke之前必须要先调用关闭路径方法closePath。而调用fill之前不需要调用closePath关闭路径,调用fill时路径会自动闭合。

    一个复杂的例子如下:

    function draw() {
      var ctx = document.getElementById('lesson01').getContext('2d');
      roundedRect(ctx,12,12,150,150,15);
      roundedRect(ctx,19,19,150,150,9);
      roundedRect(ctx,53,53,49,33,10);
      roundedRect(ctx,53,119,49,16,6);
      roundedRect(ctx,135,53,49,33,10);
      roundedRect(ctx,135,119,25,49,10);

      ctx.beginPath();
      ctx.arc(37,37,13,Math.PI/7,-Math.PI/7,false); //chiensexu  ???true??,??
      ctx.lineTo(31,37);
      ctx.fill();
      for(i=0;i<8;i++){
        ctx.fillRect(51+i*16,35,4,4);
      }
      for(i=0;i<6;i++){
        ctx.fillRect(115,51+i*16,4,4);
      }
      for(i=0;i<8;i++){
        ctx.fillRect(51+i*16,99,4,4);
      }
      ctx.beginPath();
      ctx.moveTo(83,116);
      ctx.lineTo(83,102);
      ctx.bezierCurveTo(83,94,89,88,97,88);
      ctx.bezierCurveTo(105,88,111,94,111,102);
      ctx.lineTo(111,116);
      ctx.lineTo(106.333,111.333);
      ctx.lineTo(101.666,116);
      ctx.lineTo(97,111.333);
      ctx.lineTo(92.333,116);
      ctx.lineTo(87.666,111.333);
      ctx.lineTo(83,116);
      ctx.fill();
      ctx.fillStyle = "white";
      ctx.beginPath();
      ctx.moveTo(91,96);
      ctx.bezierCurveTo(88,96,87,99,87,101);
      ctx.bezierCurveTo(87,103,88,106,91,106);
      ctx.bezierCurveTo(94,106,95,103,95,101);
      ctx.bezierCurveTo(95,99,94,96,91,96);
      ctx.moveTo(103,96);
      ctx.bezierCurveTo(100,96,99,99,99,101);
      ctx.bezierCurveTo(99,103,100,106,103,106);
      ctx.bezierCurveTo(106,106,107,103,107,101);
      ctx.bezierCurveTo(107,99,106,96,103,96);
      ctx.fill();
      ctx.fillStyle = "black";
      ctx.beginPath();
      ctx.arc(101,102,2,0,Math.PI*2,true);
      ctx.fill();
      ctx.beginPath();
      ctx.arc(89,102,2,0,Math.PI*2,true);
      ctx.fill();
    }

    function roundedRect(ctx,x,y,width,height,radius){
      ctx.beginPath();
      ctx.moveTo(x,y+radius);
      ctx.lineTo(x,y+height-radius);
      ctx.quadraticCurveTo(x,y+height,x+radius,y+height);
      ctx.lineTo(x+width-radius,y+height);
      ctx.quadraticCurveTo(x+width,y+height,x+width,y+height-radius);
      ctx.lineTo(x+width,y+radius);
      ctx.quadraticCurveTo(x+width,y,x+width-radius,y);
      ctx.lineTo(x+radius,y);
      ctx.quadraticCurveTo(x,y,x,y+radius);
      ctx.stroke();
    }

    结果如下:

    实用参考:
    官方参考文档以及API详细说明:http://www.whatwg.org/specs/web-apps/current-

    work/multipage/the-canvas-element.html
    权威开发入门:https://developer.mozilla.org/cn/Canvas_tutorial

  • 相关阅读:
    《软件工程》团队第一阶段Sprint检查表
    灭霸第一阶段绩效评估
    【Copy攻城狮日志】docker搭建jenkins拉取svn代码打包vue项目部署到nginx
    前端移动App开发环境搭建
    【Copy攻城狮日志】Node快速重命名文件,告别Potplay字幕困扰问题
    centos部署yapi爬坑记
    mint-ui之picker爬坑记
    前端内网穿透,localtunnel你值得拥有!
    Visual Studio Live Share不完全指北
    jq跑马灯效果
  • 原文地址:https://www.cnblogs.com/dxy1982/p/2363037.html
Copyright © 2011-2022 走看看