第十一周第三天笔记之canvas知识

1 canvas知识

1.1 canvas基础知识

  • canvas绘制线,矩形,描边,填充,使用图片
    • 注意点:
      • canvas的宽高属性,必须设置在行内,设置系统属性,不能设置css样式,会出错;
      • 获取canvas的宽高数值,在JS中可以通过c.widthc.height获取;
      • fillRect,strokeRect均为复合形式,即先用rect创建矩形,然后再用fill或stroke填充或描边;
      • lineWidth值不加单位;
      • 使用drawImg()方法时,需要在图片加载完成后再执行;指的是在画布上定位被剪切的部分;
       
      
      • clearRect(x,y.width,height)方法,清空画布
  • canvas设置渐变颜色
    • LinearGradient:水平渐变颜色
    • 语法:cxt.createLinearGradinet(x0,y0,x1,y1);
    • 注意:x0,y0必须与调用时的矩形起点位置相同,x1,y1为起点位置值加上矩形宽高值
    • 验证代码:
     
     
     
         
         canvas知识解读
     
     
     你的浏览器不支持canvas
     你的浏览器不支持canvas
     
     
     
    
  • canvas知识讲解链接
    canvas知识

1.2 canvas时钟实例

  • 知识点:
    • 画布偏移:translate(x,y);将画布原点(0,0)位置移动到(x,y)点;
    • 画布旋转:rotate(angle);其中angle为弧度;
      • 整个画布会被旋转;原点位置被改变;
    • save():保存当前环境的状态;
    • restore():返回之前保存过的路径状态和属性;
    • 配合使用:
      • 改变画布的位置:偏移translate(),旋转rotate();
      • 在改变画布位置之前,通过save()来保存原来画布的位置;然后进行修改;
      • 当需要使用修改之前的画布位置时,通过restore恢复原来的位置;
      • 使用:只要修改位置,就必须在此之前保存初始位置,修改位置后,相对应的操作完事后,恢复初始位置;
      • 注意:通过save()保存住第一次的位置,然后通过restore()获取第一次的位置,紧接着,若需要修改位置,必须通过save()再次保存住第一次的位置,否则,再通过restore()拿到的位置不再是第一次的位置,而是修改后的位置;
    • arc()绘圆,其中半径值为圆心到圆线的宽度中心线的距离;
    • ctx.textBaseline="top/bottom/middle/alphabetic(默认)/hanging":设置文本的对齐方式;
  • 思路:
    • 绘制时钟时,通过translate()来偏移画布原点到时钟中心点;
    • 绘制时针,分针,秒针时,通过rotate()来旋转画布,进行设置;需注意:画布位置会被修改,所以需要通过save()保存住原位置,通过restore()来恢复原位置;
  • 重点:
    • 在绘制过程中必须时刻关注画布是否被修改,即添加偏移和旋转;
    • 使用的所有命令都是相对于原点来进行赋值的;
    • 当使用translate(x,y)来偏移原点位置到画布的x,y坐标处,然后再使用translate(0,0)进行偏移设置,此时原点位置还在原地,没有变化,因为0,0取值是相对于此刻的原点位置进行设置的,如果想回到原来的位置,可以通过translate(-x,-y)来回到原位置;
    • 在绘制画布时,要使用save()和restore()来保存原位置和恢复原位置;
    • 只要修改位置,就必须在此之前保存初始位置,修改位置后,相对应的操作完事后,恢复初始位置;
  • 代码:
    • html代码:
     
     
     
         
         时钟实例
         
     
     
     

    时钟制作

    你的浏览器不支持canvas
    • canvas.js代码:
     //全局变量
     var x0=200;
     var y0=300;
     var r=190;
     var smr=5;
     var mlr=r-25;
     var numr=r-50;
     var year,month,date,h,m,s,curH,curM,curS;
     //canvas环境;
     var c=document.getElementById("mycanvas");
     var ctx=c.getContext("2d");
     
     
     toDraw();
     setInterval(toDraw,1000);
     function toDraw() {
         //获取实时时间
         var myDate=new Date();
         year=myDate.getFullYear();
         month=myDate.getMonth()+1;
         date=myDate.getDate();
         h=myDate.getHours();
         m=myDate.getMinutes();
         s=myDate.getSeconds();
         curH=h+m/60+s/60/60;//分和秒转化为时
         curM=m+s/60;
         curS=s;
         //在绘制之前,先清理画布
         ctx.clearRect(0,0,c.width,c.height);
         //绘制图形
         draw();
     }
     //绘制图形
     function draw() {
         //日期绘制
         ctx.font="30px Arial";
         ctx.fillStyle="blue";
         ctx.textAlign="center";
         ctx.fillText(year+" 年 "+month+" 月 "+date+" 日",200,65);
         //中心线绘制
         ctx.strokeStyle="lightcoral";
         ctx.lineWidth="2";
         ctx.moveTo(0,99);
         ctx.lineTo(c.width,99);
         ctx.stroke();
         //钟表图外圈绘制
         ctx.beginPath();
         ctx.strokeStyle="black";
         ctx.lineWidth=20;
         ctx.arc(x0,y0,r,0,Math.PI*2,false);
         ctx.stroke();
         ctx.closePath();
         //绘制钟表内刻度点
         drawPoint();
         //绘制钟表内的数字
         drawNum();
     
         //开始绘制时钟表盘;
         ctx.save();//改变画布位置之前先保存位置;
         //偏移原点位置时钟中心点;
         ctx.translate(c.width/2,c.height/2+50);//在绘制结束后,必须将原点偏移到原来位置;
         //绘制时针
         drawHourhand(curH);
         //绘制分针
         drawMinutehand(curM);
         //绘制秒针
         drawSecondhand(curS);
         //绘制中心圆
         drawCore();
     
         //绘制时钟表盘结束
         //恢复原来画布位置;
         ctx.restore();
     }
     //绘制钟表内刻度点
     function drawPoint() {
         var a,x1,y1;
         //钟表图内刻度点绘制
         for(var i=0; i<60; i++){
             a=i*2*Math.PI/60;
             x1=x0+mlr*Math.sin(a);
             y1=y0-mlr*Math.cos(a);
             if(i%5===0){
                 ctx.fillStyle="red";
             }else{
                 ctx.fillStyle="black";
             }
             ctx.beginPath();
             ctx.arc(x1,y1,smr,0,Math.PI*2,false);
             ctx.closePath();
             ctx.fill();
         }
     }
     //绘制钟表内的数字
     function drawNum() {
         var a,x2,y2;
         for(var i=1; i<=12; i++){
             a=i*Math.PI*2/12;
             x2=x0+numr*Math.sin(a);
             y2=y0-numr*Math.cos(a);
             ctx.textAlign="center";
             ctx.fillText(i,x2,y2+12);
         }
     }
     //绘制时针
     function drawHourhand(hour) {
         ctx.save();//保存原位置;
         ctx.rotate(Math.PI*2/12*hour);
         ctx.beginPath();
         ctx.strokeStyle="black";
         ctx.lineWidth=16;
         ctx.lineCap="round";
         ctx.moveTo(0,-r/2);
         ctx.lineTo(0,10);
         ctx.stroke();
         ctx.restore();//恢复原位置;
     }
     //绘制分针
     function drawMinutehand(min) {
         ctx.save();//保存原位置;
         ctx.rotate(Math.PI*2/60*min);
         ctx.beginPath();
         ctx.strokeStyle="black";
         ctx.lineWidth=6;
         ctx.lineCap="round";
         ctx.moveTo(0,-r/2-35);
         ctx.lineTo(0,20);
         ctx.stroke();
         ctx.restore();//恢复原位置;
     }
     //绘制秒针
     function drawSecondhand(sec) {
         ctx.save();//保存原位置;
         ctx.rotate(Math.PI*2/60*sec);
         ctx.beginPath();
         ctx.fillStyle="red";
         ctx.moveTo(1.5,-r+30);
         ctx.lineTo(4,40);
         ctx.lineTo(-4,40);
         ctx.lineTo(-1.5,-r+30);
         ctx.fill();
         ctx.restore();//恢复原位置;
     }
     //绘制中心圆
     function drawCore() {
         //此处没有改变画布位置;无需保存;
         ctx.fillStyle="white";
         ctx.beginPath();
         ctx.arc(0,0,6,0,Math.PI*2,false);
         ctx.closePath();
         ctx.fill();
     }
    

1.3 炫酷小球实例

  • 需求:实现鼠标在canvas画布上移动时,创建多个小球,向四周分散,小球半径逐渐变小,直至消失;
  • 思路解析:
    • 创建数组ary:储存每个小球实例,在定时器中,每隔一段时间,执行ary中的this实例;
    • 创建Ball类函数:
      • 构造函数:设置每个实例小球自己的属性;
        • 形参x,y,r,即创建小球的原点坐标和半径;实参为移动过程中光标的位置(计算后的相对坐标值)和小球半径值;
        • 设置私有属性x,y,r
        • 设置私有属性dx,dy,dr,color;
          • dx,dy为-5到5之间的随机数,作为原点坐标的变化值;
          • dr为0.3到1.3之间的随机数,作为半径递减的数值;
          • color为小球的背景色,为随机颜色;
        • 将实例this插入到数组中;
      • 公共方法update():计算出小球下一个位置的数据
        • 私有属性x,y,r的累加累减,数据更新;
        • 边界值判断:
          • 判断条件:1)小球移动出画布;2)半径小于等于0;二者“或”的关系;
          • 将数组中储存的该实例赋值为null;注:不能删除,赋值为null,在执行时筛选删除null;
      • 公共方法render():绘制小球
        • 获取圆心坐标和半径绘制小球
    • 类函数创建完就需要调用方法
    • 添加事件
      • mouseover事件:当光标滑上canvas画布上,开启定时器,获取数组中的实例,然后,调用update()方法和render()方法;
        • 遍历数组时,前提是数组长度大于0;
        • 遍历数组后,对元素进行筛选,将null元素删除,避免i的塌陷;
      • mousemove事件:光标移动过程中,创建小球实例;实参为光标的位置相对于canvas画布的相对位置坐标和小球半径;
      • mouseout事件:光标移出画布后,开启另外一个定时器,判断数组的长度是否为0,若为0,则关闭第一个定时器,同时也关闭自己;
  • 实例实现的整体思路:
    • onmouseover事件触发:开启定时器,执行数组ary中实例对象的update()和render()方法;不断地绘制小球;
    • onmousemove事件触发:鼠标移动中,不断创建新的实例,插入到数组中,待指定间隔时间后,获取数组,绘制小球;
    • onmouseout事件触发:关闭开启的所有定时器;
    • 绘制小球之前,必须通过clearRect()来清空画布,然后再绘制,代码放在定时器中;
    • 定时器的开启和关闭
      • 第一个定时器:目的执行数组中实例身上的方法,绘制小球;
        • 开启:在mouseover事件中开启;
        • 关闭:在mouseout事件中,通过开启另一个定时器间隔时间判断ary的长度,当长度为0时,关闭此定时器;
      • 第二个定时器:当光标移出画布后,间隔时间判断ary的长度;长度为0,关闭第一个定时器;
        • 开启:在mouseout事件中开启;
        • 关闭:当ary长度为0后,关闭第一个定时器,同时也关闭自己的定时器;
  • 注意:
    • 当开启定时器之前,一般要关闭其他定时器,包括自己;(此实例除外,在第二个定时开启时,无需关闭第一个定时器);
    • 不能在第一个定时器内设置关闭定时器的操作,会出错,如果判断ary的长度不大于0时,关闭第一个定时器;那么在画布中停止移动后,待所有小球都消失后,定时器会停止,那么此时再移动光标,就不会开启定时器创建新的小球了;会出错;最好的方法是,在光标移出画布后,再关闭第一个定时器;
    • 光标位置获取使用pageX/pageY,不能使用clientX/clientY;获取canvas元素距离浏览器左上角的距离,可以使用自己封装的offset()方法,也可以使用jQuery中的offset()方法;不能使用offsetLeft/offsetTop;
  • 代码:
    • html代码:
     
     
     
         
         炫酷小球实例
         
     
     
     

    炫酷小球实例

    your brower is not support canvas
    • moveball.js代码:
     (function () {
         //获取元素
         var $con=$(".container");
         var $can=$(".can");
         var oC=document.getElementById("mycanvas");
         var cLeft=$(oC).offset().left;
         var cTop=$(oC).offset().top;
     
         //全局变量
         var ary=[];
         var ballR=30;
         var timer=null;
         var outtimer=null;
     
         //创建canvas环境
         var ctx=oC.getContext("2d");
     
         //创建Ball类函数
         class Ball{
             constructor(x,y,r){
                 this.x=x;
                 this.y=y;
                 this.r=r;
                 this.dx=Math.random()*10-5;
                 this.dy=Math.random()*10-5;
                 this.dr=Math.random()+0.3;
                 this.color="rgb("+parseInt(Math.random()*255)+","+parseInt(Math.random()*255)+","+parseInt(Math.random()*255)+")";
                 ary.push(this);
             }
             update(){
                 //计算出下一个小球创建的位置;
                 this.x+=this.dx;
                 this.y+=this.dy;
                 this.r-=this.dr;
                 //边界值判断
                 if(this.r<=0){
                     this.r=0;//赋值为0;
                     for(var i=0; i0){
                     for(var i=0; i

你可能感兴趣的:(第十一周第三天笔记之canvas知识)