Canvas:实现在线动态时钟效果

news2024/9/20 12:34:37

想象一下,用几行代码就能创造出如此逼真的图像和动画,仿佛将艺术与科技完美融合,前端开发的Canvas技术正是这个数字化时代中最具魔力的一环,它不仅仅是网页的一部分,更是一个无限创意的画布,一个让你的想象力自由驰骋的平台。

目录

基础页面搭建

设置时分秒针

最终总结


基础页面搭建

接下来借助canvas实现一个简易的动态时钟操作,首先这里我们设置一下画布的一些基础布局样式:

<canvas id="canvas" width="800" height="600"></canvas>
<script>
    // 获取canvas画布绘制上下文对象以及获取2d画笔对象
    let canvas = document.getElementById("canvas");
    let ctx = canvas.getContext("2d");
</script>

接下来我们通过两个for循环,实现小时与分钟的刻度显示,其中ctx.save()和ctx.restore()用于管理绘图状态,确保不同的绘图操作不会相互影响,代价如下:

ctx.save() // 存档
ctx.translate(400, 300) // 平移
ctx.rotate(-Math.PI / 2) // 旋转

ctx.save() // 存档
for (let i = 0; i < 12; i++) {
    // 绘制小时的刻度
    ctx.beginPath()
    ctx.moveTo(170, 0)
    ctx.lineTo(190, 0)
    ctx.strokeStyle = 'gray';
    ctx.lineWidth = 8
    ctx.stroke()
    ctx.closePath()
    ctx.rotate(2 * Math.PI / 12)
}
ctx.restore() // 恢复上一层坐标
ctx.save() // 存档
for (let i = 0; i < 60; i++) {
    // 绘制分钟的刻度
    ctx.beginPath()
    ctx.moveTo(180, 0)
    ctx.lineTo(190, 0)
    ctx.strokeStyle = 'gray';
    ctx.lineWidth = 2
    ctx.stroke()
    ctx.closePath()
    ctx.rotate(2 * Math.PI / 60)
}
ctx.restore() // 恢复上一层坐标
ctx.save() // 存档

最终呈现的效果如下所示:

设置时分秒针

接下来我们借助设计时分秒针的样式,通过date函数获取当前的时分秒的时间,然后通过借助JS的动态渲染函数requestAnimationFrame来动态改变当前的时间,具体的步骤如下所示,整段代码就完成了利用 Canvas 绘制时钟的功能,根据当前时间动态绘制时、分、秒针的效果:

// 获取当前时间
let time = new Date();
let hour = time.getHours();
let min = time.getMinutes();
let sec = time.getSeconds();
hour = hour >= 12 ? hour - 12 : hour; // 12小时制
// 绘制时针
ctx.rotate(2 * Math.PI / 12 * hour + 2 * Math.PI / 12 / 60 * min + 2 * Math.PI / 12 / 60 / 60 * sec)
ctx.beginPath()
ctx.moveTo(-15, 0)
ctx.lineTo(110, 0)
ctx.strokeStyle = '#333';
ctx.lineWidth = 8
ctx.stroke()
ctx.closePath()
ctx.restore() // 恢复上一层坐标
ctx.save() // 存档
// 绘制分针
ctx.rotate(2 * Math.PI / 60 * min + 2 * Math.PI / 60 / 60 * sec)
ctx.beginPath()
ctx.moveTo(-20, 0)
ctx.lineTo(130, 0)
ctx.strokeStyle = '#888';
ctx.lineWidth = 4
ctx.stroke()
ctx.closePath()
ctx.restore() // 恢复上一层坐标
ctx.save() // 存档
// 绘制秒针
ctx.rotate(2 * Math.PI / 60 * sec)
ctx.beginPath()
ctx.moveTo(-30, 0)
ctx.lineTo(190, 0)
ctx.strokeStyle = 'red';
ctx.lineWidth = 2
ctx.stroke()
ctx.closePath()
ctx.restore() // 恢复上一层坐标

ctx.restore() // 恢复上一层坐标

为了让时钟能够动态的进行时间的跳转,这里我们记住requestAnimationFrame函数进行动画帧的渲染,代码如下:

requestAnimationFrame(render)

最终呈现的效果如下所示:

最终总结

接下来对代码实现了一个基于 HTML5 Canvas 的动态时钟效果,让我逐步解释其实现思路:

清除画布:ctx.clearRect(0, 0, 800, 600); 每帧开始时清除整个画布,避免之前的绘制残留。
变换画布原点:ctx.translate(400, 300); 将画布原点移到中心点位置,便于后续绘制钟表。
旋转坐标系:ctx.rotate(-Math.PI / 2); 将坐标系旋转,使得钟表的 12 点方向朝上。
绘制钟表刻度:分别用循环绘制小时和分钟的刻度,每次绘制完成后旋转坐标系到下一个刻度位置。
获取当前时间:使用 new Date() 获取当前时间的小时、分钟和秒数。
绘制时针、分针、秒针:根据当前时间计算旋转角度,分别绘制时针、分针和秒针。
动画效果:使用 requestAnimationFrame(render) 实现每秒钟更新一次画面,形成动态的钟表效果。

按照上面的步骤,这样整个代码就完成了一个基于 Canvas 的动态时钟绘制,实现了钟表的时、分、秒针的动态变化,以及刻度的静态绘制,完整代码如下所示:

<body>
    <canvas id="canvas" width="800" height="600"></canvas>
    <script>
        // 获取canvas画布绘制上下文对象以及获取2d画笔对象
        let canvas = document.getElementById("canvas");
        let ctx = canvas.getContext("2d");

        function render() {
            ctx.clearRect(0, 0, 800, 600);

            ctx.save() // 存档
            ctx.translate(400, 300) // 平移
            ctx.rotate(-Math.PI / 2) // 旋转

            ctx.save() // 存档
            for (let i = 0; i < 12; i++) {
                // 绘制小时的刻度
                ctx.beginPath()
                ctx.moveTo(170, 0)
                ctx.lineTo(190, 0)
                ctx.strokeStyle = 'gray';
                ctx.lineWidth = 8
                ctx.stroke()
                ctx.closePath()
                ctx.rotate(2 * Math.PI / 12)
            }
            ctx.restore() // 恢复上一层坐标
            ctx.save() // 存档
            for (let i = 0; i < 60; i++) {
                // 绘制分钟的刻度
                ctx.beginPath()
                ctx.moveTo(180, 0)
                ctx.lineTo(190, 0)
                ctx.strokeStyle = 'gray';
                ctx.lineWidth = 2
                ctx.stroke()
                ctx.closePath()
                ctx.rotate(2 * Math.PI / 60)
            }
            ctx.restore() // 恢复上一层坐标
            ctx.save() // 存档

            // 获取当前时间
            let time = new Date();
            let hour = time.getHours();
            let min = time.getMinutes();
            let sec = time.getSeconds();
            hour = hour >= 12 ? hour - 12 : hour; // 12小时制
            // 绘制时针
            ctx.rotate(2 * Math.PI / 12 * hour + 2 * Math.PI / 12 / 60 * min + 2 * Math.PI / 12 / 60 / 60 * sec)
            ctx.beginPath()
            ctx.moveTo(-15, 0)
            ctx.lineTo(110, 0)
            ctx.strokeStyle = '#333';
            ctx.lineWidth = 8
            ctx.stroke()
            ctx.closePath()
            ctx.restore() // 恢复上一层坐标
            ctx.save() // 存档
            // 绘制分针
            ctx.rotate(2 * Math.PI / 60 * min + 2 * Math.PI / 60 / 60 * sec)
            ctx.beginPath()
            ctx.moveTo(-20, 0)
            ctx.lineTo(130, 0)
            ctx.strokeStyle = '#888';
            ctx.lineWidth = 4
            ctx.stroke()
            ctx.closePath()
            ctx.restore() // 恢复上一层坐标
            ctx.save() // 存档
            // 绘制秒针
            ctx.rotate(2 * Math.PI / 60 * sec)
            ctx.beginPath()
            ctx.moveTo(-30, 0)
            ctx.lineTo(190, 0)
            ctx.strokeStyle = 'red';
            ctx.lineWidth = 2
            ctx.stroke()
            ctx.closePath()
            ctx.restore() // 恢复上一层坐标

            ctx.restore() // 恢复上一层坐标
            requestAnimationFrame(render)
        }
        render()
    </script>
</body>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1923617.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用宝塔安装一套linux开发环境

更新yum&#xff0c;并且更换阿里镜像源 删除yum文件 cd /etc/yum.repos.d/ 进入yum核心目录 ls sun.repo rm -rf * 删除之前配置的本地源 ls 配置阿里镜像源 wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo 配置扩展包 wge…

【JavaScript 算法】深度优先搜索:探索所有可能的路径

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、算法原理二、算法实现三、应用场景四、优化与扩展五、总结 深度优先搜索&#xff08;Depth-First Search, DFS&#xff09;是一种用于遍历或搜索图或树数据结构的算法。该算法尽可能深入图的分支&#xff0c;探索所有可…

【Lora模型推荐】Stable Diffusion创作具有玉石翡翠质感的图标设计

站长素材AI教程是站长之家旗下AI绘图教程平台 海量AI免费教程&#xff0c;每日更新干货内容 想要深入学习更多AI绘图教程&#xff0c;请访问站长素材AI教程网&#xff1a; AI教程_深度学习入门指南 - 站长素材 (chinaz.com) logo版权归各公司所有&#xff01;本笔记仅供AIGC…

防火墙的NAT策略以及智能选路

一、实验拓扑 二、实验要求 7&#xff0c;办公区设备可以通过电信链路和移动链路上网(多对多的NAT&#xff0c;并且需要保留一个公网IP不能用来转换) 8&#xff0c;分公司设备可以通过总公司的移动链路和电信链路访问到Dmz区的http服务器 9&#xff0c;多出口环境基于带宽比例进…

【机器学习】逻辑回归的原理、应用与扩展

文章目录 一、逻辑回归概述二、Sigmoid函数与损失函数2.1 Sigmoid函数2.2 损失函数 三、多分类逻辑回归与优化方法3.1 多分类逻辑回归3.2 优化方法 四、特征离散化 一、逻辑回归概述 逻辑回归是一种常用于分类问题的算法。大家熟悉的线性回归一般形式为 Y a X b \mathbf{Y}…

2024辽宁省大学生数学建模竞赛(C题)数学建模完整思路+完整代码全解全析

你是否在寻找数学建模比赛的突破点&#xff1f;数学建模进阶思路&#xff01; 作为经验丰富的数学建模团队&#xff0c;我们将为你带来2024电工杯数学建模竞赛&#xff08;B题&#xff09;的全面解析。这个解决方案包不仅包括完整的代码实现&#xff0c;还有详尽的建模过程和解…

Redis vs Memcache:哪个更适合你的应用?

Redis vs Memcache&#xff1a;哪个更适合你的应用&#xff1f; 1、存储与持久化2、数据类型支持3、性能与底层机制4、Value值大小限制5、数据备份与容灾6、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在缓存技术的选择中&#xff…

CV08_深度学习模块之间的缝合教学(3)--加载预训练权重

1.1 引言 我们在修改网络模型&#xff0c;添加或删除模块&#xff0c;或者更改了某一层之后&#xff0c;直接加载原先的预训练权重&#xff0c;肯定是会报错的&#xff0c;因为原来的模型权重和修改后的模型权重之间的结构是不匹配的。 那么我们只想加载那些没有更改过的那个…

Python酷库之旅-第三方库Pandas(020)

目录 一、用法精讲 49、pandas.merge_asof函数 49-1、语法 49-2、参数 49-3、功能 49-4、返回值 49-5、说明 49-5-1、功能 49-6、用法 49-6-1、数据准备 49-6-2、代码示例 49-6-3、结果输出 50、pandas.concat函数 50-1、语法 50-2、参数 50-3、功能 50-4、返…

中仕公考:没有教师资格证能考编吗?

没有教师资格证的考生&#xff0c;是不能参加教师编考试的。但是&#xff0c;符合“先上岗&#xff0c;再考证”的阶段性措施&#xff0c;高校毕业生可在未获得教师资格证的情况下先行就业。其他考生必须首先取得教师资格证&#xff0c;才能参与教师编考试。 报考普通小学和幼…

【Android Studio】实现底部导航栏Tab切换(提供Gitee源码)

前言&#xff1a;本期教学如何制作底部导航栏以及使用Fragment实现页面切换的完整功能&#xff0c;本篇提供所有源代码&#xff0c;均测试无误&#xff0c;大家可以放心使用。 目录 一、功能演示 二、代码实现 2.1、bottom.xml 2.2、message.xml、book.xml和mine.xml 2.3、…

第三期书生大模型实战营之Git前置知识

闯关任务1 每位参与者提交一份自我介绍。 提交地址&#xff1a;https://github.com/InternLM/Tutorial 的 camp3 分支&#xff5e; 要求 1. 命名格式为 camp3_<id>.md&#xff0c;其中 <id> 是您的报名问卷ID。 2. 文件路径应为 ./data/Git/task/。 3. 在 GitHub…

单网口设备的IP地址识别-还原-自组网

1.如果知道该设备所在网段&#xff1a; 此时可以使用nmap工具&#xff0c;进行网段扫描&#xff1a; nmap -sn 192.168.0.0/24 256个地址的子网10秒就能扫描一轮。关掉设备&#xff0c;打开设备&#xff0c;diff&#xff0c;基本就可以定位所要找到目标设备的IP 2.如果不知道…

链接追踪系列-04.linux服务器docker安装elk

[rootVM-24-17-centos ~]# cat /proc/sys/vm/max_map_count 65530 [rootVM-24-17-centos ~]# sysctl -w vm.max_map_count262144 vm.max_map_count 262144 #先创建出相应目录&#xff1a;/opt/dockerV/es/…docker run -e ES_JAVA_OPTS"-Xms512m -Xmx512m" -d -p 92…

隔离驱动-视频课笔记

目录 1、需要隔离的原因 1.2、四种常用的隔离方案 2、脉冲变压器隔离 2.1、脉冲变压器的工作原理 2.2、泄放电阻对开关电路的影响 2.3、本课小结 3、光耦隔离驱动 3.1、光耦隔离驱动原理 3.2、光耦隔离驱动的电源进行分析 3.3、本课小结 4、自举升压驱动 4.1…

哪款开放式运动耳机佩戴最舒服?2024五款备受推崇产品分享!

​热爱户外活动的你&#xff0c;定是对生活有着独到品味的行者。想象一下&#xff0c;在户外活动时&#xff0c;若有一款耳机能完美融入场景&#xff0c;为你带来无与伦比的音乐享受&#xff0c;岂不是锦上添花&#xff1f;此时&#xff0c;开放式耳机便应运而生&#xff0c;其…

SEO:6个避免被搜索引擎惩罚的策略-华媒舍

在当今数字时代&#xff0c;搜索引擎成为了绝大多数人获取信息和产品的首选工具。为了在搜索结果中获得良好的排名&#xff0c;许多网站采用了各种优化策略。有些策略可能会适得其反&#xff0c;引发搜索引擎的惩罚。以下是彭博社发稿推广的6个避免被搜索引擎惩罚的策略。 1. 内…

结合实体类型信息(3)——TransT: 基于类型的多重嵌入表示用于知识图谱补全

1 引言 1.1 问题 仅仅依赖于三元组的结构化信息有其局限性&#xff0c;因为它们往往忽略了知识图谱中丰富的语义信息以及由这些语义信息所代表的先验知识。语义信息是指实体和关系的含义&#xff0c;比如“北京”是“中国”的首都&#xff0c;“苹果”是一种水果。先验知识则…

uniapp编译成h5后接口请求参数变成[object object]

问题&#xff1a;uniapp编译成h5后接口请求参数变成[object object] 但是运行在开发者工具上没有一点问题 排查&#xff1a; 1&#xff1a;请求参数&#xff1a;看是否是在请求前就已经变成了[object object]了 结果&#xff1a; 一切正常 2&#xff1a;请求头&#xff1a;看…

yolov8-obb训练自己的数据集(标注,训练,推理,转化模型)

一、源码 直接去下载官方的yolov8源码就行&#xff0c;那里面集成了 obb ultralytics/ultralytics/cfg/models/v8 at main ultralytics/ultralytics GitHub 二、环境 如果你训练过yolov5以及以上的yolo环境&#xff0c;可以直接拷贝一个用就行&#xff0c;如果没有的话 直…