技术标签: canvas html5 JavaScript HTML html javascript HTML5进阶学习
在项目中,我们会遇到需要显示进度条或者倒计时的功能,我们今天就来实现一下。
实现效果要求:
1.环形倒计时
2.能够根据总时间和当前时间进行比例性的倒计时
3.进度条环形能够有颜色渐变效果
4.中间文字能够有颜色渐变效果
在开发canvas程序时,我们通常需要准备静态html和需要引用的js文件即可,这次我们使用的静态html模板如下:
1.html页面
<!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" />
<!-- <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" /> -->
<title>圆形倒计时</title>
</head>
<body>
<div class="clock-show" style="width: 800px;height: 700px">
<canvas id="canvas" width="800" height="700"></canvas>
</div>
</body>
<script src="./index.js"></script>
</html>
2.js文件-需要操作canvas标签的代码
我们先定义好需要去实现的方法,分别如下面代码
function CircleClock(canvas) {
// 定义一个CircleClock构造函数,用于初始化
}
CircleClock.prototype.setProgress = function (progress) {
// 用于设置从外部设置进度
};
CircleClock.prototype.getProgress = function () {
// 用于获取进度
};
CircleClock.prototype.drawBackgroundCircle = function () {
// 画圆形的背景环形条
};
CircleClock.prototype.drawCurrentProgressCircle = function () {
// 绘制倒计时环形进度条
};
CircleClock.prototype.createLinearGradientByTime = function () {
// 按照进度,计算渐变色
};
CircleClock.prototype.drawTimeText = function () {
// 绘制环中间文字倒计时
};
CircleClock.prototype.clear = function () {
// 清理canvas
};
CircleClock.prototype.setTime = function (seconds) {
// 设置初始时间,需要倒计时的时间
};
CircleClock.prototype.setCurrentTime = function (currentSeconds) {
// 实时同步当前剩下的时间
};
CircleClock.prototype.run = function (seconds, endCallback) {
// 开始运行项目,运行时传入初始时间和回调函数
};
CircleClock.prototype.update = function (unPass) {
this.setCurrentTime(unPass);
this.clear();
this.drawBackgroundCircle();
this.drawCurrentProgressCircle();
this.drawTimeText();
};
const circleClock = new CircleClock("canvas");
circleClock.run(30, () => {
console.log("倒计时执行完毕");
});
function CircleClock(canvas) {
// 定义一个CircleClock构造函数,用于初始化
this.canvas = document.querySelector(canvas);
this.context = this.canvas.getContext("2d");
this.width = 800;
this.height = 700;
this.progress = 0; // 用于记录当前的进度
this.seconds = 0; // 需要倒计时的时间,秒
this.currentSeconds = 0; // 当前倒计时到的位置
}
CircleClock.prototype.setProgress = function (progress) {
// 用于设置从外部设置进度
this.progress = progress;
};
CircleClock.prototype.getProgress = function () {
// 用于获取进度
return this.progress;
};
CircleClock.prototype.drawBackgroundCircle = function () {
// 画圆形的背景环形条
const x = this.width / 2;
const y = this.height / 2;
this.context.strokeStyle = "#40C4FF";
this.context.lineWidth = 16;
this.context.beginPath();
// 绘制圆形背景。从弧度-(Math.PI / 2)到2 * Math.PI
this.context.arc(x, y, this.width / 5, -(Math.PI / 2), 2 * Math.PI);
this.context.stroke();
};
CircleClock.prototype.drawCurrentProgressCircle = function () {
const x = this.width / 2;
const y = this.height / 2;
// 绘制倒计时环形进度条
const canvasGradient = this.context.createLinearGradient(
0,
0,
0,
this.height
);
// 在offset为0的位置(即起点位置)添加一个蓝色的渐变
canvasGradient.addColorStop(0, "#00BCD4");
// 在offset为0.4的位置(线段左起20%的位置)添加一个绿色的渐变
canvasGradient.addColorStop(0.4, "#7C4DFF");
// 在offset为0.8的位置(即终点位置)添加一个红色的渐变
canvasGradient.addColorStop(0.8, "#DCE775");
// 在offset为1的位置(即终点位置)添加一个红色的渐变
canvasGradient.addColorStop(1, "#FF5722");
// 将strokeStyle的属性值设为该CanvasGradient对象
this.context.strokeStyle = canvasGradient;
// 计算进度
const progress = 1 - this.currentSeconds / this.seconds;
this.setProgress(progress);
// - (Math.PI/2), (progress) *(3/2 *Math.PI) [-0.5, 1.5]-[0, 1],
this.context.lineWidth = 16;
this.context.lineCap = "round";
this.context.beginPath();
// 绘制圆形进度环
this.context.arc(
x,
y,
this.width / 5,
-(Math.PI / 2),
(-0.5 + 2 * progress) * Math.PI
);
this.context.stroke();
};
CircleClock.prototype.createLinearGradientByTime = function () {
// 按照进度,计算渐变色
const progress = this.getProgress();
// 修改填充颜色
const canvasGradient = this.context.createLinearGradient(
this.width / 2 - 18,
this.height / 2 - 18,
this.width / 2,
this.height / 2 + 50
);
canvasGradient.addColorStop(0, "#00BCD4");
progress > 0 && progress < 0.4 && canvasGradient.addColorStop(0.3, "#7C4DFF");
progress > 0.4 &&
progress < 0.8 &&
canvasGradient.addColorStop(0.6, "#DCE775");
progress > 0.6 &&
progress < 0.9 &&
canvasGradient.addColorStop(0.8, "#EEFF41");
canvasGradient.addColorStop(1, "#FF5722");
return canvasGradient;
};
CircleClock.prototype.drawTimeText = function () {
// 绘制环中间文字倒计时
this.context.fillStyle = this.createLinearGradientByTime();
this.context.textAlign = "start";
this.context.font = "36px bold";
this.context.textBaseline = "alphabetic";
let s = parseInt(this.currentSeconds);
let ss = parseInt(s % 60);
let mm = parseInt(s / 60);
const text = `${
mm.toString().padStart(2, 0)}: ${
ss
.toString()
.padStart(2, 0)}`;
// 计算文本长度,适配位置
const textWidth = this.context.measureText(text).width;
this.context.fillText(
text,
this.width / 2 - textWidth / 2,
this.height / 2 + 18
);
};
CircleClock.prototype.clear = function () {
// 清理canvas
this.context.clearRect(0, 0, this.width, this.height); //每改变一次动画就要对这个空间范围进行一次刷新,不然会重叠在一起
};
CircleClock.prototype.setTime = function (seconds) {
// 设置初始时间,需要倒计时的时间
this.seconds = seconds;
};
CircleClock.prototype.setCurrentTime = function (currentSeconds) {
// 实时同步当前剩下的时间
this.currentSeconds = currentSeconds;
};
运行项目,传入初始时间和回调函数,这里会不停的反复运行,如果需要停止,可以通过打开clearInterval(intervalTime);
代码进行关闭计时器
CircleClock.prototype.run = function (seconds, endCallback) {
// 开始运行项目,运行时传入初始时间和回调函数
let count = 0;
const intervalTime = setInterval(() => {
this.setTime(seconds);
const allTime = this.seconds;
const unPass = allTime - count;
count = count + 1;
console.log("unPass", unPass);
if (unPass < 0) {
// clearInterval(intervalTime);
this.setTime(30);
count = 0;
endCallback && endCallback();
} else {
this.update(unPass);
}
}, 1000);
};
用于更新当前已经倒计时倒计到的时间,相当于重新绘制整个界面
CircleClock.prototype.update = function (unPass) {
this.setCurrentTime(unPass);
this.clear();
this.drawBackgroundCircle();
this.drawCurrentProgressCircle();
this.drawTimeText();
};
const circleClock = new CircleClock("canvas");
circleClock.run(30, () => {
console.log("倒计时执行完毕");
});
上面是所有代码的分布解析,下面给出完整代码
1.html
<!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" />
<!-- <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" /> -->
<title>圆形倒计时</title>
</head>
<body>
<div class="clock-show" style="width: 800px;height: 700px">
<canvas id="canvas" width="800" height="700"></canvas>
</div>
</body>
<script src="./index.js"></script>
</html>
2.js
function CircleClock(canvas) {
// 定义一个CircleClock构造函数,用于初始化
this.canvas = document.querySelector(canvas);
this.context = this.canvas.getContext("2d");
this.width = 800;
this.height = 700;
this.progress = 0; // 用于记录当前的进度
this.seconds = 0; // 需要倒计时的时间,秒
this.currentSeconds = 0; // 当前倒计时到的位置
}
CircleClock.prototype.setProgress = function (progress) {
// 用于设置从外部设置进度
this.progress = progress;
};
CircleClock.prototype.getProgress = function () {
// 用于获取进度
return this.progress;
};
CircleClock.prototype.drawBackgroundCircle = function () {
// 画圆形的背景环形条
const x = this.width / 2;
const y = this.height / 2;
this.context.strokeStyle = "#40C4FF";
this.context.lineWidth = 16;
this.context.beginPath();
// 绘制圆形背景。从弧度-(Math.PI / 2)到2 * Math.PI
this.context.arc(x, y, this.width / 5, -(Math.PI / 2), 2 * Math.PI);
this.context.stroke();
};
CircleClock.prototype.drawCurrentProgressCircle = function () {
const x = this.width / 2;
const y = this.height / 2;
// 绘制倒计时环形进度条
const canvasGradient = this.context.createLinearGradient(
0,
0,
0,
this.height
);
// 在offset为0的位置(即起点位置)添加一个蓝色的渐变
canvasGradient.addColorStop(0, "#00BCD4");
// 在offset为0.4的位置(线段左起20%的位置)添加一个绿色的渐变
canvasGradient.addColorStop(0.4, "#7C4DFF");
// 在offset为0.8的位置(即终点位置)添加一个红色的渐变
canvasGradient.addColorStop(0.8, "#DCE775");
// 在offset为1的位置(即终点位置)添加一个红色的渐变
canvasGradient.addColorStop(1, "#FF5722");
// 将strokeStyle的属性值设为该CanvasGradient对象
this.context.strokeStyle = canvasGradient;
// 计算进度
const progress = 1 - this.currentSeconds / this.seconds;
this.setProgress(progress);
// - (Math.PI/2), (progress) *(3/2 *Math.PI) [-0.5, 1.5]-[0, 1],
this.context.lineWidth = 16;
this.context.lineCap = "round";
this.context.beginPath();
// 绘制圆形进度环
this.context.arc(
x,
y,
this.width / 5,
-(Math.PI / 2),
(-0.5 + 2 * progress) * Math.PI
);
this.context.stroke();
};
CircleClock.prototype.createLinearGradientByTime = function () {
// 按照进度,计算渐变色
const progress = this.getProgress();
// 修改填充颜色
const canvasGradient = this.context.createLinearGradient(
this.width / 2 - 18,
this.height / 2 - 18,
this.width / 2,
this.height / 2 + 50
);
canvasGradient.addColorStop(0, "#00BCD4");
progress > 0 && progress < 0.4 && canvasGradient.addColorStop(0.3, "#7C4DFF");
progress > 0.4 &&
progress < 0.8 &&
canvasGradient.addColorStop(0.6, "#DCE775");
progress > 0.6 &&
progress < 0.9 &&
canvasGradient.addColorStop(0.8, "#EEFF41");
canvasGradient.addColorStop(1, "#FF5722");
return canvasGradient;
};
CircleClock.prototype.drawTimeText = function () {
// 绘制环中间文字倒计时
this.context.fillStyle = this.createLinearGradientByTime();
this.context.textAlign = "start";
this.context.font = "36px bold";
this.context.textBaseline = "alphabetic";
let s = parseInt(this.currentSeconds);
let ss = parseInt(s % 60);
let mm = parseInt(s / 60);
const text = `${
mm.toString().padStart(2, 0)}: ${
ss
.toString()
.padStart(2, 0)}`;
// 计算文本长度,适配位置
const textWidth = this.context.measureText(text).width;
this.context.fillText(
text,
this.width / 2 - textWidth / 2,
this.height / 2 + 18
);
};
CircleClock.prototype.clear = function () {
// 清理canvas
this.context.clearRect(0, 0, this.width, this.height); //每改变一次动画就要对这个空间范围进行一次刷新,不然会重叠在一起
};
CircleClock.prototype.setTime = function (seconds) {
// 设置初始时间,需要倒计时的时间
this.seconds = seconds;
};
CircleClock.prototype.setCurrentTime = function (currentSeconds) {
// 实时同步当前剩下的时间
this.currentSeconds = currentSeconds;
};
CircleClock.prototype.run = function (seconds, endCallback) {
// 开始运行项目,运行时传入初始时间和回调函数
let count = 0;
const intervalTime = setInterval(() => {
this.setTime(seconds);
const allTime = this.seconds;
const unPass = allTime - count;
count = count + 1;
console.log("unPass", unPass);
if (unPass < 0) {
// clearInterval(intervalTime);
this.setTime(30);
count = 0;
endCallback && endCallback();
} else {
this.update(unPass);
}
}, 1000);
};
CircleClock.prototype.update = function (unPass) {
this.setCurrentTime(unPass);
this.clear();
this.drawBackgroundCircle();
this.drawCurrentProgressCircle();
this.drawTimeText();
};
const circleClock = new CircleClock("canvas");
circleClock.run(30, () => {
console.log("倒计时执行完毕");
});
文章浏览阅读1.2k次。百度ai开放平台1.百度ai开放平台内有众多功能,如文字识别,语音技术等等内容,本文章以身份证识别为例子,教大家怎么使用它啦链接走起:https://cloud.baidu.com/?from=console身份证识别1.点开链接,即可看到文字识别内的身份证识别,请求说明部分,可以看到bash,python,java,c++,PHP等,这里的例子用的是python,选择python拷贝到代码软件内..._将ai平台导入python
文章浏览阅读3.5k次。Request 与 Response1. RequestREST framework 传入视图的request对象不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。REST framework 提供了Parser解析器,在接收到请求后会自动根据Content-Type指明的请求数据类型(如JSON、表单..._restschema不能用reponse
文章浏览阅读430次。原文地址:https://www.cnblogs.com/top5/archive/2009/09/22/1571709.htmlAllow和Deny可以用于apache的conf文件或者.htaccess文件中(配合Directory, Location, Files等),用来控制目录和文件的访问授权。所以,最常用的是:Order Deny,AllowAllow from Al..._order deny,allow
文章浏览阅读748次。本题要求实现一个字符串查找的简单函数。函数接口定义:char *search( char *s, char *t );函数search在字符串s中查找子串t,返回子串t在s中的首地址。若未找到,则返回NULL。裁判测试程序样例:#include <stdio.h>#define MAXS 30char *search(char *s, char *t);void R..._6-5 查找子串 分数 20 作者 张泳 单位 浙大城市学院 本题要求实现一个字符串查找
文章浏览阅读4.2k次。一个项目需要一个权限控制的模块,因为是重构的项目,用的是dtree,所有着手研究了一手dtree。网上也有好的地案例,比如http://www.jq22.com/jquery-info5331这个网址的模式,挺好的,就是太贵了,再比如:http://www.16css.com/menu/1184.html这个网站,里面有代码,是免费的,但是就是感觉里面的方法不太全,所以自己动手写了一个,代码如..._权限控制复选框插件
文章浏览阅读2k次。最近,很多小伙伴们都觉得自己的电脑内存不够了,又想换块硬盘,但又是一件复杂的事,那么就有很多人想到了PC上安装虚拟机,占用空间呢也不是很大,又方便。那么要怎么安装呢?今天就来教大家如何安装!“叮咚——”准备做好系统一时游,我们开始吧!1.安装时必不可缺镜像!如果要正版镜像那么就去这个网址:MSDN, 我告诉你 - 做一个安静的工具站 (itellyou.cn)或这个微软官方:下载 Windows 8.1 光盘映像(ISO 文件) (microsoft.com)https://www.micros_win8镜像csdn
文章浏览阅读209次。信息技术课是很多学生都感兴趣的,根据这一点,我们可以制定相应教学计划,引导学生正确应用电脑来学习。下面是出国留学网给大家带来七年级上册信息技术教学计划,欢迎阅读。【七年级上册信息技术教学计划一】一、 学生情况分析:大部分同学对计算机有浓厚的兴趣,在学习时能够勤于动手,积极参与课堂教学。但也有部分同学对计算机还是不甚理解,所以在以后的教学中,要针对具体的学生采取不同的方法,引导他们学好计算机,为将来..._七年级上册信息技术线上教学教学计划
文章浏览阅读3.5k次。jquery grid是富客户端的,基于XML , Ajax网格插件的jQuery库。 jqGridView提供专业的解决方案,代表和编辑表格数据在网络上。精心设计的,具有强大的脚本API的,这可编辑网格是很简单的DHTML与XML 的配置,并显示出令人信服的成果与大量数据。现在我现在熟悉一下jquery grid的的使用方法和一些常用的option设置。1.调用gridjqGrid已经可_jqgrid可以在列表增删改查吗
文章浏览阅读1.7k次。delphi调试概述2007-06-13 16:15delphi调试入门级的经典文章,如果是新手的话此文值得好好的读一读Delphi调试概述除非你的程序只有几行,否则几乎不可能一次写成,因此调试就非常必要。然而许多初学者不知道如何进行调试,写完程序就运行,发现结果不对再看代码,这样觉得非常吃力。这里,简单介绍一下Delphi所提供的调试功能。1. 语法检查(Syntax Che_delphi如何联调源码
文章浏览阅读1.9w次,点赞2次,收藏21次。本文档主要介绍海康威视设备预览、回放、流媒体取流的RTSP URL和IE直接预览、回放的HTTP URL。RTSP为取流协议,取到码流后需要解码显示,可以通过VLC播放器进行测试,IE等浏览器网页不支持RTSP协议直接取流预览或者回放。网页上需要跳过登录界面直接访问我们设备的预览或者回放画面,可以使用文档中所述的HTTP的URL实现。注:1)URL中“:”“?”“&_海康威视流媒体地址
文章浏览阅读193次。转载自:https://dingjn-coder.github.io/2020/03/16/%E6%A1%86%E6%9E%B6/Mybatis%E4%BB%8B%E7%BB%8D%E5%8F%8A%E4%BD%BF%E7%94%A8/#toc-heading-41Mybatis介绍Mybatis是一个java持久层框架,内部封装了JDBC,并且做了很多的优化,开发者只需要关注如何写sq..._findbypaging(findallparam findallparam)
文章浏览阅读165次。转至:https://blog.csdn.net/hairetz/article/details/4161954(1) getch()和getche()函数 这两个函数都是从键盘上读入一个字符。其调用格式为: getch(); getche(); 两者的区别是: getch()函数不将读入的字符回显在显示屏幕上,而getche()函数却将读入..._利用getch()与getche()用于交互输入的过程中完成暂停