前端学习笔记 -- Canvas

Canvas画布
1、画图的步骤
1)先准备画布
2)准备画笔
3)先描路径
4)再填充
注:canvas标签的宽度和高度必须使用标签属性,不允许使用css设置

     2、坐标系
        坐标原点在画布的左上角
        X轴水平向右
        Y轴垂直向下

     3.镂空填充
       非零环绕规则:从路径环绕的所有的区域中,任意划出一条直接,如果穿过的线条正向的与反向的线条个数相加为零,就不会填充;如果不为零就填充

     4.画曲线(根据函数方程描点画线)

     5.路径的概念:

- 路径绘制方式(路径与隐形墨水)
+ 描边(空心 ) stroke()
+ 填充(实心) fill()
+ 既描边又填充 stroke() 和 fill()
闭合路径的方式:
1、使用closePath()可以自动闭合(推荐)
2、手动闭合路径需要多一个点才能闭合路径

     6.角度的表示方式:
             角度360、弧度2*PI     PI=180;
        一度等于多少弧度? 2*Math.PI/360=Math.PI/180

基本步骤如下:
//1.获取画布
var cas=document.getElementById(‘mycanvas’);
//2.获取画笔
var ctx=cas.getContext(‘2d’);
//3.描绘路径
ctx.moveTo(100,100);//将画笔移动到指定的坐标 x轴位置向右100 y轴位置向下100
ctx.lineTo(200,100);//用直线描路径到另外一点 从move位置创建到达位置x轴200,y轴100的一条线
//4.填充路径
ctx.stroke();

1.绘制文本
//使用fillText
var c=document.getElementById(‘mycanvas’);
var ctx=c.getContext(‘2d’);
ctx.font=’30px Arial’;
ctx.fillText(‘Hello World’,10,50);

    //使用stokeText
   var c=document.getElementById('mycanvas');
   var ctx=c.getContext('2d');
   ctx.font='30px Arial';
   ctx.strokeText('Hello World',10,50);

ctx.textAlign() 设置底线(文字水平对齐方式)
ctx.textBaseline() 设置基线(文字垂直对齐方式)
ctx.font=’30px Arial’;font 定义字体 参数1:字体大小 参数2:字体的类型
fillText(text,x,y) 在canvas上绘制实心的文本 参数1:文本内容 参数2:x轴 参数3:Y轴
strokeText(text,x,y) 在canvas上绘制空心的文本 参数1:文本内容 参数2:x轴 参数3:Y轴

2.绘制圆
var c=document.getElementById(‘mycanvas’);
var ctx=c.getContext(‘2d’);
ctx.beginPath(); //开辟一条路径
ctx.arc(100,100,50,0,2*Math.PI);
ctx.stroke();
扇形:
ctx.arc(200,200,100,0,Math.PI/6,false); //30度的扇形
ctx.lineTo(200,200);
ctx.fillStyle=’hotpink’;
ctx.fill();

arc(x,y,r,sAngle,eAngle,counterclockwise);
参数1:圆心的X坐标 参数2:圆心的Y坐标 参数3:圆的半径。参数4:起始角,以弧度计(弧的圆形的三点钟位置是0度) 参数5:结束角,以弧度计。参数6:可选,规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。
2.1 等分圆弧
//绘制一个360等分的圆,每一份的颜色都不同
var c=document.getElementById(‘cas’);
var ctx=c.getContext(‘2d’);
//角度转弧度的方法
function angleToRadian(angle){
// 参数是角度,返回值是弧度
// 先计算一个角度等于多少弧度
var one=2*Math.PI/360;
return one*angle;
}
//生成随机颜色
function randomColor(){
var r=parseInt(Math.random()*256);
var g=parseInt(Math.random()*256);
var b=parseInt(Math.random()*256);
return ‘rgb(‘+r+’,’+g+’,’+b+’)’;
}
//生成等分圆弧
function drawCircle(step){
for (var i = 0; i < 360; i+=step) {
ctx.beginPath();
ctx.moveTo(300,200);
ctx.fillStyle=randomColor();
ctx.arc(300,200,100,angleToRadian(i),angleToRadian(i+step));
ctx.closePath();
ctx.fill();
}
}
drawCircle(10);

2.2不等分圆弧
var c=document.getElementById(‘cas’);
var ctx=c.getContext(‘2d’);
//生成随机颜色
function randomColor(){
var r=parseInt(Math.random()*256);
var g=parseInt(Math.random()*256);
var b=parseInt(Math.random()*256);
return ‘rgb(‘+r+’,’+g+’,’+b+’)’;
}
//绘制等分圆弧
function drawCircle(startAngle,radianData){
for (var i = 0; i < radianData.length; i++) {
ctx.beginPath();
ctx.moveTo(300,200);
ctx.fillStyle=randomColor();
ctx.arc(300,200,100,startAngle,startAngle+radianData[i]);
startAngle+=radianData[i];
ctx.closePath();
ctx.fill();
}
}
//把数据转成对应的成比例的弧度
function dataToRadian(data){
var sum=0;
data.forEach(function(item){
sum+=item;
});
return data.map(function(item){
return 2*Math.PI*item/sum;
});
}
var data=[1000,800,600,300,50];
var radianData=dataToRadian(data);
drawCircle(0,radianData);

//map方法的作用就是把数组中的每一项数据重新处理返回一个新的数据
2.3不等分文本圆弧
function DrawChart(id,startAngle){
this.ctx=document.getElementById(id).getContext(‘2d’);
this.startAngle=startAngle;
this.x=300;
this.y=200;
this.r=100;
this.dis=20;
}
//入口函数
DrawChart.prototype.init=function(data){
var newToRadian=this.dataToRadian(data);
this.drawCircle(newToRadian);
}

   //生成随机颜色
   DrawChart.prototype.randomColor=function(){
       var r=parseInt(Math.random()*256);
       var g=parseInt(Math.random()*256);
       var b=parseInt(Math.random()*256);
       return 'rgb('+r+','+g+','+b+')';
   }
    //转换数据
   DrawChart.prototype.dataToRadian=function(data){
          var sum=0;
          data.forEach(function(item){
             sum+=item.data;
          });
          return data.map(function(item){
             item.data=2*Math.PI*item.data/sum;
             return item;
          });
    }   
   //绘制等分圆弧
   DrawChart.prototype.drawCircle=function(radianData){
        for (var i = 0; i < radianData.length; i++) {
          this.ctx.beginPath();
          this.ctx.moveTo(300,200);
          var color=this.randomColor();
          this.ctx.strokeStyle=color; 
          this.ctx.fillStyle=color;       
          //修改下次绘制的起始角度
          this.ctx.arc(this.x,this.y,this.r,this.startAngle,this.startAngle+radianData[i].data);

         //计算数据标注的线条坐标点
          var x=this.x+(this.r+this.dis)*Math.cos(this.startAngle+radianData[i].data/2);
          var y=this.y+(this.r+this.dis)*Math.sin(this.startAngle+radianData[i].data/2);   

          // 修改下次绘制的起始角度
           this.startAngle+=radianData[i].data;
           this.ctx.closePath();
           this.ctx.fill();

          //绘制数据的标注
          this.ctx.lineTo(x,y);
          //计算文字的宽度
          var width = this.ctx.measureText(radianData[i].title).width;
          if (this.x>x){
            this.ctx.textAlign='right';
            this.ctx.lineTo(x-width,y);
          }else{
            this.ctx.textAlign='left';
            this.ctx.lineTo(x+width,y);
          }
          this.ctx.strokeText(radianData[i].title,x,y-5);         
          this.ctx.stroke();           
        }       
   }

var data=[{
    title:'IE',
    data:1000
  },{
    title:'Chrome',
    data:800
  },{
    title:'FireFox',
    data:600
  },{
    title:'Safari',
    data:300
  },{
    title:'Opera',
    data:150
  }];
 var draw=new DrawChart('cas',0);
 draw.init(data);

3.绘制矩形
var ctx=document.getElementById(‘cas’);
var ctx=ctx.getContext(‘2d’);
//ctx.moveTo(100,100);
//矩形
// ctx.lineTo(100,200);
// ctx.lineTo(200,200);
// ctx.lineTo(200,100);
// ctx.lineTo(200,100);
// ctx.lineTo(100,100);

//空心矩形   
ctx.strokeStyle='red';//颜色
ctx.strokeRect(100,100,100,100);//参数1:x轴 参数2:y轴  参数3:宽  参数4:高
//ctx.stroke();

//实心矩形
ctx.fillStyle='hotpink';//颜色
ctx.fillRect(200,200,100,100)//参数1:x轴 参数2:y轴  参数3:矩形宽  参数4:矩形高

4.绘制渐变矩形
创建一个线性渐变,使用渐变填充矩形
var c=document.getElementById(‘mycanvas’);
var ctx=c.getContext(‘2d’);
var grd=ctx.createLinearGradient(0,0,200,0);
grd.addColorStop(0,’red’);
grd.addColorStop(1,’white’);
ctx.fillStyle=grd;
ctx.fillRect(10,10,150,80);

创建一个径向/圆 渐变。使用渐变填充矩形
var c=document.getElementById(‘mycanvas’);
var ctx=c.getContext(‘2d’);
var grd=ctx.createRadialGradient(75,50,5,90,60,100);
grd.addColorStop(0,’red’);
grd.addColorStop(1,’white’);
ctx.fillStyle=grd;
ctx.fillRect(10,10,150,80);

createLinearGradient (x,y,x1,y1)创建渐变条
参数1:渐变开始x坐标 参数2:渐变开始y坐标 参数3:渐变结束x坐标 参数4:渐变结束y坐标
createRadialGradient (x,y,r,x1,y1,r1)创建一个径向/圆渐变
参数1:渐变的开始圆的x坐标 参数2:渐变的开始圆的y坐标 参数3:开始圆的半径 参数4:渐变的结束圆的x坐标 参数5:渐变的结束圆的y坐标 参数6:结束圆的半径
addColorStop(1,’red’) 方法指定颜色停止,参数使用坐标来描述 可以是0-1;

5.绘制虚线
// 1、获取画布
var cas = document.getElementById(‘cas’);
// 2、获取画笔
var ctx = cas.getContext(‘2d’); // webgl
// 3、描绘路径
ctx.setLineDash([5,10]);
ctx.lineWidth = 10;
ctx.moveTo(100,100);
ctx.lineTo(400,100);
ctx.lineDashOffset = -3;// 正值向左偏移;负值向右偏移
// var ret = ctx.getLineDash();
// console.log(ret);
ctx.stroke();

ctx.beginPath();
ctx.setLineDash([]);//重新恢复实线
ctx.lineWidth = 1;
ctx.moveTo(100,200);
ctx.lineTo(400,200);
ctx.stroke();

6.绘制坐标轴(含坐标点)
// 1、获取画布
var cas = document.getElementById(‘cas’);
// 2、获取画笔
var ctx = cas.getContext(‘2d’); // webgl
// 获取画布的尺寸
// console.log(cas.width,cas.height);
// console.log(ctx.canvas.width,ctx.canvas.height);
// 坐标原点
var x0 = 20;
var y0 = ctx.canvas.height - 20;
// y轴箭头坐标
var x1 = 20;
var y1 = 20;
// x轴箭头坐标
var x2 = ctx.canvas.width - 20;
var y2 = ctx.canvas.height - 20;

// 绘制x轴
ctx.moveTo(x0,y0);
ctx.lineTo(x2,y2);
ctx.lineTo(x2 - 30,y2 - 10);
ctx.lineTo(x2 - 10,y2);
ctx.lineTo(x2 - 30,y2 + 10);
ctx.lineTo(x2,y2);
ctx.stroke();
// 绘制y轴
ctx.moveTo(x0,y0);
ctx.lineTo(x1,y1);
ctx.lineTo(x1 - 10,y1 + 30);
ctx.lineTo(x1,y1 + 10);
ctx.lineTo(x1 + 10,y1 + 30);
ctx.lineTo(x1,y1);
ctx.stroke();
// 绘制坐标点
function drawDot(ctx,edge,x0,y0,x,y){
    var tempX = x0 + x;
    var tempY = y0 - y;
    ctx.beginPath();
    ctx.moveTo(tempX-edge/2,tempY-edge/2);
    ctx.lineTo(tempX+edge/2,tempY-edge/2);
    ctx.lineTo(tempX+edge/2,tempY+edge/2);
    ctx.lineTo(tempX-edge/2,tempY+edge/2);
    ctx.closePath();
    ctx.stroke();
    return {
        x : tempX,
        y : tempY
    }
}
// 计算相对canvas坐标系的坐标
var d1 = drawDot(ctx,4,x0,y0,100,100);
var d2 = drawDot(ctx,4,x0,y0,200,300);
var d3 = drawDot(ctx,4,x0,y0,300,150);
var d4 = drawDot(ctx,4,x0,y0,400,250);

ctx.moveTo(x0,y0);
ctx.lineTo(d1.x,d1.y);
ctx.lineTo(d2.x,d2.y);
ctx.lineTo(d3.x,d3.y);
ctx.lineTo(d4.x,d4.y);
ctx.stroke();

6.1面向对象绘制坐标轴(包含坐标点,曲折线)
function DrawAxis(id){
this.ctx = document.getElementById(id).getContext(‘2d’);
this.edge = 4;
this.x0 = 20;
this.y0 = this.ctx.canvas.height - 20;
this.x1 = 20;
this.y1 = 20;
this.x2 = this.ctx.canvas.width - 20;
this.y2 = this.ctx.canvas.height - 20;
}

DrawAxis.prototype.init = function(data){
    var that = this;  // 缓存实例对象
    this.drawAxis();
    data.forEach(function(element,index){
        // 计算canvas坐标
        var x = that.x0 + element[0];
        var y = that.y0 - element[1];
        that.drawDot(x,y);
    });     
    this.drawLine(data);  // 绘制折线
}
// 绘制折线
DrawAxis.prototype.drawLine = function(data){     
    var that = this; // 缓存实例对象
    this.ctx.beginPath();
    this.ctx.moveTo(this.x0,this.y0);
    data.forEach(function(element){
        // 计算canvas坐标
        var x = that.x0 + element[0];
        var y = that.y0 - element[1];
        that.ctx.lineTo(x,y);
    });
    this.ctx.stroke();
}
// 绘制坐标点
DrawAxis.prototype.drawDot = function(x,y){
    this.ctx.beginPath();
    this.ctx.moveTo(x-this.edge/2,y-this.edge/2);
    this.ctx.lineTo(x+this.edge/2,y-this.edge/2);
    this.ctx.lineTo(x+this.edge/2,y+this.edge/2);
    this.ctx.lineTo(x-this.edge/2,y+this.edge/2);
    this.ctx.closePath();
    this.ctx.stroke();
}

// 绘制坐标轴
DrawAxis.prototype.drawAxis = function(){
    // 绘制x轴
    this.ctx.moveTo(this.x0,this.y0);
    this.ctx.lineTo(this.x2,this.y2);
    this.ctx.lineTo(this.x2 - 30,this.y2 - 10);
    this.ctx.lineTo(this.x2 - 10,this.y2);
    this.ctx.lineTo(this.x2 - 30,this.y2 + 10);
    this.ctx.lineTo(this.x2,this.y2);
    this.ctx.stroke();
    // 绘制y轴
    this.ctx.moveTo(this.x0,this.y0);
    this.ctx.lineTo(this.x1,this.y1);
    this.ctx.lineTo(this.x1 - 10,this.y1 + 30);
    this.ctx.lineTo(this.x1,this.y1 + 10);
    this.ctx.lineTo(this.x1 + 10,this.y1 + 30);
    this.ctx.lineTo(this.x1,this.y1);
    this.ctx.stroke();
}
var da = new DrawAxis('cas');
da.init([[100,100],[200,150],[300,200],[400,50]]);

var da1 = new DrawAxis('cas1');
da1.init([[100,120],[200,100],[300,240],[400,150]]);

7.绘制图像
var ctx=document.getElementById(‘cas’);
var ctx=ctx.getContext(‘2d’);
var img=new Image();
img.src=’diudiu.jpg’;
img.onload=function(){
ctx.drawImage(img,100,100);
// ctx.drawImage(img,0,0,100,100); //后面方法有说明
// ctx.drawImage(img,0,0,200,100,300,200,50,50); //后面方法有说明
}
drawImage(img,x,y);参数1: 参数2:图像位于x轴坐标 参数3:图像位于y轴坐标
7.1绘制逐帧动画
var cas = document.getElementById(‘cas’);
var ctx = cas.getContext(‘2d’);
// 逐帧动画(视觉暂留)
// setTimeout()
// setInterval()
var nowIndex = 0;
setInterval(function(){
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
var img = new Image();
img.src = ‘img/rabbit.png’;

    img.onload = function(){
        console.log(nowIndex);
        ctx.drawImage(img,40 * nowIndex,195,40,65,280,168,40,65);
        nowIndex++;
        if(nowIndex == 4){
            nowIndex = 0;
        }
    }
},200);

8.状态的保持与恢复
var cas = document.getElementById(‘cas’);
var ctx = cas.getContext(‘2d’);
// save() restore()
ctx.lineWidth = 10;
ctx.strokeStyle = ‘green’;
ctx.moveTo(100,100);
ctx.lineTo(400,100);
ctx.stroke();

ctx.save();//保存之前的状态

ctx.beginPath();
ctx.lineWidth = 30;
ctx.strokeStyle = 'blue';
ctx.moveTo(100,200);
ctx.lineTo(400,200);
ctx.stroke();

ctx.save();
ctx.beginPath();
ctx.lineWidth = 50;
ctx.strokeStyle = 'orange';
ctx.moveTo(100,260);
ctx.lineTo(400,260);
ctx.stroke();

// 回复之前保存的样式
ctx.restore();
ctx.beginPath();
ctx.moveTo(100,300);
ctx.lineTo(400,300);
ctx.stroke();

ctx.restore()
ctx.beginPath();
ctx.moveTo(100,330);
ctx.lineTo(400,330);
ctx.stroke();

9.坐标系变换
var cas = document.getElementById(‘cas’);
var ctx = cas.getContext(‘2d’);
// 平移canvas坐标系
ctx.translate(300,200);
// 旋转坐标系(旋转时圆心是坐标轴原点)
// 负值表示逆时针旋转,正值表示顺时针旋转
ctx.rotate(-Math.PI/6);
// 坐标系缩放操作
ctx.scale(2,2);
ctx.strokeRect(0,0,100,100);

常用方法及参数:
基本步骤:
ctx.moveTo(100,100);//将画笔移动到指定的坐标 x轴位置向右100 y轴位置向下100
ctx.lineTo(200,100);//用直线描路径到另外一点 从move位置创建到达位置x轴200,y轴100的一条线
ctx.beginPath(); //开辟一条路径
ctx.closePath();//闭合路径

路径绘制方式(路径与隐形墨水)
+ 描边(空心 ) stroke()
+ 填充(实心) fill()
+ 既描边又填充 stroke() 和 fill()

绘制图形样式设置(画笔的状态)
lineWidth 线宽,默认1px
lineCap 线末端类型:(butt默认)、round、square
lineJoin 相交线的拐点 miter(默认)、round、bevel
strokeStyle 线的颜色
fileStyle 填充颜色
setLineDash() 设置虚线
getLineDash() 获取虚线宽度集合
lineDashOffset 设置虚线偏移量(负值向右偏移)

绘制虚线:
ctx.lineDashOffset = -3;// 正值向左偏移;负值向右偏移
ctx.setLineDash([]);//重新恢复实线

绘制矩形:
以下:参数1:x轴 参数2:y轴 参数3:矩形宽 参数4:矩形高
rect(x,y,w,h) 没有独立路径
strokeRect(x,y,w,h) 有独立路径,不影响别的绘制
fillRect(x,y,w,h) 有独立路径,不影响别的绘制
clearRect(x,y,w,h) 擦除矩形区域

绘制渐变矩形:
createLinearGradient (x,y,x1,y1)创建渐变条
参数1:渐变开始x坐标 参数2:渐变开始y坐标 参数3:渐变结束x坐标 参数4:渐变结束y坐标
createRadialGradient (x,y,r,x1,y1,r1)创建一个径向/圆渐变
参数1:渐变的开始圆的x坐标 参数2:渐变的开始圆的y坐标 参数3:开始圆的半径 参数4:渐变的结束圆的x坐标 参数5:渐变的结束圆的y坐标 参数6:结束圆的半径
addColorStop(1,’red’) 方法指定颜色停止,参数使用坐标来描述 可以是0-1;

绘制圆:
arc(x,y,r,sAngle,eAngle,counterclockwise);
参数1:圆心的X坐标 参数2:圆心的Y坐标 参数3:圆的半径。参数4:起始角,以弧度计(弧的圆形的三点钟位置是0度) 参数5:结束角,以弧度计。参数6:可选,规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。

绘制文本:
ctx.font=’30px Arial’;//font 定义字体 参数1:字体大小 参数2:字体的类型
fillText(text,x,y,maxwidth) 在canvas上绘制实心的文本 参数1:文本内容 参数2:x轴 参数3:Y轴
strokeText(text,x,y,maxwidth) 在canvas上绘制空心的文本 参数1:文本内容 参数2:x轴 参数3:Y轴 参数4:maxwidth 设置为文本最大宽度,可选,一般不用(压缩文字宽度而不是截取);
ctx.textAlign文本水平对齐方式,相对绘制坐标来说的
+ left
+ center
+ right
+ start 默认
+ end
+ direction属性css(rtl ltr) start和end于此相关
- 如果是ltr,start和left表现一致
- 如果是rtl,start和right表现一致
ctx.textBaseline 设置基线(垂直对齐方式 )
+ top 文本的基线处于文本的正上方,并且有一段距离
+ middle 文本的基线处于文本的正中间
+ bottom 文本的基线处于文本的证下发,并且有一段距离
+ hanging 文本的基线处于文本的正上方,并且和文本粘合
+ alphabetic 默认值,基线处于文本的下方,并且穿过文字
+ ideographic 和bottom相似,但是不一样
- measureText() 获取文本宽度obj.width

绘制图像
三个参数drawImage(img,x,y)
- img 图片对象、canvas对象、video对象
- x,y 图片绘制的左上角坐标
五个参数drawImage(img,x,y,w,h)
- img 图片对象、canvas对象、video对象
- x,y 图片绘制的左上角
- w,h 图片绘制尺寸设置(图片缩放,不是截取)
九个参数drawImage(img,x,y,w,h,x1,y1,w1,h1)
- img 图片对象、canvas对象、video对象
- x,y,w,h 图片中的一个矩形区域(在图片中截取一块区域)
- x1,y1,w1,h1 画布中的一个矩形区域(在画布中截取一块区域)

坐标系变换
- 平移 移动画布的原点
+ translate(x,y) 参数表示移动目标点的坐标
- 缩放
+ scale(x,y) 参数表示宽高的缩放比例
- 旋转
+ rotate(angle) 参数表示旋转角度

关于参考文档
- MDN ;
- w3schook;

猜你喜欢

转载自blog.csdn.net/weixin_38457248/article/details/81805766