700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 使用canvas绘制圆环进度条

使用canvas绘制圆环进度条

时间:2022-06-23 15:43:35

相关推荐

使用canvas绘制圆环进度条

使用canvas绘制圆环进度条

技术要求

需要一点点数学基础

需要对canvas的常见的方法熟悉

一点点数学基础

已知圆心,半径,角度,求圆上的点坐标

canvas 常见的方法

菜鸟教程

扬帆起航

首先创建一个canvas ,并将这个dom添加在html中

方法名称:createCanvas

// 需要申明两个全局变量let isIconLoadSuccess = false;let iconLoading = null;// 以下是一个方法const canvas = document.createElement('canvas');canvas.width = 300;canvas.height = 300;canvas.style.border = '1px #ccc solid';// 提前加载图标数据const imgObj = new Image();imgObj.src = './success-filling.png';imgObj.onload = function () {isIconLoadSuccess = true;iconLoading = this;};return canvas;

定义一个绘制圆环的方法

方法名称:drawCircle(ctx, config)

绘制圆环的思路

使用arc绘制一个圆形,在其内部填充一个样式,将圆的边框lineWidth设置的宽度大一点,这个宽度就是圆环的大小,设置strokeStyle的颜色,该颜色就是圆环的颜色,最后设置连接处样式lineCap,这里建议将lineCap设置成round

因为最终想要的是圆环,所以角度应该是(0,360)

最后调用strokeclosePath上色和关闭路径

const {x, y, radius, startAngle, endAngle, color, lineWidth,} = config;ctx.beginPath();ctx.arc(x, y, radius, startAngle, endAngle, false);// 设定曲线粗细度ctx.lineWidth = lineWidth;// 给曲线着色ctx.strokeStyle = color;// 连接处样式ctx.lineCap = 'round';// 给环着色ctx.stroke();ctx.closePath();

绘制圆环

方法名称:circle(percent = '0.0')

const {width, height } = canvas;const ctx = canvas.getContext('2d');// 清除画布ctx.clearRect(0, 0, width, height);// 保存ctx.save();/* 填充文字 */ctx.font = '24px Microsoft YaHei';/* 文字颜色 */ctx.fillStyle = '#999';/* 文字内容 */const insertContent = '本月任务进度';// 拿到文本内容的像素相关信息 单位长度(px)const measureText = ctx.measureText(insertContent);/* 插入文字,后面两个参数为文字在画布中的坐标点 *//* 此处注意:text.width获得文字的宽度,然后就能计算出文字居中需要的x值 */ctx.fillText(insertContent, (width - measureText.width) / 2, (height / 2) + 45);/* 填充百分比 */ctx.font = '60px Microsoft YaHei';ctx.fillStyle = '#222';const ratioStr = `${(parseFloat(percent) * 100).toFixed(0)} %`;const text = ctx.measureText(ratioStr);ctx.fillText(ratioStr, (width - text.width) / 2, (height / 2) + 10);/* 开始圆环 */const circleConfig = {/* 圆心坐标 */x: width / 2,y: height / 2,/* 半径,下方出现的150都是半径 */radius: (width / 2) - 30,/* 环的宽度 */lineWidth: 24,/* 开始的度数-从上一个结束的位置开始 */startAngle: 0, // 注意这里的0是3点钟方向,而非12点方向,和数学里的不一样/* 结束的度数 */endAngle: 360,color: '#E7EFF4',};/* 灰色的圆环 */drawCircle(ctx, circleConfig);/* 有色的圆环 */const holeCicle = 2 * Math.PI;const angle = percent * 360; // 圆弧的角度// 圆心坐标:(x0, y0)// 半径:r// 弧度:a => 圆弧计算公式:(角度/180)*Math/.PI// 则圆上任一点为:(x1, y1)// x1 = x0 + r * cos(a)// y1 = y0 + r * sin(a)const x1 = circleConfig.x + circleConfig.radius * Math.cos(((angle - 90) / 180) * Math.PI) - 25;const y1 = circleConfig.y + circleConfig.radius * Math.sin(((angle - 90) / 180) * Math.PI) - 25;// 处理渐变色const gnt1 = ctx.createLinearGradient(circleConfig.radius * 2, circleConfig.radius * 2, 0, 0);gnt1.addColorStop(0, '#FF8941');gnt1.addColorStop(0.3, '#FF8935');gnt1.addColorStop(1, '#FFC255');drawCircle(ctx, {...circleConfig,/* 从-90度的地方开始画 */startAngle: -0.5 * Math.PI, // 把起始点改成数学里的12点方向endAngle: -0.5 * Math.PI + percent * holeCicle,color: gnt1,});// 填充小图标if (isIconLoadSuccess) {// 这里的this指的是imgObj,第二三个参数是它的坐标,四五个是长款ctx.drawImage(iconLoading, x1, y1, 50, 50);}

来一点动画

方法名称:drawFrame(percent, callback)

// 在该方法之外声明一个全局变量let speed = 0;// 以下是 drawFrame 方法体const id = window.requestAnimationFrame(() => {drawFrame(percent, callback); });circle(speed.toString());if (speed >= percent) {window.cancelAnimationFrame(id);speed = 0;if (callback) {callback();}return;}speed += 0.01;

再来一个快照功能

方法名称:createImage(src)

const image = new Image();image.src = src;return image;

调用声明好的方法

const app = document.getElementById('app');const canvas = createCanvas();let i = 0;setInterval(() => {if (i > 1) {i = 0;}i = Math.random();drawFrame(i.toString(), () => {const image = createImage(canvas.toDataURL());app.appendChild(image);window.scrollTo(0, document.body.scrollHeight);});}, 3000);app.appendChild(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>body {width: 100%;height: 100vh;overflow-y: auto;overflow-x: hidden;}</style></head><body><div id="app"></div></body><script>// 图标是否加载成功let isIconLoadSuccess = false;let iconLoading = null;function createCanvas() {const canvas = document.createElement('canvas');canvas.width = 300;canvas.height = 300;canvas.style.border = '1px #ccc solid';// 提前加载图标数据const imgObj = new Image();imgObj.src = './success-filling.png';imgObj.onload = function () {isIconLoadSuccess = true;iconLoading = this;};return canvas;}const app = document.getElementById('app');const canvas = createCanvas();/* 画曲线 */function drawCircle(ctx, config) {const {x, y, radius, startAngle, endAngle, color, lineWidth,} = config;ctx.beginPath();ctx.arc(x, y, radius, startAngle, endAngle, false);// 设定曲线粗细度ctx.lineWidth = lineWidth;// 给曲线着色ctx.strokeStyle = color;// 连接处样式ctx.lineCap = 'round';// 给环着色ctx.stroke();ctx.closePath();}function circle(percent = '0.0') {const {width, height } = canvas;const ctx = canvas.getContext('2d');// 清除画布ctx.clearRect(0, 0, width, height);// 保存ctx.save();/* 填充文字 */ctx.font = '24px Microsoft YaHei';/* 文字颜色 */ctx.fillStyle = '#999';/* 文字内容 */const insertContent = '本月任务进度';// 拿到文本内容的像素相关信息 单位长度(px)const measureText = ctx.measureText(insertContent);/* 插入文字,后面两个参数为文字在画布中的坐标点 *//* 此处注意:text.width获得文字的宽度,然后就能计算出文字居中需要的x值 */ctx.fillText(insertContent, (width - measureText.width) / 2, (height / 2) + 45);/* 填充百分比 */ctx.font = '60px Microsoft YaHei';ctx.fillStyle = '#222';const ratioStr = `${(parseFloat(percent) * 100).toFixed(0)} %`;const text = ctx.measureText(ratioStr);ctx.fillText(ratioStr, (width - text.width) / 2, (height / 2) + 10);/* 开始圆环 */const circleConfig = {/* 圆心坐标 */x: width / 2,y: height / 2,/* 半径,下方出现的150都是半径 */radius: (width / 2) - 30,/* 环的宽度 */lineWidth: 24,/* 开始的度数-从上一个结束的位置开始 */startAngle: 0, // 注意这里的0是3点钟方向,而非12点方向,和数学里的不一样/* 结束的度数 */endAngle: 360,color: '#E7EFF4',};/* 灰色的圆环 */drawCircle(ctx, circleConfig);/* 有色的圆环 */const holeCicle = 2 * Math.PI;const angle = percent * 360; // 圆弧的角度// 圆心坐标:(x0, y0)// 半径:r// 弧度:a => 圆弧计算公式:(角度/180)*Math/.PI// 则圆上任一点为:(x1, y1)// x1 = x0 + r * cos(a)// y1 = y0 + r * sin(a)const x1 = circleConfig.x + circleConfig.radius * Math.cos(((angle - 90) / 180) * Math.PI) - 25;const y1 = circleConfig.y + circleConfig.radius * Math.sin(((angle - 90) / 180) * Math.PI) - 25;// 处理渐变色const gnt1 = ctx.createLinearGradient(circleConfig.radius * 2, circleConfig.radius * 2, 0, 0);gnt1.addColorStop(0, '#FF8941');gnt1.addColorStop(0.3, '#FF8935');gnt1.addColorStop(1, '#FFC255');drawCircle(ctx, {...circleConfig,/* 从-90度的地方开始画 */startAngle: -0.5 * Math.PI, // 把起始点改成数学里的12点方向endAngle: -0.5 * Math.PI + percent * holeCicle,color: gnt1,});// 填充小图标if (isIconLoadSuccess) {// 这里的this指的是imgObj,第二三个参数是它的坐标,四五个是长款ctx.drawImage(iconLoading, x1, y1, 50, 50);}}function createImage(src) {const image = new Image();image.src = src;return image;}// 动画函数let speed = 0;function drawFrame(percent, callback) {const id = window.requestAnimationFrame(() => {drawFrame(percent, callback); });circle(speed.toString());if (speed >= percent) {window.cancelAnimationFrame(id);speed = 0;if (callback) {callback();}return;}speed += 0.01;}let i = 0;setInterval(() => {if (i > 1) {i = 0;}i = Math.random();drawFrame(i.toString(), () => {const image = createImage(canvas.toDataURL());app.appendChild(image);window.scrollTo(0, document.body.scrollHeight);});}, 3000);app.appendChild(canvas);</script></html>

使用到的小图标

最终效果图

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。