canvas实现时钟效果

news/2024/11/28 18:49:30/

写的时候遇到的下列几个问题:
1、api了解不深刻,如requestAnimationFrame

const fn =()=>{
//requestAnimationFrame(fn())//错误的写法
requestAnimationFrame(fn)//正确的写法
}

2、关于下面的clear函数(清除动画)与update(更新时间数据)函数,这两个函数都有用到requestAnimationFrame,因此我起初是打算将是合并为一个的,将clear放到update后面进行执行:

const clear =()=>{
//...
}
const update =()=>{
//...
clear()
//...
requestAnimationFrame(update)
}
update()

下面是我个人对这样写的看法:
(1)、虽然看起来是没有问题的,但是由于Demo中update函数中的获取画布像素颗粒循环次数较多,需要一定的时间,会延迟clear的执行。
(2)、获取你会想到将clear放到update最上面优先执行,这样的话就犯了最初级的错误,页面不会显示如何东西,在update中我们需要先获取画布颗粒,如果清除了,还怎么获得?

完整代码

<!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>* {box-sizing: border-box;}.canvas {border: 1px solid;zoom: 0.5;}</style>
</head><body><canvas class="canvas" width="800" height="600"></canvas>
</body>
<script>const random = (m, n) => {return Math.random() * (n - m) + m}//拿到canvas标签const canvas = document.querySelector(".canvas")let ctx = canvas.getContext("2d", {willReadFrequently: true});const cWidth = canvas.widthconst cHeight = canvas.heightconsole.log(cWidth, cHeight);//draw绘制圆的函数,传递x,y,size {x轴位置 , y轴位置 , size 圆半径}const draw = (x, y, size) => {ctx.beginPath();//填充颜色ctx.fillStyle = "#333"//描边颜色ctx.strokeStyle = "#333"ctx.arc(x, y, size, 0 * Math.PI, 2 * Math.PI);ctx.closePath();//描边ctx.stroke();//填充ctx.fill();}//构造圆圈对象class circle {constructor() {const r = Math.min(cWidth, cHeight) / 2const wid = cWidth / 2const hei = cHeight / 2const rad = random(0, 360) * Math.PI / 180const x = Math.cos(rad) * r + widconst y = Math.sin(rad) * r + heiconst size = random(1, 4)this.x = xthis.y = ythis.wid = widthis.hei = heithis.size = sizethis.r = r}drawArc() {draw(this.x, this.y, this.size)}move(duringX, duringY) {//总运动时间const speed = 500const x = this.xconst y = this.y//每毫秒运动的距离const xLen = duringX - xconst yLen = duringY - y//?这里之所以不用 当前位置 + 速度 = 下一次的位置//  而是用原来的位置+ 时间*速度 =当前的位置//是因为requestAnimationFrame并非是按照时间进行调用的,而是根据刷新率const xSpeed = xLen / speedconst ySpeed = yLen / speedconst time = (new Date()) - 0//_move,更改当前圆对象的 x坐标与y坐标const _move = () => {const now_time = (new Date()) - timethis.x = x + now_time * xSpeedthis.y = y + now_time * ySpeedif (now_time < speed) {requestAnimationFrame(_move)} else {this.x = duringXthis.y = duringY}}_move()}}//text 时间文本let text = null//返回当前日期  yyyy - MM - ddfunction getText() {return new Date().toTimeString().substring(0, 8)}const list = []function unpadte() {const now_text = getText()if (text == now_text) {requestAnimationFrame(unpadte)return}text = now_textctx.fillStyle = "#000"ctx.textBaseline = "middle"ctx.font = '100px serif'const wid = ctx.measureText(text).widthctx.fillText(text, (cWidth - wid) / 2, cHeight / 2)const points = getPoints()if (points.length < list.length) {list.splice(points.length)}// clear()for (let i = 0; i < points.length; i++) {let p = list[i]if (!p) {p = new circle()list.push(p)}const [x, y] = points[i]p.move(x, y)}requestAnimationFrame(unpadte)}//clear,定时清除画布内容,实习动画效果的次要关键内容const clear = () => {ctx.clearRect(0, 0, cWidth, cHeight)list.forEach(item => {item.drawArc()})requestAnimationFrame(clear)}clear()//获取画布所有像素坐标const getPoints = () => {const points = []const {width,height,data} = ctx.getImageData(0, 0, canvas.clientWidth, canvas.clientHeight)//gap表示间隔跨度const gap = 3;for (let i = 0; i < width; i += gap) {for (let j = 0; j < height; j += gap) {const index = (i + j * width) * 4const r = data[index]const g = data[index + 1]const b = data[index + 2]const a = data[index + 3]if (r == 0 && g == 0 && b == 0 && a == 255) {points.push([i, j])}}}return points}unpadte()</script></html>

代码是根据网络上的文章实现的(渡一),按照自己的思路又变化了一些


http://www.ppmy.cn/news/141116.html

相关文章

C++primerplus习题+答案

1.下面建立友元的尝试有什么错误&#xff1f; a. class snap { friend clasp; …… }; class clasp{……}; 声明一个友元类需要使用以下格式 friend class clasp; 题目内没有使用关键字class&#xff0c;从而造成编译错误。 b. class cuff { public: void snip(muf…

如果 100 个请求,你怎么用 Promise 去控制并发?

目录 前言 引出 明确概念 思路 实现 另一种实现 疑问 有什么能拓展的功能呢&#xff1f; 结尾 前言 现在面试过程当中 &#xff0c;手写题必然是少不了的&#xff0c;其中碰到比较多的无非就是当属 请求并发控制 了。现在基本上前端项目都是通过axios来实现异步请求的…

acing851

spfa:Dijkstra的进化版

Android查看CPU和GPU使用率(五十五)

Android查看CPU和GPU使用率 1、top -t 能打印出线程级别的CPU使用情况0.打印进程的堆栈信息。从堆栈信息里可以通过.so辨别哪个线程是干什么的&#xff0c;从而在 top -t 的结果里去查找你想要的那个线程的 CPU 使用情况。 # debuggerd -b <pid>1.查看高通821 GPU使用率…

EXCEL 怎么把一列数据转换为多行多列数据

目的&#xff1a;将一列120个数据转换为12行10列。 1,首先&#xff0c;在B1格输入“A1”&#xff0c;B2格输入“A13”&#xff0c;然后选中B1、B2&#xff0c;将鼠标移到选中框的右下角(此时鼠标变为“”形&#xff0c;下同)&#xff0c; 按住左键不放将框下拉至B5处。此时B3…

TI Sitara系列AM3352/AM3354/AM3359 ARM Cortex-A8方案分享

相对比消费类市场,工业类市场的产品更加稳定、更新换代速度较慢、生命周期更长。但是即便如此,长时间的“供货慌”,还是会对工业类市场造成冲击,因此除了积极寻求更多的供货渠道,寻求替代物料也成了维持产品生命力的又一出路,特别是主处理器。 以工业网关、工业HMI为例,…

数据结构(C语言第2版) 课后习题答案之第四章 串、数组和广义表

目录 第4章 串、数组和广义表 1&#xff0e;选择题 &#xff08;1&#xff09;串是一种特殊的线性表&#xff0c;其特殊性体现在&#xff08; &#xff09;。 &#xff08;2&#xff09;串下面关于串的的叙述中&#xff0c;&#xff08; &#xff09;是不正确的&#xf…

Linux命令之iconv命令

一、命令简介 日常工作中我们需要将windows生成的文件上传到Linux系统&#xff0c;有时候会因为编码问题出现显示乱码。例如我上传了一个csv文件到Linux服务器上&#xff0c;默认编码为GB2312&#xff0c;在Linux打开则会出现乱码&#xff0c;我们需要将文件进行编码转换。icon…