zoukankan      html  css  js  c++  java
  • 【canvas学习笔记二】绘制图形

    上一篇我们已经讲述了canvas的基本用法,学会了构建canvas环境。现在我们就来学习绘制一些基本图形。

    坐标

    canvas的坐标原点在左上角,从左到右X轴坐标增加,从上到下Y轴坐标增加。坐标的一个单元是1像素。示意如下:
    image

    矩形

    canvas可以绘制的多边形只有矩形,其他都要通过线段拼接而成。
    绘制矩形有三个API:

    fillRect(x, y, width, height)
    绘制一个填充的矩形。 
    
    strokeRect(x, y, width, height)  
    绘制一个只有描边的矩形。 
    
    clearRect(x, y, width, height)  
    清除特定的矩形区域,使之变成透明。  
    

    参数说明:

    x,y是矩形左上角的坐标,width和height是矩形的宽和高。

    代码示例:

    function draw() {
      var canvas = document.getElementById('canvas');
      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);
      }
    }
    

    效果如下:

    image

    最外面那个黑色的矩形就是第一行代码ctx.fillRect(25, 25, 100, 100)画的填充矩形。中间的透明矩形就是第二行代码ctx.clearRect(45, 45, 60, 60)清除的矩形,再中间的描边矩形就是第三行代码ctx.strokeRect(50, 50, 50, 50)画的。

    路径

    绘制路径的一般步骤如下:

    1. 创造路径
    2. 绘制路径
    3. 闭合路径
    4. 填充路径或给路径描边

    绘制的代码如下:

    ctx.beginPath();    // 创造路径
    // 路径绘制,先省略,后面再路径绘制的方法
    ctx.closePath();    // 闭合路径
    ctx.stroke();   // 描边
    // ctx.fill();  // 换成这行命令就是填充
    

    在这个一般步骤中,只有闭合路径步骤可以省略,其他步骤都是不可省略的。如果不需要画闭合的图形,可以不闭合路径。
    接下来讲述绘制路径的方法。

    移动画笔

    moveTo(x, y)这个方法可以移动画笔的坐标,将画笔移动到坐标(x, y)的位置。
    用beginPath()创造路径时,要先用moveTo(x, y)确定起始位置,除非是圆弧之类不需要初始点的路径绘制方法。

    线段

    lineTo(x, y)方法绘制一条线段,x, y指定了线段末尾的坐标。配合moveTo(x, y)方法就可以画出线段。
    示例:

          var canvas = document.getElementById('canvas');
          if (canvas.getContext) {
            var ctx = canvas.getContext('2d');
            ctx.beginPath();
            ctx.moveTo(0,0)
            ctx.lineTo(50,50);
            ctx.lineTo(100,50);
            ctx.stroke();
              
               
            ctx.beginPath();
            ctx.moveTo(75,0)
            ctx.lineTo(70,50);
            ctx.lineTo(150,50);
            ctx.closePath();
            ctx.stroke();
          }
    

    效果如下:

    image

    再来画个三角形:

    var canvas = document.getElementById('canvas');
      if (canvas.getContext) {
        var ctx = canvas.getContext('2d');
    
        ctx.beginPath();
        ctx.moveTo(75, 50);
        ctx.lineTo(100, 75);
        ctx.lineTo(100, 25);
        ctx.fill();
      }
    

    效果:
    image

    矩形******

    同样的,路径方法里也有绘制矩形的方法。

    rect(x, y, width, height)
    

    x,y是矩形左上角坐标,width是矩形的宽,height是矩形的高。
    这个方法和前面说的矩形不同在于,这个方法是路径绘制方法,要配合beginPath()和stroke()之类的方法来使用的。要先创建路径,然后用这个方法绘制矩形,再stroke()或fill(),否则画不出来。

    圆弧

    绘制圆弧有两个方法:

    arc(x, y, radius, startAngle, endAngle, anticlockwise)
    
    arcTo(x1, y1, x2, y2, radius)
    

    第一个方法中的x, y参数指定了圆弧的圆心坐标。
    radius参数是圆弧的半径长度。
    startAngle参数是圆弧起始的弧度,endAngle是圆弧结束的弧度,单位是弧度,不是度。
    anticlockwise是个布尔值,设置圆弧是顺时针画还是逆时针画,当anticlockwise为true是逆时针,为false是顺时针,这个值缺省的时候默认是顺时针。
    Tips:

    角度的单位是弧度,可以用这个表达式把度数转换成弧度:radians = (Math.PI/180)*degrees

    下面来看一个有趣的例子:

    function draw() {
      var canvas = document.getElementById('canvas');
      if (canvas.getContext) {
        var ctx = canvas.getContext('2d');
    
        for (var i = 0; i < 4; i++) {
          for (var j = 0; j < 3; j++) {
            ctx.beginPath();
            var x = 25 + j * 50; // x coordinate
            var y = 25 + i * 50; // y coordinate
            var radius = 20; // Arc radius
            var startAngle = 0; // Starting point on circle
            var endAngle = Math.PI + (Math.PI * j) / 2; // End point on circle
            var anticlockwise = i % 2 !== 0; // clockwise or anticlockwise
    
            ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
    
            if (i > 1) {
              ctx.fill();
            } else {
              ctx.stroke();
            }
          }
        }
      }
    }
    

    这段代码总共画了四行三列的圆弧。相邻的圆弧圆心X轴和Y轴都相距50像素,圆弧的半径都是20像素,每列圆弧的弧度相差90度。第一行和第三行都是顺时针,第二行和第四行都是逆时针。第一行和第二行描边,第三行和第四行填充。
    效果是这样的:
    image

    第二个圆弧方法比较复杂,效果难以控制,它其实是画一段带直线的圆弧。我尽量把它说明白。

    arcTo(x1, y1, x2, y2, radius)

    参数x1, y1, x2, y2分别是两个控制点的坐标,radius是圆弧的半径长度。
    下面用一个例子来说明控制点的意义:

    ctx.beginPath();
    ctx.moveTo(150, 20);
    ctx.arcTo(150, 100, 50, 20, 30);
    ctx.stroke();
    
    ctx.fillStyle = 'blue';
    // base point
    ctx.fillRect(150, 20, 10, 10);
    
    ctx.fillStyle = 'red';
    // control point one
    ctx.fillRect(150, 100, 10, 10);
    // control point two
    ctx.fillRect(50, 20, 10, 10);
    

    效果如图:
    image
    蓝色方块的左上角坐标是moveTo的坐标,右下方的红色方块的左上角坐标是第一个控制点的坐标,左上方的红色方块的左上角坐标是第二个控制点的坐标。
    注意,蓝色方块和圆弧之间是有一小段直线的。
    注意,这个方法的开始是必须用moveTo方法来指定起始点的,也就是蓝色方块的位置,否则画不出来。
    这个方法难以控制,所以通常不去用它。

    贝塞尔和二次曲线

    现在我要说两个更难以控制的绘图API了,二次贝塞尔曲线和三次贝塞尔曲线。

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

    上面的是二次曲线,下面的是三次曲线。下面用一张图来说明这两个曲线方法。
    image
    这两个方法的区别就是一个只有一个控制点(图中红点),一个有两个控制点。
    参数cp1x, cp1y, cp2x, cp2y是控制点的坐标,x, y是曲线的末端的坐标值,也就是图中的蓝点中的其中一个。
    因为不是在Illustrator等图形编辑软件里,不能可视化地控制点,所以用这个两个方法绘制图形相当需要耐心。
    举个二次曲线画图的例子吧:

    function draw() {
      var canvas = document.getElementById('canvas');
      if (canvas.getContext) {
        var ctx = canvas.getContext('2d');
    
        // Quadratric curves example
        ctx.beginPath();
        ctx.moveTo(75, 25);
        ctx.quadraticCurveTo(25, 25, 25, 62.5);
        ctx.quadraticCurveTo(25, 100, 50, 100);
        ctx.quadraticCurveTo(50, 120, 30, 125);
        ctx.quadraticCurveTo(60, 120, 65, 100);
        ctx.quadraticCurveTo(125, 100, 125, 62.5);
        ctx.quadraticCurveTo(125, 25, 75, 25);
        ctx.stroke();
      }
    }
    

    效果:
    image
    三次曲线的例子我就不说了。反正大家通常肯定不会用这两个方法去绘制图形的。
    有个贝塞尔曲线可视化的网页,对画贝塞尔曲线有帮助。戳这里

    2D路径对象

    实际绘图过程中,常常需要绘制很多路径,其中很多可能是重复的。2D路径对象的作用就是存储重复使用的路径,提高性能,简化代码,新版浏览器都支持。
    我先说一下初始化2D路径对象的方法,有三种:

    new Path2D(); // empty path object
    new Path2D(path); // copy from another Path2D object
    new Path2D(d); // path from SVG path data

    构造函数可以不含参数,这样创建的就是一个空的路径对象,同样也可以传一个2D路径对象作参数,这样就拷贝了一个2D路径对象,还可以传一段SVG路径数据,比如这样:var p = new Path2D('M10 10 h 80 v 80 h -80 Z');
    还是用例子来说明Path2D这个对象比较清楚:

    function draw() {
      var canvas = document.getElementById('canvas');
      if (canvas.getContext) {
        var ctx = canvas.getContext('2d');
    
        var rectangle = new Path2D();
        rectangle.rect(10, 10, 50, 50);
    
        var circle = new Path2D();
        circle.moveTo(125, 35);
        circle.arc(100, 35, 25, 0, 2 * Math.PI);
    
        ctx.stroke(rectangle);
        ctx.fill(circle);
      }
    }
    

    在这个例子中,创建了一个存储了矩形路径的对象,和一个存储了圆的路径对象,结果如下:
    image
    所有上面说过的路径绘制方法Path2D这个对象都能使用。
    另外Path2D这个对象还有一个拼接路径的方法:

    Path2D.addPath(path [, transform])
    Adds a path to the current path with an optional transformation matrix.

    把一段路径传进去就可以将这两段路径拼接起来,带有一个可选参数,是一个SVG变换矩阵。
    举个栗子:

    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    
    // Create a new path with a rect
    var p1 = new Path2D();
    p1.rect(0, 0, 100, 100);
    
    // Create another path with a rect
    var p2 = new Path2D();
    p2.rect(0, 0, 100, 100);
    
    // Create transformation matrix that moves vertically 300 points to the right
    var m = document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGMatrix();
    m.a = 1; m.b = 0;
    m.c = 0; m.d = 1;
    m.e = 300; m.f = 0;
    
    // add the second path to the first path
    p1.addPath(p2, m);
    
    // Finally, fill the first path onto the canvas
    ctx.fill(p1);
    
  • 相关阅读:
    cmd设置代理
    移动端坐标定位tap
    T02-Django基本应用结构
    支持向量机算法的Sklearn完整复现
    T01-何为Django,入门"Hello World"
    决策树算法的Sklearn完整复现
    逻辑回归算法的Sklearn完整复现
    线性回归算法Sklearn完整复现
    K-近邻算法的Sklearn完整复现
    数据分析中的'疑难杂症'小结(三)
  • 原文地址:https://www.cnblogs.com/-867259206/p/7251057.html
Copyright © 2011-2022 走看看