Canvas
用canvas怎么画不同类型的图形?下面是一些demo,具体的注释在code里,大家可以自行学习。
01.canvas-line
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas绘制线条</title>
<style>
canvas {
display: block;
margin: 10px auto 0;
border: 1px solid orange;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="500">您的浏览器当前不支持 canvas</canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
ctx.beginPath()
ctx.lineWidth = 4
ctx.strokeStyle = 'orange'
// 起点 终点 中间点
ctx.moveTo(100, 100)
ctx.lineTo(300, 300)
ctx.lineTo(500, 200)
ctx.stroke()
ctx.closePath()
</script>
</html>
2. canvas-高清绘制
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>canvas 高清绘制</title>
<style>
canvas {
display: block;
margin: 10px auto 0;
border: 1px solid orange;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="500">您的浏览器当前不支持 canvas</canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const getPixelRatio = (context) => {
return window.devicePixelRatio || 1
}
/*
高清的canvas绘制不模糊的图形
01 放大 canvas
02 再在 css 里将宽高设置为原来的大小
03 考虑到内容的缩放,因此也需将 ctx 缩放
*/
const ratio = getPixelRatio()
const oldWidth = canvas.width
const oldHeight = canvas.height
canvas.width = canvas.width * ratio
canvas.height = canvas.height * ratio
//再将canvas宽高设置为原来的 清晰度变了,宽高不变
canvas.style.width = oldWidth + 'px'
canvas.style.height = oldHeight + 'px'
ctx.scale(ratio, ratio)
ctx.beginPath()
ctx.lineWidth = 10
ctx.strokeStyle = 'orange'
ctx.moveTo(100, 100)
ctx.lineTo(300, 300)
ctx.lineTo(500, 200)
ctx.stroke()
ctx.closePath()
</script>
</html>
3. canvas-直角坐标系
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
canvas {
display: block;
margin: 10px auto 0;
border: 1px solid orange;
}
</style>
<body>
<canvas id="canvas" width="600" height="500">您的浏览器当前不支持 canvas</canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
canvas.width = canvas.width * 1.5;
canvas.height = canvas.height * 1.5;
//提前设置相关属性
const ht = canvas.clientHeight;
const wd = canvas.clientWidth;
const padding = 20;
const bottomPadding = 20;
const step = 100;
const drawAxis = (options) => {
const { ht, wd, padding, bottomPadding, step, ctx } = options;
//绘制坐标轴
ctx.beginPath();
//线宽
ctx.lineWidth = 2;
//路径颜色
ctx.strokeStyle = 'orange';
//起点 左上角
ctx.moveTo(padding, padding);
//离底边20,所以需要用canvas的高度 *1.5是因为缩放了
ctx.lineTo(padding, ht * 1.5 - padding);
//横轴 第二个参数不变 第一个参数跟上边的同理
ctx.lineTo(wd * 1.5 - padding, ht * 1.5 - padding);
ctx.stroke()
ctx.closePath()
//绘制x轴方向
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = 'green';
//绘制x轴方向的刻度 起点处不需要刻度 所以从1开始
for (let i = 1; i < Math.floor(wd * 1.5 / step); i++) {
//起点处
ctx.moveTo(padding + i * step, ht * 1.5 - bottomPadding)
ctx.lineTo(padding + i * step, ht * 1.5 - bottomPadding - 10);
}
ctx.stroke()
ctx.closePath()
//绘制y轴方向
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = 'green';
//绘制x轴方向的刻度 起点处不需要刻度 所以从1开始
for (let i = 1; i < Math.floor(ht * 1.5 / step); i++) {
//起点处 没个一个i就-一个距离 10是绘制10像素大小
ctx.moveTo(padding, (ht * 1.5 - bottomPadding) - (i * step))
ctx.lineTo(padding + 10, (ht * 1.5 - bottomPadding) - (i * step));
}
ctx.stroke()
ctx.closePath()
}
drawAxis({
ht,
wd,
padding,
bottomPadding:bottomPadding,
step,
ctx
})
</script>
</html>
4.canvas-直方图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
canvas {
display: block;
margin: 10px auto 0;
border: 1px solid orange;
}
</style>
<body>
<canvas id="canvas" width="600" height="500">您的浏览器当前不支持 canvas</canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
canvas.width = canvas.width * 1.5;
canvas.height = canvas.height * 1.5;
//提前设置相关属性
const ht = canvas.clientHeight;
const wd = canvas.clientWidth;
const padding = 20;
const bottomPadding = 20;
const step = 100;
const drawAxis = (options) => {
const { ht, wd, padding, bottomPadding, step, ctx } = options;
//绘制坐标轴
ctx.beginPath();
//线宽
ctx.lineWidth = 2;
//路径颜色
ctx.strokeStyle = 'orange';
//起点 左上角
ctx.moveTo(padding, padding);
//离底边20,所以需要用canvas的高度 *1.5是因为缩放了
ctx.lineTo(padding, ht * 1.5 - padding);
//横轴 第二个参数不变 第一个参数跟上边的同理
ctx.lineTo(wd * 1.5 - padding, ht * 1.5 - padding);
ctx.stroke()
ctx.closePath()
//绘制x轴方向
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = 'green';
//绘制x轴方向的刻度 起点处不需要刻度 所以从1开始
for (let i = 1; i < Math.floor(wd * 1.5 / step); i++) {
//起点处
ctx.moveTo(padding + i * step, ht * 1.5 - bottomPadding)
ctx.lineTo(padding + i * step, ht * 1.5 - bottomPadding - 10);
}
ctx.stroke()
ctx.closePath()
//绘制y轴方向
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = 'green';
//绘制x轴方向的刻度 起点处不需要刻度 所以从1开始
for (let i = 1; i < Math.floor(ht * 1.5 / step); i++) {
//起点处 没个一个i就-一个距离 10是绘制10像素大小
ctx.moveTo(padding, (ht * 1.5 - bottomPadding) - (i * step))
ctx.lineTo(padding + 10, (ht * 1.5 - bottomPadding) - (i * step));
}
ctx.stroke()
ctx.closePath()
}
drawAxis({
ht,
wd,
padding,
bottomPadding: bottomPadding,
step,
ctx
})
//1.有描边 有填充
// ctx.beginPath();
// ctx.lineWidth = 2;
// ctx.strokeStyle = 'orange';
// ctx.fillStyle = "hotpink";
// ctx.rect(100, 100, 300, 200);
// //先填充 再描边
// //填充
// ctx.fill();
// //描边
// ctx.stroke();
// ctx.closePath();
// //2.有描边
// ctx.beginPath();
// ctx.lineWidth = 4;
// ctx.strokeStyle = 'seaGreen';
// ctx.strokeRect(100,310,300,200)
// ctx.closePath();
// //3.有填充
// ctx.beginPath();
// ctx.fillStyle = 'skyblue';
// ctx.fillRect(400,310,300,200)
// ctx.closePath();
//绘制直方图
ctx.beginPath();
for (let i = 1; i < Math.floor(ht * 1.5 / step); i++) {
const height = Math.random() * 300 + 50;//控制在300-350之间
//随机颜色
ctx.fillStyle = '#' + parseInt(Math.random() * 0xFFFFFF).toString(16)
//绘制出来的图要跟刻度尺居中 所以是 20+ i*step -20
ctx.fillRect(i * step, (ht * 1.5) - bottomPadding - height, 40, height)
}
ctx.closePath();
</script>
</html>
5.canvas-圆形图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
canvas {
display: block;
margin: 10px auto 0;
border: 1px solid orange;
}
</style>
<body>
<canvas id="canvas" width="600" height="500">您的浏览器当前不支持 canvas</canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
canvas.width = canvas.width * 1.5;
canvas.height = canvas.height * 1.5;
//提前设置相关属性
const ht = canvas.clientHeight;
const wd = canvas.clientWidth;
const padding = 20;
const bottomPadding = 20;
const step = 100;
const drawAxis = (options) => {
const { ht, wd, padding, bottomPadding, step, ctx } = options;
//绘制坐标轴
ctx.beginPath();
//线宽
ctx.lineWidth = 2;
//路径颜色
ctx.strokeStyle = 'orange';
//起点 左上角
ctx.moveTo(padding, padding);
//离底边20,所以需要用canvas的高度 *1.5是因为缩放了
ctx.lineTo(padding, ht * 1.5 - padding);
//横轴 第二个参数不变 第一个参数跟上边的同理
ctx.lineTo(wd * 1.5 - padding, ht * 1.5 - padding);
ctx.stroke()
ctx.closePath()
//绘制x轴方向
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = 'green';
//绘制x轴方向的刻度 起点处不需要刻度 所以从1开始
for (let i = 1; i < Math.floor(wd * 1.5 / step); i++) {
//起点处
ctx.moveTo(padding + i * step, ht * 1.5 - bottomPadding)
ctx.lineTo(padding + i * step, ht * 1.5 - bottomPadding - 10);
}
ctx.stroke()
ctx.closePath()
//绘制y轴方向
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = 'green';
//绘制x轴方向的刻度 起点处不需要刻度 所以从1开始
for (let i = 1; i < Math.floor(ht * 1.5 / step); i++) {
//起点处 没个一个i就-一个距离 10是绘制10像素大小
ctx.moveTo(padding, (ht * 1.5 - bottomPadding) - (i * step))
ctx.lineTo(padding + 10, (ht * 1.5 - bottomPadding) - (i * step));
}
ctx.stroke()
ctx.closePath()
}
drawAxis({
ht,
wd,
padding,
bottomPadding: bottomPadding,
step,
ctx
})
//绘制圆环
ctx.beginPath()
ctx.lineWidth = 2;
ctx.strokeStyle = 'orange';
//圆的中心坐标 半径 开始角度 结束角度
ctx.arc(400, 300, 200, 0,Math.PI*2);
ctx.stroke()
ctx.closePath()
//绘制圆形
ctx.beginPath()
ctx.fillStyle = "skyblue";
ctx.moveTo(400,300)
//第五个参数是true 代表逆时针的角度
ctx.arc(400, 300, 100, 0,Math.PI*2);
ctx.fill()
ctx.closePath()
</script>
</html>
6.canvas-文字
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
canvas {
display: block;
margin: 10px auto 0;
border: 1px solid orange;
}
</style>
<body>
<canvas id="canvas" width="600" height="500">您的浏览器当前不支持 canvas</canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
canvas.width = canvas.width * 1.5;
canvas.height = canvas.height * 1.5;
//绘制居中线条
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = '#ccc';
ctx.moveTo(450, 0);
ctx.lineTo(450, 900)
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = '#ccc';
ctx.moveTo(0, 375);
ctx.lineTo(900, 375)
ctx.stroke();
ctx.closePath();
//实心文字 描边文字
ctx.fillStyle = "orange";
ctx.font = "bold 60px 微软雅黑";
ctx.fillText('ycq', 100, 100, 100);
ctx.strokeText('财神', 100, 240);
//d对齐属性设置
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';//top bottom middle
ctx.fillText('早日挣大钱', 450, 375)
</script>
</html>
7.canvas-动态检测
是一个动态图,小球在这个框里来回移动,不会超出去
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
canvas {
display: block;
margin: 10px auto 0;
border: 1px solid orange;
}
</style>
<body>
<canvas id="canvas" width="600" height="500">您的浏览器当前不支持 canvas</canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';
canvas.width = canvas.width * 1.5;
canvas.height = canvas.height * 1.5;
const drawCircle = (x, y, r) => {
ctx.beginPath();
ctx.fillStyle = 'red';
ctx.arc(x, y, r, 0, Math.PI * 2)
ctx.fill();
ctx.closePath();
}
//提前设置相关属性
const ht = canvas.clientHeight * 1.5;
const wd = canvas.clientWidth * 1.5;
let x = y = 100;
const r = 20;
let xSpeed = 4;
let ySpeed = 6;
setInterval(() => {
ctx.clearRect(0, 0, wd, ht);
//不超出x轴
if (x - r <= 0 || x + r >= wd) {
xSpeed = - xSpeed;
}
//不超出y轴
if (y - r <= 0 || y + r >= ht) {
ySpeed = - ySpeed;
}
x += ySpeed;
y += ySpeed;
drawCircle(x, y, r)
}, 20);
drawCircle(x, y, r)
</script>
</html>
8.canvas-动画
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>弹性球</title>
<style>
canvas {
display: block;
margin: 40px auto 0;
border: 1px solid sienna;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="400">您的浏览器不支持 canvas</canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.style.width = canvas.width + 'px'
canvas.style.height = canvas.height + 'px'
canvas.width = canvas.width * 1.5
canvas.height = canvas.height * 1.5
class Ball {
constructor(canvas) {
this.canvas = canvas
this.ctx = this.canvas.getContext('2d')
this.wd = this.canvas.clientWidth * 1.5
this.ht = this.canvas.clientHeight * 1.5
this.r = Math.random() * 40 + 10
this.x = Math.random() * (this.wd - (this.r * 2)) + this.r
this.y = Math.random() * (this.ht - (this.r * 2)) + this.r
this.color = '#' + parseInt(Math.random() * 0xFFFFFF).toString(16)
this.xSpeed = Math.random() * 4 + 6
this.ySpeed = Math.random() * 6 + 4
this.init()
}
init() {
this.run()
this.draw()
}
draw() {
this.ctx.beginPath()
this.ctx.fillStyle = this.color
this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI)
this.ctx.fill()
this.ctx.closePath()
}
run() {
if (this.x - this.r <= 0 || this.x + this.r >= this.wd) {
this.xSpeed = -this.xSpeed
}
if (this.y - this.r <= 0 || this.y + this.r >= this.ht) {
this.ySpeed = -this.ySpeed
}
this.x += this.xSpeed
this.y += this.ySpeed
}
}
let ballArr = []
for (let i = 0; i < 20; i++) {
let ball = new Ball(canvas)
ballArr.push(ball)
}
// 动画
setInterval(() => {
ctx.clearRect(0, 0, canvas.clientWidth * 1.5, canvas.clientHeight * 1.5)
for (let i = 0; i < ballArr.length; i++) {
let ball = ballArr[i]
ball.init()
}
}, 15)
</script>
</html>
9.canvas-关系图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>弹性球</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<canvas id="canvas">您的浏览器不支持 canvas</canvas>
</body>
<script>
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
canvas.style.width = document.documentElement.clientWidth - 6 + 'px'
canvas.style.height = document.documentElement.clientHeight - 6 + 'px'
canvas.width = document.documentElement.clientWidth * 1.5
canvas.height = document.documentElement.clientHeight * 1.5
class Ball {
constructor(options) {
this.canvas = options.canvas;
this.text = options.title;
this.ctx = this.canvas.getContext('2d')
this.wd = this.canvas.clientWidth * 1.5
this.ht = this.canvas.clientHeight * 1.5
this.r = Math.random() * 40 + 10
this.x = Math.random() * (this.wd - (this.r * 2)) + this.r
this.y = Math.random() * (this.ht - (this.r * 2)) + this.r
this.color = '#' + parseInt(Math.random() * 0xFFFFFF).toString(16)
this.xSpeed = Math.random() * 4 + 6
this.ySpeed = Math.random() * 6 + 4
this.init()
}
init() {
this.run()
this.draw()
}
draw() {
this.drawCircle();
this.drawText(this.text, this.x, this.y + this.r + 10)
}
//绘制圆形
drawCircle() {
this.ctx.beginPath()
this.ctx.fillStyle = this.color
this.ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI)
this.ctx.fill()
this.ctx.closePath()
}
// 绘制线条
drawLine(x1, y1, x2, y2, color) {
this.ctx.beginPath()
this.ctx.lineWidth = 1
this.ctx.strokeStyle = color || '#666'
this.ctx.moveTo(x1, y1)
this.ctx.lineTo(x2, y2)
this.ctx.stroke()
this.ctx.closePath()
}
//绘制文字
drawText(text, x, y) {
this.ctx.font = 'normal 20px 微软雅黑'
this.ctx.textAlign = 'center'
this.ctx.textBaseline = 'middle'
this.ctx.fillText(text, x, y)
}
run() {
if (this.x - this.r <= 0 || this.x + this.r >= this.wd) {
this.xSpeed = -this.xSpeed
}
if (this.y - this.r <= 0 || this.y + this.r >= this.ht) {
this.ySpeed = -this.ySpeed
}
this.x += this.xSpeed
this.y += this.ySpeed
}
}
let ballArr = []
let titleArr = ['Vue', 'Webpack', 'React', 'Angular', 'Python', 'Nodejs', 'eCharts', 'Next', '模块化', 'Bootstrap', 'Electron', 'flutter', '小程序', '混合应用', 'Git',]
for (let i = 0; i < 5; i++) {
let ball = new Ball({
canvas: canvas,
title: titleArr[i]
})
ballArr.push(ball);
// 连线
for (let j = 0; j < i; j++) {
let preBall = ballArr[j]
ball.drawLine(ball.x, ball.y, preBall.x, preBall.y)
}
}
// 做动画 先画线 再画圆
setInterval(() => {
ctx.clearRect(0, 0, canvas.clientWidth * 1.5 + 10, canvas.clientHeight * 1.5 + 10)
for (let i = 0; i < ballArr.length; i++) {
let ball = ballArr[i]
// 连线
for (let j = 0; j < i; j++) {
let preBall = ballArr[j]
ball.drawLine(ball.x, ball.y, preBall.x, preBall.y, ball.color)
}
}
for (let i = 0; i < ballArr.length; i++) {
let ball = ballArr[i]
ball.init()
}
}, 80)
</script>
</html>