内容简介:这个例子的初衷是模拟服务器与客户端的通信,我把整个需求简化变成了今天的这个例子。3D 的模拟一般需要鹰眼来辅助的,这样找产品以及整个空间的概括会比较明确,在这个例子中我也加了,这篇文章算是我对这次项目的一个总结吧。例子链接:本文动图:
这个例子的初衷是模拟服务器与客户端的通信,我把整个需求简化变成了今天的这个例子。3D 的模拟一般需要鹰眼来辅助的,这样找产品以及整个空间的概括会比较明确,在这个例子中我也加了,这篇文章算是我对这次项目的一个总结吧。
例子链接: www.hightopo.com/demo/3DEdge…
本文动图:
代码实现
进入正题,整个例子仅仅是用了两百多行代码来实现,这就是我喜欢用HT 的原因,能够进行快速开发。现在 Web3D 技术兴起,大体就是分为两派:插件派和 HTML5 派。HT 就是基于 HTML5 的,不需要安装任何插件,啊,跑题了。。。
场景搭建
首先,还是从场景的搭建开始,这个界面是在 body 体上添加了三个部分:3D 组件,表单组件以及拓扑组件(2D 组件)。添加的方式是这样的:为了最外层组件加载填充满窗口的方便性,HT 的所有组件都有 addToDOM 函数,其实现逻辑如下,其中 iv 是 invalidate 的简写:
addToDOM = function(){
var self = this,
view = self.getView(), // 获取组件的底层 div
style = view.style;
document.body.appendChild(view); // 将底层 div 添加进 body 中
style.left = '0'; // HT 默认组件的 position 为 absolute 绝对定位,所以要设置位置
style.right = '0';
style.top = '0';
style.bottom = '0';
window.addEventListener('resize', function () { self.iv(); }, false); // 当窗口大小变化时触发事件,调用 iv 函数,刷新页面
}
复制代码
HT 的组件一般都会嵌入 BorderPane、SplitView 和 TabView 等容器中使用,而最外层的HT组件则需要用户手工将 getView()返回的底层 div 元素添加到页面的 DOM 元素中,这里需要注意的是,当父容器大小变化时,如果父容器是 BorderPane 和 SplitView 等这些 HT 预定义的容器组件,则 HT 的容器会自动递归调用孩子组件 invalidate 函数通知更新。但如果父容器是原生的 html 元素, 则 HT 组件无法获知需要更新,因此最外层的 HT 组件一般需要监听 window的窗口大小变化事件,调用最外层组件 invalidate 函数进行更新。
因为这个函数是将 style 中的位置都固定了,所以不能将所有的组件都用这个函数,我们按照这个函数的方式将拓扑组件和属性组件添加进界面中,3D 组件直接利用 addToDOM 函数即可:
dm = new ht.DataModel();
g3d = new ht.graph3d.Graph3dView(dm); // 3d 组件
g3d.addToDOM(); // 将组件添加进 body 体中
g3d.setDashDisabled(false); // 开启虚线流动
g3d.setMovableFunc(function(){ // 重载移动函数
return false; // 返回false,所有的图元都不可移动
});
g3d.setEye([-813, 718, 1530]); // 设置 eye
g3d.setCenter([140, -25, 217]); // 设置 center(target)
gv = new ht.graph.GraphView(dm); // 2D 组件
gv.getView().className = 'graphview'; // HT 组件根层都是一个 div,通过 getView() 函数获取
document.body.appendChild(gv.getView()); // 将拓扑组件添加进 body 体中
gv.fitContent(true); // 缩放平移整个拓扑以展示所有的图元
var form = new ht.widget.FormPane(); // 表单面板组件
var view = form.getView(); // 获取表单底层div
document.body.appendChild(view); // 将表单组件的底层div添加进body中
form.setWidth(200); // 设置表单面板的宽度
form.setHeight(140);
view.style.top = '5px'; // 设置表单面板底层div位置
view.style.right = '5px';
view.style.background = 'rgba(255, 255, 255, 0.2)';
复制代码
拓扑组件和属性组件的样式我就不再赘述了,只是设置了一个背景颜色以及 left right top bottom 位置而已。这里要声明一下,HT 组件一般都以设置 position 为 absolute 的绝对定位方式。
添加鹰眼
大家可能会好奇,这个鹰眼怎么生成的?在 HT 中,只要 2D 和 3D 共用同一个数据容器 dataModel 即可共同拥有所有在这个 dataModel 中的元素,并且位置都是对应的,只需要类似这种做法即可:
dm = new ht.DataModel(); g3d = new ht.graph3d.Graph3dView(dm); gv = new ht.graph.GraphView(dm); 复制代码
是不是非常简单。。。可以省去大把时间开发。。。
这个例子中除了连线之外的所有元素都是 ht.Node 类型的节点,所以我们将这个节点的创建方法封装一下,好重复利用:
function createNode(p3, s3, name, shape){ // 创建节点
var node = new ht.Node(); // 创建类型为 ht.Node 类的节点
dm.add(node); // 将节点添加进数据容器 dataModel 中
node.s({ // 设置节点的样式,s 为 setStyle 的简写
'shape3d': shape, // 指定节点的形体,这边是传入 3d 模型的 json 文件
'label.position': 23, // 文字显示位置
'label.transparent': true, // 文字在 3d 下是否透明 可消除字体周围的锯齿
'label.color': '#eee', // 文字颜色
'label.t3': [0, 0, -151], // 文字在 3d 下的偏移
'label.r3': [0, Math.PI, 0], // 文字在 3d 下的旋转
'label.scale': 2 // 文字缩放
});
node.r3(0, Math.PI, 0); // 节点旋转
node.p3(p3); // 设置节点在 3d 下的位置
node.s3(s3); // 设置节点在 3d 下的大小
node.setName(name); // 设置节点的显示名称
return node; // 返回节点
}
复制代码
以及连线的创建:
function createEdge(exchange, service){ // 创建连线
var edge = new ht.Edge(exchange, service);
dm.add(edge);
edge.s({
'edge.width': 4, // 连线宽度
'edge.color': 'red', // 连线颜色
'edge.dash': true, // 是否显示虚线
'edge.dash.color': 'yellow', // 虚线颜色
'edge.dash.pattern': [32, 32], // 连线虚线样式默认为[16, 16]
});
edge.a({ // 用户自定义属性 为 setAttr 的缩写
'flow.enable': true, // 是否启用流动
'flow.direction': 1, // 方向
'flow.step': 4 // 步进
});
return edge;
}
复制代码
我们界面中的显示的连线都是虚线流动的,HT 默认是关闭虚线流动的功能的,通过下面这句来开启虚线流动的功能:
g3d.setDashDisabled(false); // 开启虚线流动 复制代码
同时我们还需要设置动画,控制时间间隔,使得连线虚线偏移,形成一种“流动”的状态,动画请参考schedule 调度手册:
flowTask = {
interval: 40,
action: function(data){
if(data.a('flow.enable')){
data.s('edge.dash.offset', data.s('edge.dash.offset')+(data.a('flow.step')*data.a('flow.direction')));
}
}
};
dm.addScheduleTask(flowTask); // 添加 flowTask 动画
复制代码
以下是界面上出现的所有的服务器以及客户端的节点的声明,都是基于 createNode 和 createEdge 函数创建的:
function initModel(){
floor = createNode([0, 5, 0], [1000, 10, 500]); // 地板图元
floor.s({
'all.color': 'rgb(47, 79, 79)',
'3d.selectable': false,
});
exchange = createNode([0, 300, -400], [200, 20, 150], 'H3C 核心交换机', 'models/机房/机柜相关/机柜设备6.json', 'symbols/机房/机柜组件1.json').s('label.t3', [0, 0, -151]); // 交换机
// 五台不同作用的服务器
service1 = createNode([-400, 140, 0], [100, 260, 100], '备用', 'models/机房/机柜相关/机柜2.json', 'symbols/机房/电阻柜.json');
service2 = createNode([-200, 140, 0], [100, 260, 100], '网站', 'models/机房/机柜相关/机柜2.json', 'symbols/机房/电阻柜.json');
service3 = createNode([0, 140, 0], [100, 260, 100], 'OA', 'models/机房/机柜相关/机柜2.json', 'symbols/机房/电阻柜.json');
service4 = createNode([200, 140, 0], [100, 260, 100], '广告', 'models/机房/机柜相关/机柜2.json', 'symbols/机房/电阻柜.json');
service5 = createNode([400, 140, 0], [100, 260, 100], '受理', 'models/机房/机柜相关/机柜2.json', 'symbols/机房/电阻柜.json');
var arr = [service1, service2, service3, service4, service5];
for(var i = 0; i < arr.length; i++){ // 创建 node 节点的时候设置了一个旋转还有字体的旋转以及位置,都是针对“设备”的
var service = arr[i];
service.r3(0, 0, 0);
service.s({
'label.r3': [0, 0, 0],
'label.t3': [0, 30, 50],
});
}
// 创建交换机与服务器之间的连线
createEdge(exchange, service1);
createEdge(exchange, service2);
createEdge(exchange, service3);
createEdge(exchange, service4);
createEdge(exchange, service5);
// 第二台交换机
exchange2 = createNode([-100, 60, 400], [200, 20, 150], 'Procurve Switch 2010-23 交换机', 'models/机房/机柜相关/机柜设备6.json', 'symbols/机房/机柜组件1.json').s('label.t3', [0, 0, -151]);
// 剩下创建的节点部分重复的太多,我就不贴代码了
}
复制代码
最后,在 form 表单中操作“连线” edge 的流动、流动方向、流动步进、连线颜色以及虚线颜色。我们在 form 表单中将这些需要操作的属性添加进去,总共 5 个属性,包括我通过 setAttr(简写为 a)自定义的属性 flow.direction、flow.step 和样式属性 edge.color 以及 edge.dash.color 还有就是直接操作动画的开关 enabled 属性来控制连线的流动。我们通过 name 属性结合 accessType 属性实现对 Data 节点的存取:
function createForm(){
var form = new ht.widget.FormPane(); // 表单面板组件
var view = form.getView(); // 获取表单底层 div
document.body.appendChild(view); // 将表单组件的底层 div 添加进 body 中
form.setWidth(200); // 设置表单面板的宽度
form.setHeight(140);
view.style.top = '5px'; // 设置表单面板底层 div 位置
view.style.right = '5px';
view.style.background = 'rgba(255, 255, 255, 0.2)';
form.setLabelColor('#fff'); // 设置表单面板中文字颜色
form.addRow([ // 通过这个函数向表单面板添加一行组件
'Enable Flow', // 用于存取属性名的显示文本值,若为空则显示 name 属性值
{
checkBox: { // 复选框,设置了该属性后HT将根据属性值自动构建 ht.widget.CheckBox 对象,并保存在 element 属性上
value: true,
onValueChanged: function(){ // 值变化后调用函数
flowTask.enabled = this.getValue();
}
}
}
, [0.1, 0.1]);
form.addRow([
{
name: 'flow.direction',
accessType: 'attr',
element: 'Flow Direction',
},
{
comboBox: {
value: 1,
labels: ['正向流动', '反向流动'],
values: [-1, 1],
onValueChanged: function(){
for(var i = 0; i < dm.size(); i++){
var data = dm.getDatas().get(i);
data.a('flow.direction', this.getValue());
}
}
}
}
], [0.1, 0.1]);
form.addRow([
{
name: 'flow.step',
element: 'Flow Step',
accessType: 'attr',
},
{
slider: { // 滑动条,设置了该属性后HT将根据属性值自动构建 ht.widget.Slider 对象,并保存在 element 属性上
min: 0,//最小值
max: 10,//最大值
step: 0.1,//步进
value: 1,
onValueChanged: function(){
for(var i = 0; i < dm.size(); i++){
var data = dm.getDatas().get(i);
data.a('flow.step', this.getValue());
}
}
}
}
], [0.1, 0.1]);
form.addRow([
{
name: 'edge.color',
accessType: 'style',
element: 'Edge Color',
},
{
colorPicker: { // 颜色选择框
instant: true, // 获取和设置是否处于即时状态,代表作为表格和属性页的编辑器时,将实时改变模型值
value: 'rgb(255, 0, 0)',
onValueChanged: function(){
for(var i = 0; i < dm.size(); i++){
var data = dm.getDatas().get(i);
data.s('edge.color', this.getValue());
}
}
}
}
], [0.1, 0.1]);
form.addRow([
{
name: 'edge.dash.color', // 虚线样式属性
element: 'Dash Color',
accessType: 'style'
},
{
colorPicker: {
instant: true,
value: 'rgb(255, 255, 0)',
onValueChanged: function(){
for(var i = 0; i < dm.size(); i++){
var data = dm.getDatas().get(i);
data.s('edge.dash.color', this.getValue());
}
}
}
}
], [0.1, 0.1]);
}
复制代码
是不是非常简单~ 快动手实践一下吧!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 告警系统主脚本,告警系统配置文件,告警系统监控项目
- 分布式系统的那些事儿(三) - 系统与系统之间的调用
- 在线考试系统从Windows系统迁移到Linux系统的整个过程
- 系统设计之系统建设的目的
- 文件系统(二)fastdfs和其他文件系统区别
- 分布式系统-->(关于系统应用的基本概念)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Mathematica Cookbook
Sal Mangano / O'Reilly Media / 2009 / GBP 51.99
As the leading software application for symbolic mathematics, Mathematica is standard in many environments that rely on math, such as science, engineering, financial analysis, software development, an......一起来看看 《Mathematica Cookbook》 这本书的介绍吧!