Canvas API 提供了一个通过 JavaScript 和 HTML 的 元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。
元素
<canvas id="tutorial" width="150" height="150">canvas>
function draw() {
var canvas = document.getElementById("canvas");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect(10, 10, 55, 50);
ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
ctx.fillRect(30, 30, 55, 50);
}
}
注意:这里不要使用css设置canvas的宽高,不然会导致图像是扭曲的。
canvas的坐标系不同于数学中的坐标系,是以左上角为原点的坐标系。
<canvas
id="c"
width="300"
height="200"
style="border: 1px solid #ccc;"
>canvas>
<script>
// 2、获取 canvas 对象
const cnv = document.getElementById('c')
// 3、获取 canvas 上下文环境对象
const cxt = cnv.getContext('2d')
// 4、绘制图形
cxt.moveTo(100, 100) // 起点坐标 (x, y)
cxt.lineTo(200, 100) // 终点坐标 (x, y)
cxt.stroke() // 将起点和终点连接起来
script>
fillRect(x, y, width, height)
绘制一个填充的矩形
strokeRect(x, y, width, height)
绘制一个矩形的边框
clearRect(x, y, width, height)
清除指定矩形区域,让清除部分完全透明。
或者 rect(x, y, width, height) 配合fill()和stroke() 使用
arc(x, y, radius, startAngle, endAngle, anticlockwise)
这里是引用arc() 函数中表示角的单位是弧度,不是角度。角度与弧度的 js 表达式:
弧度=(Math.PI/180)*角度
arcTo(cx, cy, x2, y2, radius)
根据给定的控制点和半径画一段圆弧,再以直线连接两个控制点。
// 绘制一个聊天框
const cnv = document.getElementById('c')
const ctx = cnv.getContext('2d');
ctx.moveTo(200,300)
ctx.quadraticCurveTo(150,300,150,200);
ctx.quadraticCurveTo(150,100,300,100);
ctx.quadraticCurveTo(450,100,450,200);
ctx.quadraticCurveTo(450,300,250,300);
ctx.quadraticCurveTo(250,350,150,350);
ctx.quadraticCurveTo(250,350,200,300);
ctx.stroke()
// 绘制爱心
const cnv = document.getElementById('c')
const ctx = cnv.getContext('2d');
ctx.moveTo(300,200)
ctx.bezierCurveTo(350,150,400,200,300,250)
ctx.bezierCurveTo(200,200,250,150,300,200)
ctx.closePath()
ctx.stroke()
保存一个路径对象,可以重复使用
const cnv = document.getElementById('c')
const ctx = cnv.getContext('2d');
var heartPath = new Path2D();
heartPath.moveTo(300,200)
heartPath.bezierCurveTo(350,150,400,200,300,250)
heartPath.bezierCurveTo(200,200,250,150,300,200)
ctx.stroke(heartPath)
ctx.fill(heartPath)
strokeStyle = ‘red’
全局透明度: ctx.globalAlpha = 0.5
createLinearGradient(x0: number, y0: number, x1: number, y1: number)
QQ录屏20240614093835
const cnv = document.getElementById('c')
const ctx = cnv.getContext('2d')
let index = 0
function render() {
ctx.clearRect(0, 0, 600, 400)
index += 0.01
if (index >= 1) {
index = 0
}
let linearGradient = ctx.createLinearGradient(100, 200, 400, 500)
linearGradient.addColorStop(0, 'red')
linearGradient.addColorStop(index, '#ffcccc')
linearGradient.addColorStop(1, 'blue')
ctx.fillStyle = linearGradient
ctx.fillRect(100, 200, 300, 300)
requestAnimationFrame(render)
}
requestAnimationFrame(render)
扩充:如何使用requestAnimationFrame
window.requestAnimationFrame() 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
requestAnimationFrame的出现解决了这个问题。它使用浏览器的刷新率作为参考,确保动画帧的更新在每一帧之间的间隔是最佳的,从而实现更加流畅和自然的动画效果。
function animate() {
// 执行动画逻辑
timer=requestAnimationFrame(animate);
}
// 启动动画
let timer=requestAnimationFrame(animate);
//取消动画
createRadialGradient(x0: number, y0: number, r0: number, x1: number, y1: number, r1: number)
// 案例实现一个看似3d的球体(有高光)
const cnv = document.getElementById('c')
const ctx = cnv.getContext('2d')
let radialGradient = ctx.createRadialGradient(250, 150, 10, 300, 200, 100)
radialGradient.addColorStop(0, '#e3e5ff')
radialGradient.addColorStop(1, 'blue')
ctx.fillStyle = radialGradient
ctx.arc(300, 200, 100, 0, (Math.PI / 180) * 360)
ctx.fill()
createConicGradient(startAngle: number, x: number, y: number)
let conicGradient = ctx.createConicGradient(0,300,200);
conicGradient.addColorStop(0,'red');
conicGradient.addColorStop(0.5,'yellow');
conicGradient.addColorStop(1,'blue');
const cnv = document.getElementById('c')
const ctx = cnv.getContext('2d')
var img = new Image();
img.src= '../image/fs.png';
img.onload = function () {
var pattern = ctx.createPattern(img,'repeat-y');
ctx.fillStyle = pattern;
ctx.fillRect(0,0,600,400)
}
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 2;
ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
ctx.font = "20px Times New Roman";
ctx.fillStyle = "Black";
ctx.fillText("Sample String", 5, 30);
}
属性和方法 | 说明 | 可设置的类型 |
---|---|---|
lineWidth = value | 设置线条宽度。 | |
lineCap = type | 设置线条末端样式。 | butt,round 和 square。默认是 butt。 |
lineJoin = type | 设定线条与线条间接合处的样式。 | round、bevel 和 miter。默认是 miter。 |
miterLimit = value | 限制当两条线相交时交接处最大长度;所谓交接处长度(斜接长度)是指线条交接处内角顶点到外角顶点的长度。 | |
getLineDash() | 返回一个包含当前虚线样式,长度为非负偶数的数组。 | |
setLineDash(segments) | 设置当前虚线样式,方法接受一个数组,来指定线段与间隙的交替。 | ctx.setLineDash([4, 2]); |
lineDashOffset = value | 设置虚线样式的起始偏移量。 |
fillText(text, x, y [, maxWidth])
strokeText(text, x, y [, maxWidth])
function draw() {
var ctx = document.getElementById("canvas").getContext("2d");
ctx.font = "48px serif";
ctx.fillText("Hello world", 10, 50);
}
font = value
当前我们用来绘制文本的样式。这个字符串使用和 CSS font 属性相同的语法。默认的字体是 10px sans-serif。
textAlign = value
文本对齐选项。可选的值包括: start
,end
, left
, right
or center
. 默认值是 start。
textBaseline = value
基线对齐选项。可选的值包括:top
, hanging
,middle
, alphabetic
, ideographic
, bottom
。默认值是 alphabetic。
direction = value
文本方向。可能的值包括:ltr
, rtl
, inherit
。默认值是 inherit。
measureText()
drawImage(image, x, y)
drawImage(image, x, y, width, height)
drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)
const cnv = document.getElementById('c')
const ctx = cnv.getContext('2d')
const image = new Image()
image.src = './image/flower.png'
image.width = 20
image.height = 10
image.onload = () => {
// drawImage(image, dx, dy, dw, dh)
ctx.drawImage(image, 30, 30,300,200)
// drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
// ctx.drawImage(image, 0, 0, 200, 200, 100, 100, 100, 100)
}
ctx.getImageData(sx, sy, sw, sh);
+=4
。const context = document.getElementById('c')
const ctx = context.getContext('2d')
const img = new Image() // 创建图片对象
img.src = './image/flower.png' // 加载本地图片
// 图片加载完成后在执行其他操作
img.onload = () => {
// 渲染图片
ctx.drawImage(img, 0, 0)
// 获取图片信息
const imageData = ctx.getImageData(0, 0, img.width, img.height)
console.log('imageData: ', imageData)
for (let i = 0; i < imageData.data.length; i += 4) {
// 添加上透明度
// imageData.data[i + 3] = imageData.data[i + 3] * 0.5
// 变成黑白的图片
let avg = (imageData.data[i]+imageData.data[i+1]+imageData.data[i+2])/3
imageData.data[i] = avg;
imageData.data[i+1] = avg;
imageData.data[i+2] = avg;
}
ctx.putImageData(imageData, 0, 0,200,200,200,200)
}
save()
保存画布 (canvas) 的所有状态
restore()
save 和 restore 方法是用来保存和恢复 canvas 状态的,都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。
const cnv = document.getElementById('c')
const ctx = cnv.getContext('2d')
ctx.fillStyle = 'red'
ctx.fillRect(0, 0, 100, 100)
ctx.save()
ctx.fillStyle = 'blue'
ctx.fillRect(100, 100, 100, 100)
ctx.save()
ctx.fillStyle = 'yellow'
ctx.fillRect(200, 200, 100, 100)
ctx.save()
ctx.fillStyle = 'green'
ctx.fillRect(300, 300, 100, 100)
ctx.restore()
ctx.fillRect(400, 400, 100, 100)
最后保存了 黄色,restore之后再绘制,就能画出黄色的矩形。
平移 translate(x, y)
旋转 rotate(angle)
旋转的中心点始终是 canvas 的原点,如果要改变它,我们需要用到 translate方法。
缩放 scale(x, y)
变形 transform(a, b, c, d, e, f)
这个方法是将当前的变形矩阵乘上一个基于自身参数的矩阵,如下面的矩阵所示:
setTransform()
transform VS 而setTransform
transform() 每次执行都会参考上一次变换后的结果,而setTransform() 每次调用都会基于最原始是状态进行变换。
globalCompositeOperation = type
这个属性设定了在画新图形时采用的遮盖策略,其值是一个标识 12 种遮盖方式的字符串。
clip()
将当前正在构建的路径转换为当前的裁剪路径。