canvas的用法

时间:2023-03-09 22:23:15
canvas的用法

包括:
介绍。

基础入门。(兼容性。获取canvas上下文。绘制直线/描边,填充内容。绘制表格。)

canvas是基于状态的绘图。

绘制矩形。

绘制圆形。

绘制文本。

绘制图片。

阴影。

渐变。

绘制背景图。

变换。

介绍:

HTML5的新标签<canvas></canvas>

canvas标签通过JavaScript在网页上绘制图像,本身不具备绘图功能。

canvas拥有多种绘制路径,矩形,圆形,字符以及添加图像的方法。

canvas可以做游戏,图表,广告等等。

基础入门。

设置canvas的宽和高是通过canvas标签的属性来设置,不要用css设置。

<canvas id="canvas" width="400" height="400"></canvas>

还可以在JS中通过属性指定。

var canvas = document.getElementById('canvas');  //获取canvas标签
canvas.width=400;
canvas.height=400;

兼容性。

当浏览器不支持canvas时,在canvas标签内编写提示文字。

<canvas>你的浏览器不支持canvas,请更换浏览器后再试。</canvas>

(当浏览器支持canvas时,canvas会执行相关JS代码)

获取canvas上下文。

canvas上下文就是绘制工具的集合。

写在canvas标签后,或者window.onload = function(){}

var canvas = document.getElementById('canvas');  //获取canvas标签
var ctx= canvas.getContext('2d'); //获取canvas的上下文 3D=>'webgl'

得到canvas上下文后就可以开始绘制了。

canvas的坐标系和浏览器的坐标系一致。都是左上角为(0,0)。

绘制直线/描边,填充内容。

ctx.moveTo(100,100);  //画笔移动到(100,100)
ctx.lineTo(200,100); //画一条直线到(200,100)
ctx.lineTo(100,200); //画一条直线到(100,200)
//到此为止,只绘制了路径,还没描线。 ctx.stroke(); //描线。

canvas的用法

将路径闭合。

ctx.moveTo(100,100);  //画笔移动到(100,100)
ctx.lineTo(200,100); //画一条直线到(200,100)
ctx.lineTo(100,200); //画一条直线到(100,200) ctx.lineTo(100,100); //画一条直线到(100,100) ctx.stroke(); //描线。

还可以使用ctx.closePath()来闭合路径。

ctx.moveTo(100,100);  //画笔移动到(100,100)
//必须要写moveTo(),否则画笔没有位置。
//没有写moveTo()直接写lineTo()的话,画笔的位置直接到lineTo()的位置,相当于moveTo() ctx.lineTo(200,100); //画一条直线到(200,100)
ctx.lineTo(100,200); //画一条直线到(100,200) ctx.closePath() //闭合路径 ctx.stroke(); //描线。

都是一样的效果:

canvas的用法

修改描边的样式。在stroke()描边之前设置描边样式。

ctx.lineWidth = 4;  //线宽
ctx.strokeStyle = 'red'; //颜色

canvas的用法

填充内容。默认是黑色。修改填充的样式。

ctx.fill();
ctx.fillStyle = 'blue'; //颜色

canvas的用法

问题:填充后,为什么描边变细?

答案:描边是2像素在里面2像素在外边。填充后,里面的2像素被遮盖住了。

绘制表格。

var rectH = 10;  //行高
var rectW = 10; //列宽
//绘制横线:
for(var i = 0;i< canvas.width / rectH;i++){
ctx.moveTo(0,i*rectH);
ctx.lineTo(canvas.width,i*rectH);
//绘制竖线
for(var j = 0;j<canvas.height / rectW;j++){
ctx.moveTo(j*rectW,0);
ctx.lineTo(j*rectW,canvas.height);
}
}
ctx.lineWidth = 0.5;
ctx.strokeStyle = '#ccc';
ctx.stroke();

canvas的用法

在这基础上就可以绘制折线图了。

绘制箭头的思路:

canvas的用法

绘制数据的思路:

canvas的用法

var x0 = 100,y0 = 500;
var maxHeight = 300;
var arrowWidth = 10;// 箭头宽度 // 绘制x轴
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.moveTo(x0, y0);
ctx.lineTo(500, 500); // 箭头
ctx.lineTo(500-arrowWidth, 500-arrowWidth);
ctx.moveTo(500, 500);
ctx.lineTo(500-arrowWidth, 500+arrowWidth);
ctx.stroke(); //绘制y轴
ctx.beginPath();
ctx.strokeStyle = "purple";
ctx.moveTo(x0, y0);
ctx.lineTo(100, 100); // 箭头
ctx.lineTo(100-arrowWidth, 100+arrowWidth);
ctx.moveTo(100, 100);
ctx.lineTo(100+arrowWidth, 100+arrowWidth);
ctx.stroke(); // 绘制线段
var data = [.4 ,.5 ,.8 ,.7];
var pointWidth = 400 / (data.length + 1);
ctx.beginPath();
ctx.strokeStyle = "red";
for(var i=0;i<data.length;i++){
var x =x0 +(i + 1) * pointWidth;
var y =y0 - data[i] * maxHeight;
ctx.lineTo(x, y);
}
ctx.stroke();

canvas的用法

canvas是基于状态的绘图。

比如绘制两条不同颜色的直线。

ctx.strokeStyle = 'red';
ctx.lineWidth=5; //第一条线
ctx.moveTo(100,100);
ctx.lineTo(300,100);
ctx.stroke(); //第二条线
ctx.strokeStyle = 'blue';
ctx.moveTo(100,200);
ctx.lineTo(300,200);
ctx.stroke();

canvas的用法

问题:两条线颜色为什么一样?

解决方法:canvas是基于状态的绘图。设置ctx.beginPath()即可。

//第二条线
ctx.beginPath(); ctx.strokeStyle = 'blue';
ctx.moveTo(100,200);
ctx.lineTo(300,200);
ctx.stroke();

canvas的用法

beginPath()相当于开启新状态。

绘制第一条线的时候也可以beginPath(),默认一开始就有状态。

绘制第二条线的新状态,可以继承之前的状态的样式,但是当前的状态设置的所有样式,只能作用于当前的状态。

绘制矩形。

绘制矩形:ctx.rect(x,y,w,h);  //左上角坐标(x,y),w宽,h高。

ctx.rect(50,50,50,50);
ctx.stroke(); ctx.strokeRect(120,120,50,50); //和上面写法的效果一致。 ctx.fillRect(190,190,50,50); //如果是fill(填充),会自动闭合路径。

canvas的用法

清除矩形:相当于橡皮擦。

ctx.clearRect(x,y,w,h);

ctx.clearRect(195,195,30,30);

canvas的用法

绘制圆形。

ctx.arc(x,y,r,startAngle,endAngle,counterclockwise);
//圆心坐标(x,y),半径r,开始弧度,结束弧度,顺时针/逆时针(默认顺时针如图)

canvas的用法

换算公式:rad = deg*Math.PI/180;

绘制0-30°的圆弧。

ctx.arc(100,100,100,0,30*Math.PI/180,false);

canvas的用法

加上closePath()会闭合路径。

canvas的用法

如果要连接到圆心点。先moveTo(圆心点)即可。

ctx.moveTo(100,100)
ctx.arc(100,100,100,0,30*Math.PI/180,false);
ctx.closePath();
ctx.stroke();

canvas的用法

绘制饼状图的其中一个扇形。

ctx.moveTo(200,200);
ctx.fillStyle = 'red'
ctx.arc(200,200,100,-90*Math.PI/180,-30*Math.PI/180,false);
ctx.fill()

canvas的用法

假设有这样一个JSON数据。

var data =[{
"value":.2,
"color":"red",
"title":"应届生"
},{
"value":.3,
"color":"blue",
"title":"社会招生"
},{
"value":.4,
"color":"green",
"title":"推荐"
},{
"value":.1,
"color":"yellow",
"title":"公开课"
}];

将数据变成饼状图。

value代表占比。从-90°开始绘制。

//先画扇形。
var tempAngle = -90; //从-90度开始
var x0 = 150,y0 = 150,radius = 100; //圆心和半径
for(var i=0;i<data.length;i++){
ctx.beginPath();
ctx.moveTo(x0,y0); //圆心
var angle = data[i].value*360; //当前扇形的角度
ctx.fillStyle = data[i].color; var startAngle = tempAngle * Math.PI/180; //开始角度
var endAngle = (tempAngle + angle) * Math.PI/180; //结束角度 ctx.arc(x0,y0,radius,startAngle,endAngle)
ctx.fill(); tempAngle+=angle;
}

canvas的用法

绘制文本。

ctx.strokeText('hello',450,400); //文字,坐标

ctx.fillText('hello',150,100);

ctx.moveTo(300,300);
ctx.fillStyle = 'purple';
ctx.font = '20px 微软雅黑';
ctx.textBaseline = "bottom"; //基线
ctx.textAlign = "left";
// ctx.strokeText('hello',450,400); //空心文字
ctx.fillText('hello',100,300); //实体填充文字

canvas的用法

行高行距的概念:

canvas的用法

对齐方式:

canvas的用法

饼状图的文字。假设,在角度的一半绘制一条直线出来,写上XX%,思路如图。

canvas的用法

绘制完饼状图后,fill前。绘制文字。

// 绘制文字
var txt = data[i].value * 100 +'%';
var x,y;
var textAngle = tempAngle + 1/2 *angle;
x=x0+Math.cos(textAngle * Math.PI / 180) * (radius + 20);
y=y0+Math.sin(textAngle * Math.PI / 180) * (radius + 20); // 左侧文字太长会越过饼状图。
if(textAngle>90&&textAngle<270){
ctx.textAlign = "end"
} ctx.fillText(txt,x,y);

文字会超过:

canvas的用法

文字不会超过:

canvas的用法

ctx.measureText()  //measure测量;返回文本的宽度

绘制图片:

ctx.drawImage(img,x,y);  //img是图片的DOM对象。  绘制的坐标。
// 创建图片的dom对象
var img = new Image();
img.src='img.jpg'; //只要设置了src属性,当前img对象立即去加载图片。 img.onload = function(){
// 图片加载完成后,绘制图片
ctx.drawImage(img,100,100);
}

以上的img和以下的方法获得的img是一样的,都是dom对象。

var img2 = document.getElementById('imagedemo');

canvas的用法

恶搞✧(≖ ◡ ≖✿)

for(var i=0;i<10;i++){
ctx.drawImage(img,100+i*10,100+i*10);
}

canvas的用法

还可以设置宽高,不设置的时候是图片的默认宽高。

ctx.drawImage(img,x,y,w,h);  //w,h,宽高。
ctx.drawImage(img,100,100,50,50);

被拉伸:

canvas的用法

如果要保持宽高比,则 原来的高度 / 原来的宽度 = 绘制的高度 / 绘制的宽度 。

假设已知绘制的宽度,则绘制的高度为 原来的高度*绘制的宽度/原来的宽度。

var ow = img.width;
var oh = img.height;
ctx.drawImage(img,100,100,200,200*oh/ow);

canvas的用法

绘制图片裁剪区域。

ctx.drawImage(img,sx,sy,sw,sh,x,y,w,h)  //截取的坐标。截取的宽高。绘制的坐标。绘制的宽高。

比如:网上找的一张图:截取出第一个人物:

canvas的用法

ctx.drawImage(img,195,26,276,377,100,100,200,300);

canvas的用法

逐帧动画/序列帧动画:定时器。

canvas的用法

先做第一行的动作。

var frameIndex = 0; //帧数
setInterval(function(){
// 清除之前的内容
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 如果通过代码重新设置canvas画布的宽高,canvas画布里的所有内容都被清空。(不建议使用)
//canvas.width = canvas.width;
ctx.drawImage(
img,
frameIndex*53.25, //截取的坐标
0, //截取的坐标
53.25, //截取的宽
92.75, //截取的高
200, //绘制的坐标
200, //绘制的坐标
53.25*2, //绘制的宽
92.75*2 //绘制的高
)
frameIndex++;
frameIndex%=4; //取余 4%4=0
},1000/10); //1秒10帧。

canvas的用法

添加四个方向的按钮。

<button id="btn-left">left</button>
<button id="btn-right">right</button>
<button id="btn-top">top</button>
<button id="btn-down">down</button>
var btnLeft = document.getElementById('btn-left')
var btnRight = document.getElementById('btn-right')
var btnTop = document.getElementById('btn-top')
var btnDown = document.getElementById('btn-down')

canvas的用法

在绘制图片前(new Image()前)。设置方向。相当于图片的第一行。代表向下走。

var dirIndex = 0;

然后将截取的y坐标改为dirIndex*92.75,绑定相关的按钮事件。

btnLeft.onclick = function(){
dirIndex =1 ; //第2行
}
btnRight.onclick = function(){
dirIndex =2 ; //第3行
}
btnTop.onclick = function(){
dirIndex =3 ; //第4行
}
btnDown.onclick = function(){
dirIndex =0 ; //第1行
}

点击效果:

canvas的用法

阴影

// 设置阴影
ctx.fillStyle = 'red';
ctx.shadowColor = 'teal'; //颜色
ctx.shadowBlur = 10; //模糊 ( 大于1 )
ctx.shadowOffsetX = 10; //偏移
ctx.shadowOffsetY = 10;
ctx.fillRect(100,100,100,100);

canvas的用法

渐变

// 线性渐变
var grd = ctx.createLinearGradient(0, 0, 170, 0);
grd.addColorStop(0,"black");
grd.addColorStop(0.5,"red");
grd.addColorStop(1,'white');
ctx.fillStyle = grd;
ctx.fillRect(0, 0, 300, 300);

canvas的用法

// 圆形渐变
var rlg = ctx.createRadialGradient(300, 300, 10, 300, 300, 200);
rlg.addColorStop(0,"white");
rlg.addColorStop(0.5,"red");
rlg.addColorStop(1,'black');
ctx.fillStyle = rlg;
ctx.fillRect(100, 100, 400, 400);

canvas的用法

绘制背景图

var pat = ctx.createPattern(img,repeat);  //img是DOM对象
ctx.rect(0, 0, 150, 100);
ctx.fillStyle = pat;
ctx.fill();

变换

ctx.scale(Scale Width, Scale Height);  //缩放当前绘图  1为100%
ctx.translate(X, Y); //位移画布
ctx.rotate(Rotate Angle); //旋转当前绘图
ctx.save(); //保存当前环境的状态
ctx.restore(); //返回之前保存过的路径状态和属性
ctx.globalAlpha = "Value between 0 & 1"; //绘制环境的透明度

例子:

// 状态1
ctx.fillStyle = "red";
ctx.fillRect(10, 10, 100, 100); ctx.save(); //保存状态
ctx.translate(200, 200); //把当前画布移动到200,200的位置
ctx.rotate(30* Math.PI / 180); //旋转
ctx.scale(2, 2); //缩放
ctx.globalAlpha = ".3"; //透明度 ctx.moveTo(0, 0);
ctx.lineTo(400, 0);
ctx.moveTo(0, 0);
ctx.lineTo(0, 400);
ctx.stroke();
ctx.fillRect(10, 10, 40, 40);
ctx.restore(); //返回之前保存过的路径状态和属性 ctx.fillRect(400, 400, 100, 100);

canvas的用法