文章目录
H5 canvas学习笔记
简介
HTML有两个主要的2D图形技术:Canvas和SVG
canvas | svg |
---|---|
2D | 2D |
基于JavaScript动态生成 | 使用XML静态描述 |
不会保留绘制的图形的信息,基于像素点绘制位图,放大会会失真 | 内存中保留绘制的图形的信息,用html标签描绘形状,矢量图放大不会失真 |
canvas无法对已经绘制的图像进行修改、操作 如果发生修改,需要重绘 | svg中每个图形又对应真实的dom节点、svg可以获取到标签进行操作 |
H5 Canvas就是使用JavaScript
来操作Canvas
元素(画布)的技术。
①获取Canvas
对象(画布)
②获取渲染上下文环境对象context
(画笔)
③开始绘制图形
所有canvas图形操作的属性和方法都是基于context对象
Canvas画布/画笔
坐标系是二维x/y
轴,像素为最小单元(栅格),每个像素具有RGBA数据,像素数量等于画布长*宽
- canvas画布的大小
- 可以是行间样式
- 可以通过
canvas.width/canvas.height
设置和获取画布的大小
- canvas画笔
- 2d画笔
canvas.getContext('2d')
- 3d画笔
canvas.getContext('webgl')
或者canvas.getContext('webgl2')
- 2d画笔
<body>
<canvas id="canvas">不支持时的提示文字</canvas>
</body>
<script>
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
</script>
1.Canvas标签中的文字是在不支持Canvas标签的浏览器中使用的,因为支持Canvas标签的浏览器会忽略容器中包含的内容正常渲染Canvas标签,而不支持Canvas标签的浏览器则相反,浏览器会忽略容器而显示其中的内容。
2.Canvas标签的默认大小为:300 x 150 (像素)
Canvas路径
在Canvas中,除了矩形,其他所有的Canvas基本图形(适用范围)都是以路径为基础。
方法 | 说明 |
---|---|
beginPath() | 开始一条新路径 |
closePath() | 封闭当前路径 |
isPointInPath(x,y) | 判断某一个点(x,y)是否存在当前路径内 |
beginPath()
:新建一条路径,判断是否同一路径的标准是是否使用了beginPath方法。closePath()
:闭合路径,连接起点与终点,封闭当前路径:closePath是指将同一路径的起点和终点连接起来,使其成为一个封闭图形。isPointInPath(x,y)
:不支持Canvas自带的两个方法strokeRect()
和fillRect()
,只能用rect()
Canvas状态
Canvas基于"状态"来绘制图形,每一次绘制(stroke或者fill),Canvas会检测整个程序定义的所有状态(strokeStyle、fillStyle、lineWidth等)。
①如果开启了一个新路径,则不同路径使用不同的值
②如果没有开启新路径,后面的值会覆盖前面的值
绘图样式必须先于矩形绘制方法之前,把相应参数设置好,canvas再根据已设置的参数来画图。
状态属性
状态包括:填充效果、描边效果、线条效果、文本效果、阴影效果和全局属性
- 填充效果:fillStyle
- 描边效果:strokeStyle
- 线条效果:lineCap、lineJoin、lineWidth、miterLimit
- 文本效果:font、textAlign、textBaseLine
- 阴影效果:shawBlu、shadowColor、shadowOffsetX、shadowOffsetY
- 全局属性:globalAlpha、globalCompositeOperation
globalAlpha
属性定义Canvas环境的透明度,默认为1.0,取值范围为0.0~1.0
globalCompositeOperation
属性改变图形交叉显示的顺序
属性值 | 说明 | 符号表示 |
---|---|---|
source-over | 默认值,新图覆盖旧图 | 新图B,旧图A |
destination-over | 旧图A覆盖新图B | |
copy | 只显示新图,旧图透明 | |
darker | 两种图形都显示,在重叠部分颜色由两种图形的颜色值相减后形成 | |
light | 两种图形都显示,在重叠部分颜色由两种图形的颜色值相加后形成 | |
destination-atop | 只显示新图与旧图的重叠部分以及新图的其余部分 | A∩BUB |
source-atop | 只显示新图与旧图的重叠部分以及旧图的其余部分 | A∩BUA |
destination-in | 只显示旧图中与新图的重叠部分 | |
source-in | 只显示新图中与旧图重叠的部分 | |
destination-out | 只显示旧图中与新图不重叠的部分 | |
source-out | 只显示新图中与旧图不重叠的部分 | |
xor | 两图都绘制,重叠部分透明 |
状态的保存和恢复
- 保存当前状态sava()
- 恢复之前的保存状态restore()
Canvas的状态是存储在栈中的,每次调用save()方法后,当前的状态都会被推送到栈中保存起来。调用restore()方法,栈顶的状态被pop出来。
const ctx = canvas.getContext('2d');
ctx.fillStyle = "#cccccc";
ctx.fillRect(10, 10, 300, 100);
ctx.save(); // 保存状态
ctx.fillStyle = "#ee7034";
ctx.fillRect(10, 150, 300, 100);
ctx.restore(); // 还原到上次保存的状态
ctx.fillRect(10, 300, 300, 100);
基本图形stroke/fill
strokeStyle属性
:设置边框样式stroke()
:通过线条来绘制图形轮廓,执行描边动作fillStyle属性
:设置填充的颜色fill()
:通过填充路径的内容区域生成实心的图形。如果路径未关闭, fill() 方法会从路径结束点到开始点之间添加一条线,以关闭该路径,然后填充该路径。
直线moveTo()/lineTo()
context对象的moveTo(x1,y1)
:将画笔移动到(x1,y1)
位置,表示直线的起点.。
context对象的lineTo(x2,y2)
:使用画笔从起点(x1,y1)
开始画直线,一直画到终点(x2,y2)
。
<body>
<canvas id="canvas"></canvas>
</body>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.moveTo(100,100); //
ctx.lineTo(100,200); //
ctx.stroke();//开始绘画
</script>
画多条直线
lineTo方法可以重复调用,默认是以上一次的终点位置作为本次的起点位置。
矩形trokeRect()/fillRect()/clearRect()/react()
矩形也可以使用四条直线来画,不过太复杂了。
Canvas API 给提供了三种绘制矩形的方法。
trokeRect(x, y, width, height)
绘制一个矩形的边框fillRect(x, y, width, height)
绘制一个填充的矩形clearRect(x, y, width, height)
清除指定矩形区域,让清除部分完全透明。
trokeRect(x, y, width, height):绘制矩形边框- x和y 是矩形左上角的起点坐标
- width和height 是矩形的宽高
fillRect(x, y, width, height) 绘制一个填充的矩形
- x和y 是矩形左上角的起点坐标
- width和height 是矩形的宽高。
clearRect(x, y, width, height) 清除指定矩形区域,让清除部分完全透明
- x和y 是矩形左上角的起点坐标
- width和height 是矩形的宽高
rect(x,y,width,height) 绘制一个矩形,需要调用stroke()
或fill()
方法
绘图样式属性的取值
- 颜色值
- 十六进制颜色值
#FF0000
- 颜色关键字
red
- rgb颜色
rgb(255,0,0)
- rgba颜色值
rgba(255,0,0,0.8)
- 十六进制颜色值
- 渐变色
- 图案
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillRect(100, 100, 200, 100);
ctx.strokeRect(300, 300, 200, 100)
ctx.clearRect(100, 100, 100, 70);
</script>
圆弧和圆arc()
arc(x, y, radius, startAngle, endAngle, anticlockwise)
- x和y为圆心的坐标,radius为半径
- startAngle为圆弧或圆的开始位置(弧度),endAngle为圆弧或圆的结束位置(弧度)
- anticlockwise是绘制的方向,默认为false(顺时针方向)
- 需要结合stroke()函数
在画弧的时候,arc()函数中角的单位是弧度而不是角度。
角度换算为弧度的表达式为:弧度=(Math.PI/180)*角度
。
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 绘制一段圆弧
ctx.arc(60, 60, 50, 0, Math.PI, false);
ctx.stroke();
// 绘制一个圆弧
ctx.arc(300, 300, 50, 0, Math.PI*2, false);
ctx.stroke();
</script>
关闭路径其实并不是必须的,对于新路径其实每次都开启新路径就ok。
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 绘制一段圆弧
ctx.beginPath() // 开启路径
ctx.arc(60, 60, 50, 0, Math.PI, false);
ctx.stroke();
// 绘制一个圆弧
ctx.beginPath() // 开启路径
ctx.arc(300, 300, 50, 0, Math.PI*2, false);
ctx.stroke();
</script>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.beginPath()
ctx.arc(60, 60, 50, 0, Math.PI, false);
ctx.strokeStyle="pink";
ctx.closePath()
ctx.stroke();
</script>
椭圆ellipse()
ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise)
- x、y:椭圆的圆心位置
- radiusX、radiusY:x轴和y轴的半径
- rotation:椭圆的旋转角度,以弧度表示
- startAngle:开始绘制点
- endAngle:结束绘制点
- anticlockwise:绘制的方向,默认顺时针,可选参数。
贝塞尔曲线
贝塞尔曲线一般用来绘制复杂有规律的图形,通常被用于画曲线。
常见的贝塞尔曲线:起点一般由moveTo()
或lineTo()
提供
- 二次贝塞尔
quadraticCurveTo(cx,cy,x,y)
- (cx,cy)表示控制点的坐标
- (x,y)表示结束点的坐标
- 三次贝塞尔
bezierCurveTo(cx1,cy1,cx2,cy2,x,y)
- (cx1,cy1)表示控制点1
- (cx2,cy2)表示控制点2
- 结束点
可以通过二次/三次贝塞尔曲线调试工具查看效果
二次贝塞尔案例
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.moveTo(50, 50);//起点
ctx.quadraticCurveTo(200, 200, 350, 50);//控制点
ctx.stroke();//结束点
三次贝塞尔案例
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.moveTo(50, 200);
ctx.bezierCurveTo(150, 50, 250, 350, 350, 200);
ctx.stroke();
线条的操作
lineWidth
设置当前绘线的粗细,属性值为正数,默认值为1,单位为pxlineCap
设置线段端点显示的样子。- butt:默认值,默认无处理
- round:每条线的开始处和结尾处都增加一个半圆,半圆的直径为线宽
- square:每条线的开始处和结尾处都增加一个长方形,长为线宽的一半,高为线宽
lineJoin
设置两条线条交接处样式miter
:默认是尖角round
:圆角,圆角所在圆的直径等于线宽bevel
:斜角,斜角所在正方形的对角线长等于线宽
setLineDash(array)
定义线条的虚实样式- [虚线长度px,空白长度px,…(重复)]
getLineDash()
返回当前虚线设置的样式lineDashOffset
设置虚线样式的起始偏移量
在同一个路径中,状态会被一直使用。所以如果需要定义一个新的线条样式,使用beginPath()方法开启一个新路径。
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// lineJoin 值为 miter
ctx.beginPath()
ctx.lineWidth = 40;
ctx.lineJoin='miter'
ctx.moveTo(50, 20);
ctx.lineTo(100, 60);
ctx.lineTo(150, 20);
ctx.lineTo(200, 60);
ctx.lineTo(250, 20);
ctx.stroke();
ctx.closePath();
// lineJoin 值为 round
ctx.beginPath()
ctx.lineWidth = 40;
ctx.lineJoin='round'
ctx.moveTo(50, 100);
ctx.lineTo(100, 140);
ctx.lineTo(150, 100);
ctx.lineTo(200, 140);
ctx.lineTo(250, 100);
ctx.stroke();
ctx.closePath();
// lineJoin 值为 bevel
ctx.beginPath()
ctx.lineWidth = 40;
ctx.lineJoin='bevel'
ctx.moveTo(50, 180);
ctx.lineTo(100, 220);
ctx.lineTo(150, 180);
ctx.lineTo(200, 220);
ctx.lineTo(250, 180);
ctx.stroke();
ctx.closePath();
渐变
线性渐变
createLinearGradient(x1, y1, x2, y2)
创建LinearGradient渐变对象,参数分别为渐变的起点坐标和终点坐标。- 渐变对象的实例
addColorStop(offset, color)
添加渐变的颜色,color为颜色,offset表示渐变位置的偏移量(百分比:0~1)。第一次表示渐变的开始颜色,第二次调用表示结束,第三次以上一次结束为起点进行渐变,依次类推。 - 将LinearGradient渐变对象赋值给
fillStyle
属性 - 进行绘图
fill()
、fillRect()
图形渐变、fillText()
文字渐变
gradient1.addColorStop(0, "#00ff00");
gradient1.addColorStop(1, "#ff0000");
ctx.fillStyle = gradient1
ctx.fillRect(0,0,200,200)
径向渐变
ctx.createRadialGradient(x0, y0, r0, x1, y1, r1)
参数分别为开始圆的坐标(x0,y0)
和半径r0
以及结束圆的坐标(x1,y1)
和半径r1
。
图像
Canvas中想绘制图案效果,需要用createPattern(image, type)
方法来实现
- Image 参数可以是一个 Image 对象,也可以是一个 canvas 对象
- Type 为图案绘制的类型,可用的类型分别有:repeat,repeat-x,repeat-y 和 no-repeat。
// 获取绘图上下文
const ctx = canvas.getContext('2d');
// 创建一个 image对象
const img = new Image();
img.src = "./image.png";
img.onload = function() {
// 图片加载完以后
// 创建图案
const ptrn = ctx.createPattern(img, 'no-repeat');
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, 500, 500);
}
绘制文本
canvas 中提供了两种方法来渲染文本①描边②填充
ctx.strokeText(text, x, y, maxWidth)
- text绘制的文案
- x、y文本的起始位置
- maxWidth可选参数,最大宽度。当文案大于最大宽度时不是裁剪或者换行,而是缩小字体。
ctx.fillText(text, x, y, maxWidth)
- text绘制的文案
- x、y文本的起始位置
- maxWidth可选参数,最大宽度。当文案大于最大宽度时不是裁剪或者换行,而是缩小字体。
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.font = "50px serif"; // 设置文案大小和字体
ctx.strokeText("Canvas", 100, 100);
ctx.fillText("Canvas", 100, 100);
文本样式
- font属性:绘制文案大小和字体,默认”10px sans-serif“
- textAlign属性:文本对齐的方式。可选值为:left、right、center、start(默认)和end。
- direction属性:文本的方向。可选值为:ltr(从左向右)、rtl(从右向左)、inherit(根据情况继承 Canvas元素或者 Document ,默认)
- textBaseline属性:基线对齐选项,决定文字垂直方向的对齐方式。可选值为:top、hanging、middle、alphabetic(默认)、ideographic和bottom。
direction 属性会对 textAlign 属性产生影响。如果 direction 属性设置为 ltr,则textAlign属性的 left 和 start 的效果相同,right 和 end 的效果相同,如果 direction 属性设置为 rtl,则 textAlign属性的 left 和 end 的效果相同,right 和 start 的效果相同。
阴影
- shadowOffsetX、shadowOffsetY设定阴影在 X 和 Y 轴的延伸距离,不受变换矩阵影响。负值表示阴影会往上或左延伸,正值则表示会往下或右延伸,它们默认都为 0。
- shadowBlur 用于设定阴影的模糊程度,其数值并不跟像素数量挂钩,不受变换矩阵的影响,默认为 0。
- shadowColor 是标准的 CSS 颜色值,用于设定阴影颜色效果,默认是全透明的黑色。
图片操作
drawImage()
drawImage
可以将图片导入Canvas进行平铺、切割、像素处理等操作。
必须等图片载入完成后开始绘制
drawImage()
的用法有三种,根据不同的传参实现不同的功能。
- image:绘制到上下文(页面)的图片,可以是页面中的img元素,也可以是JavaScript创建的image对象。
- sx、sy(source):裁剪框的左上角X轴坐标和Y轴坐标
- sWidth、sHeight:裁剪框的宽度和高度。
- dx、dy(destination):绘制到上下文(页面)的元素,在上下文中(页面)左上角的X轴坐标和Y轴坐标。
- dWidth、dHeight:绘制到上下文(页面)的元素,在上下文(页面)中绘制的宽度和高度。如果不说明,在绘制时image宽度和高度不会缩放。
绘制
drawImage(image,dx,dy)
:单纯的绘制功能,可以绘制图片、视频和别的Canvas对象等。
//从javaScript动态创建
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const img = new Image(); //创建image对象
img.src = '';
//图片载入完成后开始绘制
img.onload = function(){
ctx.drawImage(img, 0, 0);
}
//来自img元素,优点在于JavaScript执行时图片已经加载完成,一般会使用css隐藏图片元素,可以避免在DOM中再显示一次图片
缩放
drawImage(image, dx, dy, dWidth, dHeight)
:dWidth和dHeight可以控制绘制元素的大小。
裁剪
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
可以裁剪图片后绘制
裁剪 clip()
clip()
将当前正在构建的路径转换为当前的裁剪路径,不支持Canvas自带的两个方法strokeRect()
和fillRect()
,只能用rect()
。
默认情况下,canvas 有一个与它自身一样大的裁剪路径(也就是没有裁剪效果)。现在可以通过clip()来创建一个裁剪路劲(也就有裁剪效果了)。裁剪的作用是遮罩,用来隐藏不需要的部分,所有在路径以外的部分都不会在 canvas 上绘制出来。
裁剪路径不会在 canvas 上绘制东西,永远不受新图形的影响。超过剪切区域的部分不会被显示。
案例
1.绘制基本图形作为裁剪路径
2.使用clip()
方法
3.绘制图片
//1.绘制基本图片,用于裁剪
ctx.arc(200,200,50,0,360*Math.PI/180,true);
ctx.stroke();
//2.创建裁剪路径
ctx.clip()
//3.绘制图片
const img = new Image(); //创建image对象
img.src = '';
img.onload = function(){
ctx.drawImage(img, 0, 0);
}
像素
getImageData()获取一张图的像素
CanvasRenderingContext2D.getImageData(x,y,width.height)
返回一个 ImageData
对象,用来描述 canvas
区域隐含的像素数据。
这个区域通过矩形表示,x、y为左上角的横纵坐标,width和height表示所选区域的宽度和高度。
const imgData = ctx.getImageData(x, y, width, height);
ImageData
对象会有三个属性
height
:使用像素描述ImageData
的实际高度,这个值等于getImageData()
方法中的参数height
width
:使用像素描述ImageData
的实际高度,这个值等于 getImageData() 方法中的参数width
data
:一个一维数组,保存像素数据,每4个数(R红G绿B蓝A透明度)存储1个像素的RGBA颜色值。ImageData.data.length
表示一张图的像素总和。
说明getImageData()
方法不允许操作此域名外的图片/视频资源- 可以将图片转换成base64编码,直接把base64编码赋值给图片的src属性就可以简单的解决这个问题了。
putImageData()设置一张图的像素
putImageData(image,x,y)
:image表示重新绘制的图形ImageData
对象,x,y分别表示重新绘制的图形左上角的横坐标、纵坐标。
使用场景:通过getImageData
获取到imageData
后,然后进行处理,再通过putImageData
绘制到canvas上,