一、前景
今天遇到一个需求需要做一个环形进度条,本来想直接用Echarts这些完善的图表组件实现比较直接,但是发现这个小功能没必要使用这么高级功能的库(其实也是需求本身不负责,没必要使用),所以咱就开始从简出发,直接用canvas画一个。
二、效果图
主要有三部分:圆环背景、进度条、内部文字
三、实现步骤
- 1、绘制外圈背景圆环,直接使用canvas的arc方法
// arc(x, y, radius, 0, Math.PI * 2, false) 方法绘制
// 此部分实现代码
// 绘制背景圆环
function backgroundCircle() {
context.save()
context.beginPath()
context.lineWidth = pieLineWidth // 设置线宽
const radius = center_x - context.lineWidth;
context.lineCap = 'round'
context.strokeStyle = '#fde6cc'
context.arc(center_x, center_y, radius - pieLineWidth, 0, Math.PI * 2, false)
context.stroke()
context.closePath()
context.restore()
}
- 2、绘制进度圆环,也是直接使用canvas的但是内圈圆环就要注意起点和终点的参数
这里放一个图供大家参考起止点坐标计算
// arc(x, y, radius, 0, Math.PI * 2, false) 方法绘制
// 此部分实现代码
// 绘制运动圆环
function foregroundCircle(n) {
context.save()
context.lineWidth = pieLineWidth
context.lineCap = 'round'
var radius = center_x - context.lineWidth
context.beginPath()
context.strokeStyle = '#f78200'
context.arc(
center_x,
center_y,
radius - pieLineWidth,
startPosition*Math.PI,
startPosition*Math.PI + n * rad,
movementDirection
) // 用于绘制圆弧context.arc(x坐标,y坐标,半径,起始角度,终止角度,顺时针/逆时针)
context.stroke()
context.closePath()
context.restore()
}
-
3、绘制内部圆形背景和文字,同理圆形的可以直接使用 arc() 方法,但是我们画完了记得要填充;文字使用fillText() 方法传递字体文案,和具体坐标
-
4、最后组合前三步进行绘制,恭喜你 进度条就已经出来了
四、完整源代码参考
- html结构
<canvas id="canvas" width="500" height="500" style="margin-top: 50px" ></canvas>
- JS逻辑代码
const canvas = document.getElementById('canvas');
drawMain(canvas, 50,28,1.5,
150,'7','Days','bold 40px sans-serif','bold 40px sans-serif',
40,'white',10,false,true)
function drawMain(canvasId, percent,pieLineWidth,startPosition,insidePieRadius,
mainText,subText,mainTextStyle,subTextStyle,mainTextFs,fontColor,intervalSize,useAnimation,movementDirection){
/**
* 参数说明:
* canvasId:画布id
* percent:百分比
* pieLineWidth:饼图线条宽度
* startPosition:饼图起始位置
* insidePieRadius:饼图内圆半径
* mainText:主文字
* subText:副文字
* mainTextStyle:主文字样式 (40px sans-serif)
* subTextStyle:副文字样式 (40px sans-serif)
* mainTextFs:主文字大小
* fontColor:文字颜色
* intervalSize:间隔大小
* useAnimation:是否使用动画
* movementDirection:进度条方向 true是逆时针,false是顺时针
*/
const context = canvasId.getContext('2d');
const center_x = canvasId.width / 2;
const center_y = canvasId.height / 2;
const rad = (Math.PI * 2) / 100;
let speed = 0;
// 绘制背景圆圈
function backgroundCircle() {
context.save()
context.beginPath()
context.lineWidth = pieLineWidth // 设置线宽
const radius = center_x - context.lineWidth;
context.lineCap = 'round'
context.strokeStyle = '#fde6cc'
context.arc(center_x, center_y, radius - pieLineWidth, 0, Math.PI * 2, false)
context.stroke()
context.closePath()
context.restore()
}
// 绘制运动圆环
function foregroundCircle(n) {
context.save()
context.lineWidth = pieLineWidth
context.lineCap = 'round'
var radius = center_x - context.lineWidth
context.beginPath()
context.strokeStyle = '#f78200'
context.arc(
center_x,
center_y,
radius - pieLineWidth,
startPosition*Math.PI,
startPosition*Math.PI + n * rad,
movementDirection
) // 用于绘制圆弧context.arc(x坐标,y坐标,半径,起始角度,终止角度,顺时针/逆时针)
context.stroke()
context.closePath()
context.restore()
}
// 绘制内部文字背景
function drawBg(){
context.save()
context.beginPath()
context.arc(center_x,center_y,insidePieRadius,0,2*Math.PI);
context.fillStyle="#f78200"
context.fill();
}
// 绘制文字
function text(topText,tip,interval,topTitleStyle,tipTitleStyle,fontSize,fontColor){
context.fillStyle=fontColor
context.font=topTitleStyle
context.textAlign="center";
context.fillText(topText,center_x,
center_y - interval/4);
context.font=tipTitleStyle
context.fillText(tip,center_x,
center_y + interval + fontSize);
}
// 绘图
if(useAnimation){
// 执行动画
(function drawFrame() {
if (speed <= percent) {
window.requestAnimationFrame(drawFrame)
} else {
return false
}
context.clearRect(0, 0, canvasId.width, canvasId.height)
backgroundCircle()
foregroundCircle(speed)
drawBg()
text(mainText,subText,intervalSize,mainTextStyle,subTextStyle,mainTextFs,fontColor)
if (speed >= percent) {
speed ++
} else {
speed += 1
}
})()
}else {
context.clearRect(0, 0, canvasId.width, canvasId.height)
backgroundCircle()
foregroundCircle(percent)
drawBg()
text(mainText,subText,intervalSize,mainTextStyle,subTextStyle,mainTextFs,fontColor)
}
}
感谢各位的阅读,也希望大佬们多多指教,小弟有写的不好的地方请留言指正。如果可以的话也希望得到各位一个小小的赞哦!谢谢!