Canvas基础

Canvas

  1. canvas元素默认具有高宽:width:300px;height:150px;
  2. 替换内容
    由于某些较老的浏览器不支持Canvas,所有利用替代内容;支持canvas的浏览器将会忽略在容器中包含的内容,并且只是正常渲染canvas;不支持canvas的浏览器会显示替换内容
  3. canvas的两个属性
    只有两个属性:height,width
    画布的高宽:
    HTML属性设置高宽只会影响画布本身不会影响画布内容
    css属性设置高宽时不但会影响画布本身的高宽,还会等比例缩放画布,不要在css中指定画布的宽高
  4. 渲染上下文
    <canvas>元素只是创造一个固定大小的画布,但想在上面绘制内容,需要找到渲染
    getContext()方法:用来获得渲染上下文和它的绘画功能,只有一个参数,上下文格式。
//先拿画布
var canvas=document.querySelector("#test");
//检查有无画笔
if(canvas.getContext){
    var ctx=canvas.getContext("2d");
}
  1. 绘制矩形
    HTML中的元素canvas只支持一种原生的图形绘制:矩形。其他的图形的绘制都至少需要生成一条路径。
    canvas提供了三种方法绘制矩形:
    绘制一个填充的矩形(填充色默认为黑色)
    fillRect(x,y,width,height) 注:不加单位
    绘制一个矩形的边框(默认边框为一像素实心黑色)
    strokeRect(x,y,width,height)
    清除指定矩形区域,让清除部分完全透明
    ClearRect(x,y,width,height)
    注:x与y指定了在canvas画布上所绘制的矩形的左上角(相当于原点)的坐标。
    Width和height设置矩形的尺寸(存在边框的话,边框会在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)
strokeRect时,边框像素渲染问题
按理渲染出的边框应该是1px,canvas在渲染矩形边框时,边框宽度是平均分在偏移位置的两侧。
ctx.strokeRect(50,50,50,50)
边框会渲染在50.5和49.5之间,浏览器是不会让一个像素只用自己的一半的,相当于渲染在49到51之间,所以有2px边框。
 ctx.strokeRect(50.5,50.5,50,50)
 边框渲染在50到51之间
  1. Js,css拿不到canvas画布上的元素,那么如何改变填充颜色和样式?
    fillStyle:设置图形的填充颜色
    StrokeStyle:设置图形轮廓的颜色
    默认情况下,线条和填充颜色都是黑色(CSS 颜色值#000000)
    lineWidth:这个属性设置当前绘线的粗细。属性值必须为正值;
    描述线段宽度的数字:0,负数,NaN,Infinity会被忽略
//画笔上的特性,以下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);
  1. canvas的同步思维,有别于浏览器本身的渲染机制

  2. 覆盖渲染:填充矩形和边框矩形,谁后画就会覆盖上面的内容
    ctx.fillRect(0,0,50,50);
    ctx.strokeRect(50,50,50,50);

  3. lineJoin:设置线条与线条间结合处的样式(默认miter)
    圆角:round
    斜角:bevel
    直角:miter
    ctx.lineJoin=‘round’;

  4. 绘制路径:
    图形的基本元素是路径,路径是通过不同颜色和宽度的线段或曲线相连形成的不同形状的集合。
    步骤:
    首先,创建路径的起始点
    然后,使用画图命令去画出路径
    把路径封闭
    路径生成,通过描边或填充路径区域来渲染图形

  5. 绘制三角形:
    beginPath():新建一条路径,生成之后,图形绘制命令被指向到路径上准备生成路径。
    生成路径的第一步叫做beginPath( )。本质上,路径是由很多子路径构成,这些子路径都是在一个列表中,所有的子路径(线,弧形等等)构成图形。每次这个方法调用之后,列表清空重置,然后重新绘制新的图形。

    **moveTo(x,y):**将笔移动到指定的坐标x,y上,设置起点;会抬起画笔,前后不连续。
    **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),宽高为width及height的矩形
    当该方法执行的时候,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();
绘制图形时,注意形式:
ctx.save(); 
ctx.strokeStyle="pink";
  //样式
ctx.beginPath();
  //路径
ctx.restore();
ctx.save( ):压栈
是Canvas 2D API通过将当前状态放入栈中,保存canvas全部状态的方法
保存到栈中的绘制状态有下面部分组成:
	当前的变换矩阵
	当前的剪切区域
	当前的虚线列表
	以下属性当前值:strokeStyle,fillStyle,lineWidth,lineCap,lineJoin .....
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);
  1. 路径容器:每次调用api时,都会向路径容器里做登记
    调用beginPath( )时,清空整个路径容器
    样式容器:每次调用api时,都会向样式容器里做登记
    调用save时,将样式容器的状态压入样式栈;调用restore时,将样式栈的栈状态弹出到样式容器里,进行覆盖
    样式栈:调用save时,将样式容器的状态压入样式栈;
    调用restore时,将样式栈的栈状态弹出到样式容器里,进行覆盖
  2. 实例1–Canvas签名
    onmousemove 事件:在鼠标指针移动时发生
    onmouseout 事件:在鼠标指针移动出指定对象时发生
    onmousedown 事件:鼠标按键被按下时发生
var canvas=document.querySelector('#test');
if(canvas.getContext){
    var ctx=canvas.getContext("2d");}
canvas.οnmοusedοwn=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.οnmοusemοve=function (ev) {
    ev=ev||event;
ctx.lineTo(ev.clientX-canvas.offsetLeft,ev.clientY-canvas.offsetLeft);
    ctx.stroke();
    ctx.restore();};
document.οnmοuseup=function () {
document.οnmοusemοve=document.οnmοuseup=null;
if(document.releaseCapture){
    document.releaseCapture();}};
// ctx.restore();
return false;}
  1. 绘制曲线
    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();}
  1. 二次贝塞尔:
    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();
  1. 实例2-- canvas变换
    translate(x,y):用来移动canvas的原点到一个不同的位置
    两个参数:x左右偏移量,y上下偏移量
    在canvas中translate是累加的
ctx.translate(50,50);
ctx.translate(50,50);

rotate(angle):只接受一个参数:旋转的角度(angle),顺时针方向,以弧度为单位的值。
旋转的中心始终是canvas的原点,如果要改变它,需要用到translate方法
在canvas中rotate是累加的

//旋转:使坐标轴旋转,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像素的个数变多

放大缩小的原理:
改变css像素的面积,css像素是一个抽象单位:
放大:放大css像素的面积,使画布内的css像素的个数变少,单个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. 实例3–表盘–时钟实例:
    1.初始化:将圆心调整到画布中间
    由于canvas中画圆与旋转所参照的坐标轴系于正常坐标系有出入
    将整个画布逆时针旋转90°
    初始化一些样式数据:
ctx.lineWidth=8;
ctx.strokeStyle="black";
ctx.lineCap="round";
  1. 外层空心圆盘
    圆盘颜色:#325FA2;圆盘宽度:4;圆盘半径:140;
  2. 时针刻度
    长度为20;宽度为8;外层空心圆盘与时针刻度之间的距离为20
  3. 分钟刻度
    宽度:4;长度:3;
  4. 时针:宽度:14;圆心外溢出80收20
  5. 分针:宽度:10;圆心外溢出112收28
  6. 秒针:颜色:D40000;宽度:6;圆心外溢出83收30
  7. 中心实心圆盘,半径为10;
    秒针头:96码开外半径为10的空心圆,宽度:6
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        html,body{
            height: 100%;
            overflow: hidden;
            background-color: white;
        }
#clock{
background-color: #616161;
    position: absolute;
    left:50%;
    top:50%;
  transform: translate3d(-50%,-50%,0);
    margin:auto;
}
    </style>
</head>
<body>
<canvas id="clock" height="400"width="400">
    <span>您的浏览器不支持canvas</span>
</canvas>
</body>
</html>
<script>
  var canvas=document.querySelector('#clock');
  if(canvas.getContext){
      var ctx=canvas.getContext("2d");
      //将半自动的表变成动态的,加上定时器
      setInterval(function () {
          //清除,必须在原点未移动之前清除,要不然清除不掉
          ctx.clearRect(0,0,clock.width,clock.height);
          move();
      },1000);
      function move(){
          ctx.save();
          ctx.lineWidth=8;
          ctx.strokeStyle="black";
          ctx.lineCap="round";
          ctx.translate(200,200);
          ctx.rotate(-90*Math.PI/180);
          ctx.beginPath();
		  //外层表盘
          ctx.save();
          ctx.strokeStyle="#325FA2";
          ctx.lineWidth=14;
          ctx.beginPath();
          ctx.arc(0,0,140,0,360*Math.PI/180);
          ctx.stroke();
          ctx.restore();
          //时针刻度
          ctx.save();
          for(var i=0;i<12;i++){
              //若加上save和restore就不会出现累加现象,就会清除,所以不能写在里面;
              ctx.rotate(30*Math.PI/180);
              ctx.beginPath();
              ctx.moveTo(100,0);
              ctx.lineTo(120,0);
              ctx.stroke();
          }
          ctx.restore();
          //分针刻度
          ctx.save();
          ctx.lineWidth=4;
          for(var j=0;j<60;j++){
              //若加上save和restore就不会出现累加现象,就会清除,所以不能写在里面;
              ctx.rotate(6*Math.PI/180);
              if(i%5!==0){
                  ctx.beginPath();
                  ctx.moveTo(117,0);
                  ctx.lineTo(120,0);
                  ctx.stroke();
              }
          }
          ctx.restore();
		 // 时针,分针,秒针
          var date=new Date();
          var s=date.getSeconds();
          var m=date.getMinutes()+s/60;
          var h=date.getHours()+m/60;
          h=h>12?h-12:h;
          //时针
          ctx.save();
          ctx.lineWidth=14;
          ctx.beginPath();
          ctx.rotate(h*30*Math.PI/180);
          ctx.moveTo(-20,0);
          ctx.lineTo(80,0);
          ctx.stroke();
          ctx.restore();
		  //分针
          ctx.save();
          ctx.lineWidth=10;
          ctx.beginPath();
          ctx.rotate(m*6*Math.PI/180);
          ctx.moveTo(-28,0);
          ctx.lineTo(112,0);
          ctx.stroke();
          ctx.restore();
          //秒针
          ctx.save();
          ctx.lineWidth=6;
          ctx.strokeStyle="#D40000";
          ctx.fillStyle='#D40000';
          ctx.rotate(s*6*Math.PI/180);
          ctx.beginPath();
          ctx.moveTo(-30,0);
          ctx.lineTo(83,0);
          ctx.stroke();
          //表座
          ctx.beginPath();
          ctx.arc(0,0,10,0,360*Math.PI/180);
          ctx.fill();
          //秒头
          ctx.beginPath();
          ctx.arc(96,0,10,0,360*Math.PI/180);
          ctx.stroke();
          ctx.restore();
          ctx.restore();
      }
  }
</script>
  1. canvas中使用图片
    在canvas中插入图片(需要image对象)
    1.Canvas操作图片时,必须要等图片加载完才能操作
    2.drawImage(image,x,y,width,height)
    其中image是image或canvas对象,x和y是其在目标canvas里的起始坐标。
    这个方法多了两个参数:width和height,这两个参数用来控制当canvas画入时应该缩放的大小
var canvas=document.querySelector('#test');
  if(canvas.getContext){
      var ctx=canvas.getContext("2d");
var img=new Image();
img.src="img/1.jpg";
//必须要等图片加载完才能操作
img.οnlοad=function () {
draw();};
function draw() {
ctx.drawImage(img,0,0,img.width,img.height)
}}
  1. 在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);

  2. 渐变:
    canvas渐变(线性渐变)
    1.createLinearGradient(x1,y1,x2,y2)
    表示渐变的起始(x1,y1)和终点(x2,y2)
    gradient.addColorStop(position,color)
    gradient:createLinearGradient的返回值
    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渐变(径向渐变)
    2.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中设置简单

  3. 实例–飞鸟实例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        html,body{
            height: 100%;
            overflow: hidden;
            background-color: white;
        }
#test{
background-color: #616161;
    position: absolute;
    left:50%;
    top:50%;
  transform: translate3d(-50%,-50%,0);
    margin:auto;
}
    </style>
</head>
<body>
<canvas id="test">
    <span>您的浏览器不支持canvas</span>
</canvas>
</body>
</html>
<script>
 var canvas=document.querySelector('#test');
 //将整个视口设置为飞鸟运动的框口
 canvas.width=document.documentElement.clientWidth;
 canvas.height=document.documentElement.clientHeight;

 if(canvas.getContext){
     var ctx=canvas.getContext('2d');
var flag=0;
var value=0;
// 定时器:动态的获取飞鸟图片
     setInterval(function () {
         ctx.clearRect(0,0,canvas.width,canvas.height);
         value+=10;
         flag++;
         if(flag===9){
             flag=1;
         }
var img=new Image();
img.src="img/1"+(flag)+".jpg";
img.onload=function () {
draw();
}
     },1000/60);
function draw(img) {
ctx.drawImage(img,value,0,)
}}
</script>

  1. 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
    文本对齐选项。可选的值包括:left,right,center
    center:文本居中对齐
    文本的居中是基于在fillText的时候所给的x的值,文本一半在x的右边,一半在x的左边。
ctx.fillStyle="red";
     ctx.font="20px san-serif";
//left:将文本的左边靠在50,50;right:将文本的右边靠在50,50;
     ctx.textAlign="center";
     ctx.fillText("就是o",30,30);
ctx.strokeText("就是低",50,50);

textBaseline=value
描述设置文本时,当前文本基线的属性。
top:文本基线在文本块的顶部;
middle:文本基线在文本块的中间;
bottom:文本基线在文本块的底部。
ctx.textBaseline=“buttom”;//top顶部靠在50,50;buttom底部靠在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);
  1. 在canvas中的像素操作
    得到场景像素数据:getImageData( ):获得一个包含画布场景像素数据的ImageData对象,它代表画布区域的对象数据

    在画布中拿到一个Image对象:
    ctx.getImageData(sx,sy,sw,sh)
    sx:将要被提取的图像数据矩阵区域的左上角x坐标。
    sy:将要被提取的图像数据矩阵区域的左上角y坐标。
    sw:将要被提取的图像数据矩阵区域的宽度
    sh:将要被提取的图像数据矩阵区域的高度
    imageData对象
    width:横向上像素点的个数
    height:纵向上像素点的个数
    data:数组,每一个像素点的rgba信息
    100*100一共有一万个元素,但rgba,所以有4万个数字
    canvas中rgba都处于0-255之间,a:0是透明,255是不透明

    在场景中写入像素数据:将getImageData的像素重新放到哪里去
    putImageData()方法对场景进行像素数据的写入
    putImageData(myImageData,dx,dy)
    dx和dy参数表示在场景内左上角绘制的像素数据所得到的设备坐标

    创建一个ImageData对象:新创建一个,不用get,默认创建出来rgba(0,0,0,0)黑色图形

ctx.createImageData(width,height):
width:ImageData新对象的宽度
height:ImageData新对象的高度
var imageData=ctx.createImageData(100,100);
 for(var i=0;i<imageData.data.length;i++){
     imageData.data[4*i+3]=255;}
ctx.putImageData(imageData,0,0)}
单像素操作
<script>
    var canvas=document.querySelector("#test");
    if(canvas.getContext){
        var ctx=canvas.getContext('2d');
        ctx.save();
        ctx.fillStyle='green';
        ctx.beginPath();
        ctx.fillRect(50,50,100,100);
        ctx.restore();

        var myData=ctx.getImageData(0,0,canvas.width,canvas.height);
        //(49,49)为黑色透明;(50,50)为绿色
        var color=getPxInfo(myData,49,49);
        console.log(color);
        for(var i=0;i<myData.width;i++){
            setPxInfo(myData,49,i,[0,0,0,255]);
        }
        // 设置后将颜色放入图像中
        ctx.putImageData(myData,0,0)
    }
function getPxInfo(myData,x,y) {
var color=[];
var data=myData.data;
var w=myData.width;
var h=myData.height;
//(x,y) 前面都有x*w+y个像素点
    //r
    color[0]=data[(y*w+x)*4];
    //g
    color[1]=data[(y*w+x)*4+1];
    //b
    color[2]=data[(y*w+x)*4+2];
    //a
    color[3]=data[(y*w+x)*4+3];
return color;
}
    function setPxInfo(myData,x,y,color) {
        var data=myData.data;
        var w=myData.width;
        var h=myData.height;
//(x,y) 前面都有y*w+x个像素点,x多少列,y多少行
        //r
       data[(y*w+x)*4]= color[0];
        //g
        data[(y*w+x)*4+1]=color[1];
        //b
       data[(y*w+x)*4+2]= color[2];
        //a
        data[(y*w+x)*4+3]=color[3];
    }
将某行或者某列全部修改成黑色像素点:
for(var i=0;i<myData.width;i++){
    setPxInfo(myData,49,i,[0,0,0,255]);
}
// 设置后将颜色放入图像中
ctx.putImageData(myData,0,0)
<\script>
实例--马赛克操作
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        *{
            margin:0;
            padding:0;
        }
        body,html{
            height:100%;
            overflow: hidden;
            background: #616161;
        }
        #test{
            position: absolute;
            left:50%;
            top:50%;
            transform: translate3d(-50%,-50%,0);
            background: white;
            margin:auto;
        }
    </style>
</head>
<body>
<canvas id="test">
    <span>您的浏览器不支持canvas操作!!</span>
</canvas>
</body>
</html>
<script>
    var canvas=document.querySelector("#test");
    if(canvas.getContext) {
        var ctx = canvas.getContext('2d');
        var img=new Image();
        img.src='img/2.jpg';
        img.onload=function () {
            canvas.width=img.width;
            canvas.height=img.height;
            draw();
        };
        function draw() {
            ctx.drawImage(img,0,0);
            //获取数据:图片的长度,图片的宽度
            var oldImgData=ctx.getImageData(0,0,img.width,img.height);
            var newImgData=ctx.createImageData(img.width,img.height);
            //马赛克
            /*步骤:
                1. 选取一个马赛克矩形
                2. 从马赛克矩形中随机抽出一个像素点的信息(rgba)
                3. 将整个马赛克矩形中的像素点信息统一调成随机抽出的那个
            */
            //改变size值会使图形由清晰变得模糊
            var size=10;
            for(var i=0;i<oldImgData.width/size;i++){
                for(var j=0;j<oldImgData.width/size;j++){
                    //(i,j)为每一个马赛克矩形的坐标:(0,0):代表(0,0)--(4,4)
                    //                              (0,1):代表(0,5)--(4,9)
                    //                              (1,0):代表(5,0)--(9,4)
                    //随机拿到马赛克矩形,Math.random( )为[0,1),Math.random()*size为[0,5),Math.floor()向下取整。
                    //为第一个马赛克矩形设计getPxInfo(oldImgData,Math.floor(Math.random()*size),Math.floor(Math.random()*size));
//为所有马赛克矩形设计getPxInfo(oldImgData,i*size+Math.floor(Math.random()*size),j*size+Math.floor(Math.random()*size));
                    /*(0,1):[0,4],[5,9] 交叉形成(0,5)--(4,9)
                    (1,0):[5,9],[0,4] 交叉形成(5,0)--(9,4)
                    */
                    var color=getPxInfo(oldImgData,i*size+Math.floor(Math.random()*size),j*size+Math.floor(Math.random()*size));

                    for(var a=0;a<size;a++){
                        for(var b=0;b<size;b++){
                            setPxInfo(newImgData,i*size+a,j*size+b,color);
                        }
                    }
                }
            }
            //每次都清除上一个马赛克图形-----ctx:画布上的图;canvas:画布
            ctx.clearRect(0,0,ctx.width,ctx.height);
            // ctx.putImageData(newImgData,img.width,0);模糊与原图
            ctx.putImageData(newImgData,0,0);
            function getPxInfo(myData,x,y) {
                var color=[];
                var data=myData.data;
                var w=myData.width;
                var h=myData.height;
                color[0]=data[(y*w+x)*4];
                color[1]=data[(y*w+x)*4+1];
                color[2]=data[(y*w+x)*4+2];
                color[3]=data[(y*w+x)*4+3];
                return color;
            }
            function setPxInfo(myData,x,y,color) {
                var data=myData.data;
                var w=myData.width;
                var h=myData.height;
                data[(y*w+x)*4]= color[0];
                data[(y*w+x)*4+1]=color[1];
                data[(y*w+x)*4+2]= color[2];
                data[(y*w+x)*4+3]=color[3];
            }
        }
    }
</script>
  1. Canvas–合成
    全局透明度的设置
    globalAlpha=value
    该属性会影响到canvas中所有图形的透明度
    有效范围0-1(完全透明----不透明),默认值为1

    覆盖合成:
    source:新的图像(新图像叫源)
    destination:已经绘制过的图形(目标)

    globalCompositeOperation
    source-over(默认值):源在上面,新的图像层级比较高
    source-in:只留下源与目标的重叠部分(源的那一部分)
    source-out:只留下源超过目标的部分
    source-atop:砍掉源溢出的部分

    destination-over:目标在上面,旧的图像层级比较高
    destination-in:只留下源与目标的重叠部分(目标的那一部分)
    destination-out:只留下目标超过源的部分
    destination-atop:砍掉目标溢出的部分

ctx.fillStyle='rgba(255,255,0,100)';
ctx.fillRect(50,50,100,100);

//源已经画出,目标的操作对源有什么操作
ctx.globalCompositeOperation='destination-over';

ctx.fillStyle='rgba(255,0,255,100)';
ctx.fillRect(100,100,100,100);
  1. 将画布导出为图像
    Oc.toDataUrl():canvas接口上的方法
    事件操作:
    Ctx.isPointInPath(x,y)
    判断在当前路径中是否包含检测点
    X:检测点的x坐标
    Y:检测点的Y坐标
    注意:此方法只作用于新画出的canvas图像

  2. 复习:
    1.注意点:
    canvas图像的渲染有别于html图像的渲染,canvas的渲染极快,不会出现代码覆盖后延迟渲染的问题,写canvas代码一定要具有同步思想
    获得上下文时,一定要先判断
    画布默认宽高300*150
    切记一定要使用html的attribute的形式来定义画布的宽高
    通过css形式定义会缩放画布内的图像
    绘制矩形的问题:边框宽度的问题,边框宽度是在偏移量上下分别渲染一半,可能会出现小数边框,一旦出现小数边框都会向上取整
    canvas的api只支持一种图像的直接渲染:矩形
    无法使用选择器选到canvas中的图像,只能靠自己的api
    2.画布API(画布)
    Oc.getContext(‘2d’):获取画布的2d上下文
    Oc.width:画布的宽度
    Oc.height:画布在纵向上CSS像素的个数
    Oc.toDataUrl():拿到画布的图片地址
    3.上下文API(画笔)
    矩形:Ctx.fillRect(x,y,w,h):填充矩形
    Ctx.strokeRect(x,y,width,height):带边框的矩形
    Ctx.clearRec(0,0,oc.width,oc.height):清除整个画布(注意:原点的位置)
    Ctx.fillStyle:
    填充颜色;
    背景fillStyle的值可以是createPattern(image,repetition)的返回对象;
    线性渐变fillStyle值可以是createLinearGradient(x1,y1,x2,y2)的返回对象;
    addColorStop(position,Color)
    径向渐变fillStyle值可以是createRadialGradient(x1,y1,r1,x2,y2,r2)的返回对象;addColorStop(position,Color)

    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.fill():画完点后,填充
    ctx.stroke():画完点后,连接线条
    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像素的个数不变

    ctx.drawImage(img,x,y,w,h):在canvas中引入图片一定在图片加载完成之后再操作

    ctx.measureText(“文本”):返回一个持有文本渲染宽度的对象
    ctx.fillText(“test”,x,y):在指定的(x,y)位置填充指定的文本
    ctx.strokeText(“test”,x,y):在指定的(x,y)位置绘制文本边框
    ctx.font=value:当前用来绘制文本的样式
    ctx.textAlign=value:文本对齐选项
    ctx.textBaseline=value:描述设置文本时,当前文本基线的属性。

    阴影(文本阴影&盒模型阴影)
    ctx.shadowOffsetX=float
    ctx.shadowOffsetY=float
    shadowOffsetX和shadowOffsetY用来设置阴影在X和Y轴的延伸距离
    默认为0;
    ctx.shadowBlur=float
    shadowBlur用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,也不受变换矩阵影响,默认值为0;
    ctx.shadowColor=color(必需项)
    shadowColor用于设定阴影颜色效果,默认是全透明的黑色

    ctx.getImageData(x,y,w,h):
    ImageData对象
    width:宽度
    height:高度
    data:数组 选中区域所有像素点的rgba信息,rgba的取值为0-255

    ctx.putImageData(ImageData,x,y):
    ctx.createImageData(w,h):返回的是imgdata对象,默认像素点的信息是rgba(0,0,0,0)

    ctx.globalAlpha=value:canvas中所有图形的透明度,0-1(完全透明----不透明),默认值1
    ctx.globalCompositeOperation=“”
    source-over(默认值):源在上面,新的图像层级比较高
    source-in:只留下源与目标的重叠部分(源的那一部分)
    source-out:只留下源超过目标的部分
    source-atop:砍掉源溢出的部分

    destination-over:目标在上面,旧的图像层级比较高
    destination-in:只留下源与目标的重叠部分(目标的那一部分)
    destination-out:只留下目标超过源的部分
    destination-atop:砍掉目标溢出的部分

    ctx.ispointinpath(x,y):x,y这个点是否在路径上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值