#实现圆环渐变倒计时效果

内容

  1. 效果图
  2. 需求分析
  3. 实现技术
  4. 实现过程
  5. 全部源码

1. 效果图展示

随着时间的减少, 圆环的红黄色部分会慢慢的减少,圆环中的数字会变小,一直到0停止.

2. 需求分析

  • 可以自定义倒计时结束的时间
  • 圆环的颜色是渐变的
  • 倒计时的动画在视觉上是流畅运行, 而不是一格一格的减少

3. 实现的技术

语言 框架
HTML5
CSS3 BootStrap SASS
JavaScript

4. 实现的过程

1. HTML 部分

主要用到的是 HTML5 中的画布元素 canvas, 一共4个 canvas 元素拍成一排, 每个元素都是高144px, 宽144px的正方形, 两个圆环中的两个小点部分可以使用伪元素 after 和 before 来实现

源码如下:

<div class="count-down"><div class="container"><div class="row"><div class="days col-lg-3 col-md-3 col-sm-3 col-xs-6"><div class="colck"><canvas id="days" width="144" height="144"></canvas></div></div><div class="hours col-lg-3 col-md-3 col-sm-3 col-xs-6"><div class="colck"><canvas id="hours" width="144" height="144"></canvas></div></div><div class="minutes col-lg-3 col-md-3 col-sm-3 col-xs-6"><div class="colck"><canvas id="minutes" width="144" height="144"></canvas></div></div><div class="seconds col-lg-3 col-md-3 col-sm-3 col-xs-6"><div class="colck"><canvas id="seconds" width="144" height="144"></canvas></div></div></div></div>
</div>

用 BootStrap 提供的栅格布局快速的把 canvas 元素排成一排
为每个 cnavas 元素设置对应的 id, 方便用 JavaScript 获取到该元素.

2. SASS部分

css 的部分是用 Sass 来写的, Sass 是一个 css 的 扩展语言, html 文件中引用的是写好的 Sass 文件编译生成 css 文件.

源码如下

.count-down {width: 100%;.row {padding: 0 145px;}.col-lg-3 {padding: 0;position: relative;.colck {width: 144px;height: 144px;background-color: #fff;margin: 0 auto;}}.days, .hours, .minutes {&:after, &:before {content: "";display: block;width: 12px;height: 12px;background-color: #fff;position: absolute;right: -6px;}&:after {bottom: 45px;}&:before {top: 45px;} }
}

控制圆环的运动主要靠 JavaScript 代码, 这里 sass 的作用是用来把把元素的位置排列好, 把两个圆环中间的点画出来,

因为背景色是黑色的
为了看的更加直观, 我先把包裹 canvas 的元素背景色设为白色,

此时的效果:

3. JavaScript部分

最终的运动效果靠 js 代码来实现:

  1. 我们先来获取到这4个 canvas 元素
// 获取4个 canvas 元素
var days_canvas = document.getElementById('days');
var hours_canvas = document.getElementById('hours');
var minutes_canvas = document.getElementById('minutes');
var seconds_canvas = document.getElementById('seconds');

  1. 为了可以自定义指定倒计时结束时间, 写一个设置结束时间的函数, 返回值为一个 Date 对象.
// 设置倒计时时间:年 月 日 小时 分钟 秒 毫秒
endTime = setEndTime(2020, 11, 30, 15, 0, 0);// 设置到期时间
function setEndTime(year, month, day, hour, minute, millisecond) {return new Date(year, month - 1, day, hour, minute, millisecond);
}

js 中创建 Date 对象的5种方式
new Date(“month dd,yyyy hh:mm:ss”);
new Date(“month dd,yyyy”);
new Date(yyyy,mth,dd,hh,mm,ss);
new Date(yyyy,mth,dd);
new Date(ms);

注意 Date 对象中的月份取值是 0 - 11, 0 就表示 1 月,
用变量 endTime 保存这个设置好的 Date 对象


  1. 根据现在的时间和设置好的到期时间计算现在到到期时间还有多少秒,多少分钟, 多少小时, 多少天.
// 计算距离到期时间还剩下多少 days, hours, minutesfunction getLeftTimeObj() {var date = new Date();var millisecond = date.getTime()var end_millisecond = endTime.getTime();if (end_millisecond < millisecond) {return {days: 0,hours: 0,minutes: 0,seconds: 0}}// 距离结束时间的秒数var left_seconds = (( end_millisecond - millisecond ) / 1000);var seconds = (left_seconds % 60);var left_minutes = (left_seconds - seconds) / 60;var minutes = (left_minutes % 60);var left_hours = (left_minutes - minutes) / 60;var hours = (left_hours % 24);var left_days = ((left_hours - hours) / 24);return {days: left_days,hours: hours,minutes: minutes,seconds: seconds}}var dateObj = getLeftTimeObj();

思路:

  • Date 对象中有一个方法 getTime(), 返回值是从 1970 年 1 月 1 日至今的毫秒数。
  • 用两个 Date 对象的 getTime() 返回值相减值再 ÷ 1000 获得两者相差的秒数
  • 用两者相差的秒数换算出两者相差多少天,多少小时,多少分钟,多少秒
  • 最后返回一个对象
    {
    days: 还有多少天,
    hours: 还有多少个小时,
    minutes: 还有多少分钟,
    secondsL: 还有多少秒
    }

我们定义一个变量 dateObj 保存这个对象, 然后根据这个对象去在相应的 canvas 元素上画图


  1. 绘图

我们先不考虑怎么让圆环动起来, 而是先考虑怎么把图画出来

观察单个图形的样子如下图所示:

可以把这个图形分成4个部分

  • 灰色的整个圆环
  • 红黄渐变的不完整圆环
  • 中间的数字 54
  • 下面的字符串 Seconds

我们可以为写四个方法分别完成每一个步骤

 // 画整个圆
function drawCricle(canvas) {// 获取 context 对象var context = canvas.getContext('2d');// 获取 canvas 的中心点的 x 坐标var centerX = canvas.width / 2;// 获取 canvas 的中心点的 y 坐标var centerY = canvas.height / 2;context.save();context.beginPath();context.lineWidth = 7;context.strokeStyle = "#636363";// 圆环的宽度为 7, canvas 元素的长和宽是 144, 所以圆半径应为 (144 - 7) / 2, 也就是 canvas.width / 2 - 3.5context.arc(centerX, centerY, canvas.width / 2 - 3.5 , 0, Math.PI*2, false);context.stroke();context.closePath();context.restore();
}// 画数字下的字符
function drawStr(canvas, str) {var context = canvas.getContext('2d');var centerX = canvas.width / 2;var centerY = canvas.height / 2;context.save();context.fillStyle = '#fff';context.font = "14px Arial"; //设置字体大小和字体context.textAlign = 'center';context.fillText(str, centerX, centerY+54);context.restore();
}// 画数字
function drawNumber(canvas, num) {var context = canvas.getContext('2d');var centerX = canvas.width / 2;var centerY = canvas.height / 2;num = num.toFixed();num = num < 10 ? '0' + num : num;context.save();context.fillStyle = '#fff';context.font = "bolder 60px Arial"; //设置字体大小和字体context.textAlign = 'center';// context.fontWeight = 'bold';context.fillText(num, centerX, centerY+10);context.restore();
}// 画进度条 -0.5为起点
// percentage 为进度条的百分比(0<percentage<1), 1 表示整个圆
function drawProgress(canvas, percentage) {var context = canvas.getContext('2d');var centerX = canvas.width / 2;var centerY = canvas.height / 2;var end_cricle = (percentage * 2) - 0.5;end_cricle = Number(end_cricle.toFixed(4))// 设置垂直渐变var linearGrad = context.createLinearGradient(canvas.width / 2, 0, canvas.width / 2, canvas.height);linearGrad.addColorStop(0, '#ff0503');linearGrad.addColorStop(1, '#ff8200');context.save();context.strokeStyle = linearGrad; //设置描边样式context.lineWidth = 7; //设置线宽context.beginPath(); //路径开始context.arc(centerX, centerY, canvas.width / 2 -3.5 , -0.5 * Math.PI, end_cricle * Math.PI, false); //用于绘制圆弧context.arc(x坐标,y坐标,半径,起始角度,终止角度,顺时针/逆时针)context.stroke(); //绘制context.closePath(); //路径结束context.restore();
}
// 为秒计数的 canvas 绘图, 画图依赖 dateObj.seconds
drawCricle(seconds_canvas);
drawStr(seconds_canvas, 'Seconds');
// 每一分钟有60秒, 用 dateObj.seconds / 60 获得 当前进度
drawProgress(seconds_canvas, (dateObj.seconds / 60).toFixed(4));
drawNumber(seconds_canvas, dateObj.seconds);

写一个绘制 4 个 canvas 的方法 draw(); 然后执行

// 绘图
function draw() {drawCricle(days_canvas);drawStr(days_canvas, 'Days');drawProgress(days_canvas, dateObj.days / 10);drawNumber(days_canvas, dateObj.days);drawCricle(hours_canvas);drawStr(hours_canvas, 'Hours');drawProgress(hours_canvas, (dateObj.hours / 24).toFixed(4));drawNumber(hours_canvas, dateObj.hours);drawCricle(minutes_canvas);drawStr(minutes_canvas, 'Minutes');drawProgress(minutes_canvas, (dateObj.minutes / 60).toFixed(4));drawNumber(minutes_canvas, dateObj.minutes);drawCricle(seconds_canvas);drawStr(seconds_canvas, 'Seconds');drawProgress(seconds_canvas, (dateObj.seconds / 60).toFixed(4));drawNumber(seconds_canvas, dateObj.seconds);
}drwa();

然后先记得把之前设置的白色背景色去掉

执行了 draw() 之后效果如下图:

但是现在还没有实现让他动起来,


  1. 让倒计时动起来

先明白动起来的逻辑:

  • 用定时器每过 16ms 清除一次所有 canvas 画的图像
  • 重新获取所剩下的时间的对象 dateObj
  • 再次绘图 draw();
// 清除 canvas 内容
function clear() {var days_ctx = days_canvas.getContext('2d');var hours_ctx = hours_canvas.getContext('2d');var minutes_ctx = minutes_canvas.getContext('2d');var seconds_ctx = seconds_canvas.getContext('2d');days_ctx.clearRect(0, 0, days_canvas.width, days_canvas.height);hours_ctx.clearRect(0, 0, hours_canvas.width, hours_canvas.height);minutes_ctx.clearRect(0, 0, minutes_canvas.width, minutes_canvas.height);seconds_ctx.clearRect(0, 0, seconds_canvas.width, seconds_canvas.height);
}// 让倒计时动起来
// 可以直接用定时器
setInterval(function() {clear();dateObj = getLeftTimeObj();draw();
}, 16)// 也可以考虑使用 requestAnimationFrame 这个方法
(function count() {requestAnimationFrame(count);clear();dateObj = getLeftTimeObj();draw();
})();

到现在为止整个完整的功能全部实现了。

5. 全部源码

1.index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><link rel="stylesheet" href="./bootstrap.min.css"><link rel="stylesheet" href="./style.css"><style>.count-down {background: #000;}</style>
</head>
<body><div class="count-down"><div class="container"><div class="row"><div class="days col-lg-3 col-md-3 col-sm-3 col-xs-6"><div class="colck"><canvas id="days" width="144" height="144"></canvas></div></div><div class="hours col-lg-3 col-md-3 col-sm-3 col-xs-6"><div class="colck"><canvas id="hours" width="144" height="144"></canvas></div></div><div class="minutes col-lg-3 col-md-3 col-sm-3 col-xs-6"><div class="colck"><canvas id="minutes" width="144" height="144"></canvas></div></div><div class="seconds col-lg-3 col-md-3 col-sm-3 col-xs-6"><div class="colck"><canvas id="seconds" width="144" height="144"></canvas></div></div></div></div></div><script src="./index.js"></script>
</body>
</html>

2. style.scss

.count-down {position: absolute;bottom: 90px;left: 0;width: 100%;.row {padding: 0 145px;}.col-lg-3 {padding: 0;position: relative;.colck {width: 144px;height: 144px;// background-color: #fff;margin: 0 auto;}}.days, .hours, .minutes {&:after, &:before {content: "";display: block;width: 12px;height: 12px;background-color: #fff;position: absolute;right: -6px;}&:after {bottom: 45px;}&:before {top: 45px;} }
}

index.js

// 倒计时
// 到期时间
// 设置倒计时时间:年 月 日 小时 分钟 秒 毫秒
endTime = setEndTime(2020, 11, 30, 15, 0, 0);// 设置到期时间
function setEndTime(year, month, day, hour, minute, millisecond) {return new Date(year, month - 1, day, hour, minute, millisecond);
}// 获取4个 canvas 元素
var days_canvas = document.getElementById('days');
var hours_canvas = document.getElementById('hours');
var minutes_canvas = document.getElementById('minutes');
var seconds_canvas = document.getElementById('seconds');// 计算距离到期时间还剩下多少 days, hours, minutes
function getLeftTimeObj() {var date = new Date();var millisecond = date.getTime()var end_millisecond = endTime.getTime();if (end_millisecond < millisecond) {return {days: 0,hours: 0,minutes: 0,seconds: 0}}// 距离结束时间的秒数var left_seconds = (( end_millisecond - millisecond ) / 1000);var seconds = (left_seconds % 60);var left_minutes = (left_seconds - seconds) / 60;var minutes = (left_minutes % 60);var left_hours = (left_minutes - minutes) / 60;var hours = (left_hours % 24);var left_days = ((left_hours - hours) / 24);return {days: left_days,hours: hours,minutes: minutes,seconds: seconds}
}var dateObj = getLeftTimeObj();// 画整个圆
function drawCricle(canvas) {var context = canvas.getContext('2d');var centerX = canvas.width / 2;var centerY = canvas.height / 2;context.save();context.beginPath();context.lineWidth = 7;context.strokeStyle = "#636363";context.arc(centerX, centerY, canvas.width / 2 - 3.5 , 0, Math.PI*2, false);context.stroke();context.closePath();context.restore();
}// 画数字下的字符
function drawStr(canvas, str) {var context = canvas.getContext('2d');var centerX = canvas.width / 2;var centerY = canvas.height / 2;context.save();context.fillStyle = '#fff';context.font = "14px Arial"; //设置字体大小和字体context.textAlign = 'center';context.fillText(str, centerX, centerY+54);context.restore();
}// 画数字
function drawNumber(canvas, num) {var context = canvas.getContext('2d');var centerX = canvas.width / 2;var centerY = canvas.height / 2;num = num.toFixed();num = num < 10 ? '0' + num : num;context.save();context.fillStyle = '#fff';context.font = "bolder 60px Arial"; //设置字体大小和字体context.textAlign = 'center';// context.fontWeight = 'bold';context.fillText(num, centerX, centerY+10);context.restore();
}// 画进度条 -0.5为起点
// percentage 为进度条的百分比(0<percentage<1), 1 表示整个圆
function drawProgress(canvas, percentage) {var context = canvas.getContext('2d');var centerX = canvas.width / 2;var centerY = canvas.height / 2;var end_cricle = (percentage * 2) - 0.5;end_cricle = Number(end_cricle.toFixed(4))// 设置垂直渐变var linearGrad = context.createLinearGradient(canvas.width / 2, 0, canvas.width / 2, canvas.height);linearGrad.addColorStop(0, '#ff0503');linearGrad.addColorStop(1, '#ff8200');context.save();context.strokeStyle = linearGrad; //设置描边样式context.lineWidth = 7; //设置线宽context.beginPath(); //路径开始context.arc(centerX, centerY, canvas.width / 2 -3.5 , -0.5 * Math.PI, end_cricle * Math.PI, false); //用于绘制圆弧context.arc(x坐标,y坐标,半径,起始角度,终止角度,顺时针/逆时针)context.stroke(); //绘制context.closePath(); //路径结束context.restore();
}// 清除 canvas 内容
function clear() {var days_ctx = days_canvas.getContext('2d');var hours_ctx = hours_canvas.getContext('2d');var minutes_ctx = minutes_canvas.getContext('2d');var seconds_ctx = seconds_canvas.getContext('2d');days_ctx.clearRect(0, 0, days_canvas.width, days_canvas.height);hours_ctx.clearRect(0, 0, hours_canvas.width, hours_canvas.height);minutes_ctx.clearRect(0, 0, minutes_canvas.width, minutes_canvas.height);seconds_ctx.clearRect(0, 0, seconds_canvas.width, seconds_canvas.height);
}// 绘图
function draw() {drawCricle(days_canvas);drawCricle(hours_canvas);drawCricle(minutes_canvas);drawCricle(seconds_canvas);drawStr(days_canvas, 'Days');drawStr(hours_canvas, 'Hours');drawStr(minutes_canvas, 'Minutes');drawStr(seconds_canvas, 'Seconds');drawProgress(days_canvas, dateObj.days / 10 >= 1 ? 1 : dateObj.days / 10);drawNumber(days_canvas, dateObj.days);drawProgress(hours_canvas, (dateObj.hours / 24).toFixed(4));drawNumber(hours_canvas, dateObj.hours);drawProgress(minutes_canvas, (dateObj.minutes / 60).toFixed(4));drawNumber(minutes_canvas, dateObj.minutes);drawProgress(seconds_canvas, (dateObj.seconds / 60).toFixed(4));drawNumber(seconds_canvas, dateObj.seconds);
}draw();(function count() {requestAnimationFrame(count);clear();dateObj = getLeftTimeObj();draw();
})();

参考文章:
https://www.cnblogs.com/moqiutao/p/6430079.html

写作时间:2020.11.21
作者:李茂斌
转载请说明出处

利用 canvas 实现圆形进度条,实现倒计时效果相关推荐

  1. 自定义圆形进度条 自定义倒计时进度条

    自定义圆形进度条 自定义倒计时进度条 版权声明:转载必须注明本文转自严振杰的博客: http://blog.csdn.net/yanzhenjie1003 此控件源码已开源到Github:https: ...

  2. WPF利用动画实现圆形进度条

    WPF利用动画实现圆形进度条 原文:WPF利用动画实现圆形进度条 这是我的第一篇随笔,最近因为工作需要,开始学习WPF相关技术,自己想实现以下圆形进度条的效果,逛了园子发现基本都是很久以前的文章,实现 ...

  3. html数字显示百分比,扣丁学堂html5 教程之Canvas实现圆形进度条并显示数字百分比效果...

    今天扣丁学堂html5培训小编和大家分享一下Canvas实现圆形进度条并显示数字百分比效果示例,对html5感兴趣的小伙伴或者是参加学习的小伙伴可以了解一下. Canvas实现圆形进度条并显示数字百分 ...

  4. canvas 绘制圆形进度条

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  5. html的canvas显示数字,HTML5效果:Canvas 实现圆形进度条并显示数字百分比

    实现效果 1.首先创建html代码 2.创建canvas环境 var canvas = document.getElementById('canvas'), //获取canvas元素 context ...

  6. android绘制环形进度_Android使用Canvas绘制圆形进度条效果

    前言 Android自定义控件经常会用到Canvas绘制2D图形,在优化自己自定义控件技能之前,必须熟练掌握Canvas绘图机制.本文从以下三个方面对Canvas绘图机制进行讲解: 画布Canvas ...

  7. 使用canvas绘制圆形进度条

    实现步骤: 绘制一个圆: 绘制圆环: 绘制进度环: 绘制文字: 一.创建画布 <canvas id='myCanvas' width='200' height='200'></can ...

  8. html 环形进度条,详解利用canvas实现环形进度条的方法

    前提:有时候在项目中会有用到进度条的情况,使用css3也可以实现,但是对于性能不好的设备,或者网络不好的情况下,卡顿现象非常明显,避免出现不流畅的尴尬情况,所以记录一下,使用canvas来实现的方法. ...

  9. 使用h5 canvas绘制圆形进度条

    创建一个Html容器canvas: <canvas id="myCanvasTag" width="300" height="300" ...

最新文章

  1. 转转转![Spring MVC] - 500/404错误处理-SimpleMappingExceptionResolver
  2. linux内核杂记(5)-进程终结
  3. 数制转换itoa atoi int转字符串 字符串转int string转int int转string
  4. 2016年Web前端面试题
  5. 树视图主要属性 c# 0207
  6. centos8 用u盘安装失败_CentOS8 的安装过程
  7. 计算机二级真题c.doc,2018计算机二级C语言考试真题试卷汇总.doc
  8. 手机论文查重软件哪个好?
  9. 对图像高通滤波matlab,高通巴特沃斯滤波器在MATLAB中对图像进行滤波
  10. 同城滴滴啦啦啦啦啦啦啦啦
  11. 再谈OT算法的协同文档制作的底层基础架构记录
  12. nn.Flatten()函数详解及示例
  13. python微信发红包看照片_微信发原图会泄露位置信息?用Python教你通过图片获取用户信息!...
  14. mysql答辩会问什么_计算机科学与技术专业,毕设答辩会问什么问题?
  15. android DAY1--搭建开发环境与Helloworld
  16. WR | 西湖大学鞠峰组揭示微塑料污染对人工湿地菌群与脱氮功能的影响
  17. Python语言:节日贺卡
  18. 流氓软件卸载了又偷偷冒出来,dllhost.exe暗藏安装玄机
  19. 程莉计算机网络课后答案,信息学院2011-2012学年学生先进集体和先进个人.doc
  20. .manifest是什么文件

热门文章

  1. Win11电脑上登录的微软账号怎么退出登录?
  2. ontology nlp_如何使用Python on Ontology编写智能合约? 第1部分:区块链和区块API
  3. C++处理日期和时间的chrono库
  4. 被羞辱的Overflow
  5. 有了谷歌Chrome,依然离开不开微软IE
  6. 【愚公系列】2023年01月 网安实验-.NET程序的破解与加密
  7. 词向量Word Embedding原理及生成方法
  8. android多媒体框架介绍(五)显示图形系统之SurfaceFlinger初步介绍
  9. error: C1083: 无法打开包括文件: “QtGui/QApplication”: No such file or directory
  10. pygame Sprite类(4)