HTML5数据可视化第二弹:打造最美3D机房

2024-02-10 05:48

本文主要是介绍HTML5数据可视化第二弹:打造最美3D机房,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近项目开发任务告一段落,刚好有时间整理这大半年的一些成果。使用html5时间还不久,对js的认识还不够深入。没办法,以前一直搞java,对js的一些语言特性和概念一时还转换不过来。

 

上一篇第一弹介绍了项目中做的一个彩虹爆炸图,主要用了 html5canvas2d绘制技术。这一回我想介绍一下项目中的一个亮点技术:html53D,以及如何用它打造精美的3D机房监控系统。

 

目标效果图

下图是领导给找的一张的效果参考图,客户希望机房至少能达到下面的3D效果。懂的人都知道,这可是一张设计公司出的装修效果图啊,就算是用max建模,也需要大量的工作,何况咱可是程序员在做数据中心的可视化项目啊。。。强忍心中奔腾的万千头**马,静下心来思考,那就先从搭建一个webGL的场景开始把。

  


 

WebGL基本场景搭建

html5里面使用3D已经不是什么高深技术,它的基础是WebGL,一个openGL的浏览器子集,支持大部分主要3D功能接口。目前最新的浏览器都有比较好的支持,IE需要到11(是的,你没有看错)。

 

要检测你的浏览器是否支持webGL,直接访问网页http://get.webgl.org/ 看是否能看到一个旋转的立方体。如果能看到,说明你的浏览器支持webgGL,否则,可以下一个最新的chrome试试吧。相对来说chrome对webGL的支持最好,效率也很优秀。

 

 

要在浏览器里面使用webGL,就要研究webGL相关的技术和用法。做3D应用并不是一件轻松的事。就算最简单的搭建一下webGL场景,也需要下面这些代码:

 

<script>    var width = window.innerWidth;  var height= window.innerHeight;  var container = document.createElement( 'div' );  document.body.appendChild( container );  var webglcanvas = document.createElement('canvas');               container.appendChild(webglcanvas);   var gl = webglcanvas.getContext("experimental-webgl");                function updateFrame () {             gl.viewport ( 0, 0, width, height );  gl.clearColor(0.4, 0.4, 0.7, 1);  gl.clear ( gl.COLOR_BUFFER_BIT );       setTimeout(   function(){updateFrame()},  20);  }  setTimeout(   function(){updateFrame();},  20);  
</script>   

 

 

html一样,需要先创建一个canvas元素,并获得其webgl上下文:

 

var gl = webglcanvas.getContext("experimental-webgl");

 

 

然后在一个updateFrame的函数中,像html52d context一样,去绘制3D的内容。另外,要再起一个死循环,每隔**毫秒调用一次这个updateFrame函数来重绘场景。2D不同,3D场景里面的变化是随时随地的,所以需要不停刷新,就像播放电影或视频,静止不动的画面基本没有,所以死循环刷新基本是必要的。不过实际项目使用中会有很多优化,尽量做到“按需刷新”,节省cpu和移动设备电量。这一点也是很重要的,有感兴趣的同学,可以单独写文章介绍。这段程序基本上什么也没做,就画了一个静止不动的区域,如下图:




虽然看不见任何3D的内容,不过它已经是一个最简单的webgl程序了。我们的精美的3D机房,也是要在这上面不断丰富而已。

 

对象封装

要做项目,搭建下去工作量太大了,时间周期也不允许。使用第三方辅助工具是不可避免的,像Three.jstwaver.js都是选择。这些工具都可以提供3D的基本对象和各种特效。当然这都不是最主要的,主要是如何利用它做出我想要的效果:好看。为了避免大量修改代码,在项目里做了一些封装,把原始3D的立方体等对象进行进一步封装,让一个json数据就可以提供这些对象的定义。这样使用起来就比较方便了。Json大致结构如下:

 

var json={	objects: [{name: '地板',…},{…}],
}

 

下面我们逐一来看这些3D对象是怎么进行美化的,过程可能稍显啰嗦,但实际工作就是这么繁琐的有木有?

 

地板和斜坡

第一个要做,也是应该比较简单的,就是地板。这个地板应该是一个有点厚度、有格子贴图的薄薄立方体平面。还好经过封装,就写一段json对象就能定义了:

 

{name: '地板',type: 'cube',width: 1600,height: 10,depth: 1300,style: {'m.color': '#BEC9BE','m.ambient': '#BEC9BE',}
}

 

通过定义,创建一个13*16米的地板块:



 

只有颜色还不够,找一个地板砖纹理图。需要注意的是,纹理图的尺寸都需要是宽和高都是2的幂,例如128x128256*256等,这样出来效果才会好。这也是3D软件一般所要求的。另外纹理要能连续拼接不露破绽,这样才好。例如下面我google出来的图:



 

style里面添加:

 

   'top.m.texture.image': 'images/floor.png','top.m.texture.repeat': new mono.Vec2(10,10),

 

 

效果如下:



有图片材质纹理,效果果然好多了。不过客户说他们这里底面有一个方便运送设备的斜坡,要画出来。这……



 
后来想到twaver里面的对象可以支持运算。可以定义一个斜的立方体,让地板剪掉立方体,应该可以做到。于是继续定义json

 

{name: '地板切坡',type: 'cube',width: 200,height: 20,depth: 260,translate: [-348,0,530],rotate: [Math.PI/180*3, 0, 0],op: '-',style: {…,}}

 这里定义的一个倾斜的立方体,通过translate定义位置,通过rotate定义旋转角度,然后再通过op定义运算符,这里是“减去”,就用“-”。被剪掉的立方体也可以设置材质、纹理、贴图、颜色….等等。看看效果:


 

 

走廊桌

按要求走廊要放一个接待桌。为了简单就偷懒做一个立方体表示吧!这个简单,继续使用上述办法:

 

{name: '走廊板凳',type: 'cube',width: 300,height: 50,depth: 100,translate: [350, 0, -500],}

 

效果如下:



 再
增加一点配色并启动阴影效果后,看着就好多了。尽管只是个简单的立方体,但只要和整体风格一致,并不显得简陋。很3D里面最重视的就是效率,千万不要放一些很复杂的模型,尤其是这些非业务对象。


 墙体

 

墙体是机房里很重要的一个部分,有好的光照、阴影的效果才能看起来更加逼真。由于墙体是不规则的路径,一段一段去生成还真挺麻烦的,还好引擎支持这种物体,甚至曲线路径都可以。这里只要在json里面定义一组数字的坐标,让这些数字依次连接,组成一个墙体,最后生成3D对象放入场景中就行啦。

 

json定义如下:

 

{name: '主墙体',type: 'path',width: 20,height: 200,translate: [-500, 0, -500],data:[[0, 0],[1000, 0],[1000, 500],[500, 500],[500, 1000],[0, 1000],[0,0],],
}

 

注意这里的类型变成了pathdata中定义了一个二维坐标数组来描述墙体。由于墙都是从底面开始的,所以只定义它的平面的xy坐标就行了。看看效果:



 

不如前文所说,还是需要上色、上阴影,才能有更好的效果。这里我们启用阴影并咨询设计师美眉几个颜色值,加上去,再看下效果:



 还有细节:



 


看着雪白的墙,是不是觉得少了点什么?对,就是门。在3D机房的监控系统里,门禁是很重要的一块,客户要求门应该与实际位置相对应,并且要有开门关门的动画效果。这样,实际的门禁信息采集上来后,就能在界面实时看到门的状态了。

 

这里,考虑到门如果直接放上去,会被墙盖住;如果比墙厚,又难看不符合实际。还是应该先定义一个门洞立方体,把门所在的位置挖掉:

{name: '门洞',type: 'cube',width: 195,height: 170,depth: 30,op: '-',translate:[-350,2,500],
}

 

刚好挖在斜坡的位置,这样设备进屋就方便了:

 



 

不过这门没有一个门框,感觉不太生动。多一个门框会感觉立体感强一些。门框可以是一个比门洞略大的立方体,在挖门洞之前添加:

{name: '门框',type: 'cube',width: 205,height: 180,depth: 26,translate: [-350, 0, 500],op: '+',}

 加上阴影和光线等综合效果,还不错,挺有档次的。

 

 来张全景图看看:



 

接着,只要把门安上去就行了。门的定义比较简单,就是一个薄的立方体。不过为了做到玻璃效果,需要设置透明度,让它看上去更像一个玻璃,再让设计师美眉弄一张好看一点的门的图,贴上去。尽管有了webGL,复杂的建模工作可以省略了,不过设计师美眉的配合仍然很重要。

先做左边的门:

{name: '左门',type: 'cube',width: 93,height: 165,depth: 2,translate:[-397,4,500],style:{'m.transparent': true,'m.texture.image': 'images/door_left.png',					}

 上面增加的style主要透明和贴图两项。看看效果:



同样的方法,再把右侧门贴上就搞定了。
为了增加体验,也是用户的要求,门上面设置了动画:双击可以自动打开,再双击可以直接关闭。动画功能引擎做好了封装,在json中直接指定动画类型就行了。不过要注意左右门的动画旋转方向要相反,要不然一个向里开一个向外开感觉比较怪异。



 

 

 

项目中,窗本身不需要有任何业务属性,但是美观度的要求可一点都不能少。方法和门类似,先放窗框后挖窗体。不过为了有点变化,这里不做窗框了,做一个窗台,方法和道理与门相同。

 

{name: '主窗户洞',type: 'cube',width: 420,height: 150,depth: 50, translate: [200, 30, 500],op: '-',},{name: '主窗户台',type: 'cube',width: 420,height: 10,depth: 40, translate: [200, 30, 510],op: '+',}
 

 

定义了一个窗洞(挖掉)、一个窗台(添加)。一个大窗户就做好了:



 

再添加一个略带颜色的透明玻璃。玻璃设置点高光和反射,增加“玻璃”感觉:

 

{name: '主窗户玻璃',type: 'cube',width: 420,height: 150,depth: 2,translate: [200, 30, 500],op: '+',style: {'m.transparent': true,'m.opacity':0.4,'m.color':'#58ACFA',},			}
  Json 中玻璃设置了透明度和颜色。这样一个半透明的茶色玻璃就好了:

 

 



到这里突然在想:盖房子如果像写程序一样简单就好了,所有的程序猿就不会是无房一族单身狗了。当然写程序和盖房子一样:该封装好的要封装好,最后就是搭积木组装就行了。如果盖房子都是从挖土活泥巴开始,那就杯具了。写程序也是一样,如果从webGLmain开始写……3D机房的系统要几个月甚至几年才能做出来呢?

 

外侧墙

按照项目实际要求,继续增加更多建筑物墙体。主要是房间外侧有两道走廊隔墙。这是一个中间有大片透明玻璃的走廊隔墙,需要做的好看一点。由于是直线墙,没有复杂走向,直接用立方体定义得了:

 

{name: '左外墙',type: 'cube',width: 20,height: 200,depth: 1300,translate: [-790, 0, 0],op: '+',
}
 

 

效果如下:
 

再继续挖掉中间的窗户部分:

 

{name: '左外墙洞',type: 'cube',width: 30,height: 110,depth: 1300,translate: [-790, 60, 0],op: '-',
}
 

 



 

空白显得很奇怪,加上玻璃试试:

 

{name: '左外墙玻璃',type: 'cube',width: 4,height: 110,depth: 1300,translate: [-790, 60, 0],op: '+',style: {'m.transparent': true,'m.opacity':0.6,},
}
 

 

有了半透明和高光的效果,看起来就有质感了,右边也如法炮制:



 

 

这样,整个建筑的外观就基本完成了。最后,放一些绿植,增加些生气吧。

 

植物

做一盆植物,需要有一个空的花盆,花盆里面有泥土,上面有一株植物。这些东西用3D做起来都有点啰嗦。不过也不难。花盆用一个大圆柱剪掉中间的小圆柱,做成空心花盆;植物用贴图+透明模拟一下就行,不用真的去做植物的3D模型,否则要累死了。

 

 

根据上面的思路,在项目中通过仔细调整,把创建花盆的代码封装好,然后在json中定义花盆位置就行了。下面定义一个:

 

{name: '花1',type: 'plant',translate: [560, 0, 400],
}
  程序中解析如果 type plant 则创建植物对象并添加场景。

 


 

在房间、走廊、甚至窗台上都可以放几盆,窗台上的可以通过设置scale缩小一些,并提升其高度到窗台位置即可。



 

看看下整体效果,还不赖吧。



 写了那么一大篇,才终于把3D机房的外观装修完成,咱也算是个设计师程序员的混合型人才了呢。其实机房最核心的资源——机柜,还没找落呢,没办法,形象工程也是项目建设的一大亮点。

 

机柜

机柜,以及其中的服务器设备。这才是3D机房里面最终要管理的内容。在我们的实际项目中,这些资产都是在数据库中存储,并通过json接口加载到浏览器中显示。这里为了演示方便,直接写几个机柜的片段,看一下显示效果。

 

机柜对象在项目中是这样封装的:用一个立方体来表示机柜,并加上贴图。项目中,为了提高显示速度,机柜一开始并不加载内部服务器内容,而是只显示自身一个立方体。当用户双击后,会触发一个延迟加载器,从服务器端加载机柜内部服务器,并加载到对应的位置上。此时,机柜会被挖空成一个空心的立方体,以便视觉上更像一个机柜。

 

 

定义机柜的json如下:

 

 

{name: '机柜',type: 'rack',lazy: true,width: 70,depth: 100,height: 220,translate: [-370, 0, -250],severity: CRITICAL,}
上面的机柜定义中,有一个 lazy 标记,标记它是否延迟加载其内容。如果延迟加载,则双击触发,否则程序显示时直接加载其内容。 Severity 是定义了机柜的告警信息,它是否有业务告警。如果有告警,会用一个气泡显示在机柜的上方,同时机柜也会被染色成告警对应的颜色。

 



加入更多的机柜看看效果: 



 

 

设备

简单起见,这里管理的设备假设都是机架设备,尺寸规格比较规整,因此比较容易在机柜中组织。一个设备的外观确定后,在数据库中定义好模板,加载时根据其所在机柜的位置放置即可。

 

 

这里只是随机生成了几个服务器设备,并按位置摆放。在实际应用中,可以通过手工录入或者智能机架报送的信息来确定服务器的类型和位置。

 



 

如果需要监控到端口级别,还可以在服务器弹出后,再进一步延迟加载设备商的板卡、端口对象,并点击后进一步进行配置、监控等操作。当然加载的数据越细,对3D引擎和浏览器的压力会越大。可以通过动态延迟加载/卸载策略,获取一些平衡折中。

 

电视机

纯属无聊,再做一个电视机挂在墙上。依旧,定义一个立方体、挖空屏幕,放上透明玻璃,再贴上我们喜欢的电视节目画面,就ok了。

 

{name: '电视机体',type: 'cube',width: 150,height: 80,depth: 5,translate: [80, 100, 13],op: '+',		},{name: '电视机挖空',type: 'cube',width: 130,height: 75,depth: 5,translate: [80, 102.5, 17],op: '-',},{name: '电视机屏幕',type: 'cube',width: 130,height: 75,depth: 1,translate: [80, 102.5, 14.6],op: '+',style: {'front.m.texture.image': 'images/screen.jpg',},}

 当然,实际项目中,也可以换上监控大屏幕的效果:


 

总结

整个场景写到最后,我也已经脑洞大开游刃有余了。3D场景,尤其是这类业务系统,并不一定要死抠模型的仿真度,才能做到“好看”的效果。先来一张全景看一下:



 

 

怎么样,还算精美吧?基本不输前面看到的广告公司的效果图。但和效果图一张死图片不一样,我们这是一个能操作、能漫游、能缩放、有动画、显示流畅、浏览器无需插件就能直接打开的3D机房小程序,就一个json文件和一百多行代码和一天的时间就搞定了,还是让人有点惊讶的。

 



 

不用插件、不用3Dmax,不用模型库,干干净净纯粹的小程序,手机和平板也能用哦,而且还很流畅!上一张我的Nexus5截图瞅瞅:



 

经过优化,场景加载已经控制在600毫秒以内,缩放漫游也很流畅。当然技术和美化永无止境,用户的需求也千变万化精益求精。但只要我们选择好了技术和工具,就能事半功倍。Html5就是极佳的一个选择。

 

Html5,也许它还不是银弹,但它确实是很好的一个炮弹。本文这一弹,你还喜欢吗?欢迎来信留言索取代码、技术交流:tw-service@servasoft.com

 

 

 

这篇关于HTML5数据可视化第二弹:打造最美3D机房的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/696267

相关文章

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

更改docker默认数据目录的方法步骤

《更改docker默认数据目录的方法步骤》本文主要介绍了更改docker默认数据目录的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1.查看docker是否存在并停止该服务2.挂载镜像并安装rsync便于备份3.取消挂载备份和迁

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

Java如何接收并解析HL7协议数据

《Java如何接收并解析HL7协议数据》文章主要介绍了HL7协议及其在医疗行业中的应用,详细描述了如何配置环境、接收和解析数据,以及与前端进行交互的实现方法,文章还分享了使用7Edit工具进行调试的经... 目录一、前言二、正文1、环境配置2、数据接收:HL7Monitor3、数据解析:HL7Busines

Mybatis拦截器如何实现数据权限过滤

《Mybatis拦截器如何实现数据权限过滤》本文介绍了MyBatis拦截器的使用,通过实现Interceptor接口对SQL进行处理,实现数据权限过滤功能,通过在本地线程变量中存储数据权限相关信息,并... 目录背景基础知识MyBATis 拦截器介绍代码实战总结背景现在的项目负责人去年年底离职,导致前期规

Redis KEYS查询大批量数据替代方案

《RedisKEYS查询大批量数据替代方案》在使用Redis时,KEYS命令虽然简单直接,但其全表扫描的特性在处理大规模数据时会导致性能问题,甚至可能阻塞Redis服务,本文将介绍SCAN命令、有序... 目录前言KEYS命令问题背景替代方案1.使用 SCAN 命令2. 使用有序集合(Sorted Set)

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.