canvas基础

创建canvas画布

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
css:
canvas{
border:3px solid blue;
}

html:
<canvas width="700" height="700" id="myCanvas">
您的浏览器不支持canvas,请更换浏览器访问!
</canvas>

Javascript:

<script>
let canvas = document.getElementById("myCanvas");
let ctx = canvas.getContext("2d");
</script>

Point:

  1. canvas标签是一个双标签,其内部写的是当浏览器不支持canvas时显示的内容,可以插入其他元素,比如文字,图片等。

  2. canvas画布的宽高应该在其标签内定义,不能在其CSS内定义,否则其绘制的图像会按照300*150发生缩放。

  3. 所有绘图行为都在script标签中进行。

    let ctx = canvas.getContext(“2d”);

所有canvas的API都是定义在该对象上的,其中参数可以是2D,或者3D.

Canvas绘制图像

canvas的绘制图形有两种方式:

  • context.fill()

fill()指的是填充,其默认颜色是黑色,可以在使用fill()之前使用fillStyle()方法改变填充颜色,如果是闭合图像,那么就直接填充。如果是非闭合的路径,则fill()先帮其闭合,然后填充。

1
2
ctx.fillStyle = "red";//设置填充色
ctx.fillRect(10,10,100,100);//绘制一个填充矩形
  • context.stroke()

stroke()方法会实际的绘制出moveTo()和lineTo()方法的路径。默认颜色是黑色,在绘制之前,可以使用strokeStyle()进行设置。

1
2
ctx.strokeStyle = "red";//设置边框填充色
ctx.strokeRect(10,10,100,100);//绘制空心矩形

绘制矩形

绘制基本矩形

1
2
ctx.fillRect(x,y,height,width)//实心矩形
ctx.strokeRect(x,y,height,width)//空心边框
  • x:起点的x坐标(即左上角的x坐标)
  • y:起点的y坐标(即左上角的y坐标)
  • height:矩形的高
  • width:矩形的宽

改变颜色

1
2
3
4
ctx.fillStyle = "red";//设置填充颜色
ctx.fillRect(10,10,100,100);
ctx.strokeStyle = "red";//设置边框颜色
ctx.strokeRect(200,200,100,100);

Point:

  • ctx.fillStyle = “red”用来设置填充颜色
  • ctx.strokeStyle = “red”用来设置边框颜色
  • 这些描述都要放在绘制图形之前声明

擦除矩形区域

  • ctx.clearRect(x,y,height,width)

    ctx.clearRect(50,50,200,200)//绘制一个矩形区域并擦除该区域之前的内容

绘制圆形

绘制基本圆

实心圆

  • ctx.arc(x,y,radius,starAngle,endAngle,anticlockwise)

    • x:圆心的x坐标
    • y:圆心的y坐标
    • radius:半径
    • startAngle:开始角度
    • endAngle:结束角度
    • anticlockwise:旋转方向,
      • true:逆时针(可选参数,默认为false)
      • false:顺时针
    1
    2
    3
    ctx.fillStyle = "red"; //设置填充色
    ctx.arc(200,200,50,0,Math.PI*2,true);//绘制圆形
    ctx.fill();//填充

空心圆

1
2
3
4
5
ctx.beginPath()
ctx.arc(200,200,50,0,Math.PI*2,true);
ctx.strokeStyle = "red";
ctx.closePath();
ctx.stroke();

Point

上面用到了路径,实际ctx.arc()相当于是一个lineTo()的一个集合。利用其绘制出一个圆形,最后要关闭(ctx.cloePath()),以及要(stroke())才能完全绘制出该图形。

非完整圆

如果要绘制一个非完整的圆,比如一个实心半圆,该如何绘制呢?

答案是使用arc方法中的startAngle和endAngle来改变。

1
2
ctx.fillStyle = "red";
ctx.arc(200,200,50,0,Math.PI,true);

空心圆形

1
2
3
4
5
ctx.beginPath();
ctx.strokeStyle = "red";
ctx.arc(400,400,100,0,Math.PI);
ctx.closePath();
ctx.stroke();

绘制线段

  • moveTo(x,y):把画笔移动至画布的制定位置,不创建线条

  • lineTo(x,y):添加一个点(x,y)

  • stroke():按照之前添加的点绘制路径

    1
    2
    3
    4
    ctx.strokeStyle = "red";//设置填充色
    ctx.moveTo(0,0);//将画笔移动至(0,0)
    ctx.lineTo(100,100);//添加一个点(100,100)
    ctx.stroke();//按点绘制路径

Point

  • 如果没有在第一次指定moveTo(x,y),则第一个lineTo(x,y) == moveTo(x,y)

  • 如果在lineTo()后没有使用moveTo()方法,则依次连接,eg:

    ctx.moveTo(0,0);
    ctx.lineTo(10,10);
    ctx.lineTo(20,20);
    ctx.lineTo(30,30);
    ctx.stroke();

则画出后是一段从点(0,0)=>(10,10)=>(20,20)=>(30,30)的一段折线。

  • ctx.beginPath():开始一段路径
  • ctx.closePath():闭合路径,即canvas会自动将未闭合的线段的首尾连接起来。

eg(一个三角形):

1
2
3
4
5
6
ctx.beginPath();
ctx.moveTo(0,0);
ctx.lineTo(10,10);
ctx.lineTo(20,20);
ctx.closePath();
ctx.stroke();

案例(六边形):

六边形

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var n = 0;
var dx = 150;//路径开始x坐标
var dy = 150;//路径开始y坐标
var s = 100;//边长
ctx.beginPath();//路径开始
ctx.fillStyle = 'pink';//设置填充色
ctx.strokeStyle = 'rgb(0,0,100)';//设置边框颜色
var dig = Math.PI / 3;//计算偏移角度
for (var i = 0; i < 6; i++) {
var x = Math.sin(i * dig);//计算以下个点的x坐标的增量
var y = Math.cos(i * dig);//计算下一个点的y坐标的增量
ctx.lineTo(dx + x * s, dy + y * s);//绘制下一个点
//console.log( x ,y )
}
ctx.closePath();//闭合整个路径
ctx.fill();//设置填充
ctx.stroke();//绘制路径

Point

这个例子用了一点数学知识,主要是:

1
2
3
4
5
6
for (var i = 0; i < 6; i++) {
var x = Math.sin(i * dig);//计算以下个点的x坐标的增量
var y = Math.cos(i * dig);//计算下一个点的y坐标的增量
ctx.lineTo(dx + x * s, dy + y * s);//绘制下一个点
//console.log( x ,y )
}

其原理是利用了简单的沟股定理,计算下一个点的坐标

线性渐变

  • let lg = ctx.createLinearGradient(xStart,yStart,xEnd,yEnd)
  • lg.addColorStop(offset,color)
  • xSart:渐变开始点的x坐标
  • yStart:渐变开始点的y坐标
  • xEnd:渐变结束点的x坐标
  • yEnd:渐变结束点的y坐标
  • offset:设定的颜色离渐变结束点的偏移量
  • color:绘制的颜色

eg:
let lg = ctx.createLinearGradient(0,0,100,200);
lg.addColorStop(0,”#E55D87”);
lg.addColorStop(1,”#5FC3E4”);
ctx.fillStyle = lg;
ctx.fillRect(0,0,200,200);

Point

  • 线性渐变仅仅是相当于设置填充色,在定义完填充色之后,我们还需要将填充设置为该线性渐变(ctx.fillStyle = gl)
  • 由于线性渐变仅仅是设置填充色,所以具体的背景容器还需要我们自己设置,比如设置一个矩形作为容器ctx.fillRect(0,0,200,200)
  • 由于渐变背景的坐标是相对于画布,而图形的坐标也是相对于画布,所以在定义背景时,需要注意与图形的坐标搭配以达到需要的效果

径向渐变

径向渐变

1
2
let rg = ctx.createRadialGradient(xStart,yStart,radiusStart,xEnd,yEnd,radiusEnd)
rg.addCOlorStop(offset,color);
  • xSart:发散开始的圆心x坐标

  • yStart:发散开始的圆心y坐标

  • radiusStart:发散开始圆的半径

  • xEnd:发散结束圆心的x坐标

  • yEnd:发散结束圆心的y坐标

  • radiusEnd:发散结束圆的半径

  • offset:设定的颜色结束点的偏移量(0-1)

  • color:绘制颜色

    1
    2
    3
    4
    5
    6
    7
    8
    var g1 = ctx.createRadialGradient(200, 150, 0, 200, 150, 200);
    g1.addColorStop(0.1, '#F09819');
    g1.addColorStop(1, '#EDDE5D');
    ctx.fillStyle = g1;
    ctx.beginPath();
    ctx.arc(200, 150, 100, 0, Math.PI * 2, true);
    ctx.closePath();
    ctx.fill();

图形变形

缩放

  • scale(x,y)

  • x:x坐标轴按x比例缩放

  • y:y坐标轴按y比例缩放

  • 前面参数的是按倍数来衡量的(0.5=>50%,1=>100%,2=>200%)

eg:

1
2
3
4
5
6
7
ctx.strokeStyle = "red";
ctx.scale(2,2);
ctx.strokeRect(5,5,25,15);
ctx.scale(2,2);
ctx.strokeRect(5,5,25,15);
ctx.scale(2,2);
ctx.strokeRect(5,5,25,15);

Point

  • 缩放一个图形,先使用ctx.scale(x,y)对画布进行缩放处理,后面再创建要缩放的工具ctx.strokeRect(5,5,25,15);
  • 缩放的原点都是在(0,0)位置。

旋转

  • ratate(angle)

  • angle:旋转的角度,以弧度计。

eg:

1
2
3
4
ctx.strokeStyle = "red";
// ctx.strokeRect(5,5,200,200);
ctx.rotate(20*Math.PI/180);//旋转5°
ctx.strokeRect(5,5,200,300);

Point:

默认的旋转中心是在(0,0)位置。下面介绍如何改变旋转中心。

平移

  • translate(x,y)

  • x:坐标原点向x轴平移x

  • y:坐标原点想y轴平移y

eg1(以矩形中心为原点旋转):

1
2
3
4
5
6
7
8
9
10
11
ctx.strokeStyle = "red";
//以(0,0)为原点绘制一个起点为(200,200),边长为200的正方形
ctx.strokeRect(200,200,200,200);
//移动原点至(300,300),即上面矩形的中心位置
ctx.translate(300,300);
//将画布进行一个45°的旋转,得到一个旋转后的图形
ctx.rotate(45*Math.PI/180);
//将原点坐标改为(0,0)
ctx.translate(-300,-300);
//绘制出旋转后的矩形
ctx.strokeRect(200,200,200,200);

eg2(以矩形中心为原点缩放图形):

1
2
3
4
5
6
ctx.strokeStyle = "red";
ctx.strokeRect(200,200,100,100);
ctx.translate(250,250);
ctx.scale(2,2);
ctx.translate(-250,-250);
ctx.strokeRect(200,200,100,100);

Point

上面提到的,scale,rotate方法的操作都是对画布而言的,貌似整的canvas的思维都是这样,需要我们有反向思考的能力。

组合图形

径向渐变

1
globalCompositeOperation = type

后绘制的图形如何与之前的图像叠加渲染,取决于type。下面是type的种类:

  • source-over(默认):在原图形之上绘制(覆盖)。
  • destination-over:在原图形之下绘制。
  • source-in:显示原有图形和新图形的交集,新图形在上,所以颜色为新图形颜色
  • destination-in:显示原图形和新图形的交集,原图形在上,所以颜色为原图形的颜色
  • source-out:只显示新图形的非交集部分
  • destination-out:只显示旧图形的非交集部分
  • source-atop:显示原图形和交集部分,新图形在上,所以交集部分为新图形颜色
  • destination-atop:显示新图形和交集部分,新图形在上,所以交集部分为新图形颜色
  • lighter:显示原有图形和新图形,交集部分做颜色叠加
  • copy:只显示新图形

eg:

1
2
3
4
5
ctx.globalCompositeOperation = "lighter";  
ctx.fillStyle = "red";
ctx.fillRect(50,50,200,200);
ctx.fillStyle = "blue";
ctx.fillRect(100,100,200,200);

Point

该属性与上面的ctx.translate(x,y)一样,一旦作用,就对下面的元素都起作用,如果要还原,请在此使用该属性还原。

阴影

  • shadowOffsetX:设置或返回阴影距形状的水平距离(默认值为0)
    -shadowOffsetY:设置或返回阴影形状的垂直距离(默认值为0)
  • shadowColor:设置或返回阴影的颜色
  • shadowBlur:设置或返回阴影的模糊级别(值越大越模糊)

eg:
ctx.shadowOffsetX=20;
ctx.shadowColor=”blue”;
ctx.shadowBlur = 50;
ctx.fillStyle = “red”;
ctx.fillRect(100,100,200,200);

1
2
3
4
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.fillStyle = "yellow";
ctx.fillRect(400,400,100,100);

Point

相同的是,阴影属性也是对一下的所有图形都生效。要取消阴影效果,必须重置:

1
2
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;

图像操作

  • drawImage(img,x,y):在画布上定位图像
  • drawImage(img,x,y,width,height):在画布上定位图像,并规定图像的宽度和高度
  • drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
    • img:规定要使用的图像,画布或视频
    • sx(可选):开始剪切的x坐标位置
    • sy(可选):开始剪切的y坐标位置
    • swidth(可选):被剪切的图像的宽度
    • sheight(可选):被剪切的图像的高度
    • x:在画布上放置img的x坐标位置
    • y:在画布上放置img的y坐标位置
    • width(可选):要使用的图像的宽度。(拉伸或压缩)
    • height(可选):要使用的图像的高度。(拉伸或压缩)

eg:

1
2
3
4
5
let img = new Image();
img.src = "expi.jpg";
img.onload = function(){
ctx.drawImage(img,100,100,200,200,200,200,200,200);
}

Point

  1. img应该是一个img对象,img = new Image()或者是一个Image的DOM标签document.getElementById("img")(实际也是一个Image对象,因为在HTML中,每创建一个img标签,就会自动创建一个Image对象。)

  2. 在使用该标签时,应当使用,Image对象的回调函数onload,否则不能渲染成功,其原因是:

    1
    2
    let img = new Image();
    img.src = "expi.jpg";

    这个过程中,对img.src赋值的时候,可能还没有赋值完成,就进行了ctx.drawImage语句,由于还没赋值完成,此使img.src还是空,所以无法渲染出来。

图像平铺

  • createPattern(image,type)

type:

  • no-repeat:不平铺
  • repeawt-x:按x轴方向平铺
  • repeat-y:按y轴方向平铺
  • repeat:全方向平铺

eg:
let img = new Image;
img.src = “beauty.png”;
img.onload = function(){
let pattern = ctx.createPattern(img,”repeat-x”);
ctx.fillStyle = pattern;
ctx.fillRect(10,10,500,500);
}

Point

  • 相同的是,必须要配合Image的oload回调函数来使用,道理同上。

图像剪切

  • clip()

该函数的使用方法:

  1. 创建剪切区域:ctx.rect(x,y,width,heigth)
  2. 设置剪切部分的填充色:ctx.fillStyle = “pink”
  3. 进行填充:ctx.fill();
  4. 进行剪切:ctx.clip();

eg:

1
2
3
4
5
6
7
8
9
10
ctx.fillStyle = "yellow";
ctx.fillRect(0,0,300,300);

ctx.rect(100,100,500,500);
ctx.fillStyle = "pink";
ctx.fill();
ctx.clip();

ctx.fillStyle = "blue";
ctx.fillRect(0,0,200,200);

Point

-一旦剪切了某个区域,则之后的所有绘图都会被限制在被剪切区域内进行(不能访问画布上的其他区域)。我们也可以在使用clip()方法之前通过使用save()方法将之前的画布保存下来,并在任意时间使用restored()方法。

绘制文字

  • fillText(text,x,y):绘制实心文字
    • x:文字的中心点x坐标
    • y:文字的中心点y坐标
  • strokeText():绘制文字描边(空心文字)
  • textAlign:设置或返回文字内容的当前对齐方式(注意:其都是相对于该文字对象的中心),其值有:
    • start:默认。文本在指定的位置开始。
    • end:文本在指定的位置结束。
    • left:文本左对齐。
    • center:文本的中心被放置在指定的位置。
    • right:文本右对齐。
  • textBaseline:设置会返回在绘制文本时使用的当前文字基线,其值有:
    • Bottom:文本基线是 em 方框的底端。
    • Top:文本基线是 em 方框的顶端。
    • Middle:文本基线是 em 方框的正中。
    • Alphabetic:默认。文本基线是普通的字母基线。
    • hanging:文本基线是悬挂基线。
  • font:设置或返回文本内容的当前文字属性

eg:

1
2
3
4
5
ctx.font = "40px Arial";
ctx.textAlign = "center";
ctx.fillText("Hello World",200,200);
ctx.strokeText("Hello World",200,300);
console.log(ctx.textBaseline);

textAlign
textBaseline

Powered by Hexo and Hexo-theme-hiker

Copyright © 2019 - 2024 My Wonderland All Rights Reserved.

UV : | PV :