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.οnlοad=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;