canvas
文章目录
画直线
const canvas = document.querySelector('#box');
const ctx = canvas.getContext('2d');
ctx.beginPath(); // 起始一条路径,或重置当前路径。
ctx.moveTo(10, 10); // 定义线条开始坐标,把路径移动到画布中的指定点,不创建线条。
ctx.lineTo(10, 400); // 定义线条结束坐标,添加一个新点,然后在画布中创建从该点到最后指定点的线条。
ctx.strokeStyle = '#0f0'; // 设置或返回用于笔触的颜色、渐变或模式。
ctx.lineWidth = 10; // 设置或返回当前的线条宽度。
ctx.stroke(); // 绘制已定义的路径。
ctx.closePath(); // 创建从当前点回到起始点的路径。
要在ctx.beginPath();
和 ctx.closePath();
中绘制想要的东西
画虚线
原理:就是由一段一段直线组成的
const canvas = document.querySelector('#dashed');
const ctx = canvas.getContext('2d');
drawDashed(100, 100, 110, 100, 50, 20, 0);
drawDashed(100, 100, 102, 102, 50, 15, 5);
drawDashed(100, 100, 102, 102, 50, 35, 5);
drawDashed(100, 100, 110, 110, 50, 20, 20);
drawDashed(100, 100, 100, 110, 50, 0, 20);
/*
x1,y1: 起始坐标
x2,y2: 终点坐标
count: 有多少个虚点
stepX: 线段直线x的间距多远
stepY: 线段直线y的间距多远
*/
function drawDashed(x1, y1, x2, y2, count, stepX, stepY) {
for (let i = 0; i < count; i++) {
ctx.beginPath();
ctx.moveTo(x1 + stepX * i, y1 + stepY * i);
ctx.lineTo(x2 + stepX * i, y2 + stepY * i);
ctx.stroke();
ctx.closePath();
}
}
画矩形
方法一: 绘制四条直线,拼接起来
const canvas = document.querySelector('#box');
const ctx = canvas.getContext('2d');
drawline(10, 10, 10, 400, 'red', 10);
drawline(15, 15, 400, 15, 'black', 10);
drawline(400, 400, 10, 400, 'yellow', 10);
drawline(10, 395, 395, 395, 'blue', 10);
/*
x1,y1: 起始坐标
x2,y2: 终点坐标
color: 线条颜色
width: 线条宽度
*/
function drawline(x1, y1, x2, y2, color, width) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.stroke();
ctx.closePath();
}
方法二:直线连用
const canvas = document.querySelector('#line');
const ctx = canvas.getContext('2d');
ctx.lineWidth = 10;
ctx.strokeStyle = '#000';
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(400, 100);
ctx.lineTo(400, 400);
ctx.lineTo(100, 400);
ctx.lineTo(100, 95);
ctx.stroke();
ctx.closePath();
方法三:rect()方式创建一个矩形
const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
/*
context.rect(x,y,width,height); x,y 表示矩形左上角的 x,y 坐标;width,height 表示矩形的宽高
*/
ctx.beginPath();
ctx.rect(100, 100, 200, 100);
// 原则:先填充再描边
ctx.fillStyle = '#0ff'; // 设置填充色
ctx.fill(); // 填充
ctx.strokeStyle = '#f00'; // 设置描边颜色
ctx.lineWidth = 5; // 设置描边线宽
ctx.stroke(); // 描边
ctx.closePath();
方法四:fillRect()方式创建一个"被填充"的矩形。
/*
context.fillRect(x,y,width,height); x,y 表示矩形左上角的 x,y 坐标;width,height 表示矩形的宽高
*/
const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.fillRect(100, 300, 100, 100);
ctx.closePath();
方法五:strokeRect()方式创建一个"无填充"的矩形。
/*
context.strokeRect(x,y,width,height); x,y 表示矩形左上角的 x,y 坐标;width,height 表示矩形的宽高
*/
const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
ctx.strokeRect(300, 300, 100, 100);
画坐标系
原理: 就是先画两条起始点相同,且垂直的直线,在画一个矩形
const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(100, 400);
ctx.lineTo(400, 400);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.rect(300, 200, 50, 200);
ctx.fillStyle = 'red'; // 设置填充色
ctx.fill(); // 填充
ctx.strokeStyle = 'red'; // 设置描边颜色
ctx.lineWidth = 0; // 设置描边线宽
ctx.stroke(); // 描边
ctx.closePath();
随机生成柱状图
const canvas = document.getElementById('rect');
const ctx = canvas.getContext('2d');
init();
let timerId = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height); // 在给定的矩形内清除指定的像素。
drawCoordinateAxis();
drawBars(6);
}, 1000);
setTimeout(() => {
clearInterval(timerId);
}, 60 * 10000);
function init() {
// 绘制坐标轴
drawCoordinateAxis();
// 绘制矩形
drawBars(6);
}
// 绘制坐标系
function drawCoordinateAxis() {
ctx.beginPath();
ctx.moveTo(100, 0);
ctx.lineTo(100, 400);
ctx.lineTo(900, 400);
ctx.stroke();
ctx.closePath();
}
// 绘制多个矩形
function drawBars(count) {
for (let i = 0; i < count; i++) {
drawBar(130 + 60 * i, 400 * Math.random(), 30);
}
}
// 实现矩形方法
function drawBar(x, y, w) {
ctx.beginPath();
ctx.rect(x, y, w, 400 - y);
ctx.fillStyle = randomColor(); // 设置填充色
ctx.fill(); // 填充
ctx.strokeStyle = randomColor(); // 设置描边颜色
ctx.stroke(); // 描边
ctx.closePath();
}
// 生成随机颜色
function randomColor() {
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
//返回随机生成的颜色
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
画圆
const canvas = document.querySelector('#arc');
const ctx = canvas.getContext('2d');
ctx.beginPath();
/*
context.arc(x,y,r,sAngle,eAngle[,counterclockwise]);
x,y 表示圆的中心 x,y 坐标;r 表示圆的半径;
sAngle 起始角,以弧度计(弧的圆形的三点钟位置是 0 度);eAngle 结束角,以弧度计;
counterclockwise 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。
*/
ctx.arc(100, 100, 50, 0, Math.PI * 2, false);
ctx.fillStyle = randomColor();
ctx.fill();
ctx.lineWidth = 10; // 边的宽度
ctx.strokeStyle = randomColor();
ctx.stroke();
ctx.closePath();
function randomColor() {
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
//返回随机生成的颜色
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
小案例 —— 绘制五环
此案例中点在于将五个圆的中心点找到
const canvas = document.querySelector('#arc');
const ctx = canvas.getContext('2d');
drawCircle();
function drawCircle(lineWidth) {
ctx.lineWidth = 10;
circle(200, 200);
circle(540, 200);
circle(370, 200);
circle(285, 347);
circle(460, 347);
}
function circle(x, y) {
ctx.beginPath();
ctx.arc(x, y, 100, 0, Math.PI * 2, false);
ctx.strokeStyle = randomColor();
ctx.stroke();
ctx.closePath();
}
function randomColor() {
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
//返回随机生成的颜色
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
小案例 —— 画一个字母 “S”
原理:一个字母 s 是由两个半圆组成,一个半圆顺时针一个半圆逆时针
const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI);
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
ctx.beginPath();
ctx.arc(200, 100, 50, 0, Math.PI, true);
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
小案例 —— 画八卦镇
原理:先画最外面的大圆,再画两个小圆和一个 s,小圆的中心坐标是(大圆中心坐标 ± 大圆半径的一半), s 的中心点坐标和小圆的中心的坐标一样,半径是大圆的一半
const canvas = document.getElementById('circle');
const ctx = canvas.getContext('2d');
init();
function init() {
bigCircle();
smallCircle(100, 75, true);
smallCircle(100, 125, false);
halfCricle(100, 75, true);
halfCricle(100, 125, false);
}
function bigCircle() {
ctx.beginPath();
ctx.arc(100, 100, 50, 0, Math.PI * 2);
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
}
function smallCircle(x, y, color) {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI * 2);
ctx.fillStyle = color ? '#fff' : '#000';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = color ? '#000' : '#fff';
ctx.stroke();
ctx.closePath();
}
function halfCricle(x, y, flag) {
ctx.beginPath();
ctx.arc(x, y, 25, Math.PI / 2, (Math.PI * 3) / 2, flag);
ctx.lineWidth = 1;
ctx.strokeStyle = '#000';
ctx.stroke();
ctx.closePath();
}
小案例 —— 圆形进度条
原理: 开启一个定时器一步一步的画圆
const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');
ctx.lineWidth = 5;
ctx.strokeStyle = 'skyblue';
let step = (Math.PI * 2) / 360;
let count = 0;
let timerId = setInterval(() => {
count++;
if (count >= 360) {
// 整圆时停止
clearInterval(timerId);
}
ctx.beginPath();
ctx.arc(250, 250, 30, -Math.PI / 2, step * count - Math.PI / 2, false);
/*
context.clearRect(x,y,width,height); x,y 表示矩形左上角的 x,y 坐标;width,height 表示要清除的矩形的宽度和高度
*/
ctx.clearRect(230, 230, 40, 40); // 清空指定位置的东西
/*
context.font="字体样式 字体变体 字体的粗细 字号和行高 字体系列 ";
*/
ctx.font = 'italic 20px 黑体'; // 定义字体的样式
ctx.textAlign = 'center'; // 设置或返回文本内容的当前对齐方式
/*
context.fillText(text,x,y[,maxWidth]); text 规定在画布上输出的文本;x,y 表示开始绘制文本的 x,y 坐标;maxWidth 最大文本宽度
*/
ctx.fillText(parseInt((100 / 360) * count) + '%', 250, 255, 30); // 插入文本
ctx.stroke();
}, 10);
小案例 —— 饼状图
原理:通过将一个圆划分成不同比例给不同比例设置颜色实现
const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');
drawCircle(0, (Math.PI * 2 * 1) / 10);
drawCircle((Math.PI * 2 * 1) / 10, (Math.PI * 2 * 3) / 10);
drawCircle((Math.PI * 2 * 3) / 10, (Math.PI * 2 * 4) / 10);
drawCircle((Math.PI * 2 * 4) / 10, (Math.PI * 2 * 7) / 10);
drawCircle((Math.PI * 2 * 7) / 10, (Math.PI * 2 * 10) / 10);
function drawCircle(start, end) {
ctx.beginPath();
ctx.moveTo(250, 250); // 这里注意,一点要将起始点放在圆的中心位置上,这样才能画出圆锥形
ctx.arc(250, 250, 100, start, end);
ctx.fillStyle = randomColor();
ctx.fill();
}
function randomColor() {
var r = Math.floor(Math.random() * 256);
var g = Math.floor(Math.random() * 256);
var b = Math.floor(Math.random() * 256);
//返回随机生成的颜色
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
小案例 —— 小球弹一弹
const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');
let xStep = 2;
let yStep = 4;
let r = 20; // 小球的半径
let x = 40; // 小球的起始位置,x坐标
let y = 40; // 小球的起始位置,y坐标
const timerId = setInterval(() => {
// 清空canvas中的东西
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (x - r <= 0 || x + r >= 500) {
// 触碰左右边界回弹
xStep = -xStep;
}
x += xStep;
if (y - r <= 0 || y + r >= 500) {
// 触碰上下边界回弹
yStep = -yStep;
}
y += yStep;
drawBall(x, y, r);
}, 1);
// 画小球
function drawBall(x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2, false);
ctx.fillStyle = '#000';
ctx.fill();
}
setTimeout(() => {
clearInterval(timerId);
}, 60 * 1000);
小案例 —— 小球弹一弹封装
const canvas = document.getElementById('arc');
const ctx = canvas.getContext('2d');
class Ball {
constructor(x, y, r, xSpeed, ySpeed, color) {
this.x = x; // 小球的起始位置,x坐标
this.y = y; // 小球的起始位置,y坐标
this.r = r; // 小球的半径
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.color = color; // 小球的颜色
}
drawBall() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
ctx.fillStyle = this.color;
ctx.fill();
return this;
}
run() {
if (this.x - this.r <= 0 || this.x + this.r >= canvas.width) {
this.xSpeed = -this.xSpeed;
}
this.x += this.xSpeed;
if (this.y - this.r <= 0 || this.y + this.r >= canvas.height) {
this.ySpeed = -this.ySpeed;
}
this.y += this.ySpeed;
}
}
let ballList = [];
// 实例化多个小球
for (let i = 0; i < 10; i++) {
let ball = new Ball(r() + 50, r() + 50, r(50), r(14), r(16), randomColor());
ball.drawBall();
ballList.push(ball);
}
const timerId = setInterval(() => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ballList.forEach(ball => {
ball.run();
ball.drawBall();
});
}, 10);
setTimeout(() => {
clearInterval(timerId);
}, 60 * 1000);
function r(n = 1) {
return Math.random() * n;
}
画文字
const canvas = document.querySelector('#text');
const ctx = canvas.getContext('2d');
// 设置字体样式 context.font="字体样式 字体变体 字体的粗细 字号和行高 字体系列 ";
ctx.font = '40px 楷书';
// 设置字体填充颜色
ctx.fillStyle = 'gold';
// 绘制填充文字 context.fillText(text,x,y[,maxWidth]); text 规定在画布上输出的文本;x,y 表示开始绘制文本的 x,y 坐标;maxWidth 最大文本宽度
ctx.fillText('hello canvas!!!', 100, 100, 300);
// 绘制描边文字
// 设置文字边框颜色
ctx.strokeStyle = 'red';
ctx.strokeText('你好,canvas!!', 100, 200, 300);
// 绘制渐变文字
// 1. 创建渐变对象
const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
// 2. 设置渐变颜色
gradient.addColorStop('0', 'orange');
gradient.addColorStop('0.25', 'purple');
gradient.addColorStop('0.5', 'red');
gradient.addColorStop('0.75', 'blue');
gradient.addColorStop('1', 'green');
// 3. 应用渐变
ctx.fillStyle = gradient;
ctx.strokeStyle = gradient;
// 4. 绘制渐变文字
ctx.fillText('hello gradient', 100, 300, 300);
ctx.strokeText('hello gradient', 100, 400, 300);
画一个闹钟
const canvas = document.querySelector('#clock');
const ctx = canvas.getContext('2d');
class Clock {
/*
x: 时钟中心坐标
y: 时钟中心坐标
r: 时钟半径
r_hour: 时针长度
r_minute: 分针长度
r_second: 秒针长度
r_text: 文字距离中点的半径
r_square: 刻度
r_circle: 中心点
deg: 基本周期
*/
constructor(x, y, r, r_hour, r_minute, r_second, r_text, r_square, r_circle, deg) {
this.x = x;
this.y = y;
this.r_hour = r_hour;
this.r_minute = r_minute;
this.r_second = r_second;
this.r_text = r_text;
this.r_square = r_square;
this.r_circle = r_circle;
this.deg = deg;
}
draw() {
// 画圆
this.drawCircle(0, 0, this.r, '#fff');
// 获取当前时间
var date = new Date();
// 根据当前时间获取对应的角度
var h = date.getHours() * (this.deg / 12) - Math.PI / 2;
var m = date.getMinutes() * (this.deg / 60) - Math.PI / 2;
var s = date.getSeconds() * (this.deg / 60) - Math.PI / 2;
// 3、画指针
this.drawLine(0, 0, this.r_hour * Math.cos(h), this.r_hour * Math.sin(h), '#000', 10);
this.drawLine(0, 0, this.r_minute * Math.cos(m), this.r_minute * Math.sin(m), '#000', 6);
this.drawLine(0, 0, this.r_second * Math.cos(s), this.r_second * Math.sin(s), '#000', 4);
// 4、画指针中心
this.drawCircle(0, 0, this.r_circle, 'black');
// 5、画1-12数字
for (var i = 1; i <= 12; i++) {
var β = ((Math.PI * 2) / 12) * i - Math.PI / 2;
var x = this.r_text * Math.cos(β);
var y = this.r_text * Math.sin(β);
this.drawText(i, x, y);
}
// 6、画60个刻度
for (var i = 1; i <= 60; i++) {
var β = ((Math.PI * 2) / 60) * i - Math.PI / 2;
var x1 = this.r * Math.cos(β); // 最外层元的半径
var y1 = this.r * Math.sin(β);
if (i % 5 === 0) {
var x2 = this.r_square * Math.cos(β);
var y2 = this.r_square * Math.sin(β);
this.drawLine(x1, y1, x2, y2, 'green', 3);
} else {
var x2 = (this.r_square + 5) * Math.cos(β);
var y2 = (this.r_square + 5) * Math.sin(β);
this.drawLine(x1, y1, x2, y2, '#999', 3);
}
}
}
drawCircle(x, y, r, color) {
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fillStyle = color;
ctx.fill();
ctx.closePath();
}
drawText(text, x, y) {
ctx.font = '26px 微软雅黑';
ctx.fillStyle = '#000';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(text, x, y);
}
drawLine(x1, y1, x2, y2, color, width) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.lineCap = 'round'; // 指针尾部圆滑
ctx.stroke();
ctx.closePath();
}
}
ctx.translate(canvas.width / 2, canvas.height / 2);
let clock = new Clock(200, 200, 180, 80, 120, 140, 140, 165, 10, Math.PI * 2);
clock.draw();
const timerId = setInterval(() => {
ctx.clearRect(0, 0, 400, 400);
clock.draw();
}, 1000);