Highcharts实战:基于Gauge仪表盘打造实时动态时钟可视化开发全解析
先上Highcharts 时钟的Code,直接复制用! 
javascript
/**
* Get the current time
*/
const getNow = () => {
const now = new Date();
return {
date: now,
hours: now.getHours() + now.getMinutes() / 60,
minutes: now.getMinutes() * 12 / 60 + now.getSeconds() * 12 / 3600,
seconds: now.getSeconds() * 12 / 60
};
};
let now = getNow();
// Create the chart
Highcharts.chart('container', {
chart: {
type: 'gauge',
plotBackgroundColor: null,
plotBackgroundImage: null,
plotBorderWidth: 0,
plotShadow: false,
height: '80%'
},
credits: {
enabled: false
},
title: {
text: 'The Highcharts Clock'
},
pane: {
background: [{
borderWidth: 1,
outerRadius: '105%'
}, {
// reflex for supported browsers
backgroundColor: {
radialGradient: {
cx: 0.5,
cy: -0.4,
r: 1.9
},
stops: [
[0.5, 'rgba(255, 255, 255, 0.2)'],
[0.5, 'rgba(200, 200, 200, 0.2)']
]
}
}],
startAngle: 0,
endAngle: 360,
innerSize: 0
},
yAxis: {
labels: {
distance: -23,
style: {
fontSize: '18px'
}
},
min: 0,
max: 12,
lineWidth: 0,
showFirstLabel: false,
offset: 0,
minorTickInterval: 'auto',
minorTickWidth: 3,
minorTickLength: 5,
minorTickPosition: 'inside',
minorTicksPerMajor: 5,
minorGridLineWidth: 0,
tickInterval: 1,
tickWidth: 4,
tickPosition: 'inside',
tickLength: 10,
title: {
text: 'Powered by<br/>Highcharts',
style: {
color: '#BBB',
fontWeight: 'normal',
fontSize: '10px',
lineHeight: '10px'
},
y: 10
}
},
tooltip: {
format: '{series.chart.tooltipText}'
},
series: [{
data: [{
id: 'hour',
y: now.hours,
dial: {
radius: '60%',
baseWidth: 6,
baseLength: '95%',
rearLength: 0,
topWidth: 1,
borderRadius: 0
}
}, {
id: 'minute',
y: now.minutes,
dial: {
baseLength: '95%',
baseWidth: 4,
rearLength: 0,
topWidth: 1,
borderRadius: 0
}
}, {
id: 'second',
y: now.seconds,
dial: {
radius: '100%',
baseWidth: 1,
topWidth: 1,
rearLength: '20%'
}
}],
animation: false,
dataLabels: {
enabled: false
}
}]
},
// Move
function (chart) {
setInterval(function () {
now = getNow();
if (chart.axes) { // not destroyed
const hour = chart.get('hour'),
minute = chart.get('minute'),
second = chart.get('second');
// Cache the tooltip text
chart.tooltipText = Highcharts.dateFormat('%H:%M:%S', now.date);
hour.update(now.hours, true, false);
minute.update(now.minutes, true, false);
// Move to 59 sec without animation ...
if (now.seconds === 0) {
second.update(-0.2, true, false);
}
// ... then bounce to next second
second.update(now.seconds, true, {
easing: 'easeOutBounce'
});
}
}, 1000);
});
/**
* Easing function from https://github.com/danro/easing-js/blob/master/easing.js
*/
Math.easeOutBounce = function (pos) {
if ((pos) < (1 / 2.75)) {
return (7.5625 * pos * pos);
}
if (pos < (2 / 2.75)) {
return (7.5625 * (pos -= (1.5 / 2.75)) * pos + 0.75);
}
if (pos < (2.5 / 2.75)) {
return (7.5625 * (pos -= (2.25 / 2.75)) * pos + 0.9375);
}
return (7.5625 * (pos -= (2.625 / 2.75)) * pos + 0.984375);
};
一、前言:可视化大屏里,时钟为何要用专业图表库实现?
很多前端开发从业者会有固有认知:时钟仅属于简单UI组件,通过CSS+定时器就能快速实现,没必要引入重型图表库。
但在政企大屏、工业控制、数字孪生、金融交易中心这类企业级可视化项目中,时间展示模块从来不是单纯"看时间",而是一套高实时性动态数据可视化载体。 结合落地项目,典型应用场景包含:
- 智慧城市指挥大屏:多时区全球同步时钟面板
- 产线工控操作台:设备累计运行时长监控表盘
- 航空航天任务管控系统:任务计时、发射倒计时表盘
- 证券交易大厅:开盘/收盘倒计时、市场实时计时
- 园区数字孪生驾驶舱:全域统一标准时间同步展示
- 集团运营监控中心:多分支机构时间统一展示
这类业务场景对时间组件有硬性技术要求:高精度帧级刷新、多指针联动平滑动画、全自定义表盘主题、支持与折线/柱状/热力图等图表数据联动、兼容大屏4K自适应渲染。
Highcharts内置的Gauge仪表盘系列,底层基于SVG矢量渲染,原生支持多指针、自定义圆弧、分段刻度、弹性动画,无需手动绘制坐标系,是实现专业级动态时钟的最优方案之一。本文基于Highcharts官方时钟Demo改造落地,拆解底层实现逻辑、核心API、动画原理,同时补充工业大屏落地优化方案。
二、成品效果预览:三指针机械风格实时时钟
案例完整复刻传统机械钟表视觉逻辑,包含独立时针、分针、秒针三组动态指针,每秒自动刷新角度:
- 时针:粗短,随分钟缓慢偏移,不生硬整点跳转
- 分针:中等粗细,随秒数微小偏移
- 秒针:纤细最长,走动带回弹缓冲动画,还原机械表阻尼手感
- 完整360°圆形表盘,12小时主刻度+分钟细分刻度
- 悬浮Tooltip展示完整年月日时分秒
- 透明表盘底色,可无缝嵌入深色可视化大屏
简易布局示意:
markdown
12
11 1
10 2
9 ●圆心 3
8 4
7 5
6
秒针逐秒刷新动态流转,时分针连续平滑过渡,无卡顿跳帧。
三、整体技术架构链路
整套时钟组件遵循数据驱动视图的标准Highcharts开发范式,完整执行链路清晰分层,便于后续扩展改造:
javascript
原生Date时间对象
↓
时间数值映射转换模型(24小时→0~12表盘刻度换算)
↓
Highcharts Gauge仪表盘容器
↓
多Point独立指针(时针/分针/秒针Dial样式分离配置)
↓
requestAnimationFrame驱动帧动画,定时更新数值
核心设计思路:不直接操作DOM绘制指针,而是将时分秒时间,换算为仪表盘0~12区间的可视化数值,依靠Gauge原生指针渲染能力自动生成视图,所有动画、缩放、自适应逻辑由图表库接管。
四、核心步骤1:时间数据映射换算逻辑
基础数据区间差异
原生Date对象获取的时间数值区间,和Gauge仪表盘0~12的刻度体系不匹配,需要统一换算映射:
- 小时:0~23(24小时制)
- 分钟:0~59
- 秒:0~59
- Gauge表盘统一区间:0~12
封装统一时间获取函数,完成数值换算:
javascript
const getNowTime = () => {
const now = new Date();
// 时针:小时 + 分钟偏移量,实现分针带动时针缓慢移动
const hours = now.getHours() % 12 + now.getMinutes() / 60;
// 分针:每分钟对应表盘0.2刻度,叠加秒数微小偏移
const minutes = now.getMinutes() * 0.2 + now.getSeconds() * (0.2 / 60);
// 秒针:每秒固定0.2刻度
const seconds = now.getSeconds() * 0.2;
return { date: now, hours, minutes, seconds };
};
换算逻辑拆解
-
时针换算 例:10点30分,不能直接赋值10,半小时需要偏移0.5刻度,最终数值10.5,保证时针随分针缓慢转动,贴合真实钟表视觉。
10 + 30/60 = 10.5 -
分针换算 表盘一圈12刻度,60分钟走完一圈,单分钟占比 12/60=0.2刻度;叠加秒数偏移,分针随秒针轻微移动。
-
秒针换算 同分针换算逻辑,每秒移动0.2刻度,60秒完整走完表盘一圈。
设计核心思想
所有可视化组件开发的底层逻辑,都是业务原始数据 → 视觉坐标系映射。仪表盘、折线图、热力图、树形图均遵循这套转换逻辑,掌握映射思路可快速迁移到任意可视化场景。
五、核心步骤2:Gauge表盘基础容器配置
1. 图表类型指定
javascript
chart: {
type: 'gauge',
backgroundColor: 'transparent', // 透明背景适配大屏
reflow: true // 窗口自动自适应
}
Gauge是Highcharts专属仪表盘系列,原生支持圆弧、指针、分段刻度,区别于普通线性图表。
2. 关闭冗余图表边框样式
时钟无坐标轴、绘图边框,默认图表边框、阴影全部关闭,保证表盘干净简洁:
javascript
plotBorderWidth: 0,
plotShadow: false,
credits: { enabled: false } // 隐藏Highcharts水印
3. Pane面板:从半圆改为完整圆形表盘
Gauge默认是180°半圆仪表盘,通过startAngle、endAngle调整为完整360°圆形,实现钟表表盘基础轮廓:
javascript
pane: {
startAngle: 0,
endAngle: 360,
background: [{ fill: 'rgba(30,30,40,0.6)' }] // 深色表盘底色适配大屏
}
4. 刻度系统配置,还原机械钟表刻度分层
- tickInterval: 1 :每1个刻度单位绘制主刻度(对应1/2/3...12小时数字)
- minorTickInterval: 'auto' :自动生成细分分钟小刻度
javascript
yAxis: {
min: 0,
max: 12,
tickInterval: 1,
minorTickInterval: 'auto',
labels: { distance: 20 } // 数字刻度向外偏移,避免遮挡指针
}
六、核心步骤3:多指针分离配置(时分秒视觉分层)
Highcharts Gauge支持单series内配置多个Point,每个Point独立定制Dial指针样式,以此区分时针、分针、秒针粗细、长度。
javascript
series: [{
data: [
{ id: 'hour', dial: { radius: '60%', baseWidth: 6 } },
{ id: 'minute', dial: { radius: '80%', baseWidth: 4 } },
{ id: 'second', dial: { radius: '100%', baseWidth: 1 } }
]
}]
样式分层逻辑完全复刻实体钟表:
- 时针:最短、最粗,radius限制60%表盘半径,baseWidth宽度6px
- 分针:长度中等,宽度4px,视觉层级弱于时针
- 秒针:最长、最纤细,宽度仅1px,视觉上最突出
七、核心步骤4:实时刷新与弹性动画实现
1. 定时更新机制
采用1000ms定时器每秒获取最新时间,也可替换requestAnimationFrame实现帧级刷新:
javascript
const timer = setInterval(() => {
const time = getNowTime();
// 获取三个指针实例,更新数值并开启动画
chart.get('hour').update(time.hours, true);
chart.get('minute').update(time.minutes, true);
chart.get('second').update(time.seconds, true, {
easing: 'easeOutBounce' // 秒针专属回弹缓动函数
});
}, 1000);
2. update API 动画原理
调用point.update更新数值时,图表不会销毁重建指针DOM,复用原有SVG元素,仅修改旋转角度属性,浏览器渲染开销极低,4K大屏多实例同时渲染也不会卡顿。
3. 秒针回弹动画细节
为秒针单独配置easeOutBounce缓动曲线,数值到达目标刻度后轻微回弹,模拟机械钟表齿轮阻尼效果,视觉真实度大幅提升;时分针使用默认线性缓动,保证平缓连续转动。
八、Highcharts Gauge时钟方案核心技术优势
1. 原生数据驱动动画,无需手动操作渲染层
传统CSS时钟需要自行计算transform旋转角度、管理帧动画;Gauge完全通过数值驱动视图,仅需维护时间业务数据,旋转、过渡、缓冲全部由图表库封装,减少大量底层DOM操作代码。
2. SVG矢量渲染,大屏无损缩放
底层基于SVG而非Canvas,适配2K/4K、异形大屏拉伸场景,指针、刻度不会模糊,是数字孪生、指挥中心大屏的硬性需求。
3. 多组件联动拓展能力强
时钟本身属于仪表盘组件,可和Highcharts其他系列图表联动:比如设备运行时钟搭配实时功率曲线、交易时钟搭配行情K线,共用一套图表实例数据体系,数据同步更便捷。
4. 统一主题体系,批量切换样式
支持全局预设主题一键切换深色/浅色、工业风/科技风表盘,项目中几十块时钟面板可统一配置,对比纯CSS时钟大幅降低样式维护成本。
九、落地拓展业务场景
场景1:多时区全球时钟面板
创建多个独立Gauge图表实例,分别绑定北京、纽约、伦敦、东京时区时间,统一布局为多表盘面板,用于海关、跨境业务监控大屏。
场景2:工业产线运行计时表盘
修改刻度区间,不再是012小时,改为0720小时(30天),表盘展示设备连续运行时长,搭配红色警戒刻度标识维护周期,替代传统文本计时。
场景3:金融交易倒计时表盘
限定开盘、收盘刻度区间,通过分段色标区分可交易时段/休市时段,秒针作为倒计时指针,交易大厅大屏实时展示剩余交易时间。
场景4:航天任务计时表盘
双Gauge组合,主表盘展示任务总时长,副表盘展示分段倒计时,搭配警示色阶标识关键操作节点。
十、方案横向对比:CSS原生时钟 VS Highcharts Gauge时钟
| 对比维度 | CSS纯手写时钟 | Highcharts Gauge实现时钟 |
|---|---|---|
| 圆形刻度绘制 | 手动计算坐标,代码冗余 | yAxis刻度原生支持,一行配置 |
| 多指针联动动画 | 手动管理transform动画 | 内置point.update动画API |
| 4K大屏自适应 | 缩放易模糊,需适配多分辨率 | SVG矢量无损拉伸,自带reflow自适应 |
| 多实例批量主题 | 需批量修改CSS变量 | 全局统一主题配置,一键切换 |
| 与其他图表联动 | 数据隔离,联动开发成本高 | 共用图表库数据总线,联动简单 |
| 企业级可视化集成 | 仅UI组件,无扩展能力 | 可无缝嵌入Dashboards大屏套件 |
十一、项目落地开发总结
看似简单的时钟组件,实则完整覆盖Highcharts可视化核心开发思想:数据映射模型、仪表盘容器配置、多元素独立样式管控、实时帧动画渲染。 Gauge系列也并非只能做时钟,工业压力表盘、设备转速仪表盘、能耗指标仪表盘、进度环形表盘都可以复用这套开发逻辑。
很多开发者将Highcharts局限于柱状图、折线图等统计图表,忽略了Gauge、Solidgauge、Treegraph等拓展系列的可视化潜力。在数字孪生、工控大屏、指挥中心这类ToB可视化项目中,各类仪表盘组件是高频需求,掌握数据驱动视图的开发范式,可快速交付各类自定义监控表盘,大幅降低可视化页面开发周期。
整套方案兼容Vue/React框架,支持按需引入模块减小打包体积,适配内网离线部署场景,满足政企项目国产化、本地化部署要求。