Canvas(基础)

作者: IgorZhang | 来源:发表于2016-10-14 22:16 被阅读2032次

    标签:canvas 简单示例 入门知识
    作者: 张耀国 ( IgorZhang )
    E-mail: igorzhangcn@163.com


    canvas 是 HTML5 新增的元素,可使用JavaScript脚本来绘制图形。例如:画图,合成照片,创建动画甚至实时视频处理与渲染。

    基本用法

    <canvas id="canvas" width="500px" height="500px" >
        您的浏览器不支持canvas,请升级您的浏览器!
    </canvas>
    

    canvas 标签只有两个属性—— width 和 height。这些都是可选的,当没有设置宽度和高度的时候,canvas会初始化宽度为300像素和高度为150像素。宽高只可以通过 JavaScript 进行修改。该元素可以使用CSS来定义大小,但在绘制时图像会伸缩以适应它的框架尺寸:如果CSS的尺寸与初始画布的比例不一致,它会出现扭曲。
    如果浏览器版本过低,或者浏览器内核不支持canvas标签的话,那么标签内部的替换内容将会对用户做出提示,若浏览器支持canvas,替换内容将不会出现。

    绘制前准备

    在绘制之前我们必须先获取canvas元素以及开启2d绘图的渲染上下文(简称获取画笔)

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    

    代码的第一行通过使用 document.getElementById() 方法来为 canvas 元素得到DOM对象。一旦有了元素对象,你可以通过使用它的getContext() 方法来访问绘画上下文。

    栅格

    栅格

    在我们开始画图之前,我们需要了解一下画布栅格(canvas grid)以及坐标空间。如右图所示,canvas元素默认被网格所覆盖。通常来说网格中的一个单元相当于canvas元素中的一像素。栅格的起点为左上角(坐标为(0,0))。所有元素的位置都相对于原点定位。所以图中蓝色方形左上角的坐标为距离左边(Y轴)x像素,距离上边(X轴)y像素(坐标为(x,y))。

    绘制路径

    直线

    绘制一条直线,我们需要两个点,即起点和终点。这两个点都将用坐标(x,y)表示。

    // 获取元素
    var canvas = document.getElementById("canvas");
    // 获取上下文对象
    // 获取“画笔”,大多数操作都是使用画笔进行
    var ctx = canvas.getContext("2d");
    
    // 画一条直线
    // 1.开始绘制
    ctx.beginPath();
    // 2,放置起始点
    ctx.moveTo(100, 100);
    // 3.放置后续的点 (可以写任意多个)
    ctx.lineTo(200, 200);
    // 4.结束路径绘制(闭合路径) (非必需)
    ctx.closePath();
    // 5.画线
    ctx.stroke();
    

    此时,我们已经画出了一条直线

    我们这里要注意了:
    ctx.closePath(); 使用这个方法之后,会自动将起点与终点链接起来,如果不需要连接的话,可以不用写这个方法。但是如果要绘制第二个图形的话,第二个图形必须先使用ctx.beginPath(); 方法,防止与上个图形连接。

    绘制一个三角形

    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    
    // 1.开始绘制
    ctx.beginPath();
    // 2.放置起始点
    ctx.moveTo(75,50);
    // 3.放置后续两个点
    ctx.lineTo(100,75);
    ctx.lineTo(100,25);
    // 4.闭合路径
    ctx.closePath();
    // 5.画线
    ctx.stroke();
    

    我们通过获取三个点之后用ctx.stroke()方法进行连接。就可以得到一个三角形。但是:我们此时绘制的仅仅是三条细长的直线连接。有没有什么方法可以修改它的样式呢? 有的,这里我们只需要设置几个属性即可。

    // 设置线条宽度
    ctx.lineWidth = 20;
    // 设置线条颜色
    ctx.strokeStyle = "red";
    // 设置填充颜色
    ctx.fillStyle = "brown";
    
    // 设置线两端为圆角
    // 在使用lineCap的时候,一定要非常小心closePath
    ctx.lineCap = "round";
    // 设置交叉线的交接为圆角
    ctx.lineJoin = "round";
    

    这里我们要介绍另一个方法了:fill(); (填充)

    fill ( ) 方法能够将绘制的图形进行填充。在刚刚我们绘制三角形时,如果使用 fill ( ) 方法,我们将会获得一个经过颜色填充的三角形。那么我们可以 stroke()和 fill()两个方法同时使用吗? 没问题,这是可以的。

    综合实例:绘制一个边框宽度为20像素,边框颜色为红色,填充颜色为黄色的三角形

    ctx.beginPath();
    ctx.moveTo(75,50);
    ctx.lineTo(100,75);
    ctx.lineTo(100,25);
    ct.lineWidth = 20;
    ctx.strokeStyle = "red";
    ctx.stroke();
    ctx.fillStyle = "yellow";
    ctx.fill();
    

    绘制矩形

    绘制矩形,canvas 给我们提供了非常便捷的方法:
    绘制一个矩形边框
    strokeRect(x, y, width, height);
    绘制一个填充后的矩形
    fillRect(x, y, width, height);
    擦除指定大小的矩形区域(可以理解为橡皮擦)
    clearRect(x, y, width, height);

    x , y 是相对于canvas左上角(原点)的坐标,同样。我们要绘制的矩形也将以 x, y为原点进行绘制。 width 和 height 即为我们要绘制矩形的宽和高。

    • 简单实例:
    ctx.fillRect(25,25,100,100);
    ctx.clearRect(45,45,60,60);
    ctx.strokeRect(50,50,50,50);
    //fillRect()函数绘制了一个边长为100px的黑色正方形。clearRect()函数从正方形的中心开始擦除了一个60*60px的正方形,接着strokeRect()在清除区域内生成一个50*50的正方形边框。
    

    实现效果:


    综合实例:绘制一个长宽为200px,边框为10px红色,填充颜色为绿色的,且中间部分矩形区域透明的矩形
    ctx.fillStyle = "green";
    ctx.lineWidth = "10px";
    ctx.strokeStyle = "red";
    ctx.strokeRect( 100, 100, 200, 200);
    ctx.strokeRect( 100, 100, 200, 200);
    ctx.clearRect( 150, 150, 100, 100);
    

    绘制圆和圆弧

    绘制圆弧或者圆,我们使用arc()方法。

    arc(x, y, radius, startAngle, endAngle, anticlockwise)
    画一个以(x,y)为圆心的以radius为半径的圆弧(圆),从startAngle开始到endAngle结束,按照anticlockwise给定的方向(默认为顺时针)来生成。

    arcTo(x1, y1, x2, y2, radius)
    根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。

    该方法有五个参数:x,y为绘制圆弧所在圆上的圆心坐标。radius为半径。startAngle以及endAngle参数用弧度定义了开始以及结束的弧度。这些都是以x轴为基准。参数anticlockwise 为一个布尔值。为true时,是逆时针方向,否则顺时针方向。

    注意:arc()函数中的角度单位是弧度,不是度数。角度与弧度的js表达式:radians=(Math.PI/180)*degrees。

    小例子:绘制笑脸

    // 笑脸
    ctx.beginPath();
    ctx.arc(250,430,70, 0,Math.PI*2, true);
    ctx.stroke();
    ctx.beginPath();
    ctx.arc(250,430,50, 0,Math.PI, false);
    ctx.stroke();
    ctx.beginPath();
    ctx.arc(230,410,10, 0,Math.PI*2, true);
    ctx.stroke();
    ctx.beginPath();
    ctx.arc(270,410,10, 0,Math.PI*2, true);
    ctx.stroke();
    

    小例子:绘制一个绘制一个由多个随机颜色不同大小的圆组成的镖靶

    // 定义一个函数,用于获取随机颜色
    function random () {
        return parseInt(Math.random() * 255);
    }
    // 用for循环创建10个填充了随机颜色的圆形
    for( var i = 10; i > 0 ; i--){
        ctx.beginPath();
        ctx.arc(200, 200, 20 * i, 0, Math.PI * 2, true);
        ctx.fillStyle = "rgb(" + random() + "," + random() + "," +random() + ")";
        ctx.fill();
        ctx.stroke();
    }
    

    绘制二次贝塞尔曲线及三次贝塞尔曲线

    贝塞尔曲线

    在绘制图形时,贝塞尔全非常有用,常用来绘制复杂的有规律的图形。

    • quadraticCurveTo(cpx, cpy, x, y)  
      绘制二次贝塞尔曲线,cpx,cpy表示控制点的坐标, x,y表示终点坐标;
    • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
      绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。

    上边的图能够很好的描述两者的关系,贝塞尔曲线有一个开始、结束点(蓝色)以及一个控制点(红色),而三次贝塞尔曲线使用两个控制点。

    参数x、y在这两个方法中都是结束点坐标。cp1x,cp1y为坐标中的第一个控制点,cp2x,cp2y为坐标中的第二个控制点。

    二次贝塞尔曲线

    quadraticCurveTo(cpx, cpy, x, y)  
    cpx,cpy表示控制点的坐标, x,y表示终点坐标;

    P0 为起点, P2为终点, P1为控制点。

    // 先简单绘制一个二次贝塞尔曲线
    var canvas=document.getElementById('canvas');
    var context=canvas.getContext('2d');
    //绘制起始点、控制点、终点  
    context.beginPath();  
    context.moveTo(20,170);  
    context.lineTo(130,40);  
    context.lineTo(180,150);    
    context.stroke();            
    //绘制二次贝塞尔曲线  
    context.beginPath();  
    context.moveTo(20,170);  
    context.quadraticCurveTo(130,40,180,150); 
    context.strokeStyle = "red"; 
    context.stroke();   
    
    效果如图:

    实例: 用二次贝塞尔曲线绘制对话气泡

    // 二次贝尔赛曲线
    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();
    

    代码效果如下:


    三次贝塞尔曲线

    bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
    绘制三次贝塞尔曲线,cp1x,cp1y为控制点一,cp2x,cp2y为控制点二,x,y为结束点。

    P0 和 P3 为起点和终点, P1 和 P2 为控制点

    先简单绘制一个三次贝塞尔曲线模型感受一下。

    var canvas=document.getElementById('canvas');
    var context=canvas.getContext('2d'); 
    //绘制起始点、控制点、终点 
    context.beginPath(); 
    context.moveTo(25,175); 
    context.lineTo(60,80); 
    context.lineTo(150,30); 
    context.lineTo(170,150); 
    context.stroke();
    //绘制3次贝塞尔曲线 
    context.beginPath(); 
    context.moveTo(25,175); 
    context.bezierCurveTo(60,80,150,30,170,150); 
    context.strokeStyle = "red"; 
    context.stroke(); 
    

    效果图如下:


    实例:使用三次贝塞尔曲线绘制一个心形❤

     // 三次贝塞尔曲线
    ctx.beginPath();
    ctx.moveTo(75,40);
    ctx.bezierCurveTo(75,37,70,25,50,25);
    ctx.bezierCurveTo(20,25,20,62.5,20,62.5);
    ctx.bezierCurveTo(20,80,40,102,75,120);
    ctx.bezierCurveTo(110,102,130,80,130,62.5);
    ctx.bezierCurveTo(130,62.5,130,25,100,25);
    ctx.bezierCurveTo(85,25,75,37,75,40);
    ctx.fill();
    

    代码效果如下:

    !

    绘制文本

    canvas 提供了两种方法来渲染文本:

    fillText(text, x, y [, maxWidth])
    在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的.

    strokeText(text, x, y [, maxWidth])
    在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的

    上代码:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    
    // 获取canvas的宽度和高度
    var canvasWidth = canvas.width;
    var canvasHeight = canvas.height;
    
    // 设置字体
    ctx.font = "50px 宋体"
    // 设置水平对其方式
    // 水平对齐选项. 可选的值包括:start, end, left, right or center. 默认值是 start。
    ctx.textAlign = "center";
    
    // 设置垂直对齐方式
    // 基线(垂直)对齐选项. 可选的值包括:top, hanging, middle, alphabetic, ideographic, bottom。默认值是 alphabetic。
    ctx.textBaseline = "middle"
    
    // 绘制文字
    ctx.storkeText("今天要是啊",100,100);
    
    // 让文字水平垂直居中
    ctx.font = "40px 楷体"
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillText("哈哈哈", canvasWidth/2, canvasHeight/2);
    

    文本同样可以使用 strokeText() 和 fillText() 来绘制空心或实心文字,并且可以添加各种样式

    使用图片

    从零创建一个图片

    我们可以用脚本创建一个新的Image对象。要实现这个方法,我们可以使用很方便的Image()构造函数。

    var img = new Image();   // 创建一个<img>元素
    img.src = 'myImage.png'; // 设置图片源地址
    
    

    当脚本执行后,图片开始装载。

    若调用 drawImage 时,图片没装载完,那什么都不会发生(在一些旧的浏览器中可能会抛出异常)。因此你应该用load时间来保证不会在加载完毕之前使用这个图片:

    var img = new Image();   // 创建img元素
    img.src = 'myImage.png'; // 设置图片源地址
    // 当图片加载完毕之后,才把图片绘制到canvas中
    img.onload = function(){
      // 执行drawImage语句
      ctx.drawImage(img, 100, 100);
    }
    img.src = 'myImage.png'; // 设置图片源地址
    

    使用视频帧

    你还可以使用<video> 中的视频帧(即便视频是不可见的)。例如,如果你有一个ID为“myvideo”的<video> 元素,你可以这样做:

    function getMyVideo() {
      var canvas = document.getElementById('canvas');
      if (canvas.getContext) {
        var ctx = canvas.getContext('2d');
    
        return document.getElementById('myvideo');
      }
    }
    

    它将为这个视频返回HTMLVideoElement对象,抓取当前视频帧作为一个图像。

    形变

    旋转、位移、缩放

    旋转: ctx.rotate(deg);
    以坐标原点进行 deg 角度的旋转,可以为负值

    位移: ctx.translate(x, y);
    以坐标原点进行横向(x 像素),纵向(y 像素)的位移,可以为负值

    缩放: ctx.scale(x, y);
    以坐标原点进行横向(x 倍数),纵向(y 倍数)的缩放。

    综合实例: 利用一个综合性的小实例进行学习(制作一个表盘)

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    
    // 获取canvas的宽度和高度
    var canvasWidth = canvas.width;
    var canvasHeight = canvas.height;
    
    // 将坐标原点移动至画布中心
    ctx.translate(canvasWidth/2, canvasHeight/2);
    
    // 设置线的两端为圆角
    ctx.lineCap = "round";
    
    // 设置线条宽度为10px
    ctx.lineWidth = 10;
    
    // 用foru循环绘制表盘的时间刻度
    for(var i = 0; i < 12; i++) {
        ctx.beginPath();
        // 绘制一条长度为20的线
        ctx.moveTo(0,-200);
        ctx.lineTo(0, -180);
        ctx.stroke();
        // 绘制完成后将坐标原点旋转30度
        ctx.rotate(Math.PI / 6);
    }
    

    建议将代码拷贝到你自己的编辑器中多进行修改,可更快的了解每个方法和属性的作用。祝你学习愉快。

    相关文章

      网友评论

      本文标题:Canvas(基础)

      本文链接:https://www.haomeiwen.com/subject/ksdnyttx.html