基於 HTML5 WebGL 的 CPU 監控系統

前言

科技改變生活,科技的發展帶來了生活方式的巨大改變。隨著通訊技術的不斷演進,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 個重要值:

屬性值   含義
DeviceOrientationEvent.alpha 設備水平放置時,沿 z 軸的旋轉角度,範圍 [0,360] 。
DeviceOrientationEvent.beta 設備水平放置時,沿 x 軸的旋轉角度,範圍 [-180, 180] 。
DeviceOrientationEvent.gamma 設備水平放置時,沿 y 軸的旋轉角度,範圍 [-90, 90] 。

以下是事件處理的簡單程式碼:

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 個屬性:

屬性值  含義
DeviceMotionEvent.acceleration 加速度,需要陀螺儀支援。
DeviceMotionEvent.accelerationIncludingGravity 重力加速度。
DeviceMotionEvent.rotationRate 旋轉速度。
DeviceMotionEvent.interval 從設備獲取數據的頻率,單位為毫秒。

以下是事件的簡單程式碼:

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.html 獲取更多案例及效果。