路弯弯 發表於 2020-4-20 00:04:00

基于 HTML5 WebGL 的 CPU 监控系统

<p><strong>前言</strong></p>
<p>科技改变生活,科技的发展带来了生活方式的巨大改变。随着通信技术的不断演进,5G 技术应运而生,随时随地万物互联的时代已经来临。5G 技术不仅带来了更快的连接速度和前所未有的用户体验,也为制造业,微电子及集成电路发展带来了巨大的发展机遇和挑战。 5G 技术商业实施过程中,5G 网络芯片面临低功耗、低延时、高可靠性和高精度的技术挑战。 本文将以大家熟悉的 CPU 为例,介绍以 HT 为基础,应用 JavaScript,WebGL 和 HTML5 技术开发的 CPU 监控系统。在大型数据中心,实时监控 CPU 的温度,使用率等具有重要的意义。在服务器级别进行 CPU 温度监控,能够实时了解服务器 CPU 的温度,及时发现能效问题,防止出现服务延迟、服务器宕机,从而节约成本。实时监控 CPU 使用率等,能够实时查看服务器的 CPU 使用情况,合理分配服务器资源。</p>
<p><strong>系统预览</strong></p>
<p><strong>- PC&nbsp;</strong><strong>端</strong></p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1496396/202004/1496396-20200408222745063-966050939.jpg"></strong></p>
<p><strong>-&nbsp;</strong><strong>移动端</strong></p>
<p><strong><img src="https://img2020.cnblogs.com/blog/1496396/202004/1496396-20200408222940349-363682649.jpg"></strong></p>
<p>Demo 中的场景是由 2D 和 3D 结合搭建而成,移动端的左上数据框部分显示的是手机陀螺仪数据,仅在移动端开启陀螺仪时显示。</p>
<p><strong>功能实现</strong></p>
<p><strong>-&nbsp;</strong><strong>判断页面打开设备</strong></p>
<p>在移动互联网时代,建设移动端和 PC 端网站具有同等重要的意义。与 PC 端相比,移动端能够实现随时随地的浏览,宣传和移动营销,因此 HT 设计和开发的系统都能很好地兼容移动端的访问和展示。</p>
<p>为了带来更好的用户体验,Demo 使用 Navigator 对象的 userAgent 属性,判断用户请求来自于 PC 端还是移动端,做不同的动画处理和数据展示。Navigator 对象包含了浏览器的信息,其 userAgent 属性则声明了浏览器用于 HTTP 请求的用户代理头的值。下面分别是在 Windows 端和 Android 端打印出的 userAgent 信息。</p>
<p><img src="https://img2020.cnblogs.com/blog/1496396/202004/1496396-20200408223048001-166503094.png"></p>
<p><img src="https://img2020.cnblogs.com/blog/1496396/202004/1496396-20200408223118107-2063078762.png"></p>
<p>对应到代码中,基于 userAgent 属性信息,使用正则表达式去判断请求是否来自于移动端(主要考虑了 Android 端 和 IOS 端)。</p>
<div class="cnblogs_code">
<pre><span data-mce-="">isMobile() {
    <span data-mce-="">return (/(iPhone|iPad|iPod|iOS|Android)/<span data-mce-="">i.test(navigator.userAgent));
}</span></span></span></pre>
</div>
<p><strong>-&nbsp;</strong><strong>动画原理</strong></p>
<p>本 Demo 使用 HT 内置的 ht.Default.startAnim 函数来生成动画,此函数支持 Frame-Based 和 Time-Based 两种方式的动画。我采用的是 Time-Based 方法,即用户使用 duration 指定动画周期 (单位为毫秒)。easing 参数是用于让用户定义函数,通过数学公式控制动画,如匀速变化、先慢后快等效果。action 函数的第一个参数 v 代表通过 easing(t) 函数运算后的值, t代表当前动画进行的进度 ,一般属性变化根据 v 参数进行。finishFunc 参数代表动画结束后的动作。本实例中的 startAnim 函数均采用了如下结构的 JSON 参数结构:</p>
<div class="cnblogs_code">
<pre><span data-mce-="">ht.Default.startAnim({
    duration: 500, <span data-mce-="">//<span data-mce-=""> 动画周期毫秒数
    easing: <span data-mce-="">function (t) {}, <span data-mce-="">//<span data-mce-=""> 动画缓动函数
    action: <span data-mce-="">function (v, t) {…} <span data-mce-="">//<span data-mce-=""> 动画过程属性变化
    finishFunc: <span data-mce-="">function () {} <span data-mce-="">//<span data-mce-=""> 动画结束后调用的函数
});</span></span></span></span></span></span></span></span></span></span></span></span></pre>
</div>
<p><strong>-&nbsp;</strong><strong>旋转 180&nbsp;</strong><strong>度并抬高视角</strong></p>
<p><img src="https://img2020.cnblogs.com/blog/1496396/202004/1496396-20200418180728283-618653237.gif"></p>
<p>3D 场景中的视角是由 eye (相机位置) 和 center (目标位置) 决定的,因此视角的变化改变这两个参数即可,本 Demo 使用 HT 内置的 moveCamera 方法实现。动画采用圆的参数方程计算 eye 的 x 值和 z 值,完成 180 度的旋转。在旋转过程中半径和角度都随着 t 的变化而变化,通过 ( t – 0.5 ) * Math.PI 使得角度变化范围为 [ - Math.PI / 2, Math.PI / 2] 。圆的参数方程如下所示:</p>
<p><img src="https://img2020.cnblogs.com/blog/1496396/202004/1496396-20200408223631935-1064468584.png"></p>
<p>旋转过程中,y 值也随 t 变化,完成 3D 场景视角的提升。finishFunc 参数用来定义该动画结束后继续调用的下一个动画,实现多个动画效果。</p>
<div class="cnblogs_code">
<pre><span data-mce-="">//<span data-mce-=""> 旋转 180 度并抬高视角
<span data-mce-="">startRotationAnimation(onFinish) {
    let that = <span data-mce-="">this<span data-mce-="">;
    let r = 849<span data-mce-="">
    ht.Default.startAnim({
      duration: 6000<span data-mce-="">,
      easing: <span data-mce-="">function (t) { <span data-mce-="">return<span data-mce-=""> t; },
      action: <span data-mce-="">function (v, t) { <span data-mce-="">// <span data-mce-="">圆的参数方程 半径和角度都在变
            let r1 = (1 - t) *<span data-mce-=""> r;
            let angle = (t - 0.5) *<span data-mce-=""> Math.PI;
            let x = r1 *<span data-mce-=""> Math.cos(angle);
            let z = r1 *<span data-mce-=""> Math.sin(angle);
            let y = 126 + (1968 - 126) * t * t *<span data-mce-=""> t;
            that.g3d.moveCamera();
      },
      finishFunc: <span data-mce-="">function<span data-mce-=""> () {
            <span data-mce-="">if (!<span data-mce-="">onFinish) {
                <span data-mce-="">return<span data-mce-="">;
            }
            onFinish.call(that);
      }
    });
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
</div>
<p>在运行该动画时,需要延时调用另外两个动画完成 CPU 卡扣的抬起及消失,这样可使得动画错开执行,以达到更好的视觉效果。这部分使用 ht.Default.callLater(func, scope, args, delay) 延时调用动画函数,最后一个参数 delay 定义延迟的时间间隔。</p>
<div class="cnblogs_code">
<pre>ht.Default.callLater(() =&gt; { <span data-mce-="">this.startCap1Animation(); }, <span data-mce-="">this, <span data-mce-="">null, 500<span data-mce-="">);
ht.Default.callLater(() =&gt; { <span data-mce-="">this.startCap2Animation(); }, <span data-mce-="">this, <span data-mce-="">null, 1000);</span></span></span></span></span></span></span></pre>
</div>
<p><strong>-&nbsp;</strong><strong>视角切换</strong></p>
<p>本部分根据页面在 PC 端还是手机端打开,使用 moveCamera 方法分别切换到不同视角。以 PC 端视角切换为例,通过 getEye() 方法获取相机所在位置作为起始位置,终止位置为预定义的数值。通过 action 参数定义视角从起始位置到终点位置的切换。</p>
<div class="cnblogs_code">
<pre><span data-mce-="">//<span data-mce-=""> 视角切换
<span data-mce-="">startMoveAngle3AnimationPC(onFinish) {
    let startPos = <span data-mce-="">this<span data-mce-="">.g3d.getEye();
    let endPos = ;
    let that = <span data-mce-="">this<span data-mce-="">;
    ht.Default.startAnim({
      duration: 2000<span data-mce-="">,
      easing: <span data-mce-="">function (t) { <span data-mce-="">return t *<span data-mce-=""> t; },
      action: <span data-mce-="">function<span data-mce-=""> (v, t) {
            let x, y, z;
            x = startPos + (endPos - startPos) *<span data-mce-=""> t;
            y = startPos + (endPos - startPos) *<span data-mce-=""> t;
            z = startPos + (endPos - startPos) *<span data-mce-=""> t;
            that.g3d.moveCamera();
      },
      finishFunc: <span data-mce-="">function<span data-mce-=""> () {…}
    });
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
</div>
<p><strong>- CPU&nbsp;</strong><strong>外壳隐藏动画</strong></p>
<p><img src="https://img2020.cnblogs.com/blog/1496396/202004/1496396-20200418190124788-1581384621.gif"></p>
<p>为带来更好的视觉效果,视角切换的同时使用 ht.Default.callLater() 延迟调用 CPU 外壳隐藏动画。通过 getElevation() 获取外壳在 3D 坐标系中 y 的初始坐标,动画过程中使用 setElevation() 方法设置 y 坐标,动画结束后设置其可见属性为 false。代码如下:</p>
<div class="cnblogs_code">
<pre>easing: <span data-mce-="">function (t) { <span data-mce-="">return t *<span data-mce-=""> t; },
action: <span data-mce-="">function<span data-mce-=""> (v, t) {
    let val = start + (end - start) * t; <span data-mce-="">//<span data-mce-=""> start: 起始 y 坐标;end: 终止 y 坐标
<span data-mce-="">    that.hide1.setElevation(val);
}
finishFunc: <span data-mce-="">function<span data-mce-=""> () {
    that.hide1.s('3d.visible', <span data-mce-="">false<span data-mce-="">);
}</span></span></span></span></span></span></span></span></span></span></span></span></pre>
</div>
<p><strong>-&nbsp;</strong><strong>芯片冒出及呼吸灯渲染</strong></p>
<p><img src="https://img2020.cnblogs.com/blog/1496396/202004/1496396-20200418190147941-248502574.gif"></p>
<p>视角切换完成后,在 CPU 外壳隐藏的同时,CPU 内部结构逐渐冒出。与外壳隐藏相同,该部分也是通过setElevation方法完成。</p>
<div class="cnblogs_code">
<pre>action: <span data-mce-="">function<span data-mce-=""> (v, t) {
    let e = start1Y + (end1Y - start1Y) *<span data-mce-=""> t
    that.up1.setElevation(e);
}</span></span></span></pre>
</div>
<p>与芯片冒出动画间隔 1s, 呼吸灯渲染动画开启,使用 shape3d.blend 和 shape3d.opacity 分别设置呼吸灯染色和透明度。</p>
<div class="cnblogs_code">
<pre><span data-mce-="">easing: easing.easeBothStrong,
action: <span data-mce-="">function<span data-mce-=""> (v, t) {
    let val = 255 - (255 - endBlend) *<span data-mce-=""> t;
    val = val.toFixed(0<span data-mce-="">);
    let blend = 'rgb(' + val + ',' + val + ',' + val + ')'<span data-mce-="">;
    let opacity = startOpa + (endOpa - startOpa) *<span data-mce-=""> t
    that.blend.s('shape3d.blend'<span data-mce-="">, blend);
    that.opacity.s('shape3d.opacity'<span data-mce-="">, opacity);<span data-mce-="">
}</span></span></span></span></span></span></span></span></span></span></pre>
</div>
<p>此部分动画采用 easeBothStrong 方式,即开始慢且减速, t 的四次方,代码实现如下:</p>
<div class="cnblogs_code">
<pre>easeBothStrong: <span data-mce-="">function<span data-mce-=""> (t) {
    <span data-mce-="">return (t *= 2) &lt; 1 ?<span data-mce-="">
      .5 * t * t * t *<span data-mce-=""> t :
      .5 * (2 - (t -= 2) * t * t *<span data-mce-=""> t);
}</span></span></span></span></span></span></pre>
</div>
<p><strong>- PC&nbsp;</strong><strong>端结束动画</strong></p>
<p><img src="https://img2020.cnblogs.com/blog/1496396/202004/1496396-20200418182122909-313213867.gif"></p>
<p>当动画结束后,PC 端重置 interactors,并启动线的流动及点位地面的旋转动画。</p>
<div class="cnblogs_code">
<pre><span data-mce-="">startAnimation() {
    setInterval(() =&gt;<span data-mce-=""> {
      <span data-mce-="">this.uvOffset = <span data-mce-="">this.uvOffset + <span data-mce-="">this<span data-mce-="">.uvSpeed;
      <span data-mce-="">this.line.s('top.uv.offset', [-<span data-mce-="">this.uvOffset, 0]); <span data-mce-="">//<span data-mce-=""> 线的流动
      <span data-mce-="">this.rotationAngle = <span data-mce-="">this.rotationSpeed + <span data-mce-="">this<span data-mce-="">.rotationAngle;
      <span data-mce-="">this.flagReflection.setRotationY(<span data-mce-="">this.rotationAngle); <span data-mce-="">//<span data-mce-=""> 点位地面旋转
    }, 16.7<span data-mce-="">);
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
</div>
<p>移动端动画结束后,会读取手机陀螺仪数据并展示,具体原理及实现在手机传感器数据部分。</p>
<p><strong>&nbsp;</strong><strong>手机传感器数据</strong></p>
<p>HTML5 提供了几个 DOM 事件来获得移动端方向及运动的信息,deviceorientation 提供设备的物理方向信息;devicemotion 提供设备的加速度信息。</p>
<p><strong>-&nbsp;</strong><strong>处理方向 (orientation)&nbsp;</strong><strong>事件</strong></p>
<p>要接收设备方向变化信息,需要首先注册监听 deviceorientation 事件:</p>
<div class="cnblogs_code">
<pre>window.addEventListener('deviceorientation', (e) =&gt;<span data-mce-=""> {
    <span data-mce-="">this<span data-mce-="">.onOrientationEvent(e);
});</span></span></span></pre>
</div>
<p>orientation 事件中 3 个重要值:</p>
<table border="0" data-mce-="">
<tbody>
<tr>
<td align="center" valign="middle">属性值  </td>
<td align="center" valign="middle">含义</td>
</tr>
<tr>
<td align="left">DeviceOrientationEvent.alpha</td>
<td align="left">设备水平放置时,沿 z 轴的旋转角度,范围 。</td>
</tr>
<tr>
<td align="left">DeviceOrientationEvent.beta</td>
<td align="left">设备水平放置时,沿 x 轴的旋转角度,范围 [-180, 180] 。</td>
</tr>
<tr>
<td align="left">DeviceOrientationEvent.gamma</td>
<td align="left">设备水平放置时,沿 y 轴的旋转角度,范围 [-90, 90] 。</td>
</tr>
</tbody>
</table>
<p>以下是事件处理的简单代码:</p>
<div class="cnblogs_code">
<pre><span data-mce-="">onOrientationEvent(e) {
    let alpha, beta, gamma, compass;
    let compassFlag = <span data-mce-="">true<span data-mce-="">;
    alpha = e.alpha ? e.alpha : 0<span data-mce-="">;
    beta = e.beta ? e.beta : 0<span data-mce-="">;
    gamma = e.gamma ? e.gamma : 0<span data-mce-="">;
}</span></span></span></span></span></span></pre>
</div>
<p>值得注意的是, IOS 和 Android 对手机硬件提供的 alpha 值不完全一样,所以需要借助 webkitCompassHeading 属性来判断是 IOS 还是 Android。当 webkitCompassHeading 不为空时,代表是 IOS 系统。</p>
<p><strong>-&nbsp;</strong><strong>处理移动 (Motion)&nbsp;</strong><strong>事件</strong></p>
<p>与方向事件处理类似,移动事件的处理也是首先注册监听 devicemotion:</p>
<div class="cnblogs_code">
<pre>window.addEventListener('devicemotion', (e) =&gt;<span data-mce-=""> {
    <span data-mce-="">this.dataTextarea.s('2d.visible', <span data-mce-="">true<span data-mce-="">);
    <span data-mce-="">this<span data-mce-="">.onMotionEvent(e);

});</span></span></span></span></span></span></pre>
</div>
<p>移动事件包含 4 个属性:</p>
<table border="0" data-mce-="">
<tbody>
<tr>
<td>属性值 </td>
<td>含义</td>
</tr>
<tr>
<td>DeviceMotionEvent.acceleration</td>
<td>加速度,需要陀螺仪支持。</td>
</tr>
<tr>
<td>DeviceMotionEvent.accelerationIncludingGravity</td>
<td>重力加速度。</td>
</tr>
<tr>
<td>DeviceMotionEvent.rotationRate</td>
<td>旋转速度。</td>
</tr>
<tr>
<td>DeviceMotionEvent.interval</td>
<td>从设备获取数据的频率,单位为毫秒。</td>
</tr>
</tbody>
</table>
<p>以下是事件的简单代码:</p>
<div class="cnblogs_code">
<pre><span data-mce-="">onMotionEvent(e) {
    let MAX1 = 2<span data-mce-="">;
    let MAX2 = 5<span data-mce-="">;

    <span data-mce-="">this.acceleration = e.acceleration.x ?<span data-mce-=""> e.acceleration : {
      x: 0<span data-mce-="">,
      y: 0<span data-mce-="">,
      z: 0<span data-mce-="">
    };
    <span data-mce-="">this.accGravity = e.accelerationIncludingGravity.x ?<span data-mce-=""> e.accelerationIncludingGravity : {
      x: 0<span data-mce-="">,
      y: 0<span data-mce-="">,
      z: 0<span data-mce-="">
    };
    <span data-mce-="">this.rotationRate = e.rotationRate.alpha ?<span data-mce-=""> e.rotationRate : {
      alpha: 0<span data-mce-="">,
      beta: 0<span data-mce-="">,
      gamma: 0<span data-mce-="">
    };
    <span data-mce-="">this.interval =<span data-mce-=""> e.interval;

}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></pre>
</div>
<p><strong>总结</strong></p>
<p>芯片强则产业强。随着 5G 技术、物联网和人工智能的发展,集成电路作为最重要也是最基础的科技技术,必将获得更快地发展。随着国内信息产业的快速发展,自主研发一颗好的中国“芯”已经迫在眉睫。本文以大家熟知的 CPU 为例抛转引玉,讲述微观世界 HT 的应用,如果你有更深入的需求和更好的想法,欢迎提出,我们进行更深入地讨论,也可以进行差异化业务定制。 如果你对工业互联网感兴趣,可以从 &nbsp;<strong><span data-mce-="">https://www.hightopo.com/demos/index.html&nbsp;</span></strong>获取更多案例及效果。</p><br><br>
来源:https://www.cnblogs.com/xhload3d/p/12735213.html
頁: [1]
查看完整版本: 基于 HTML5 WebGL 的 CPU 监控系统