基于Canvas的Html5多时区动态时钟实战

news2024/10/6 22:23:18

目录

前言

一、关于Canvas技术

1、Canvas是什么

2、Canvas的属性及渲染特性

二、Canvas动态多时区展示

1、新建html页面

2、创建Canvas对象

3、绘制所有的时钟

总结


前言

        出差旅行相信大家一定会住酒店,大家在酒店的前台进行预订的时候,是不是都会留意。通常在大堂的前方会有一面时钟,大概是下面这种样子:

        这里只是一个截图,其实不太完整。上面详细的罗列了巴黎、北京、纽约、伦敦、莫斯科、东京等城市的时间。 通常来说,之所以要展示这么多的时钟,一般是对外的酒店,所面向的客人很多都是外国人,他们来自于四面八方,需要将时间和自己国家的时间一致,也是对时间同步的一种保障,这是一种服务力的体现。

        当然,上面这种是实体的钟,需要实体钟表的采购成本。现在电子屏已经很常见也很普及,那么有没有可能将Web界面投放到电子屏中,实现电子钟的web化展示,加上前端的样式控制,应该也是可以满足酒店等场所的显示需求。也因此有了本文和相关的程序设计。

        本文即以Canvas为基础,以支持多时区的多时钟的动态Web展示为例。实现一种在Html5上的电子钟展示方法,首先介绍Canvas是什么,然后具体介绍如何进行时钟的绘制,其次介绍时钟的多时区支持,最后给出运行的实际效果。通过本文可以了解Canvas的详细用法,掌握基本的文本绘制、样式控制、属性管理的基本知识,通过多时钟的展示场景,将各个知识点融会贯通。如果您想了解Canvas的使用方法,可以来这里看看,有什么疑问的也可以在评论区留言交流。

一、关于Canvas技术

        虽然Canvas不是最新的技术,相信很多朋友也不是很熟悉,因此本节还是花一点时间简单的将Canvas的知识做个介绍,让大家有个基本的了解,为下一节内容的讲解打下基础。主要包含三个部分,首先介绍canvas是什么,然后介绍它的语法。更详细的内容,大家可以去看html的教程,上面有详细的描述。

1、Canvas是什么

        Canvas API(画布)是在HTML5中新增的标签用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图(bitmap)。Canvas 对象表示一个 HTML 画布元素 -<canvas>。<canvas> 标记由 Apple 在 Safari 1.3 Web 浏览器中引入。对 HTML 的这一根本扩展的原因在于,HTML 在 Safari 中的绘图能力也为 Mac OS X 桌面的 Dashboard 组件所使用,并且 Apple 希望有一种方式在 Dashboard 中支持脚本化的图形。Firefox 1.5 和 Opera 9 都跟随了 Safari 的引领。这两个浏览器都支持 <canvas> 标记。我们甚至可以在 IE 中使用 <canvas> 标记,并在 IE 的 VML 支持的基础上用开源的 JavaScript 代码(由 Google 发起)来构建兼容性的画布。<canvas> 的标准化的努力由一个 Web 浏览器厂商的非正式协会在推进, <canvas> 已经成为 HTML 5 草案中一个正式的标签。

        在现代 Web 开发中,开发者们更多的会借助 Canvas 提供的API去绘制上下文,可以自由绘制各种2D和3D图形,创建富有视觉冲击力的游戏场景和角色。Canvas的使用可以使得游戏能够实现流畅的动态效果和用户交互。无论是简单的小游戏还是复杂的游戏引擎,Canvas 都被广泛应用。

        在WebGIS开发当中,canvas也是一个非常重要的展示场景,比如我们之前用过的动态标绘组件,也是基于Canvas来实现的,它的性能是非常高的。不管是面向2D还是3D的场景,canvas都有用武之地。

2、Canvas的属性及渲染特性

        Canvas的属性比较简单,而且它的属性比较简单,跟普通的Html标签的属性是一致的,也可以使用如ID、高度和宽度这几个属性。其作用就不再赘述,比较简单。canvas的强大还是取决于它的渲染特性,因此这里简单介绍一下Canvas的渲染特性。

        说高性能渲染时得说说DOM驻留模式和Canvas快速模式。

        DOM驻留模式:一种基于文档对象模型(DOM)的渲染技术。在DOM驻留模式下,页面的布局和样式是由DOM树来掌管的。当页面需要更新时,浏览器会重新计算布局和样式并重新渲染。此模式非常灵活,特别适用于处理动态页面交互和多样化的样式控制。

        Canvas快速模式:利用HTML5的Canvas元素进行图形渲染。开发者可以使用Canvas提供的2D或3D绘图API直接在画布上绘制图形。相比于DOM驻留模式,Canvas快速模式更加高效。它不关心页面的布局和样式,而是在需要时只重绘受影响的部分。

        分层提高Canvas性能:可以进一步提升Canvas性能的策略,即对变化较少和变化较多的内容进行分开渲染。它能够显著降低完全没有必要的渲染性能开销。分层渲染的思想被广泛应用于各种图形相关的领域,从古老的皮影戏、套色印刷术,到现代电影/游戏工业以及虚拟现实领域等等。

        上面简单的对Canvas的相关知识进行简单介绍,有了上述的基本知识,下面结合实例讲解Canvas的多时区时钟动态展示。

二、Canvas动态多时区展示

        在了解Canvas的基本知识以后,我们来介绍Canvas的基本使用。在这个实例中,我们需要在Html5页面中,使用Canvas绘制6个不同城市的时钟,并且要在时钟上标注是属于哪个城市,其对应的24小时制时间是多少,同时时钟要可以动态转动。本节即以详细代码的形式进行讲解。

1、新建html页面

        Canvas也是建立在Html页面上的组件,因此想要把Canvas渲染出来,就一定要创建展示的基础。新建一个html文件,关键代码如下所示:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Canvas 多时区时钟可视化</title>
    <style>
        body {
            background-color: #F5F5F5;
        }
        canvas {
            border: 1px dashed #444;
        }
    </style>
</head>
<body>
	<table style="width:99%;margin: auto;align:center;">
		<tbody>
			<tr>
				<td >
					<canvas id="clock0" width="300" height="300"></canvas>
				</td>
				<td>
					<canvas id="clock1" width="300" height="300"></canvas>
				</td>
				<td>
					<canvas id="clock2" width="300" height="300"></canvas>
				</td>
			</tr>
			<tr>
				<td>
					<canvas id="clock3" width="300" height="300"></canvas>
				</td>
				<td>
					<canvas id="clock4" width="300" height="300"></canvas>
				</td>
				<td>
					<canvas id="clock5" width="300" height="300"></canvas>
				</td>
			</tr>
		</tbody>
	</table>
</body>
</html>

        这里仅展示Canvas的功能API,对于页面的特效样式没有做过多的设置,如果是真实项目,建议在这个基础上狠狠地记性样式的修改,改造成符合项目需要的美观的。上面采用table布局,为了展示6个不同城市的时钟,我们使用两行三列的布局模式,每个单元格展示一个时钟。为了实现动态的控制这些时钟,比如第一个时钟用来显示纽约的时间,因此有必要使用id对每个canvas进行分别定义。

2、创建Canvas对象

        在创建了html页面展示元素之后,我们还需要使用canvas来绘制时钟的效果,为了能实现时钟的动态效果,我们将canvas的id属性从0-5分别设置为clock0-clock5,分别用来代表"纽约","伦敦","巴黎","莫斯科","北京","东京"这五个不同时区的城市。为了在后面的时间绘制中能精准控制,我们将所有的Canvas创建出来之后,设置到对应的数组当中。

//创建时钟数组
var clockArray = new Array();
var timeZoneArray = ["纽约","伦敦","巴黎","莫斯科","北京","东京"];
for(var i = 0;i < 6; i++){
	const canvas = document.getElementById("clock" + i);
	const ctx = canvas.getContext("2d");
	const centerX = canvas.width / 2;
	const centerY = canvas.height / 2;
	// 将坐标系移动到中心点
	ctx.translate(centerX, centerY);
	clockArray.push(canvas);
}

3、绘制所有的时钟

        将Canvas创建出来后,就可以进行时钟的绘制了。下面将结合源码来详细介绍如何进行时钟的绘制。

function drawClock() {
     const now = new Date();
	for(var j = 0;j < 6;j++){
		var _canvas = clockArray[j];
		var _ctx = _canvas.getContext("2d");
		const radius = _canvas.width / 2 - 5;
		const centerX = _canvas.width / 2;
		const centerY = _canvas.height / 2;
		_ctx.clearRect(-centerX, -centerY, _canvas.width, _canvas.height); // 每次绘制前清空整个画布
		_ctx.beginPath();
		_ctx.arc(0, 0, radius, 0, 2 * Math.PI);
		_ctx.stroke();

		// 绘制钟表数字
		_ctx.textAlign = "center";
		_ctx.textBaseline = "middle";
		_ctx.font = "20px sans-serif";
		var text = timeZoneArray[j];
		_ctx.strokeText(text + "时间", 2, - 80);
				
		_ctx.font = "bold 14px Arial";
		drawClockNumber(_ctx,radius);//绘制数字
			   
		// 绘制时针
		var bjHour = now.getHours();
		//获取小时
		var hour = getHour(j,bjHour);
				
		var minute = now.getMinutes();
		var second = now.getSeconds();
		drawShowTime(_ctx,hour,minute,second);//绘制当前时间
				
		var hourAngle = (hour % 12 + minute / 60 + second / 3600) * Math.PI / 6;
		var hourLength = 0.6 * radius;
		var hourX = Math.sin(hourAngle) * hourLength;
		var hourY = -Math.cos(hourAngle) * hourLength;

		_ctx.beginPath();
		_ctx.moveTo(0, 0);
		_ctx.lineTo(hourX, hourY);
		_ctx.lineWidth = 4;
		_ctx.lineCap = "round";
		_ctx.stroke();

		// 绘制分针
		const minuteAngle = (minute + second / 60) * Math.PI / 30;
		const minuteLength = 0.8 * radius;
		const minuteX = Math.sin(minuteAngle) * minuteLength;
		const minuteY = -Math.cos(minuteAngle) * minuteLength;

		_ctx.beginPath();
		_ctx.moveTo(0, 0);
		_ctx.lineTo(minuteX, minuteY);
		_ctx.lineWidth = 2;
		_ctx.stroke();

		// 绘制秒针
		const secondAngle = second * Math.PI / 30;
		const secondLength = 0.9 * radius;
		const secondX = Math.sin(secondAngle) * secondLength;
		const secondY = -Math.cos(secondAngle) * secondLength;
		drawScale(_ctx,radius);//绘制刻度
        _ctx.beginPath();
		_ctx.moveTo(0, 0);
		_ctx.lineTo(secondX, secondY);
		_ctx.lineWidth = 1;
		_ctx.strokeStyle = "red"; // 设置颜色
		_ctx.stroke();

		// 绘制中央圆点
		_ctx.beginPath();
		_ctx.arc(0, 0, 5, 0, 2 * Math.PI);
		_ctx.fillStyle = "#333"; // 设置颜色
		_ctx.fill();
	}
			
    // 循环绘制
    setTimeout(drawClock, 1000);
}

        上面的代码非常详细的给出了时钟的展示过程,下面将绘制的步骤进行了简单的介绍。

        首先获取canvas对象,并且清空画布,因为时钟每隔一秒即变化,同时分针秒针都要发生不断地变化,这些就像橡皮擦一样,要不断擦除和不断重新绘制。

        然后在表盘中绘制具体是什么时间,比如北京时间,绘制后如下图所示:

        接下来就是绘制时钟的数字刻度,比如1到12这几个数字,如下图所示:

//绘制刻度
function drawClockNumber(_ctx,radius){
	for (let i = 1; i <= 12; i++) {
			var angle = i * Math.PI / 6;
			_ctx.rotate(angle);
			_ctx.translate(0, -radius + 15);
			_ctx.rotate(-angle);
			_ctx.fillText(i.toString(), 0, 0);
			_ctx.rotate(angle);
			_ctx.translate(0, radius - 15);
			_ctx.rotate(-angle)
	}
}

 绘制刻度的具体代码:

// 绘制刻度
		function drawScale(_ctx,radius){
			// 假设最大刻度线长度是半径的5%
			const maxMajorTickLength = radius * 0.05; // 较大刻度线长度
			const maxMinorTickLength = radius * 0.025; // 较小刻度线长度
			for (let m = 0; m < 60; m++) {
				// 计算每个刻度的角度
				const minuteAngle = m * Math.PI / 30;
				// 根据分钟数决定刻度线的长度
				let tickLength;
				if (m % 5 === 0) {
					// 如果是每5分钟的刻度,使用较大刻度线长度
					tickLength = maxMajorTickLength;
				} else {
					// 否则使用较小刻度线长度
					tickLength = maxMinorTickLength;
				}
				// 计算刻度线端点的坐标
				var x1 = Math.sin(minuteAngle) * radius; // 圆边缘的x坐标
				var y1 = -Math.cos(minuteAngle) * radius; // 圆边缘的y坐标
				var x2 = Math.sin(minuteAngle) * (radius - tickLength); // 刻度线端点的x坐标
				var y2 = -Math.cos(minuteAngle) * (radius - tickLength); // 刻度线端点的y坐标

				// 绘制刻度线
				_ctx.beginPath();
				_ctx.moveTo(x1, y1); // 从圆边缘开始
				_ctx.lineTo(x2, y2); // 向内延伸到刻度线端点
				_ctx.stroke();
			}
		}

        在绘制刻度的这里,我刚开始一直没成功,主要原因是没掌握方法,刻度的两个起始点没绘制准确,因此导致了刻度绘制一直不准确,请记得一定计算好位置,尤其是使用moveTo和lineTo两个方法类调整,主要刻度从圆边缘开始,而不要movoTo(0,0),这样从圆心开始,绘制出来的效果就不对了。

        由于这6个城市分别属于6个不同的时区,因此也就造成了这6个城市的时间是不一样的,也就是我们常说的时差,通过查找资料可以知道,这里每个城市的时差大约是如下代码表示的。

function getHour(index,bjHour){
			var hour = bjHour; // bjHour是北京时间的小时数
			var offset; // 定义时区偏移量
			// 根据时区索引计算偏移量
			switch(index) {
				case 0: // 纽约 (北京时间比纽约快13小时)
					offset = -13;
					break;
				case 1: // 伦敦 (北京时间比伦敦快8小时)
					offset = -8;
					break;
				case 2: // 巴黎 (北京时间比巴黎快7小时)
					offset = -7;
					break;
				case 3: // 莫斯科 (北京时间比莫斯科快5小时)
					offset = -5;
					break;
				case 4: // 北京 (默认为北京时间)
					offset = 0;
					break;
				case 5: // 东京 (假设北京时间比东京慢1小时)
					offset = 1;
					break;
				default: // 如果索引不在预期范围内,返回原始小时数
					return hour;
			}

			// 应用时区偏移量,并确保小时数在0到23之间
			hour += offset;
			hour = (hour + 24) % 24; // 循环处理,确保结果在24小时制内

			return hour;
		}

        这里通过计算偏移量的方式来计算城市的时间,刚开始没有注意,这样计算出来的结果,会有不准确,因此才采用了时区偏移的处理方式,这样出来能保证每个时钟都是24小时之内。当然,为了计算方便,您也可以直接使用我上面的转换逻,是可以直接使用的。

        经过上面的代码,就可以实现时钟的动态展示。效果如下所示:

总结

        以上就是本文的主要内容,本文以Canvas为基础,支持多时区的多时钟的动态Web展示为例实现一种在Html5上的电子钟展示方法,首先介绍Canvas是什么,然后具体介绍如何进行时钟的绘制,其次介绍时钟的多时区支持,最后给出运行的实际效果。通过本文可以了解Canvas的详细用法,掌握基本的文本绘制、样式控制、属性管理的基本知识,通过多时钟的展示场景,将各个知识点融会贯通。如果您想了解Canvas的使用方法,可以来这里看看。行文仓促,定有诸多不足之处,欢迎各位专家朋友有什么疑问的也可以在评论区留言交流。

        为方便朋友们学习,源码已经上传至资源,大家可以下载:源码传送地址。

        博客编写过程中参考以下内容,供参考:

1、【技术干货】高性能渲染:一文详解HTML Canvas的优势与性能。

2、canvas 百度百科。

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

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

相关文章

简单实现Anaconda/Miniforge虚拟环境的克隆和迁移

简单实现Anaconda/Miniforge虚拟环境的克隆和迁移 一、问题描述一、方式一&#xff1a;使用命令克隆二、方式二&#xff1a;直接复制粘贴 欢迎学习交流&#xff01; 邮箱&#xff1a; z…1…6.com 网站&#xff1a; https://zephyrhours.github.io/ 一、问题描述 使用Anaconda…

【Node-RED 4.0.2】4.0版本新增特性(官方版)

二、重要功能 *1.时间戳格式改进 过去&#xff0c;node-red 只提供了 最原始的 timestamp 的格式&#xff08;1970-01-01 ~ now&#xff09; 但是现在&#xff0c;额外增加了 2 种格式&#xff1a; ISO 8601 -A COMMON FORMAT&#xff08;YYYY-MM-DDTHH:mm:ss:sssZ&#xff…

Cocos制作抖音小游戏接入侧边栏复访接口实例

本篇文章主要讲解&#xff0c;使用cocos接入抖音小游戏侧边栏接口的实例教程。 日期&#xff1a;2024年7月1日 作者&#xff1a;任聪聪 教程实例&#xff1a;https://download.csdn.net/download/hj960511/89509196 下载后可直接导入运行 上传游戏后抖音预审不通过 注意&#x…

如何找BMS算法、BMS软件的实习

之前一直忙&#xff0c;好久没有更新了&#xff0c;今天就来写一篇文章来介绍如何找BMS方向的实习&#xff0c;以及需要具备哪些条件&#xff0c;我的实习经历都是在读研阶段找的&#xff0c;读研期间两段的实习经历再加上最高影响因子9.4分的论文&#xff0c;我的秋招可以说是…

张颂文百花提名,男配界笑出“颂”彩

在这个星光熠熠的百花奖舞台上&#xff0c; 张颂文老师犹如一坛陈年老酒&#xff0c;越品越有味&#xff0c; 竟不声不响地提名了最佳男配角&#xff01;这下可好&#xff0c; 男配界仿佛一夜之间被“颂”风吹得花枝乱颤&#xff0c;笑料百出。你说张颂文老师这演技&#xf…

Linux_fileio实现copy文件

参考韦东山老师教程&#xff1a;https://www.bilibili.com/video/BV1kk4y117Tu?p12 目录 1. 通过read方式copy文件2. 通过mmap映射方式copy文件 1. 通过read方式copy文件 copy文件代码&#xff1a; #include <sys/types.h> #include <sys/stat.h> #include <…

补浏览器环境

一&#xff0c;导言 // global是node中的关键字&#xff08;全局变量&#xff09;&#xff0c;在node中调用其中的元素时&#xff0c;可以直接引用&#xff0c;不用加global前缀&#xff0c;和浏览器中的window类似&#xff1b;在浏览器中可能会使用window前缀&#xff1a;win…

comfyui定制外包

&#x1f308; 最强AI绘画comfyui模型训练、定制服务公司出炉 —— 触站AI&#xff0c;引领设计智能新潮流 &#x1f680; &#x1f3a8; 触站AI&#xff0c;以AI绘画模型训练重塑设计边界 &#x1f3a8;在AI技术的浪潮中&#xff0c;触站AI以其前沿的AI绘画模型训练技术&…

cesium 添加 Echarts图层(人口迁徒图)

cesium 添加 Echarts 人口迁徒图(下面附有源码) 1、实现思路 1、在scene上面新增一个canvas画布 2、通坐标转换,将经纬度坐标转为屏幕坐标来实现 3、将ecarts 中每个series数组中元素都加 coordinateSystem: ‘cesiumEcharts’ 2、示例代码 <!DOCTYPE html> <ht…

java反射和注解

反射 获取class对象的三种方法 ①&#xff1a;Class.forName("全类名"); ②&#xff1a;类名.class ③&#xff1a;对象.getclass(); 代码样例 package com.ithema;public class Main {public static void main(String[] args) throws ClassNotFoundException {//第…

Centos7修改yum源

安装好系统后&#xff0c;网络能通信&#xff0c;源也没有配置&#xff0c;但是安装软件失败。 解决办法&#xff1a;配置阿里yum源 # curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo # yum clean all # yum make cache再次安装软…

阿里228x82y还原之递归数组解密

声明 本文章中所有内容仅供学习交流&#xff0c;抓包内容、敏感网址、数据接口均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff0c;若有侵权&#xff0c;请联系我立即删除&#xff01; 目标网站 某里228 分析逆…

详解C语言分支与循环语句

分支语句 if elseswitch 循环语句 whilefordo while goto语句 文章目录 1.什么是语句2.分支语句&#xff08;选择结构&#xff09;2.1 if语句2.1.1 悬空else2.1.3 练习 2.2 switch语句2.2.1 在switch语句中的break2.2.2 default子句 3.循环语句3.1 while循环3.1.1 while语句中…

Studying-代码随想录训练营day26| 491.递增子序列、46.全排列、47.全排列 II、51.N皇后、37.解数独、回溯总结

第26天&#xff0c;回溯part04&#xff0c;昨天休息复习总结回溯内容&#xff0c;&#x1f4aa;(ง •_•)ง&#x1f4aa; 目录 491.递增子序列 46.全排列 47.全排列 II 51.N皇后 37.解数独 回溯总结 491.递增子序列 文档讲解&#xff1a;代码随想录递增子序列 视频讲…

3D Gaussian Splatting代码中的forward和backward两个文件代码解读

3dgs代码前向传播部分 先来讨论一下glm&#xff0c;因为定义变量的时候用到了这个。 glm的解释 glm 是指 OpenGL Mathematics&#xff0c;这是一个针对图形编程的数学库。它的全称是 OpenGL Mathematics (GLM)&#xff0c;主要用于 OpenGL 的开发。这个库是基于 C 的模板库&…

递归算法练习

112. 路径总和 package Tree;import java.util.HashMap; import java.util.Map;class TreeNode {int val;TreeNode left;TreeNode right;public TreeNode(int val) {this.val val;} }/*** 求 树的路径和* <p>* 递归 递减* <p>* 询问是否存在从*当前节点 root 到叶…

现代工作场所中的睡岗检测算法应用

在现代职场环境中&#xff0c;员工的工作状态直接影响到公司的整体效益。睡岗现象&#xff0c;即员工在工作时间内打瞌睡或睡觉&#xff0c;不仅降低了生产力&#xff0c;还可能带来安全隐患。因此&#xff0c;如何有效地检测和预防睡岗行为成为了企业管理中的一个重要课题。随…

The Sandbox 通过创作者挑战推动社区参与

游戏开发者并不是每天都有机会让自己的作品赢得大奖。但在 The Sandbox&#xff0c;这已经成为一种趋势&#xff01;首届 "创作者挑战 "让顶尖创作者将 150 万 SAND 捧回家。现在&#xff0c;我们要带着另一个巨额奖池回来了&#xff01; 关于首届创作者挑战&#xf…

02.C1W1.Sentiment Analysis with Logistic Regression

目录 Supervised ML and Sentiment AnalysisSupervised ML (training)Sentiment analysis Vocabulary and Feature ExtractionVocabularyFeature extractionSparse representations and some of their issues Negative and Positive FrequenciesFeature extraction with freque…

Vue.js中的计算属性:如何让数据自动更新

引言 在Vue.js的世界里&#xff0c;computed属性就像是你的智能助手&#xff0c;它能自动追踪变化&#xff0c;帮你快速做出反应。想象一下&#xff0c;你在做一道菜&#xff0c;调料&#xff08;数据&#xff09;一变&#xff0c;味道&#xff08;界面&#xff09;立刻跟上。…