canvas学习之华丽小球滚动电子时钟

news2024/11/24 0:17:01

教程来自 4-3 华丽的小球滚动效果

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>华丽小球滚动时钟</title>
	<style type="text/css">
		* {
			margin:  0;
			padding: 0;
		}
		html, body {
			width: 100%;
			height: 100%;
		}
	</style>
</head>
<body>
	<canvas id="mainCanvas" style="display: block;border: 1px solid #eee;margin: 0 auto;"></canvas>
<!-- digit.js代码在下面 -->
<script type="text/javascript" src="digit.js"></script>
<script type="text/javascript">
	const CANVAS_WIDTH = document.body.clientWidth - 4;
	const CANVAS_HEIGHT = document.body.clientHeight - 4;
	const BALL_ARC_R = 8; // 半径8像素
	const OFF_LEFT = parseInt((CANVAS_WIDTH - (6 * 7 + 2 * 4) * 20)/2);
	const OFF_TOP = 50;
	const BALL_TUPLE = [];
	const COLORS = ["#33B5E5","#0099CC","#AA66CC","#9933CC","#99CC00","#669900","#FFBB33","#FF8800","#FF4444","#CC0000"];
	let animationTimer = null; // 动画定时器
	let lastTimes = {times: 0, hour_t: 0, hour_a: 0, minute_t: 0, minute_a: 0, second_t: 0, second_a: 0}; // 上次时间
	window.onload = () => {
		let canvasDom = document.querySelector('#mainCanvas')
		canvasDom.width = CANVAS_WIDTH;
		canvasDom.height = CANVAS_HEIGHT;
		let ctx = canvasDom.getContext('2d')

		// 动画入口函数
		function animationEntry() {
			renderCanvas(ctx);
			animationTimer = window.requestAnimationFrame(animationEntry);
		}
		animationTimer = window.requestAnimationFrame(animationEntry);
	}

	// 更新帧率
	function updateFPS() {
	}
	
	// 绘画渲染
	function renderCanvas(ctx) {
		let dateObj = new Date();

		let tempTimes = parseInt(dateObj.valueOf()/ 50);
		if (lastTimes.times != tempTimes) {
			let hour = dateObj.getHours();
			let minute = dateObj.getMinutes();
			let second = dateObj.getSeconds();
			let hour_t = parseInt(hour/10)
			let hour_a = parseInt(hour%10)
			let minute_t = parseInt(minute/10)
			let minute_a = parseInt(minute%10)
			let second_t = parseInt(second/10)
			let second_a = parseInt(second%10)
			if (lastTimes.times == 0) {
				lastTimes.hour_t = hour_t
				lastTimes.hour_a = hour_a
				lastTimes.minute_t = minute_t
				lastTimes.minute_a = minute_a
				lastTimes.second_t = second_t
				lastTimes.second_a = second_a
			}
			lastTimes.times = tempTimes;
			// 清理画布
			ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
			
			drawDigit(ctx, OFF_LEFT, OFF_TOP, hour_t, 'rgb(0, 102, 153)', lastTimes.hour_t != hour_t? (lastTimes.hour_t = hour_t,true): false)
			drawDigit(ctx, OFF_LEFT + 140, OFF_TOP, hour_a, 'rgb(0, 102, 153)', lastTimes.hour_a != hour_a? (lastTimes.hour_a = hour_a,true): false)
			drawDigit(ctx, OFF_LEFT + 140 * 2, OFF_TOP, 10, 'rgb(0, 102, 153)')
			drawDigit(ctx, OFF_LEFT + 140 * 2 + 80, OFF_TOP, minute_t, 'rgb(0, 102, 153)', lastTimes.minute_t != minute_t? (lastTimes.minute_t = minute_t,true): false)
			drawDigit(ctx, OFF_LEFT + 140 * 3 + 80, OFF_TOP, minute_a, 'rgb(0, 102, 153)', lastTimes.minute_a != minute_a? (lastTimes.minute_a = minute_a,true): false)
			drawDigit(ctx, OFF_LEFT + 140 * 4 + 80, OFF_TOP, 10, 'rgb(0, 102, 153)')
			drawDigit(ctx, OFF_LEFT + 140 * 4 + 80 * 2, OFF_TOP, second_t, 'rgb(0, 102, 153)', lastTimes.second_t != second_t? (lastTimes.second_t = second_t,true): false)
			drawDigit(ctx, OFF_LEFT + 140 * 5 + 80 * 2, OFF_TOP, second_a, 'rgb(0, 102, 153)', lastTimes.second_a != second_a? (lastTimes.second_a = second_a,true): false)
			// console.log(BALL_TUPLE);
			let j = 0;
			for (let i = 0; i < BALL_TUPLE.length; i++) {
				let item = BALL_TUPLE[i];
				item.x += item.vx;
				item.y += item.vy;
				item.vy += item.vg;
				if (ctx.canvas.height < item.y) {
					item.y = ctx.canvas.height - BALL_ARC_R;
					item.vy *= -0.8;
				}
				if (ctx.canvas.width > (item.x - BALL_ARC_R)  && (item.x + BALL_ARC_R) > 0) {
					BALL_TUPLE[j++] = item;
				}
			}
			// 截取有效小球
			if (BALL_TUPLE.length != j) {
				BALL_TUPLE.splice(j);
			}
			console.log(BALL_TUPLE.length);
			drawBallMotion(ctx);
		}
		

	}

	// 绘画电子时钟
	function drawDigit(ctx, x, y, num, color, isChange = false) {
		ctx.fillStyle = color;
		const PI2 = 2 * Math.PI;
		let nums = digit[num];
		for (let i = 0; i < nums.length; i++) 
			for (let j = 0; j < nums[i].length; j++)
				if (digit[num][i][j] == 1) {
					let ballX = x + (BALL_ARC_R + 1) * ( 2 * j - 1);
					let ballY = y + (BALL_ARC_R + 1) * ( 2 * i - 1);
					if (isChange) {
						BALL_TUPLE.push({
							x: ballX,
							y: ballY,
							vx: Math.pow( -1, Math.ceil( Math.random() * 1000)) * 2,
							vy: -5,
							vg: 1.5 + Math.random(),
							color: COLORS[ Math.floor(Math.random() * COLORS.length)]
						})
					}
					ctx.beginPath();
					ctx.arc(ballX, ballY, BALL_ARC_R, 0, PI2);
					ctx.closePath();
					ctx.fill();
				}
	}

	// 绘画运动小球
	function drawBallMotion(ctx) {
		const PI2 = 2 * Math.PI;
		for (let item of BALL_TUPLE) {
			ctx.fillStyle = item.color;
			ctx.beginPath();
			ctx.arc(item.x, item.y, BALL_ARC_R, 0, PI2);
			ctx.closePath();
			ctx.fill();
		}
	}
</script>
</body>
</html>

在这里插入图片描述

digit.js

const digit=[[[0,0,1,1,1,0,0],[0,1,1,0,1,1,0],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[0,1,1,0,1,1,0],[0,0,1,1,1,0,0]],[[0,0,0,1,1,0,0],[0,1,1,1,1,0,0],[0,0,0,1,1,0,0],[0,0,0,1,1,0,0],[0,0,0,1,1,0,0],[0,0,0,1,1,0,0],[0,0,0,1,1,0,0],[0,0,0,1,1,0,0],[0,0,0,1,1,0,0],[1,1,1,1,1,1,1]],[[0,1,1,1,1,1,0],[1,1,0,0,0,1,1],[0,0,0,0,0,1,1],[0,0,0,0,1,1,0],[0,0,0,1,1,0,0],[0,0,1,1,0,0,0],[0,1,1,0,0,0,0],[1,1,0,0,0,0,0],[1,1,0,0,0,1,1],[1,1,1,1,1,1,1]],[[1,1,1,1,1,1,1],[0,0,0,0,0,1,1],[0,0,0,0,1,1,0],[0,0,0,1,1,0,0],[0,0,1,1,1,0,0],[0,0,0,0,1,1,0],[0,0,0,0,0,1,1],[0,0,0,0,0,1,1],[1,1,0,0,0,1,1],[0,1,1,1,1,1,0]],[[0,0,0,0,1,1,0],[0,0,0,1,1,1,0],[0,0,1,1,1,1,0],[0,1,1,0,1,1,0],[1,1,0,0,1,1,0],[1,1,1,1,1,1,1],[0,0,0,0,1,1,0],[0,0,0,0,1,1,0],[0,0,0,0,1,1,0],[0,0,0,1,1,1,1]],[[1,1,1,1,1,1,1],[1,1,0,0,0,0,0],[1,1,0,0,0,0,0],[1,1,1,1,1,1,0],[0,0,0,0,0,1,1],[0,0,0,0,0,1,1],[0,0,0,0,0,1,1],[0,0,0,0,0,1,1],[1,1,0,0,0,1,1],[0,1,1,1,1,1,0]],[[0,0,0,0,1,1,0],[0,0,1,1,0,0,0],[0,1,1,0,0,0,0],[1,1,0,0,0,0,0],[1,1,0,1,1,1,0],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[0,1,1,1,1,1,0]],[[1,1,1,1,1,1,1],[1,1,0,0,0,1,1],[0,0,0,0,1,1,0],[0,0,0,0,1,1,0],[0,0,0,1,1,0,0],[0,0,0,1,1,0,0],[0,0,1,1,0,0,0],[0,0,1,1,0,0,0],[0,0,1,1,0,0,0],[0,0,1,1,0,0,0]],[[0,1,1,1,1,1,0],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[0,1,1,1,1,1,0],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[0,1,1,1,1,1,0]],[[0,1,1,1,1,1,0],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[1,1,0,0,0,1,1],[0,1,1,1,0,1,1],[0,0,0,0,0,1,1],[0,0,0,0,0,1,1],[0,0,0,0,1,1,0],[0,0,0,1,1,0,0],[0,1,1,0,0,0,0]],[[0,0,0,0],[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0],[0,0,0,0],[0,1,1,0],[0,1,1,0],[0,0,0,0],[0,0,0,0]]];

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

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

相关文章

【AVL树的模拟实现】

1 AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决…

人工智能基础部分14-蒙特卡洛方法在人工智能中的应用及其Python实现

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能基础部分14-蒙特卡洛方法在人工智能中的应用及其Python实现&#xff0c;在人工智能领域&#xff0c;蒙特卡洛方法&#xff08;Monte Carlo Method, MCM&#xff09;被广泛应用于各种问题的求解。本文首先将…

wvp-GB28181-pro录像功能开发环境搭建、配置、使用

开发环境、调试环境搭建 开发wvp平台搭建 离线安装脚本&#xff1a;https://gitcode.net/zenglg/ubuntu_wvp_online_install.git 下载离线安装脚本&#xff0c;完成wvp平台的部署 开发环境要求 操作系统&#xff1a;包管理工具是apt ky10桌面版uos桌面版deepin桌面版ubuntu桌面…

ArmDot.NET Crack

ArmDot.NET Crack ArmDot是一个.NET加密工具&#xff0c;用于保护使用.NET编写的程序。 企业需要保护他们的知识产权&#xff0c;包括他们的算法、产品和使用的资源的源代码。 然而&#xff0c;.NET编译器会生成一个通用的可访问代码。代码中嵌入的资源很容易访问&#xff0c;并…

RocketMQ不同的类型消息

目录 普通消息 可靠同步发送 可靠异步发送 单向发送 三种发送方式的对比 顺序消息 事物消息 两个概念 事务消息发送步骤 事务消息回查步骤 消息消费要注意的细节 RocketMQ支持两种消息模式: 普通消息 RocketMQ提供三种方式来发送普通消息&#xff1a;可靠同步发送、…

剑指Offer题集(力扣)

文章目录 剑指Offer题集&#xff08;[力扣题单](https://leetcode.cn/problemset/all/?listIdlcof&page1)&#xff09;[剑指 Offer 03. 数组中重复的数字](https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/)[剑指 Offer 04. 二维数组中的查找](https:…

SSM框架练习一(登录后关联数据表的业务模型)

需要实现的整体功能&#xff1a; 登录反馈信息列表展示查询反馈信息发表反馈 1.数据库设计 创建数据库 创建表结构及其约束 添加测试数据 工具&#xff1a;PHP、Navicat create table tab_user(id int primary key auto_increment,uname varchar(30) not null,pwd varc…

Weblogic XMLDecoder 反序列化漏洞(CVE-2017-10271复现)

文章目录 前言影响版本环境搭建漏洞复现深度利用 前言 CVE-2017-10271漏洞产生的原因大致是Weblogic的WLS Security组件对外提供webservice服务&#xff0c;其中使用了XMLDecoder来解析用户传入的XML数据&#xff0c;在解析的过程中出现反序列化漏洞&#xff0c;导致可执行任意…

从搬砖工到架构师,Java全栈学习路线总结

&#x1f307;文章目录 前言一、前置知识二、 Web前端基础示例&#xff1a;1.文本域2.密码字段 三、后端基础一. Java基础二. 数据库技术三. Web开发技术四. 框架技术五. 服务器部署 四、其他技术五、全栈开发六、综合实践七、学习教程一、前端开发二、后端开发三、数据库开发四…

springboot+jsp乡村中小学校园网站建设

随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;乡村小学校园网当然也不能排除在外&#xff0c;从校园概况、学校风采、招生信息的统计和分析&#xff0c;在过程中会产生大量的…

Maven依赖原则及如何解决Maven依赖冲突

前言 在大数据应用中&#xff0c;现在发现依赖关系非常复杂&#xff0c;在上线之前很长测试&#xff0c;前一段时间在部署udf 出现了导致生产Hiveserver2 宕机问题&#xff0c;出现严重事故。现在就咨询研究一下。Maven虽然已经诞生多年&#xff0c;但仍然是当前最流行的Java系…

Arrays:点燃你的数组操作技巧的隐秘武器。

前言 数组在 Java 中是一种常用的数据结构&#xff0c;用于存储和操作大量数据。但是在处理数组中的数据&#xff0c;可能会变得复杂和繁琐。Arrays 是我们在处理数组时的一把利器。它提供了丰富的方法和功能&#xff0c;使得数组操作变得更加简单、高效和可靠。无论是排序、搜…

【c语言】字符串类型转换 | itoa函数的使用

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ …

MySQL innodb介绍

InnoDB引擎的优点是支持兼容ACID的事务&#xff0c;以及参数完整性&#xff08;即对外键的支持&#xff09;。 Oracle公司2005年10月收购了Innovase&#xff1b;Innobase采用双认证授权。它使用GNU发行&#xff0c;也允许其他想将InnoDB结合到商业软件的团体好的授权 mysql5.…

Java 动态原理详解

Java 动态代理是一种非常重要的编程技术&#xff0c;它在很多场景下都有着广泛的应用。本文将介绍 Java 动态代理的实现原理&#xff0c;并附上相应的源码&#xff0c;以帮助读者更好地理解和应用这一技术。 一、什么是 Java 动态代理&#xff1f; Java 动态代理是一种在运行时…

【并发基础】Happens-Before模型详解

目录 一、Happens-Before模型简介 二、组成Happens-Before模型的八种规则 2.1 程序顺序规则&#xff08;as-if-serial语义&#xff09; 2.2 传递性规则 2.3 volatile变量规则 2.4 监视器锁规则 2.5 start规则 2.6 Join规则 一、Happens-Before模型简介 除了显示引用vo…

双目测距--5 双目相机 联合 YOLOv8

目录 效果&#xff1a; 1、立体矫正不改变图像尺寸 2、视差图尺寸与原图尺寸一致 3、视差图、深度信息图 4、几个重要的函数 createTracker() 5、代码 main.cpp utils.cpp 效果&#xff1a; 1、立体矫正不改变图像尺寸 左右相机图像立体矫正后&#xff0c;图像尺寸为变化…

freeRTOS中使用看门狗的一点思考

关于看门狗想必各位嵌入式软件开发的朋友应该都不会陌生的。在嵌入式软件开发中&#xff0c;看门狗常被用于监测cpu的程序是否正常在运行&#xff0c;如果cpu程序运行异常会由看门狗在达到设定的阈值时触发复位&#xff0c;从而让整个cpu复位重新开始运行。 看门狗的本质是一个…

Qt QQueue 安全的多线程队列、阻塞队列

文章目录 1. C queue 队列基本用法2. Qt QQueue 队列基本用法3. Qt QQueue 多线程队列4. Qt BlockingQueue 自定义线程安全的阻塞队列 1. C queue 队列基本用法 在C中&#xff0c;queue是一个模板类&#xff0c;用于实现队列数据结构&#xff0c;遵循先进先出的原则。 ♦ 常用…

测试3:用例

目录 1.测试用例的基本要素 2.测试用例的设计方法 1.基于需求的设计方法 2.等价类 1.概念 2.步骤: 3.例子 3.边界值 1.概念 2.步骤 3.例子 4.判定表 1.概念 2.设计测试用例 3.例子 5.正交排列 1.什么是正交表 2.测试用例 3.如何通过正交表设计测试用例 6.场景…