Canvas基础

Canvas

1. canvas元素默认具有高宽:width300px;height150px;

2. 替换内容

  由于某些较老的浏览器不支持Canvas,所有利用替代内容;支持canvas的浏览器将会忽略在容器中包含的内容,并且只是正常渲染canvas;不支持canvas的浏览器会显示替换内容

3. canvas的两个属性

  只有两个属性:heightwidth

画布的高宽:

  HTML属性设置高宽只会影响画布本身不会影响画布内容

  Css属性设置高宽时不但会影响画布本身的高宽,还会等比例缩放画布,不要在css中指定画布的宽高

 4. 渲染上下文

  <canvas>元素只是创造一个固定大小的画布,但想在上面绘制内容,需要找到渲染

  getContext()方法:用来获得渲染上下文和它的绘画功能,只有一个参数,上下文格式。

    //先拿画布
    var canvas=document.querySelector("#test");
    //检查有无画笔
    if(canvas.getContext){
        var ctx=canvas.getContext("2d");
    }

 

5. HTML中的元素canvas只支持一种原生的图形绘制:矩形。其他的图形的绘制都至少需要生成一条路径。

绘制矩形:

  1. canvas提供了三种方法绘制矩形:

    绘制一个填充的矩形(填充色默认为黑色)

      fillRect(x,y,width,height)  注:不加单位

    绘制一个矩形的边框(默认边框为一像素实心黑色)

      strokeRect(x,y,width,height)

    清除指定矩形区域,让清除部分完全透明

      ClearRect(x,y,width,height)

 xy指定了在canvas画布上所绘制的矩形的左上角(相当于原点)的坐标。

Widthheight设置矩形的尺寸(存在边框的话,边框会在width上占据一个边框的宽度,height同理)

//画笔上的特性
        //画一个填充的矩形
        ctx.fillRect(0,0,50,50);
        //带边框的矩形(与上一个矩形叠在一起)
        //100:99.5--100.5
        //100.5:100--101
        ctx.strokeRect(50,50,50,50);
        //没有擦掉,只是叠了一层上去
        ctx.clearRect(50,50,50,50)

 

  2. strokeRect时,边框像素渲染问题

    按理渲染出的边框应该是1pxcanvas在渲染矩形边框时,边框宽度是平均分在偏移位置的两侧。

       ctx.strokeRect(50,50,50,50)

    边框会渲染在50.549.5之间,浏览器是不会让一个像素只用自己的一半的,相当于渲染在4951之间,所以有2px边框。

       ctx.strokeRect(50.5,50.5,50,50)

    边框渲染在5051之间

   3. Js,css拿不到canvas画布上的元素,那么如何改变填充颜色和样式?

    fillStyle:设置图形的填充颜色

    StrokeStyle:设置图形轮廓的颜色

      默认情况下,线条和填充颜色都是黑色(CSS 颜色值#000000

    lineWidth:这个属性设置当前绘线的粗细。属性值必须为正值;

    描述线段宽度的数字:0,负数,NaNInfinity会被忽略

      //画笔上的特性,以下3行代码必须写在前面,同步思想,所见即所得
            //矩形的填充颜色
            ctx.fillStyle="grey";
            //矩形的边框
            ctx.strokeStyle='red';
            //矩形的粗细
            ctx.lineWidth=10;
            //画一个填充的矩形
            ctx.fillRect(0,0,50,50);
            //带边框的矩形(与上一个矩形叠在一起)
            //100:99.5--100.5
            //100.5:100--101
            ctx.strokeRect(50,50,50,50);
            //没有擦掉,只是叠了一层上去
            ctx.clearRect(50,50,50,50);

   4. canvas的同步思维,有别于浏览器本身的渲染机制

  5. 覆盖渲染:填充矩形和边框矩形,谁后画就会覆盖上面的内容

      ctx.fillRect(0,0,50,50);

      ctx.strokeRect(50,50,50,50);

  6. lineJoin:设置线条与线条间结合处的样式(默认miter

      圆角:round

      斜角:bevel

      直角:miter

      ctx.lineJoin='round';

 

绘制路径:

  1. 图形的基本元素是路径,路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的集合。
  2. 步骤:

    首先,创建路径的起始点

    然后,使用画图命令去画出路径

    把路径封闭

    路径生成,通过描边或填充路径区域来渲染图形

  3. 绘制三角形:

    beginPath()新建一条路径,生成之后,图形绘制命令被指向到路径上准备生成路径。

    生成路径的第一步叫做beginPath( )。本质上,路径是由很多子路径构成,这些子路径都是在一个列表中,所有的子路径(线,弧形等等)构成图形。每次这个方法调用之后,列表清空重置,然后重新绘制新的图形。

     moveTo(x,y):将笔移动到指定的坐标xy上,设置起点;会抬起画笔,前后不连续。

    lineTo(x,y):绘制一条从当前位置到指定x,y位置的直线

    closePath()闭合路径之后图形绘制命令又重新指向上下文中

      闭合路径closePath( ),不是必须的。这个方法会通过绘制一条从当前的点到开始点的直线来闭合图形。

      当你调用fill( )函数时,所有没有闭合的形状都会自动闭合,所以不需要使用closePath( )函数,但调用stroke( )时不会自动闭合

注:画线的时候,不会自动调用;填充的时候,会自动调用

    stroke( )通过线条来绘制图形轮廓,不会自动调用closePath( )

    fill( )通过填充路径的内容区域生成实心的图形,会自动调用closePath( )

     ctx.lineWidth=4;
          ctx.strokeStyle='pink';
          // 抬起画笔,路径的起始点
          ctx.moveTo(50,50);
          //三角形的三个点
          ctx.lineTo(50,100);
          ctx.lineTo(100,100);
          //自己封闭路径,没有closePath(),直接stroke( ):会缺边
          ctx.closePath();
          //ctx.lineTo(50,50);
          //画线,图形大于填充图形,画线在外面画边框
          // ctx.stroke();
          //填充,会自动闭合路径
          ctx.fill();
          //画第2个三角形时,要清空之前的路径
          ctx.beginPath();
          ctx.moveTo(100,100);
          //三角形的三个点
          ctx.lineTo(100,150);
          ctx.lineTo(150,150);
          ctx.closePath();
          ctx.stroke();

 

 绘制矩形:

  1. rect(x,y,width,height)

    绘制一个左上角坐标为(x,y),宽高为widthheight的矩形

    当该方法执行的时候,moveTo( )方法自动设置坐标参数(0,0

      ctx.rect(20,20,100,100);

   2. lineCap:是Canvas 2D API指定如何绘制每一条线段末端的属性

    值:butt :线段末端以方形结束,默认值

      round:线段末端以圆形结束

      Square:线段末端以方形结束,但增加了一个宽度和线段相同,高度是线段厚度一半的矩形区域。

        ctx.lineCap='round';
        ctx.moveTo(20,20);
        ctx.lineTo(100,100);
        ctx.stroke();

  3. 绘制图形时,注意形式:

    ctx.save(); 
    ctx.strokeStyle="pink";
      //样式
    ctx.beginPath();
      //路径
    ctx.restore();

  4. ctx.save( ):压栈

    ctx.restore( ):弹栈

    一个save对应一个restore,成对出现

      ctx.save(); //压栈:黑色
      ctx.fillStyle="pink";
       ctx.save(); //粉色
      ctx.fillStyle="blue";
         ctx.save();  //蓝色
      ctx.fillStyle="red";
      ctx.save();  //红色
      ctx.beginPath();
      ctx.restore();//弹栈:红色
      ctx.restore(); //蓝色
      ctx.restore(); //粉色
      ctx.restore(); //黑色
      ctx.fillRect(20,20,100,100);

   5. 路径容器:每次调用api时,都会向路径容器里做登记

      调用beginPath( )时,清空整个路径容器

   样式容器:每次调用api时,都会向样式容器里做登记

      调用save时,将样式容器的状态压入样式栈;调用restore时,将样式栈的栈状态弹出到样式容器里,进行覆盖

   样式栈:调用save时,将样式容器的状态压入样式栈;

      调用restore时,将样式栈的栈状态弹出到样式容器里,进行覆盖

 

Canvas签名

  1. onmousemove 事件:在鼠标指针移动时发生

      onmouseout 事件:在鼠标指针移动出指定对象时发生

      onmousedown 事件:鼠标按键被按下时发生

 

      var canvas=document.querySelector('#test');
     if(canvas.getContext){
          var ctx=canvas.getContext("2d");}
          canvas.onmousedown=function (ev) {
    ev=ev||event;
    if(canvas.setCapture){
        canvas.setCapture();}
      ctx.save();  //在栈里添加黑色
    ctx.strokeStyle='pink';   //将样式改成粉色
        // ctx.lineWidth=10;
    ctx.beginPath();  ctx.moveTo(ev.clientX-canvas.offsetLeft,ev.clientY-canvas.offsetLeft);
      //鼠标移动时发生
    document.onmousemove=function (ev) {
        ev=ev||event;
    ctx.lineTo(ev.clientX-canvas.offsetLeft,ev.clientY-canvas.offsetLeft);
        ctx.stroke();
        ctx.restore();};
     document.onmouseup=function () {
     document.onmousemove=document.onmouseup=null;
     if(document.releaseCapture){
        document.releaseCapture();}};
    // ctx.restore();
      return false;}

绘制曲线

  1. 绘制圆形

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

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

      true:逆时针

      false:顺时针

    x,y为绘制圆弧所在圆上的圆心坐标

    Radius:半径

    StartAngle以及endAngle参数用弧度定义了开始以及结束的弧度,以x轴为基准

    参数anticlockwise为一个布尔值。为true时,逆时针;否则为顺时针。

      画一个弧度时:ctx.arc(100,100,20,0,270*Math.PI/180,false);

 

    arcTo(x1,y1,x2,y2,radius):根据给定的控制点和半径画一段圆弧

      肯定会从(x1,y1)但不一定经过(x2,y2),(x2,y2)只控制一个方向

      var canvas=document.querySelector('#test');
      if(canvas.getContext){
          var ctx=canvas.getContext("2d");
          ctx.beginPath();
          //arcTo()需要3个控制点:moveTo( 1 ) arcTo( 2 )
          ctx.moveTo(50,50);
          ctx.arcTo(200,50,200,200,50);
          ctx.closePath();
          ctx.stroke();}

 

  2. 二次贝塞尔:

  quadraticCurveTo(cp1x,cp1y,x,y)

    绘制二次贝塞尔曲线,cp1x,cp1y为一个控制点,x,y为结束点

    起始点为moveTo时指定的点

 

 

  三次贝塞尔:

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

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

    起始点为moveTo时指定的点

 

 

    ctx.beginPath();
    ctx.moveTo(50,50);
    ctx.lineTo(300,0);
    ctx.lineTo(200,200);
    ctx.lineTo(300,300);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(50,50);
    ctx.bezierCurveTo(300,0,200,200,300,300);
    ctx.stroke();

 

canvas变换

  translate(x,y):用来移动canvas的原点到一个不同的位置

    两个参数:x左右偏移量,y上下偏移量

    在canvastranslate是累加的

      ctx.translate(50,50);
      ctx.translate(50,50);

  rotate(angle):只接受一个参数:旋转的角度(angle),顺时针方向,以弧度为单位的值。

    旋转的中心始终是canvas的原点,如果要改变它,需要用到translate方法

    在canvasrotate是累加的

      //旋转:使坐标轴旋转,rotate为累加操作
          ctx.rotate(20*Math.PI/180);
          ctx.beginPath();
          ctx.fillRect(0,0,100,100);

  Scale(x,y)scale方法接受两个参数。x,y分别是横轴和纵轴的缩放因子,必须是正值。<1表示缩放;>1表示放大;=1没有效果

    缩放:用来增减图形在canvas中的像素数量,对形状,位图进行缩小或放大。

    改变css像素的面积,css像素是一个抽象单位:

    放大:区域内css像素的个数变少

    缩小:区域内css像素的个数变多

 

 

缩放---变换实例:

 var canvas=document.querySelector('#test');
  var flag=0;
  var scale=0;
  var flagScale=0;
  if(canvas.getContext){
      var ctx=canvas.getContext("2d");
      ctx.save();
      ctx.translate(150,150);
      ctx.beginPath();
      ctx.fillRect(-50,-50,100,100);
      ctx.restore();
      //不停的旋转,加一个定时器
      setInterval(function () {
          flag++;
          //将图形擦掉
          ctx.clearRect(0,0,canvas.width,canvas.height);
          ctx.save();
          ctx.translate(150,150);
          //旋转
          ctx.rotate(flag*Math.PI/180);
//首先,将尺寸放大+1,直到加到100;然后缩小-1
if(scale===100){
    flagScale=-1;
}else if(scale===0){
    flagScale=1;}
scale+=flagScale;
ctx.scale(scale/50,scale/50);
          ctx.beginPath();
          ctx.fillRect(-50,-50,100,100);
          ctx.restore();
      },10)}

总结:

1. 注意点:canvas图像的渲染有别于html图像的渲染,canvas的渲染极快,不会出现代码覆盖后延迟渲染的问题,写canvas代码一定要具有同步思想

         获得上下文时,一定要先判断

      画布默认宽高300*150

      切记一定要使用htmlattribute的形式来定义画布的宽高

      通过css形式定义会缩放画布内的图像

   绘制矩形的问题:边框宽度的问题,边框宽度是在偏移量上下分别渲染一半,可能会出现小数边框,一旦出现小数边框都会向上取整

      canvasapi只支持一种图像的直接渲染:矩形

2. 画布API

  oc.getContext(‘2d’)

  oc.width

  oc.height

3. 上下文API

矩形:ctx.fillRect(x,y,w,h):填充矩形

  ctx.strokeRect(x,y,width,height):带边框的矩形

  ctx.clearRec(0,0,oc.width,oc.height):清除整个画布(注意:原点的位置)

  ctx.fillStyle

  ctx.strokeStyle

  ctx.lineWidth

  ctx.lineCap

  ctx.lineJoin

路径:ctx.moveTo(x,y):将画笔抬起,点到x,y

  ctx.lineTo(x,y):将画笔移到x,y

  ctx.rect(x,y,w,h):画一个矩形

  ctx.arc(x,y,r,起始角度,终止角度):画一个圆

  ctx.arcTo(x1,y1,x2,y2,r)2个坐标,一个半径;3个控制点,结合moveTo(x,y)使用,不一定经过起始点和终止点

    x,y:起始点

    x1,y1:控制点

    x2,y2:结束点

  ctx.quadraticCurveTo(x1,y1,x2,y2):二次贝塞尔曲线,3个控制点,结合moveTo(x,y)使用,必须经过起始点和终止点

    x,y:起始点

    x1,y1:控制点

    x2,y2:结束点

  bezierCurveTo(x1,y1,x2,y2,x3,y3):三次贝塞尔曲线,4个点,结合moveTo(x,y)使用,必须经过起始点和终止点

    x,y:起始点

    x1,y1:控制点

    x2,y2:控制点

    x3,y3:结束点 

  ctx.beginPath():清除路径容器

  ctx.closePath():闭合路径;fill(自动闭合)stroke(手动闭合)

  ctx.save():将画布当前状态(样式相关 变换相关)压入到样式栈中

  ctx.restore():将样式栈中栈顶的元素弹到样式容器中,图像最终渲染依赖于样式容器

 

  ctx.translate(x,y):将原点按当前坐标轴位移x,y个单位

  ctx.rotate(弧度):将坐标轴按顺时针方向旋转

  ctx.scale(缩放因子):放大:放大画布,画布中的一个css像素所占据的物理面积变大,画布中的css像素个数变少,画布中图像所包含的css像素的个数不变

            缩小:缩小画布,画布中的一个css像素所占据的物理面积变小,画布中的css像素个数变多,画布中图像所包含的css像素的个数不变

 

 

canvas中使用图片

canvas中插入图片(需要image对象)

  1. Canvas操作图片时,必须要等图片加载完才能操作
  2. drawImage(image,x,y,width,height)

  其中imageimagecanvas对象,xy是其在目标canvas里的起始坐标。

  这个方法多了两个参数:widthheight,这两个参数用来控制当canvas画入时应该缩放的大小

    var canvas=document.querySelector('#test');
      if(canvas.getContext){
         var ctx=canvas.getContext("2d");
      var img=new Image();
      img.src="img/1.jpg";

    //必须要等图片加载完才能操作
    img.onload=function () {
    draw();};
    function draw() {
    ctx.drawImage(img,0,0,img.width,img.height)
    }}

 

canvas中设置背景(需要image对象)

  1. createPattern(image,repetition)

    image:图像源

    repetition’repeat’

             ‘repeat-x’

         ‘repeat-y’

            ‘no-repeat’

一般情况下,会将createPattern返回的对象作为fillstyle的值

    var pattern=ctx.createPattern(img,'repeat');
    ctx.fillStyle=pattern;
    ctx.fillRect(0,0,1000,1000);

 

渐变:

canvas渐变(线性渐变)

  1. createLinearGradient(x1,y1,x2,y2)

  表示渐变的起始(x1,y1)和终点(x2,y2)

  gradient.addColorStop(position,color)

  gradientcreateLinearGradient的返回值

  addColorStop方法接受2个参数:

    position参数必须是一个0-1之间的数值,表示渐变中颜色所在的相对位置。

    Color参数必须是一个有效的CSS颜色值(#FFF,rgba(0,0,0,1)等)

        var gradient=ctx.createLinearGradient(0,0,300,300);
         gradient.addColorStop(0,"red");
         gradient.addColorStop(.4,"yellow");
         gradient.addColorStop(.6,"green");
         gradient.addColorStop(1,"red");
         ctx.fillStyle=gradient;
         ctx.fillRect(0,0,300,300);

 

canvas渐变(径向渐变)

  1. createRadialGradient(x1,y1,r1,x2,y2,r2)

  前三个参数:以(x1,y1)为原点,半径为r1的圆

  后三个参数:以(x2,y2)为原点,半径为r2的圆

      var gradient=ctx.createRadialGradient(150,150,50,150,150,100);
      gradient.addColorStop(0,'red');
      gradient.addColorStop(0.5,'green');
      gradient.addColorStop(1,'blue');
      ctx.fillStyle=gradient;
      ctx.fillRect(0,0,300,300);

注意:canvas中设置背景比CSS中设置简单

 

canvas文本相关

canvas内部无法编写文本

canvas中绘制文本:

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

  fillText(text,x,y)

    在指定的(x,y)位置填充指定的文本

  strokeText(text,x,y)

    在指定的(x,y)位置绘制文本边框

文本样式

font=value

  当前用来绘制文本的样式,这个字符串使用和CSS font属性相同的语法

  默认字体是10px san-serif

  font属性在指定时,必须要有大小和字体缺一不可

textAlign=value

  文本对齐选项。可选的值包括:leftrightcenter

  Center:文本居中对齐

  文本的居中是基于在fillText的时候所给的x的值,文本一半在x的右边,一半在x的左边。

    ctx.fillStyle="red";
         ctx.font="20px san-serif";

    //left:将文本的左边靠在50,50right:将文本的右边靠在50,50
        ctx.textAlign="center";
        ctx.fillText("就是o",30,30);
    ctx.strokeText("就是低",50,50);

 textBaseline=value 描述设置文本时,当前文本基线的属性。

  top:文本基线在文本块的顶部;

  middle:文本基线在文本块的中间;

  bottom:文本基线在文本块的底部。

  ctx.textBaseline="buttom";//top顶部靠在50,50buttom底部靠在50,50

measureText

  measureText()方法返回一个TextMetrics对象,包含关于文本尺寸的信息(文本宽度等)

canvas中文本水平垂直居中

      var oc=document.getElementById('test');
      var odc=oc.getContext('2d');
      odc.foont='60px impact';
      odc.textBaseline="middle";
      var w=odc.measureText('尚继谷').width;
      odc.fillText('尚继谷',(oc.width-w)/2,(oc.height-60)/2); 

posted @ 2020-08-18 08:18  花未眠0619  阅读(311)  评论(0)    收藏  举报