赞
踩
需要一点点数学基础
需要对canvas
的常见的方法熟悉
方法名称:
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)
最后调用stroke
和closePath
上色和关闭路径
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>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。