基于 HTML5 WebGL 的 CPU 监控系统

543 阅读7分钟

前言

科技改变生活,科技的发展带来了生活方式的巨大改变。随着通信技术的不断演进,5G 技术应运而生,随时随地万物互联的时代已经来临。5G 技术不仅带来了更快的连接速度和前所未有的用户体验,也为制造业,微电子及集成电路发展带来了巨大的发展机遇和挑战。 5G 技术商业实施过程中,5G 网络芯片面临低功耗、低延时、高可靠性和高精度的技术挑战。 本文将以大家熟悉的 CPU 为例,介绍以 HT 为基础,应用 JavaScript,WebGL 和 HTML5 技术开发的 CPU 监控系统。在大型数据中心,实时监控 CPU 的温度,使用率等具有重要的意义。在服务器级别进行 CPU 温度监控,能够实时了解服务器 CPU 的温度,及时发现能效问题,防止出现服务延迟、服务器宕机,从而节约成本。实时监控 CPU 使用率等,能够实时查看服务器的 CPU 使用情况,合理分配服务器资源。

系统预览

- PC

- 移动端

Demo 中的场景是由 2D 和 3D 结合搭建而成,移动端的左上数据框部分显示的是手机陀螺仪数据,仅在移动端开启陀螺仪时显示。

功能实现

- 判断页面打开设备

在移动互联网时代,建设移动端和 PC 端网站具有同等重要的意义。与 PC 端相比,移动端能够实现随时随地的浏览,宣传和移动营销,因此 HT 设计和开发的系统都能很好地兼容移动端的访问和展示。

为了带来更好的用户体验,Demo 使用 Navigator 对象的 userAgent 属性,判断用户请求来自于 PC 端还是移动端,做不同的动画处理和数据展示。Navigator 对象包含了浏览器的信息,其 userAgent 属性则声明了浏览器用于 HTTP 请求的用户代理头的值。下面分别是在 Windows 端和 Android 端打印出的 userAgent 信息。

对应到代码中,基于 userAgent 属性信息,使用正则表达式去判断请求是否来自于移动端(主要考虑了 Android 端 和 IOS 端)。

isMobile() {
    return (/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent));
}

- 动画原理

本 Demo 使用 HT 内置的 ht.Default.startAnim 函数来生成动画,此函数支持 Frame-Based 和 Time-Based 两种方式的动画。我采用的是 Time-Based 方法,即用户使用 duration 指定动画周期 (单位为毫秒)。easing 参数是用于让用户定义函数,通过数学公式控制动画,如匀速变化、先慢后快等效果。action 函数的第一个参数 v 代表通过 easing(t) 函数运算后的值, t代表当前动画进行的进度 [0, 1],一般属性变化根据 v 参数进行。finishFunc 参数代表动画结束后的动作。本实例中的 startAnim 函数均采用了如下结构的 JSON 参数结构:

ht.Default.startAnim({
    duration: 500, // 动画周期毫秒数
    easing: function (t) {}, // 动画缓动函数
    action: function (v, t) {…} // 动画过程属性变化
    finishFunc: function () {} // 动画结束后调用的函数
});

- 旋转 180 度并抬高视角

3D 场景中的视角是由 eye (相机位置) 和 center (目标位置) 决定的,因此视角的变化改变这两个参数即可,本 Demo 使用 HT 内置的 moveCamera 方法实现。动画采用圆的参数方程计算 eye 的 x 值和 z 值,完成 180 度的旋转。在旋转过程中半径和角度都随着 t 的变化而变化,通过 ( t – 0.5 ) * Math.PI 使得角度变化范围为 [ - Math.PI / 2, Math.PI / 2] 。圆的参数方程如下所示:

旋转过程中,y 值也随 t 变化,完成 3D 场景视角的提升。finishFunc 参数用来定义该动画结束后继续调用的下一个动画,实现多个动画效果。

// 旋转 180 度并抬高视角
startRotationAnimation(onFinish) {
    let that = this;
    let r = 849
    ht.Default.startAnim({
        duration: 6000,
        easing: function (t) { return t; },
        action: function (v, t) { // 圆的参数方程 半径和角度都在变
            let r1 = (1 - t) * r;
            let angle = (t - 0.5) * Math.PI;
            let x = r1 * Math.cos(angle);
            let z = r1 * Math.sin(angle);
            let y = 126 + (1968 - 126) * t * t * t;
            that.g3d.moveCamera([x, y, z]);
        },
        finishFunc: function () {
            if (!onFinish) {
                return;
            }
            onFinish.call(that);
        }
    });
}

在运行该动画时,需要延时调用另外两个动画完成 CPU 卡扣的抬起及消失,这样可使得动画错开执行,以达到更好的视觉效果。这部分使用 ht.Default.callLater(func, scope, args, delay) 延时调用动画函数,最后一个参数 delay 定义延迟的时间间隔。

ht.Default.callLater(() => { this.startCap1Animation(); }, this, null, 500);
ht.Default.callLater(() => { this.startCap2Animation(); }, this, null, 1000);

- 视角切换

本部分根据页面在 PC 端还是手机端打开,使用 moveCamera 方法分别切换到不同视角。以 PC 端视角切换为例,通过 getEye() 方法获取相机所在位置作为起始位置,终止位置为预定义的数值。通过 action 参数定义视角从起始位置到终点位置的切换。

// 视角切换
startMoveAngle3AnimationPC(onFinish) {
    let startPos = this.g3d.getEye();
    let endPos = [0, 728, 661];
    let that = this;
    ht.Default.startAnim({
        duration: 2000,
        easing: function (t) { return t * t; },
        action: function (v, t) {
            let x, y, z;
            x = startPos[0] + (endPos[0] - startPos[0]) * t;
            y = startPos[1] + (endPos[1] - startPos[1]) * t;
            z = startPos[2] + (endPos[2] - startPos[2]) * t;
            that.g3d.moveCamera([x, y, z]);
        },
        finishFunc: function () {…}
    });
}

- CPU 外壳隐藏动画

为带来更好的视觉效果,视角切换的同时使用 ht.Default.callLater() 延迟调用 CPU 外壳隐藏动画。通过 getElevation() 获取外壳在 3D 坐标系中 y 的初始坐标,动画过程中使用 setElevation() 方法设置 y 坐标,动画结束后设置其可见属性为 false。代码如下:

easing: function (t) { return t * t; },
action: function (v, t) {
    let val = start + (end - start) * t; // start: 起始 y 坐标;end: 终止 y 坐标
    that.hide1.setElevation(val);
}
finishFunc: function () {
    that.hide1.s('3d.visible', false);
}

- 芯片冒出及呼吸灯渲染

视角切换完成后,在 CPU 外壳隐藏的同时,CPU 内部结构逐渐冒出。与外壳隐藏相同,该部分也是通过setElevation方法完成。

action: function (v, t) {
    let e = start1Y + (end1Y - start1Y) * t
    that.up1.setElevation(e);
}

与芯片冒出动画间隔 1s, 呼吸灯渲染动画开启,使用 shape3d.blend 和 shape3d.opacity 分别设置呼吸灯染色和透明度。

easing: easing.easeBothStrong,
action: function (v, t) {
    let val = 255 - (255 - endBlend) * t;
    val = val.toFixed(0);
    let blend = 'rgb(' + val + ',' + val + ',' + val + ')';
    let opacity = startOpa + (endOpa - startOpa) * t
    that.blend.s('shape3d.blend', blend);
    that.opacity.s('shape3d.opacity', opacity);
}

此部分动画采用 easeBothStrong 方式,即开始慢且减速, t 的四次方,代码实现如下:

easeBothStrong: function (t) {
    return (t *= 2) < 1 ?
        .5 * t * t * t * t :
        .5 * (2 - (t -= 2) * t * t * t);
}

- PC 端结束动画

当动画结束后,PC 端重置 interactors,并启动线的流动及点位地面的旋转动画。

startAnimation() {
    setInterval(() => {
        this.uvOffset = this.uvOffset + this.uvSpeed;
        this.line.s('top.uv.offset', [-this.uvOffset, 0]); // 线的流动
        this.rotationAngle = this.rotationSpeed + this.rotationAngle;
        this.flagReflection.setRotationY(this.rotationAngle); // 点位地面旋转
    }, 16.7);
}

移动端动画结束后,会读取手机陀螺仪数据并展示,具体原理及实现在手机传感器数据部分。

手机传感器数据

HTML5 提供了几个 DOM 事件来获得移动端方向及运动的信息,deviceorientation 提供设备的物理方向信息;devicemotion 提供设备的加速度信息。

- 处理方向 (orientation) 事件

要接收设备方向变化信息,需要首先注册监听 deviceorientation 事件:

window.addEventListener('deviceorientation', (e) => {
    this.onOrientationEvent(e);
});

orientation 事件中 3 个重要值:


onOrientationEvent(e) {以下是事件处理的简单代码:

    let alpha, beta, gamma, compass;
    let compassFlag = true;
    alpha = e.alpha ? e.alpha : 0;
    beta = e.beta ? e.beta : 0;
    gamma = e.gamma ? e.gamma : 0;
}

值得注意的是, IOS 和 Android 对手机硬件提供的 alpha 值不完全一样,所以需要借助 webkitCompassHeading 属性来判断是 IOS 还是 Android。当 webkitCompassHeading 不为空时,代表是 IOS 系统。

- 处理移动 (Motion) 事件

与方向事件处理类似,移动事件的处理也是首先注册监听 devicemotion:

window.addEventListener('devicemotion', (e) => {
    this.dataTextarea.s('2d.visible', true);
    this.onMotionEvent(e);

});

移动事件包含 4 个属性:


onMotionEvent(e) {以下是事件的简单代码:

    let MAX1 = 2;
    let MAX2 = 5;

    this.acceleration = e.acceleration.x ? e.acceleration : {
        x: 0,
        y: 0,
        z: 0
    };
    this.accGravity = e.accelerationIncludingGravity.x ? e.accelerationIncludingGravity : {
        x: 0,
        y: 0,
        z: 0
    };
    this.rotationRate = e.rotationRate.alpha ? e.rotationRate : {
        alpha: 0,
        beta: 0,
        gamma: 0
    };
    this.interval = e.interval;

}

总结

芯片强则产业强。随着 5G 技术、物联网和人工智能的发展,集成电路作为最重要也是最基础的科技技术,必将获得更快地发展。随着国内信息产业的快速发展,自主研发一颗好的中国“芯”已经迫在眉睫。本文以大家熟知的 CPU 为例抛转引玉,讲述微观世界 HT 的应用,如果你有更深入的需求和更好的想法,欢迎提出,我们进行更深入地讨论,也可以进行差异化业务定制。 如果你对工业互联网感兴趣,可以从 www.hightopo.com/demos/index… 获取更多案例及效果。