什么是Canvas
canvas概述:是HTML5提供的一种新标签, ie9才开始支持的,Canvas是一个矩形区域的画布,可以用JS控制每一个像素在上面绘画。canvas 标签使用 JavaScript 在网页上绘制图像,本身不具备绘图功能。canvas 拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。
Canvas主要应用的领域
1 可视化数据: 各类统计图表,比如:百度的echart
2 场景秀: 用Canvas实现动态的广告效果能够非常融洽的跨平台运行。如:手机中微产品.在移动端兼容性很好
3 游戏: canvas在基于Web的图像显示方面比Flash更加立体、更加精巧,canvas成为HTML5小游戏开发首选。现阶段h5做游戏,营业方式不是很明确. 25 超棒的 HTML5 Canvas 游戏
4 其他可嵌入网站的内容 (多用于活动页面、特效):类似图表、音频、视频,还有许多元素能够更好地与Web融合,并且不需要任何插件。
5 趋势=> 模拟器: 无论从视觉效果还是核心功能方面来说,模拟器产品可以完全由JavaScript来实现。模拟真实硬件环境,如移动端各种类型手机.
6 趋势=> 远程计算机控制: Canvas可以让开发者更好地实现基于Web的数据传输,构建一个完美的可视化控制界面。
7 趋势=> 图形编辑器: Photoshop图形编辑器将能够100%基于Web实现。
创建Canvas
<canvas id="canvas" width="200" height="200">
您的浏览器不支持canvas,请升级或更换浏览器
</canvas>
由于canvas是h5新出的标签,有些老牌浏览器不支持,标签内包裹的内容将在不支持的浏览器显示
其中width和height并不是指canvas的真正尺寸,而是canvas的精度,即将整个画布分为200*200的像素点。真正制定canvas尺寸的是css制定,
#canvas {
width: 500px;
height: 500px;
}
渲染上下文
通过js操作canvas的渲染上下文
let canvas = document.getElementById('canvas') // 获取canvas元素
ctx = canvas.getContext('2d') // 获取到canvas上下文(画笔) -> CanvasRenderingContext2D
坐标空间
上面说了canvas的属性width和height将canvas平分为200*200的像素点,左上角为坐标(0,0),右下角为(200,200)。
绘制基础图形
绘制矩形
canvas提供三种方式绘制矩形:
fillRect(x, y, width, height) 绘制一个填充的矩形
strokeRect(x, y, width, height) 绘制一个矩形的边框
clearRect(x, y, widh, height) 清除指定的矩形区域,这块区域会变的完全透明。 (可以理解为一块矩形橡皮擦)
参数说明:
x, y :矩形的左上角的坐标。
width, height :绘制的矩形的宽和高。
填充的默认颜色为黑色。
示例:
ctx.fillRect(10, 10, 100, 100)
ctx.clearRect(20, 20, 50, 50)
ctx.strokeRect(120, 10, 20, 20)
绘制路径
使用路径绘制图形一般需要以下步骤:
- 创建路径起始点
- 调用绘制方法去绘制路径
- 把路径封闭(可以不封)
- 一旦路径生成,通过描边或填充来渲染图形
beginPath()//新建一条路径
moveTo(x,y)//路径起始点
lineTo(x,y)//将画笔移动到另一个坐标
closePath()//封闭路径
stroke()//通过线条绘制
fill()//通过填充绘制
//通过路径绘制矩形
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(50, 100);
ctx.lineTo(100, 100);
ctx.lineTo(100, 50);
ctx.closePath();
ctx.fill()
效果如下:
在绘制图形路径时,一定要先调用beginPath()。beginPath()方法将会清空内存中之前的绘制路径信息。如果不这样做,对于绘制单个图形可能没什么影响,但是在绘制多个图形时,将会导致路径绘制或者颜色填充等操作出现任何意料之外的结果。
绘制虚线
ctx.setLineDash(segments)
setLineDash 接收一个数组,按照数组元素组成 (线长,间距) 的形式,循环调用数组中的所有元素作为线长与间距
ctx.save();
ctx.setLineDash([40,30,20]);
ctx.lineWidth = 4;
ctx.strokeStyle = '#0f0';
ctx.beginPath();
ctx.moveTo(10, 100);
ctx.lineTo(400, 100);
ctx.stroke();
ctx.restore();
效果如下:
原理如下:
绘制样式
添加颜色
fillStyle=color //设置图形的填充颜色
strokeStyle=color //设置图形轮廓的颜色
globalAlpha = ‘值’//这个值影响到canva里所有图形的透明度 0为完全透明,1不透明
//tips::个人觉得 rgba() 更好用
注意:
color 可以表示css颜色值的字符串、渐变对象或者图案对象
默认颜色都是黑色
一旦设置的strokeStyle或fillstyle的值,这个将成为默认值,要改变需重新设置fillstyle。
例子:
for (let i = 0; i < 100; i++){
for (let j = 0; j < 100; j++){
for (let k = 0; k < 100; k++) {
ctx.fillStyle = 'rgb(' +
Math.floor(255 - 20 * i) + ',' +
Math.floor(255 - 20 * j) + ',' +
Math.floor(255 - 20 * k) + ')';
ctx.fillRect(j * 10, i * 10, 10, 10);
}
}
}
效果如下:
function randomInt(from, to){
return parseInt(Math.random() * (to - from + 1) + from);
}
for (let i = 0; i < 6; i++){
for (let j = 0; j < 6; j++){
ctx.strokeStyle = `rgb(${randomInt(0, 255)},${randomInt(0, 255)},${randomInt(0, 255)})`;
ctx.strokeRect(j * 50, i * 50, 40, 40);
}
}
效果:
添加样式
lineWidth=value 线宽。只能是正值,默认1
lineCap=type 线条末端样式
butt:以方形结束
round:以圆形结束
square:以方形结束,但增加了一个宽度与线段相同,高度是宽度的一半的矩形区域
lineJoin= type 同一个path内,设定线条与线条接合处的样式
round 通过填充一个额外的,圆心在相连部分末端的扇形,绘制拐角的形状。 圆角的半径是线段的宽度。
bevel 在相连部分的末端填充一个额外的以三角形为底的区域, 每个部分都有各自独立的矩形拐角。
miter (默认) 通过延伸相连部分的外边缘,使其相交于一点,形成一个额外的菱形区域。
设置虚线样式: setLineDash 方法接受一个数组,来指定线段与间隙的交替; lineDashOffset 属性设置起始偏移量。
示例:线条末端
ctx.beginPath();
ctx.moveTo(10, 10);
ctx.lineTo(100, 10);
ctx.lineWidth = 10;
ctx.lineCap = 'butt'
ctx.stroke();
ctx.beginPath();
ctx.moveTo(10, 40);
ctx.lineTo(100, 40);
ctx.lineWidth = 10;
ctx.lineCap = 'round'
ctx.stroke();
ctx.beginPath();
ctx.moveTo(10, 70);
ctx.lineTo(100, 70);
ctx.lineWidth = 10;
ctx.lineCap = 'square'
ctx.stroke();
效果:
示例:线条结合处
let lineJoin = ['round', 'bevel', 'miter'];
ctx.lineWidth = 20;
for (let i = 0; i < lineJoin.length; i++){
ctx.lineJoin = lineJoin[i];
ctx.beginPath();
ctx.moveTo(50, 50 + i * 50);
ctx.lineTo(100, 100 + i * 50);
ctx.lineTo(150, 50 + i * 50);
ctx.lineTo(200, 100 + i * 50);
ctx.lineTo(250, 50 + i * 50);
ctx.stroke();
}
效果:
示例:设置虚线
ctx.setLineDash([20, 5, 10, 5]); // [实线长度, 间隙长度]
ctx.lineDashOffset = 10;
ctx.strokeRect(50, 50, 100, 100);
效果:
绘制文字
canvas 提供了两种方法来渲染文本:
fillText(text, x, y [, maxWidth]) 在指定的(x,y)位置填充指定的文本,绘制的最大宽度是可选的.
strokeText(text, x, y [, maxWidth]) 在指定的(x,y)位置绘制文本边框,绘制的最大宽度是可选的.
let text = 'Hello canvas!'
ctx.font = "20px sans-serif"
ctx.fillText(text, 50, 50)
ctx.strokeText(text, 50, 100)
效果:
文本样式
font = value 当前我们用来绘制文本的样式。这个字符串使用和 CSS font 属性相同的语法. 默认的字体是 10px sans-serif
textAlign = value 文本对齐选项. 可选的值包括: start、end、left、right 、center 默认值start
textBaseline = value 基线对齐选项,可选的值包括: top hanging middle alphabetic ideographic bottom 。默认值是 alphabetic
direction = value 文本方向。可能的值包括: ltr rtl inherit ,默认值inherit
绘制图形
使用drawImage绘制图像
有以下三种使用方式
1.context.drawImage(img,x,y)
2.contenxt.drawImage(img,x,y,width,height)
3.context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height)
第一个参数img可以是一个image()的实例,也可以是一个的dom元素
sx,sy必选,为绘制图像的顶点坐标
swidth,sheight可以选,为图片的缩放大小
var img = new Image(); // 创建img元素
img.onload = function(){
ctx.drawImage(img, 20, 20, 150, 100)
}
img.src = 'https://img.xiaoyulive.top/img/shortcut/096.jpg'; // 设置图片源地址
效果:
如果除了img外有8个参数:
前4个是定义图像源的切片位置和大小
后4个则是定义切片的目标显示位置和大小
原理图:
绘制圆弧
arc
语法:
arc(x, y, r, startAngle, endAngle, anticlockwise)
以(x,y)为圆心,以r为半径,从startAngle弧度开始到endAngle弧度结束,注意:单位为弧度
anticlosewise 是布尔值,true表逆时针;false顺时针。(默认顺时针)
0弧度为在一个笛卡尔坐标系中的x轴正方向
通常使用Math.PI进行弧度运算,一个Math.PI就是180deg
radians=(Math.PI/180)*degrees //角度转换成弧度1
示例
ctx.beginPath();
ctx.arc(50, 50, 40, 0, Math.PI / 2, false);
ctx.stroke();
效果如下:
可以看到从x轴正方向顺时针绘制出了半径为40的 1/4 圆弧。
arcTo
//语法
arcTo(x1, y1, x2, y2, radius)
根据给定的控制点和半径画一段圆弧,最后再以直线连接两个控制点。
示例:
ctx.beginPath();
ctx.moveTo(50, 50);
//参数1、2:控制点1坐标 参数3、4:控制点2坐标 参数5:圆弧半径
ctx.arcTo(200, 50, 200, 200, 50);
ctx.lineTo(200, 200)
ctx.stroke();
效果如下:
原理图:
可以理解为:绘制的弧形是由两条切线所决定。
第 1 条切线:起始点和控制点1决定的直线。
第 2 条切线:控制点1 和控制点2决定的直线。
圆弧半径可以回想一下css中 border-radius 的实现
贝塞尔曲线
贝塞尔曲线 (Bézier curve),又称 贝兹曲线 或 贝济埃曲线 ,是应用于二维图形应用程序的数学曲线。
一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。
原理动画
一次贝塞尔曲线:
二次贝塞尔曲线:
三次贝塞尔曲线:
绘制二次贝塞尔曲线
//语法
quadraticCurveTo(cp1x, cp1y, x, y);
参数说明:
- 参数1和2:控制点坐标
- 参数3和4:结束点坐标
ctx.beginPath();
let bX = 10, bY = 160; // 起始点
ctx.moveTo(bX, bY);
let cX = 40, cY = 100; // 控制点
let toX = 180, toY = 180; // 结束点
// 绘制二次贝塞尔曲线
ctx.quadraticCurveTo(cX, cY, toX, toY);
ctx.stroke();
ctx.beginPath();
ctx.rect(bX, bY, 10, 10);
ctx.rect(cX, cY, 10, 10);
ctx.rect(toX, toY, 10, 10);
ctx.fill();
效果:
为了方便理解,将起始点、控制点、结束点都用实心矩形标出。
绘制三次贝塞尔曲线
//语法
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
参数说明:
- 参数1和2:控制点1的坐标
- 参数3和4:控制点2的坐标
- 参数5和6:结束点的坐标
ctx.beginPath();
let bX = 10, bY = 160; // 起始点
ctx.moveTo(bX, bY);
let cX1 = 20, cY1 = 50; // 控制点1
let cX2 = 60, cY2 = 150; // 控制点2
let toX = 180, toY = 180; // 结束点
// 绘制二次贝塞尔曲线
ctx.bezierCurveTo(cX1, cY1, cX2, cY2, toX, toY);
ctx.stroke();
ctx.beginPath();
ctx.rect(bX, bY, 10, 10);
ctx.rect(cX1, cY1, 10, 10);
ctx.rect(cX2, cY2, 10, 10);
ctx.rect(toX, toY, 10, 10);
ctx.fill();
效果:
渐变
线性渐变
//语法
createLinearGradient(x1, y1, x2, y2);
使用 createLinearGradient(x1, y1, x2, y2) 可以创建一个线性渐变,线性渐变会从第一个点(x1, y1)扩展到第二个点(x2, y2),即定义了渐变的线长与方向。
//语法
addColorStop(position, endColor);
使用 addColorStop 可以添加一个颜色节点
- 第一个参数是0-1之间的一个数值,这个数值指定该颜色进入渐变多长的距离
- 第二个参数是颜色值
示例
let x1 = 0;
let y1 = 0;
let x2 = 100;
let y2 = 0;
let linearGradient1 = ctx.createLinearGradient(x1, y1, x2, y2);
linearGradient1.addColorStop(0, 'rgb(255, 0, 0)');
linearGradient1.addColorStop(0.5, 'rgb(0, 0, 255');
linearGradient1.addColorStop(1, 'rgb(0, 0, 0)');
ctx.fillStyle = linearGradient1
ctx.fillRect(10, 10, 100, 50);
效果:
径向渐变
径向渐变是一种圆形的颜色扩展模式,颜色从圆心位置开始向外辐射。 一个径向渐变于两个圆形来定义。每一个圆都有一个圆心和一条半径。
//语法
ctx.createRadialGradient(x1, y1, r1, x2, y2, r2)
使用 createRadialGradient 可以创建一个径向渐变,(x1, y1, r1)和(x2, y2, r2)分别为两个圆的圆心坐标和半径。
示例:
let x1 = 100; // 第一个圆圆心的X坐标
let y1 = 100; // 第一个圆圆心的Y坐标
let r1 = 30; // 第一个圆的半径
let x2 = 100; // 第二个圆圆心的X坐标
let y2 = 100; // 第二个圆圆心的Y坐标
let r2 = 100; // 第二个圆的半径
let radialGradient1 = ctx.createRadialGradient(x1, y1, r1, x2, y2, r2);
radialGradient1.addColorStop(0, 'rgb(0, 0, 255)');
radialGradient1.addColorStop(1, 'rgb(0, 255, 0)');
ctx.fillStyle = radialGradient1
ctx.fillRect(10, 10, 200, 200);
效果:
addColorStop 的用法同线性渐变。
如果两个圆形的圆心位置相同,那么径向渐变将是一个完整的圆形。如果两个圆的圆心位置不相同,那么径向渐变看起来就像是一个探照灯发出的光线。
示例:
let x1 = 100; // 第一个圆圆心的X坐标
let y1 = 100; // 第一个圆圆心的Y坐标
let r1 = 30; // 第一个圆的半径
let x2 = 150; // 第二个圆圆心的X坐标
let y2 = 120; // 第二个圆圆心的Y坐标
let r2 = 100; // 第二个圆的半径
let radialGradient1 = ctx.createRadialGradient(x1, y1, r1, x2, y2, r2);
radialGradient1.addColorStop(0, 'rgb(0, 0, 255)');
radialGradient1.addColorStop(1, 'rgb(0, 255, 0)');
ctx.fillStyle = radialGradient1
ctx.fillRect(10, 10, 200, 200);
效果: