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

目录

前言

一、关于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.mfbz.cn/a/765496.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【开发篇】明明配置跨域声明,为什么却仍可以发送HTTP请求

一、问题 在SpringBoot项目中&#xff0c;明确指定仅允许指定网站跨域访问&#xff1a; 为什么开发人员却仍旧可以通过HTTP工具调用接口&#xff1f; 二、为什么 在回答这个问题之前&#xff0c;我们首先要了解一下什么是CORS&#xff01; 1、什么是CORS CORS的全称为跨域资源…

TOGAF培训什么内容?参加TOGAF培训有什么好处?考试通过率多少?

TOGAF培训什么内容&#xff1f;参加TOGAF培训有什么好处&#xff1f;考试通过率多少&#xff1f; TOGAF培训哪些内容&#xff1f; 通过本课程&#xff0c;你将掌握TOGAF的理论和实践&#xff0c;理解企业架构的影响&#xff0c;能够评估、启动、设 计、执行新一轮企业和IT架构…

实用软件分享-----一款免费的投屏软件(支持手机投屏到电脑)Aiseesoft Phone Mirror 2.2.36 x64

专栏介绍:本专栏主要分享一些实用的软件(Po Jie版); 声明1:软件不保证时效性;只能保证在写本文时,该软件是可用的;不保证后续时间该软件能一直正常运行;不保证没有bug;如果软件不可用了,我知道后会第一时间在题目上注明(已失效)。介意者请勿订阅。 声明2:本专栏的…

燃料电池混合电源的能量管理系统

这个例子显示了燃料电池混合电源的能量管理系统。 这个例子展示了燃料电池混合电源的能量管理系统。 电路描述 本文给出了基于燃料电池的多电动飞机应急动力系统的仿真模型。随着MEA中起落架和飞控系统的电气化程度的提高&#xff0c;常规应急电源系统(冲压式空气涡轮或空气驱…

分解+降维+预测!多重创新!直接写核心!EMD-KPCA-Transformer多变量时间序列光伏功率预测

分解降维预测&#xff01;多重创新&#xff01;直接写核心&#xff01;EMD-KPCA-Transformer多变量时间序列光伏功率预测 目录 分解降维预测&#xff01;多重创新&#xff01;直接写核心&#xff01;EMD-KPCA-Transformer多变量时间序列光伏功率预测效果一览基本介绍程序设计参…

WSL2安装ContOS7并更新gcc

目录 WSL2安装CentOS7下载安装包安装启动CentOS7 CentOS7更换国内源gcc从源码安装gcc卸载gcc CMake中使用gcc关于linux配置文件参考 WSL2安装CentOS7 Windows11官方WSL2已经支持Ubuntu、Open SUSE、Debian。但是没有centos&#xff0c;所以centos的安装方式略有不同。 下载安…

cesium 聚合

cesium 聚合(下面附有源码) 示例代码 <html lang="en"><head><!-- Use correct character set. -->

你喜欢波段交易吗?

波段交易的核心在于精准捕捉市场中的长期趋势波动&#xff0c;以实现更为稳健的收益。与剥头皮和日内交易不同&#xff0c;波段交易者更倾向于持有交易头寸数日乃至数周&#xff0c;以更宽广的视角把握市场动态。 这种交易方式的优势在于&#xff0c;它降低了对即时市场反应的…

思考如何学习一门编程语言?

一、什么是编程语言 编程语言是一种用于编写计算机程序的人工语言。通过编程语言&#xff0c;程序员可以向计算机发出指令&#xff0c;控制计算机执行各种任务和操作。编程语言由一组语法规则和语义规则组成&#xff0c;这些规则定义了如何编写代码以及代码的含义。 编程语言…

详解反向传播(BP)算法

文章目录 what&#xff08;是什么&#xff09;where&#xff08;用在哪&#xff09;How&#xff08;原理&&怎么用&#xff09;原理以及推导过程pytorch中的反向传播 what&#xff08;是什么&#xff09; 反向传播算法&#xff08;Backpropagation&#xff09;是一种用于…

鸿蒙开发Ability Kit(程序访问控制):【安全控件概述】

安全控件概述 安全控件是系统提供的一组系统实现的ArkUI组件&#xff0c;应用集成这类组件就可以实现在用户点击后自动授权&#xff0c;而无需弹窗授权。它们可以作为一种“特殊的按钮”融入应用页面&#xff0c;实现用户点击即许可的设计思路。 相较于动态申请权限的方式&am…

【聊聊原子性,中断,以及nodejs中的具体示例】

什么是原子性 从一个例子说起&#xff0c; x &#xff0c;读和写 &#xff0c; 如图假设多线程&#xff0c;线程1和线程2同时操作变量x&#xff0c;进行x的操作&#xff0c;那么由于写的过程中&#xff0c;都会先读一份x数据到cpu的寄存器中&#xff0c;所以这个时候cpu1 和 c…

【ONLYOFFICE】| 桌面编辑器从0-1使用初体验

目录 一. &#x1f981; 写在前面二. &#x1f981; 在线使用感受2.1 创建 ONLYOFFICE 账号2.2 编辑pdf文档2.3 pdf直接创建表格 三. &#x1f981; 写在最后 一. &#x1f981; 写在前面 所谓桌面编辑器就是一种用于编辑文本、图像、视频等多种自媒体的软件工具&#xff0c;具…

OBS 免费的录屏软件

一、下载 obs 【OBS】OBS Studio 的安装、参数设置和录屏、摄像头使用教程-CSDN博客 二、使用 obs & 输出无黑屏 【OBS任意指定区域录屏的方法-哔哩哔哩】 https://b23.tv/aM0hj8A OBS任意指定区域录屏的方法_哔哩哔哩_bilibili 步骤&#xff1a; 1&#xff09;获取区域…

Qt源码分析:窗体绘制与响应

作为一套开源跨平台的UI代码库&#xff0c;窗体绘制与响应自然是最为基本的功能。在前面的博文中&#xff0c;已就Qt中的元对象系统(反射机制)、事件循环等基础内容进行了分析&#xff0c;并捎带阐述了窗体响应相关的内容。因此&#xff0c;本文着重分析Qt中窗体绘制相关的内容…

Vue3快速上手--3小时掌握

1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;n经历了&#xff1a;4800次提交、40个RFC、600次PR、300贡献者官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core截止2023年10月&#xff0c;最新的…

阿里Nacos下载、安装(保姆篇)

文章目录 Nacos下载版本选择Nacos安装Windows常见问题解决 更多相关内容可查看 Nacos下载 Nacos官方下载地址&#xff1a;https://github.com/alibaba/nacos/releases 码云拉取&#xff08;如果国外较慢或者拉取超时可以试一下国内地址&#xff09; //国外 git clone https:…

数组-长度最小的子数组

M长度最小的子数组&#xff08;leetcode209&#xff09; /*** param {number} target* param {number[]} nums* return {number}*/ var minSubArrayLen function(target, nums) {const n nums.length;let ans n 1;let sum 0; // 子数组元素和let left 0; // 子数组…

美团实习—后端开发凉经

面试经历分享 日期&#xff1a; 4月22日时长&#xff1a; 50分钟 意外之喜 没想到在面试过程中&#xff0c;我再次被选中进行下一轮&#xff0c;这确实让我感到有些意外和欣喜。这次面试经历对我而言&#xff0c;不仅是一次技能的检验&#xff0c;更是一次知…

MySQL:设计数据库与操作

设计数据库 1. 数据建模1.1 概念模型1.2 逻辑模型1.3 实体模型主键外键外键约束 2. 标准化2.1 第一范式2.2 链接表2.3 第二范式2.4 第三范式 3. 数据库模型修改3.1 模型的正向工程3.2 同步数据库模型3.3 模型的逆向工程3.4 实际应用建议 4. 数据库实体模型4.1 创建和删除数据库…