1. 程式人生 > >基於 HTML5 WebGL 的 CPU 監控系統

基於 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 的應用,如果你有更深入的需求和更好的想法,歡迎提出,我們進行更深入地討論,也可以進行差異化業務定製。 如果你對工業網際網路感興趣,可以從  https://www.hightopo.com/demos/index.html 獲取更多案例及效