前言
前端Canvas开发应该属于图形开发技术了,不少前端小伙伴在Canvas开发上都有些困难。
其实我想说,会Canvas开发的更难,实现些功能想破头,难呀!整理下之前写Canvas用到的一些基础操作,方便后面查阅。
基础概念
Canvas元素
和其他普通元素一样,可以直接插入文档,也可以通过JavaScript
创建欻
<canvas id="canvas" width="500" height="400">
Sorry, canvas tag is not supported.
</canvas>
const canvas = document.createElement('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.body.insertBefore(canvas, document.body.firstChild);
画布
<canvas>
提供了绘制2D
的图形接口和上下文。 了解画布的概念有助于解决类似图片模糊的问题,处理精度。
canvas元素大小
直接给<canvas>
元素设置样式只会改变<canvas>
在DOM里面的大小,而不会改变像素点的多少。
document.getElemntById("canvas").style.width=300
document.getElemntById("canvas").style.height=400
使用这种方式来进行修改,最直观的感受就是会导致canvas里面的内容拉伸变形。
const canvas = document.getElemntById('canvas');
// 既可以读取也可以修改该元素的大小
canvas.style.width = 100;
canvas.style.height = 100;
canvas画布大小
即<canvas>
绘图画布的大小。当他的style
大小固定,画布里面的尺寸越大,精度越高。举例来讲,比如你展示一幅3440x1660
的图片在300x400
的<canvas>
元素上时,出现模糊的时,提高画布的大小则可以改善模糊的问题。
<canvas id="canvas" width="300" height="500"></canvas>
const canvas = document.getElementById("canvas")
// 当然你也可以直接在这儿赋值进行改变,应该是这样不行用下面的方法
console.log(canvas.width); // 300
console.log(canvas.height); // 500
通过 <canvas width="500" height="300" />
在元素上设置width
和height
时,他同时设置了该元素的元素大小
和画布大小
document.getElemntById("canvas").setAttribute("width", 300)
document.getElemntById("canvas").setAttribute("height", 500)
上下文
获取
const canvas = document.getElementById('canvasid');
const context = canvas.getContext('2d');
基础操作
直线
// 填充三角形
ctx.beginPath();
ctx.moveTo(25, 25);
ctx.lineTo(105, 25);
ctx.lineTo(25, 105);
ctx.fill(); // 自动闭合路径
// 描边三角形
ctx.beginPath();
ctx.moveTo(125, 25);
ctx.lineTo(125, 105);
ctx.lineTo(205, 25);
ctx.closePath(); // 手动闭合路径
ctx.stroke();
圆和弧线 参考
arc
arc(x, y, radius, startAngle, endAngle, anticlockwise);
x
圆弧中心(圆心)的x
轴坐标y
圆弧中心(圆心)的y轴坐标r
圆弧半径startAngle
圆弧的起始点,x
轴方向开始计算,单位以弧度表示endAngle
圆弧的重点,单位以弧度表示anticlockwise
可选Boolean
值,如果为true
,逆时针绘制圆弧,反之顺时针绘制。
示例
HTML
<canvas id="canvas"></canvas>
JavaScript
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(75, 75, 50, 0, 2 * Math.PI);
ctx.stroke();
其中到startAngle
为0 ,endAngle
为2 * Math.PI
时,圆弧封闭变成一个圆形。
不同形状展示
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// Draw shapes
for (i=0;i<4;i++){
for(j=0;j<3;j++){
ctx.beginPath();
var x = 25+j*50; // x coordinate
var y = 25+i*50; // y coordinate
var radius = 20; // Arc radius
var startAngle = 0; // Starting point on circle
var endAngle = Math.PI+(Math.PI*j)/2; // End point on circle
var clockwise = i%2==0 ? false : true; // clockwise or anticlockwise
ctx.arc(x,y,radius,startAngle,endAngle, clockwise);
if (i>1){
ctx.fill();
} else {
ctx.stroke();
}
}
}
arcTo
arcTo(x1, y1, x2, y2, radius);
x1
第一个控制点的 x 轴坐标。y1
第一个控制点的 y 轴坐标。x2
第二个控制点的 x 轴坐标。y2
第二个控制点的 y 轴坐标。
示例
这是一段绘制圆弧的简单的代码片段。 基础点是蓝色的,两个控制点是红色的。
假设两个红色方块儿之间的虚线是直线B,红色方块儿和蓝色方块儿的直线为A。
- 直线A与直线B是
arcTo
所画圆的切线 - 半径为
radius
- 靠下的红色方块儿为
(x1,y1)
坐标,靠上的红色方块儿为(x2,y2)
的坐标 - 蓝色方块儿坐标由
(x1,y2)
所确定。
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.setLineDash([])
ctx.beginPath();
ctx.moveTo(150, 20);
ctx.arcTo(150,100,50,20,30);
ctx.stroke();
ctx.fillStyle = 'blue';
// base point
ctx.fillRect(150, 20, 10, 10);
ctx.fillStyle = 'red';
// control point one
ctx.fillRect(150, 100, 10, 10);
// control point two
ctx.fillRect(50, 20, 10, 10);
//
ctx.setLineDash([5,5])
ctx.moveTo(150, 20);
ctx.lineTo(150,100);
ctx.lineTo(50, 20);
ctx.stroke();
ctx.beginPath();
ctx.arc(120,38,30,0,2*Math.PI);
ctx.stroke();
矩形
void ctx.rect(x, y, width, height);
示例
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.rect(10, 10, 100, 100);
ctx.fill();
绘制带边框的矩形
strokeRect(x, y, width, height);
绘制填充矩形
fillRect(x, y, width, height);
清理矩形区域
clearRect(x, y, width, height);
画布也是矩形区域,所以,也可以用来清理画布。
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
图像
基础概念
图像加载
window.onload = () => {
let canvas = document.getElementById('demo')
let ctx = canvas.getContext('2d')
let image = new Image()
image.src = './imgs/otome1.png'
image.onload = () => {
ctx.fillStyle = ctx.createPattern(image, 'repeat') // 性质相当于css中的background-image
ctx.fillRect(0, 0, 1000, 550) // 最终渲染的位置
}
}
一般是通过Image
标签进行加载,网络链接也可以通过一样的方式进行加载。 当然,也可以加载svg的图像,不过最终被转换后的图像都是8bit深度的图像。即 0~255
深度的图像
对于16bit
深度的图像来讲,虽然可以加载,但是在里面的表示仍然是8bit的内容。
drawImage方法
void ctx.drawImage(image, dx, dy);
void ctx.drawImage(image, dx, dy, dWidth, dHeight);
void ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
- sx 可选:需要绘制到目标上下文中的,
image
的矩形(裁剪)选择框的左上角 X 轴坐标。 - sy 可选:需要绘制到目标上下文中的,
image
的矩形(裁剪)选择框的左上角 Y 轴坐标。 - sWidth 可选: 需要绘制到目标上下文中的,
image
的矩形(裁剪)选择框的宽度。如果不说明,整个矩形(裁剪)从坐标的sx
和sy
开始,到image
的右下角结束。 - sHeight 可选:需要绘制到目标上下文中的,
image
的矩形(裁剪)选择框的高度。 - 其他
示例
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var image = document.getElementById('source');
ctx.drawImage(image, 33, 71, 104, 124, 21, 20, 87, 104);
实战:弹力小球
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>弹力小球</title>
</head>
<body>
<canvas id="canvas" style="border: 1px solid #aaa; display: block; margin: 50px auto;"></canvas>
</body>
</html>
JavaScript
var ball = { x: 512, y: 100, r: 20, g: 2, vx: -4, vy: 0, color: "#005588"}
var peg = { x: 100, y: 50, r: 10, color: "#eeeeee" }
window.onload = function () {
var canvas = document.getElementById("canvas");
canvas.width = 1024;
canvas.height = 768;
var context = canvas.getContext("2d")
setInterval(function () {
render(context);
update(context);
}, 50)
}
function drawPeg(ctx) {
ctx.beginPath();
ctx.fillStyle = peg.color;
ctx.arc(peg.x, peg.y, peg.r, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
}
function update(context) {
ball.x += ball.vx;
ball.y += ball.vy;
ball.vy += ball.g;
if (ball.y > context.canvas.height) {
ball.vy = -ball.vy * 0.75
}
}
function render(ctx) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.fillStyle = ball.color;
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, 2 * Math.PI);
ctx.closePath();
ctx.fill();
drawPeg(ctx);
}
暂无评论