基于HTML5快速搭建3D机房设备面板
以真实设备为模型,搭建出设备面板,并实时获取设备运行参数,显示在设备面板上,这相比于纯数值的设备监控系统显得更加生动直观。今天我们就在HT for Web的3D技术上完成设备面板的搭建。
我们今天模拟的设备是机房设备,先来目睹下最终效果:http://www.hightopo.com/demo/blog_3d_20150810/server.html

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

看起来有模有样的,其实呢,它就是一个长方体,然后在长方体的正面贴上一张图片,这样子设备的壳就出来了,创建代码如下:
var node = createNode([0, 0, 0], [475, 100, 0]);
node.s({
'front.image': 'panel',
'all.color': '#E6DEEC'
});
node.setToolTip('Double click to pop the server’);
其中设置设备的正面图片的方法是通过设置节点的front.image样式属性来实现的,在代码中将front.image属性设置为’panel’,而’panel’属性是已经通过ht.Default.setImage()方法注册了的图片的别名,在代码中还设置了长方体各个面的颜色和鼠标悬停时的提示语。
在代码中还调用了createNode()的方法,该方法并没有做什么特殊的操作,只是将创建3D拓扑节点的代码封装起来,精简代码,避免相同的代码重复书写,具体的封装如下:
/**
* 创建3D拓扑节点,并添加到dataModel中
* @param p3 {array} 位置信息
* @param s3 {array} 长宽高信息
* @returns {ht.Node} 3D拓扑节点
*/
function createNode(p3, s3) {
var node = new ht.Node();
node.s({
'shape' : 'rect'
});
node.p3(p3);
node.s3(s3);
dataModel.add(node);
return node;
}
该方法通过传入位置信息和大小信息创建出一个3D拓扑节点,并添加到dataModel中,最后返回该节点对象。
刚刚我们只是创建了设备的外壳而已,在设备上又部分端口是被被占用的,所以接下来我们要做的就是填充设备端口,仔细看了下设备的端口形状,发现形状是不规则的呢,那么设备端口该如何填充呢?我们只需要找一个和端口形状一样的图片贴在长方体的正面,然后套在设备上就可以了,具体的实现如下:
/**
* 创建端口节点,并吸附到指定的节点上
* @param indexes {array} 端口位置信息
* @param host {ht.Node} 被吸附的节点对象
*/
function createPort(indexes, host) {
var p3 = host.p3(),
s3 = host.s3(),
x = -s3[0] / 2,
y = 100 / 2 + p3[1],
z = 1 + s3[2] / 2;
indexes.forEach(function(index) {
var port = new ht.Node();
port.setName('Port');
port.s({
'front.image' : 'port_green',
'all.light' : true
});
port.setHost(host);
port.setSize3d(28, 23, 10);
if (index % 2 === 0) {
var col = (index - 2) / 2;
port.setPosition3d(x + 67.5 + col * 32, y - 60.5, z);
port.s({
'front.uv' : [0, 1, 0, 0, 1, 0, 1, 1]
});
}
else {
var col = (index - 1) / 2;
port.setPosition3d(x + 67.5 + col * 32, y - 26.5, z);
}
dataModel.add(port);
});
}
在设备上总共有20个端口,我们通过传入的端口位置信息来确定创建出来的节点位置,仔细观察设备端口可以发现,第二排的端口和第一排的端口方向不一样,所以在创建第二排的端口时需要通过设置front.uv属性来控制贴图的翻转,当然贴图也是我们事先注册好了的。
好了,到这里我们的设备模型就构建出来了,那么接下来就是创建机柜了,机柜的创建就和设备外壳的创建基本相似,不一样的地方在于,机柜有一个门,这个门有开合的功能,由于拓扑节点无法单独对节点的某一面分离出来做旋转操作,所以门必须是一个单独的拓扑节点,我们先来看看机柜的效果图:

效果图种,我们把门稍微装饰了一下,在门的边缘上加上了蓝色的贴边,让门看起来更有质感,效果图和思路都有了,代码自然而然就出来了,瞧瞧下面的代码,有一点点小复杂哦。
var h = 1000, w = 477, d = 400, k = 20;
// 创建机柜
var main = createNode([0, 0, 0], [w, h, d]); main.s({
'all.color' : '#403F46',
'front.visible' : false
}); // 创建门
var face = new ht.Shape(),
s = {'all.visible' : false, 'front.visible' : true}; dataModel.add(face);
face.addPoint({x : -w / 2, y : d / 2 - 1});
face.addPoint({x : w / 2, y : d / 2 - 1});
face.addPoint({x : w + w / 2, y : d / 2 - 1});
face.setSegments([1, 2, 1]);
face.setTall(h);
face.setThickness(1);
face.s(s);
face.setHost(main); face.s({
'all.color' : 'rgba(0, 40, 60, 0.7)',
'all.reverse.flip' : true,
'all.transparent' : true,
'3d.movable' : false
});
face.face = true;
face.open = false;
face.angle = -Math.PI * 0.6;
face.setToolTip('Double click to open the door'); // 创建门的贴边
var up = createNode([0, h / 2 - k / 2, d / 2], [w, k, 1], false, false).s(s),
down = createNode([0, -h / 2 + k / 2, d / 2], [w, k, 1], false, false).s(s),
right = createNode([w / 2 - k / 2, 0, d / 2], [k, h, 1], false, false).s(s),
left = createNode([-w / 2 + k / 2, 0, d / 2], [k, h, 1], false, false).s(s); up.setHost(face);
down.setHost(face);
left.setHost(face);
right.setHost(face);
代码的逻辑是这样的,先创建一个长方体作为机柜的外壳,然后将长方体的正面设置为隐藏,然后创建一个多边形作为门,将门设为浅蓝色半透明,最后创建4个蓝色长方体贴到门的边缘作为装饰,如此一个机柜就搭建完成了。
设备模型有了,机柜有了,接下来的工作就是将两者合并起来,方法很简单,就是创建设备并将设备吸附到机柜上,具体的代码如下:
var num = 5,
start = 400;
for (var i = 0; i < num; i++) {
var y = start - 170 * i,
z = (d - 30) / 2;
var node = createNode([0, y, 0], [w - 2, 100, d - 30]);
node.s({
'front.image' : 'panel',
'all.color' : '#E6DEEC',
'all.reverse.cull' : true,
'3d.movable' : false
});
node.pop = false;
node.setToolTip('Double click to pop the server');
node.setHost(main);
createPort([1, 2, 3, 4, 5, 6, 7, 13, 16, 17, 20], node);
}
还记得前面构建设备模型和机柜门的代码中,我们对这两个模型添加了鼠标悬停时的提示内容,双击可以打开门,双击可以抽出设备,那么我们现在就来实现这两个效果,首先我们来分析下具体的实现方案:
双击的事件要添加在哪里呢?对每个拓扑节点做监听吗?这是最直接的方法,但是这样做的话,有多少节点将会有多少个对应的处理函数,而且同一类型的处理函数又是一样的,那么这就会导致系统资源的浪费,所以对每个节点做双击的监听方案是不可取的,那么我们该如何处理双击事件呢?我们可以换个角度思考,所有的节点都是添加到3D拓扑组件上的,那么我们是否可以通过监听3D拓扑组件的双击事件,然后通过事件对象获取到对应的节点,然后通过判断节点上设置的自定义标识属性来做相应的处理,具体的代码如下:
// 监听3D拓扑组件的dataDoubleClicked事件
g3d.onDataDoubleClicked = function(data, e, dataInfo) {
// 若果节点为门
if (data.face) {
// 遍历所有吸附在机柜下的节点
data.getHost().getAttaches().each(function(attach) {
// 如果节点状态为弹出,则调用函数还原节点位置
if (attach.pop) {
toggleData(attach);
}
});
}
// 如果节点为端口节点,则触发其所吸附设备的双击事件
else if (data.a('port')) {
toggleData(data.getHost());
return;
}
toggleData(data);
};
阅读上面的代码,大家会发现实现的方案和我们提到的方案不太一样,我们通过监听3D拓扑组件的dataDoubleClicked事件就可以直接获取到被双击的节点对象,而无需我们自己通过事件对象获取对应的节点对象,当然就监听dataDoubleClicked事件了。
在代码中,我们调用了toggleData()方法来处理双击事件,具体的处理代码如下:
/**
* 节点双击处理函数
* @param data {ht.Node} 被双击的节点
*/
function toggleData(data) {
var angle = data.angle,
pop = data.pop; // 当前双击的对象为门
if (angle != null) {
if (anim) {
anim.stop(true);
}
var oldAngle = data.getRotation();
if (data.open) {
angle = -angle;
}
data.open = !data.open;
anim = ht.Default.startAnim({
action : function(t) {
data.setRotation(oldAngle + t * angle);
}
});
}
// 当前双击的对象为设备
else if (pop != null) {
if (anim) {
anim.stop(true);
}
var p3 = data.p3(),
s3 = data.s3(),
dist = (pop ? -s3[2] : s3[2]) / 2;
data.pop = !data.pop;
anim = ht.Default.startAnim({
action : function(t) {
data.p3(p3[0], p3[1], p3[2] + t * dist);
}
});
}
}
在代码中,根据节点预设的不同的属性值来确认该做什么处理,如果节点对象是门的话,则通过ht.Default.startAnim()方法缓慢的修改门的rotation;如果节点对象是设备的话,则缓慢修改设备的position。
到这里,今天的Demo的所有表现和功能就完成了,今天的内容中有设计到节点的style应用,我没有做深入的讲解,后续会给大家一一介绍,感兴趣的朋友可以通过HT for Web的样式手册来了解更多的内容。
下面附上今天的Demo源码及视频。
我已经把今天的Demo上传至官网了,感兴趣的朋友可以点击这里访问。
http://www.hightopo.com/demo/blog_3d_20150810/server.html
http://v.youku.com/v_show/id_XMTMwNTY2ODE0NA==.html
基于HTML5快速搭建3D机房设备面板的更多相关文章
- 基于HT for Web 快速搭建3D机房设备面板
以真实设备为模型,搭建出设备面板,并实时获取设备运行参数,显示在设备面板上,这相比于纯数值的设备监控系统显得更加生动直观.今天我们就在HT for Web的3D技术上完成设备面板的搭建. 我们今天模拟 ...
- 基于HTML5快速搭建TP-LINK电信拓扑设备面板
今天我们以真实的TP-LINK设备面板为模型,完成设备面板的搭建,和指示灯的闪烁和图元流动. 先来目睹下最终的实现效果:http://www.hightopo.com/demo/blog_tplink ...
- 基于 HTML5 Canvas 的 3D 机房创建
对于 3D 机房来说,监控已经不是什么难事,不同的人有不同的做法,今天试着用 HT 写了一个基于 HTML5 的机房,发现果然 HT 简单好用.本例是将灯光.雾化以及 eye 的最大最小距离等等功能在 ...
- 基于 HTML5 WebGL 的 3D 机房
前言 用 WebGL 渲染的 3D 机房现在也不是什么新鲜事儿了,这篇文章的主要目的是说明一下,3D 机房中的 eye 和 center 的问题,刚好在项目中用上了,好生思考了一番,最终觉得这个例子最 ...
- 基于 HTML5 的 WebGL 3D 档案馆可视化管理系统
前言 档案管理系统是通过建立统一的标准以规范整个文件管理,包括规范各业务系统的文件管理的完整的档案资源信息共享服务平台,主要实现档案流水化采集功能.为企事业单位的档案现代化管理,提供完整的解决方案,档 ...
- 基于HTML5的燃气3D培训仿真系统
最近上线了的基于HTML5的燃气3D培训仿真系统,以前的老系统是采用基于C++和OpenGL的OpenSceneGraph引擎设计的,OSG引擎性能和渲染效果各方面还是不错的,但因为这次新产品需求要求 ...
- 基于 HTML5 WebGL 的 3D 风机 Web 组态工业互联网应用
基于 HTML5 WebGL 的 3D 风机 Web 组态工业互联网应用 前言 在目前大数据时代背景之下,数据可视化的需求也变得越来越庞大,在数据可视化的背景之下,通过智能机器间的链接并最终将人机链接 ...
- 基于 Jenkins 快速搭建持续集成环境--转
源地址:http://www.ibm.com/developerworks/cn/java/j-lo-jenkins/ 持续集成是一种软件开发实践,对于提高软件开发效率并保障软件开发质量提供了理论基础 ...
- 基于html5顶部导航3D翻转展开特效
基于html5顶部导航3D翻转展开特效是一款基于jQuery+HTML5实现的3D翻转网站导航菜单代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <header cla ...
随机推荐
- WCF Failed to invoke the service. Possible causes: The service is offline or inaccessible
今天写WCf 时遇到如下报错: 调试过程发现,各个过程都无异常,但是返回给调用端数据时出现如下错误. Failed to invoke the service. Possible causes: Th ...
- 使用WPF动态生成Code 39条形码
最近在看些条形码方面相关的资料,而如果只是看的话,效果似乎并不怎么好,所以决定动手做点Demo,以增强对相关知识的记忆. 这里是一个我编写的使用WPF生成Code 39的例子,Code 39的编码很简 ...
- ENode 1.0 - 消息队列的设计思路
开源地址:https://github.com/tangxuehua/enode 上一篇文章,简单介绍了enode框架内部的整体实现思路,用到了staged event-driven architec ...
- mongodb(回滚)
事实上mongodb是不支持事务的,个人理解原因如下:1.避免大量对document加锁,从而影响性能,2.非关系型的数据库,从设计上就应能尽可能的比较关联复杂的多document,一个数据应能记录在 ...
- 公共代码参考(httpclient)
public class HttpClientUtils { private static final String CHARSET = "UTF-8"; /* * http ge ...
- Programming Erlang 学习笔记(一)
入门 启动Shell 在cmd中输入命令”erl”,百分号(%)表示一个注释的开始,从百分号开始到这行结束的所有文本都被看做是注释. 一个完整的命令需要以一个句点和一个回车结束. 退出erlang的命 ...
- .NET在线培训 | C#在线培训 | .NET培训 | 最课程培训
最课程(www.zuikc.com) 软件开发培训,在线软件培训的创新者!我们的创新在于: 1:一次购买,终身服务.每个最课程学员都会分配一位专职教师及一位监管教师,点对点跟进课程进度,直到您学会课程 ...
- 基于Css反射形自触发事件,优化你的延时事件
昨天听w3ctech分享时候,说道orientationchange在不同OS和版本中,存在兼容问题,很多时候触发时候都没有渲染结束,开发同学一般都是基于setTimeout一段时间之后,在去执行具体 ...
- Vue.js线程机制问题还是数据双向绑定有延迟的问题
最近用select2做一个下拉多选,若只是从后端获取一个列表渲染还好说,没有任何问题.但要用select2对数据初始化时进行selected的默认选项进行显示,就出现问题了. vm.$set('are ...
- [Java面试六]SpringMVC总结以及在面试中的一些问题.
1.简单的谈一下SpringMVC的工作流程? 流程 1.用户发送请求至前端控制器DispatcherServlet 2.DispatcherServlet收到请求调用HandlerMapping处理 ...