以真实设备为模型,搭建出设备面板,并实时获取设备运行参数,显示在设备面板上,这相比于纯数值的设备监控系统显得更加生动直观。今天我们就在HT for Web的3D技术上完成设备面板的搭建。

我们今天模拟的设备是机房设备,先来目睹下最终效果:

我来解释下这个模型,一个带有透明玻璃门的机柜,机柜里装有5台设备,门可以开合,设备可以插拔,那么我么该如何搭建这样的设备呢?方法不难,我们一步一步来。

我们先从设备开始,设备的示意图如下:

看起来有模有样的,其实呢,它就是一个长方体,然后在长方体的正面贴上一张图片,这样子设备的壳就出来了,创建代码如下:

  1. var node = createNode([0, 0, 0], [475, 100, 0]);
  2. node.s({
  3. 'front.image': 'panel',
  4. 'all.color': '#E6DEEC'
  5. });
  6. node.setToolTip('Double click to pop the server’);

其中设置设备的正面图片的方法是通过设置节点的front.image样式属性来实现的,在代码中将front.image属性设置为’panel’,而’panel’属性是已经通过ht.Default.setImage()方法注册了的图片的别名,在代码中还设置了长方体各个面的颜色和鼠标悬停时的提示语。

在代码中还调用了createNode()的方法,该方法并没有做什么特殊的操作,只是将创建3D拓扑节点的代码封装起来,精简代码,避免相同的代码重复书写,具体的封装如下:

  1. /**
  2. * 创建3D拓扑节点,并添加到dataModel中
  3. * @param p3 {array} 位置信息
  4. * @param s3 {array} 长宽高信息
  5. * @returns {ht.Node} 3D拓扑节点
  6. */
  7. function createNode(p3, s3) {
  8. var node = new ht.Node();
  9. node.s({
  10. 'shape' : 'rect'
  11. });
  12. node.p3(p3);
  13. node.s3(s3);
  14. dataModel.add(node);
  15. return node;
  16. }

该方法通过传入位置信息和大小信息创建出一个3D拓扑节点,并添加到dataModel中,最后返回该节点对象。

刚刚我们只是创建了设备的外壳而已,在设备上又部分端口是被被占用的,所以接下来我们要做的就是填充设备端口,仔细看了下设备的端口形状,发现形状是不规则的呢,那么设备端口该如何填充呢?我们只需要找一个和端口形状一样的图片贴在长方体的正面,然后套在设备上就可以了,具体的实现如下:

  1. /**
  2. * 创建端口节点,并吸附到指定的节点上
  3. * @param indexes {array} 端口位置信息
  4. * @param host {ht.Node} 被吸附的节点对象
  5. */
  6. function createPort(indexes, host) {
  7. var p3 = host.p3(),
  8. s3 = host.s3(),
  9. x = -s3[0] / 2,
  10. y = 100 / 2 + p3[1],
  11. z = 1 + s3[2] / 2;
  12. indexes.forEach(function(index) {
  13. var port = new ht.Node();
  14. port.setName('Port');
  15. port.s({
  16. 'front.image' : 'port_green',
  17. 'all.light' : true
  18. });
  19. port.setHost(host);
  20. port.setSize3d(28, 23, 10);
  21. if (index % 2 === 0) {
  22. var col = (index - 2) / 2;
  23. port.setPosition3d(x + 67.5 + col * 32, y - 60.5, z);
  24. port.s({
  25. 'front.uv' : [0, 1, 0, 0, 1, 0, 1, 1]
  26. });
  27. }
  28. else {
  29. var col = (index - 1) / 2;
  30. port.setPosition3d(x + 67.5 + col * 32, y - 26.5, z);
  31. }
  32. dataModel.add(port);
  33. });
  34. }

在设备上总共有20个端口,我们通过传入的端口位置信息来确定创建出来的节点位置,仔细观察设备端口可以发现,第二排的端口和第一排的端口方向不一样,所以在创建第二排的端口时需要通过设置front.uv属性来控制贴图的翻转,当然贴图也是我们事先注册好了的。

好了,到这里我们的设备模型就构建出来了,那么接下来就是创建机柜了,机柜的创建就和设备外壳的创建基本相似,不一样的地方在于,机柜有一个门,这个门有开合的功能,由于拓扑节点无法单独对节点的某一面分离出来做旋转操作,所以门必须是一个单独的拓扑节点,我们先来看看机柜的效果图:

效果图种,我们把门稍微装饰了一下,在门的边缘上加上了蓝色的贴边,让门看起来更有质感,效果图和思路都有了,代码自然而然就出来了,瞧瞧下面的代码,有一点点小复杂哦。

  1. var h = 1000, w = 477, d = 400, k = 20;
  2. // 创建机柜
  3. var main = createNode([0, 0, 0], [w, h, d]);
  4.  
  5. main.s({
  6. 'all.color' : '#403F46',
  7. 'front.visible' : false
  8. });
  9.  
  10. // 创建门
  11. var face = new ht.Shape(),
  12. s = {'all.visible' : false, 'front.visible' : true};
  13.  
  14. dataModel.add(face);
  15. face.addPoint({x : -w / 2, y : d / 2 - 1});
  16. face.addPoint({x : w / 2, y : d / 2 - 1});
  17. face.addPoint({x : w + w / 2, y : d / 2 - 1});
  18. face.setSegments([1, 2, 1]);
  19. face.setTall(h);
  20. face.setThickness(1);
  21. face.s(s);
  22. face.setHost(main);
  23.  
  24. face.s({
  25. 'all.color' : 'rgba(0, 40, 60, 0.7)',
  26. 'all.reverse.flip' : true,
  27. 'all.transparent' : true,
  28. '3d.movable' : false
  29. });
  30. face.face = true;
  31. face.open = false;
  32. face.angle = -Math.PI * 0.6;
  33. face.setToolTip('Double click to open the door');
  34.  
  35. // 创建门的贴边
  36. var up = createNode([0, h / 2 - k / 2, d / 2], [w, k, 1], false, false).s(s),
  37. down = createNode([0, -h / 2 + k / 2, d / 2], [w, k, 1], false, false).s(s),
  38. right = createNode([w / 2 - k / 2, 0, d / 2], [k, h, 1], false, false).s(s),
  39. left = createNode([-w / 2 + k / 2, 0, d / 2], [k, h, 1], false, false).s(s);
  40.  
  41. up.setHost(face);
  42. down.setHost(face);
  43. left.setHost(face);
  44. right.setHost(face);

代码的逻辑是这样的,先创建一个长方体作为机柜的外壳,然后将长方体的正面设置为隐藏,然后创建一个多边形作为门,将门设为浅蓝色半透明,最后创建4个蓝色长方体贴到门的边缘作为装饰,如此一个机柜就搭建完成了。

设备模型有了,机柜有了,接下来的工作就是将两者合并起来,方法很简单,就是创建设备并将设备吸附到机柜上,具体的代码如下:

  1. var num = 5,
  2. start = 400;
  3. for (var i = 0; i < num; i++) {
  4. var y = start - 170 * i,
  5. z = (d - 30) / 2;
  6. var node = createNode([0, y, 0], [w - 2, 100, d - 30]);
  7. node.s({
  8. 'front.image' : 'panel',
  9. 'all.color' : '#E6DEEC',
  10. 'all.reverse.cull' : true,
  11. '3d.movable' : false
  12. });
  13. node.pop = false;
  14. node.setToolTip('Double click to pop the server');
  15. node.setHost(main);
  16. createPort([1, 2, 3, 4, 5, 6, 7, 13, 16, 17, 20], node);
  17. }

还记得前面构建设备模型和机柜门的代码中,我们对这两个模型添加了鼠标悬停时的提示内容,双击可以打开门,双击可以抽出设备,那么我们现在就来实现这两个效果,首先我们来分析下具体的实现方案:

双击的事件要添加在哪里呢?对每个拓扑节点做监听吗?这是最直接的方法,但是这样做的话,有多少节点将会有多少个对应的处理函数,而且同一类型的处理函数又是一样的,那么这就会导致系统资源的浪费,所以对每个节点做双击的监听方案是不可取的,那么我们该如何处理双击事件呢?我们可以换个角度思考,所有的节点都是添加到3D拓扑组件上的,那么我们是否可以通过监听3D拓扑组件的双击事件,然后通过事件对象获取到对应的节点,然后通过判断节点上设置的自定义标识属性来做相应的处理,具体的代码如下:

  1. // 监听3D拓扑组件的dataDoubleClicked事件
  2. g3d.onDataDoubleClicked = function(data, e, dataInfo) {
  3. // 若果节点为门
  4. if (data.face) {
  5. // 遍历所有吸附在机柜下的节点
  6. data.getHost().getAttaches().each(function(attach) {
  7. // 如果节点状态为弹出,则调用函数还原节点位置
  8. if (attach.pop) {
  9. toggleData(attach);
  10. }
  11. });
  12. }
  13. // 如果节点为端口节点,则触发其所吸附设备的双击事件
  14. else if (data.a('port')) {
  15. toggleData(data.getHost());
  16. return;
  17. }
  18. toggleData(data);
  19. };

阅读上面的代码,大家会发现实现的方案和我们提到的方案不太一样,我们通过监听3D拓扑组件的dataDoubleClicked事件就可以直接获取到被双击的节点对象,而无需我们自己通过事件对象获取对应的节点对象,当然就监听dataDoubleClicked事件了。

在代码中,我们调用了toggleData()方法来处理双击事件,具体的处理代码如下:

  1. /**
  2. * 节点双击处理函数
  3. * @param data {ht.Node} 被双击的节点
  4. */
  5. function toggleData(data) {
  6. var angle = data.angle,
  7. pop = data.pop;
  8.  
  9. // 当前双击的对象为门
  10. if (angle != null) {
  11. if (anim) {
  12. anim.stop(true);
  13. }
  14. var oldAngle = data.getRotation();
  15. if (data.open) {
  16. angle = -angle;
  17. }
  18. data.open = !data.open;
  19. anim = ht.Default.startAnim({
  20. action : function(t) {
  21. data.setRotation(oldAngle + t * angle);
  22. }
  23. });
  24. }
  25. // 当前双击的对象为设备
  26. else if (pop != null) {
  27. if (anim) {
  28. anim.stop(true);
  29. }
  30. var p3 = data.p3(),
  31. s3 = data.s3(),
  32. dist = (pop ? -s3[2] : s3[2]) / 2;
  33. data.pop = !data.pop;
  34. anim = ht.Default.startAnim({
  35. action : function(t) {
  36. data.p3(p3[0], p3[1], p3[2] + t * dist);
  37. }
  38. });
  39. }
  40. }

在代码中,根据节点预设的不同的属性值来确认该做什么处理,如果节点对象是门的话,则通过ht.Default.startAnim()方法缓慢的修改门的rotation;如果节点对象是设备的话,则缓慢修改设备的position。

到这里,今天的Demo的所有表现和功能就完成了,今天的内容中有设计到节点的style应用,我没有做深入的讲解,后续会给大家一一介绍,感兴趣的朋友可以通过HT for Web样式手册来了解更多的内容。

下面附上今天的Demo源码及视频。

我已经把今天的Demo上传至官网了,感兴趣的朋友可以点击这里访问。

http://v.youku.com/v_show/id_XMTMwNTY2ODE0NA==.html

基于HT for Web 快速搭建3D机房设备面板的更多相关文章

  1. 基于HTML5快速搭建3D机房设备面板

    以真实设备为模型,搭建出设备面板,并实时获取设备运行参数,显示在设备面板上,这相比于纯数值的设备监控系统显得更加生动直观.今天我们就在HT for Web的3D技术上完成设备面板的搭建. 我们今天模拟 ...

  2. 基于HT for Web矢量实现3D叶轮旋转

    在上一篇<基于HT for Web矢量实现2D叶轮旋转>中讲述了叶轮旋转在2D上的应用,今天我们就来讲讲叶轮旋转在3D上的应用. 在3D拓扑上可以创建各种各样的图元,在HT for Web ...

  3. 基于HT for Web的3D呈现A* Search Algorithm

    最近搞个游戏遇到最短路径的常规游戏问题,正巧看到老同事写的3D机房最短路径巡线文章,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈现,算法基于开源 https://github.c ...

  4. 基于HT for Web 3D呈现Box2DJS物理引擎

    上篇我们基于HT for Web呈现了A* Search Algorithm的3D寻路效果,这篇我们将采用HT for Web 3D来呈现Box2DJS物理引擎的碰撞效果,同上篇其实Box2DJS只是 ...

  5. 基于HT for Web的Web SCADA工控移动应用

    在电力.油田燃气.供水管网等工业自动化领域Web SCADA的概念已经提出了多年,早先年的Web SCADA前端技术大部分还是基于Flex.Silverlight甚至Applet这样的重客户端方案,在 ...

  6. 基于HT for Web矢量实现HTML5文件上传进度条

    在HTML中,在文件上传的过程中,很多情况都是没有任何的提示,这在体验上很不好,用户都不知道到时有没有在上传.上传成功了没有,所以今天给大家介绍的内容是通过HT for Web矢量来实现HTML5文件 ...

  7. Reactjs-generator-cli 一款基于Ink构建用于快速搭建React应用的CLI scaffolding工具

    Reactjs-generator-cli 一款基于Ink构建用于快速搭建React应用的CLI scaffolding工具 A simple CLI for scaffolding React.js ...

  8. 基于HT for Web 3D技术快速搭建设备面板

    以真实设备为模型,搭建出设备面板,并实时获取设备运行参数,显示在设备面板上,这相比于纯数值的设备监控系统显得更加生动直观.今天我们就在HT for Web的3D技术上完成设备面板的搭建. 我们今天模拟 ...

  9. 基于HT for Web的3D拓扑树的实现

    在HT for Web中2D和3D应用都支持树状结构数据的展示,展现效果各异,2D上的树状结构在展现层级关系明显,但是如果数据量大的话,看起来就没那么直观,找到指定的节点比较困难,而3D上的树状结构在 ...

随机推荐

  1. .NET JSON对象序列化和反序列化

    class Program { static void Main(string[] args) { Console.WriteLine("========================== ...

  2. [转]phoneGap3.0安装步骤(以windows下的android环境为例):

    phoneGap3.0安装步骤(以windows下的android环境为例): 环境: WIN系统,JDK,Android,Eclipse,Ant,Git,PhoneGap3.x (Cordova) ...

  3. asp.net WebApi and protobuff

    protobuff 是谷歌开发的,在性能上要比Json xml好很多,对性能要求比较高的时候这个是一个不错的选择,但是这个目前只是一个序列化反序列化的东西,以前原生的只有几种语言的现在在github ...

  4. C#中的线程四(System.Threading.Thread)

    C#中的线程四(System.Threading.Thread) 1.最简单的多线程调用 System.Threading.Thread类构造方法接受一个ThreadStart委托,改委托不带参数,无 ...

  5. Javascript函数节流

    最近在做网页的时候有个需求,就是浏览器窗口改变的时候需要改一些页面元素大小,于是乎很自然的想到了window的resize事件,于是乎我是这么写的 <!DOCTYPE html> < ...

  6. webservice4

    原理: 参考 http://lvwenwen.iteye.com/blog/1478236 客户端通过get请求可以得到wsdl文件,也就知道服务器提供的方法和参数了,然后客户端会通过webservi ...

  7. iOS xcode6 添加.pch文件

    1, 新建文件 (command+N)选择other组,再次选择pch,输入文件名保存. eg: 创建的工程为Demo; 创建文件名为DemoPrefixHeader.pch 2,到工程里面的buil ...

  8. 我心中的核心组件(可插拔的AOP)~分布式Session组件

    回到目录 对于目前的网站来说,为了满足高可用,高并发,高负载,一台WEB服务器已经远远不够用了,以后的WEB应用服务器应该是一种集群的环境,它们之间使用一些工具进行数据的同步,在由1台变成多台服务器时 ...

  9. Nodejs·进程

    之前对这部分的内容很感兴趣,没想到读起来有点晦涩,还是因为对服务器的知识不是很了解. 说道服务器一般人都会想到tomcat或者Jboss或者weblogic,现在流行起来的Node总让人不太放心,JS ...

  10. 【原创】NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示

    前言 NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能.这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2.而Netty的主要版本是Netty3和Netty ...