这个基于HTML5WebGL的3DSCADA主站系统的例子的初衷是模拟服务器和客户端之间的通信。我将整个需求简化为今天的例子。3D模拟一般需要鹰眼的辅助,这样产品搜索和整个空间的概览才会更加清晰。在这个例子中,我也添加了它。这篇文章可以算是我对这个项目的总结。例子链接:http://www.hightopo.com/demo/...本文动图:进入正题,整个例子用200多行代码实现,这也是我喜欢用的原因HT,它可以快速开发。现在Web3d技术兴起,大致分为两大派系:插件派和HTML5派。HT是基于HTML5的,不需要安装任何插件啊,扯远了。..首先,让我们从场景的搭建开始。该接口在body上增加了三个部分:3d组件、表单组件和拓扑组件(2d组件)。添加方式是这样的:为了方便加载最外层组件填充窗口,HT所有组件都有addToDOM函数,其实现逻辑如下,其中iv是invalidate的简写:addToDOM=function(){varself=this,view=self.getView(),//获取组件底层divstyle=view.style;document.body.appendChild(view);//将底层div添加到body中style.left='0';//HT默认组件的position是绝对的,所以设置positionstyle.right='0';style.top='0';style.bottom='0';window.addEventListener('resize',function(){self.iv();},false);//窗口大小变化时触发事件,调用iv函数,刷新页面}HT组件一般嵌入在BorderPane、SplitView和TabView容器中,最外层的HT组件需要用户手动添加底层返回的div元素通过getView()到页面的DOM元素。这里需要注意的是,当父容器的尺寸变化时,如果父容器是HT预定义的容器,如BorderPane、SplitView组件,HT容器会自动递归调用子组件的invalidate函数通知更新。但是如果父容器是原生的html元素,HT组件无法知道它需要更新,所以最外层的HT组件一般需要监听窗口的窗口大小变化事件,调用最外层的invalidate函数要更新的组件。因为这个函数固定了样式中的位置,所以我们不能对所有组件都使用这个函数。我们根据这个功能在界面中添加拓扑组件和属性组件。3d组件可以直接使用addToDOM函数:dm=newht.DataModel();g3d=newht.graph3d.Graph3dView(dm);//3d组件g3d.addToDOM();//添加组件到bodyg3d.setDashDisabled(false);//启用虚线流g3d.setMovableFunc(function(){//重载的移动函数returnfalse;//返回false,所有图元不可移动});g3d.setEye([-813,718,1530]);//设置眼睛g3d.setCenter([140,-25,217]);//setcenter(target)gv=newht.graph.GraphView(dm);//2d组件gv.getView().className='graphview';//HT组件的根层是一个div,通过getView()函数获取document.body.appendChild(gv.getView());//将拓扑组件添加到body中gv.fitContent(true);//缩放和平移整个拓扑显示所有primitivesvarform=newht.widget.FormPane();//表单面板组件varview=form.getView();//获取底层divdocument.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)';拓扑组件和属性组件的样式我就不细说了,只设置一个背景色和左右上下位置而已。在这里声明一下,HT组件一般使用position设置为absolute的绝对定位方式。你可能想知道,这个鹰眼是怎么来的?在HT中,只要2D和3D共享同一个数据容器dataModel,就可以共享这个dataModel中的所有元素,位置都是对应的,就像这样:dm=newht.DataModel();g3d=newht.graph3d.Graph3dView(dm);gv=newht.graph.GraphView(dm);是不是很简单。..可以节省大量的开发时间。..本例中除了connection之外的所有元素都是ht.Node类型的节点,所以我们封装了这个节点的创建方法以便复用:functioncreateNode(p3,s3,name,shape){//CreateNodevarnode=newht.Node();//创建一个ht.Node类型的节点dm.add(node);//将节点添加到数据容器dataModelnode.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下的大小3dnode.setName(name);//设置节点的显示名称returnnode;//returnnode}和连接的创建:functioncreateEdge(exchange,service){//创建连接varedge=newht.Edge(交换,服务);dm.add(edge);edge.s({'edge.width':4,//连线宽度'edge.color':'red',//连线颜色'edge.dash':true,//是否显示虚线'edge.dash.color':'黄色',//虚线颜色'edge.dash.pattern':[32,32],//默认虚线样式为[16,16]});edge.a({//用户自定义属性是setAttr的缩写'flow.enable':true,//是否开启flow'flow.direction':1,//direction'flow.step':4//步进});returnedge;}我们界面显示的连接都是虚线流,HT默认关闭虚线流功能,使用下面一句开启虚线流功能:g3d.setDashDisabled(false);//打开虚线流,我们还需要设置动画,控制时间间隔,让虚线偏移,形成“流”的状态。动画请参考调度手册: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动画下面是所有出现在界面上的server和client节点声明,都是基于createNode和createEdge函数创建的:functioninitModel(){floor=createNode([0,5,0],[1000,10,500]);//地板元素floor.s({'all.color':'rgb(47,79,79)','3d.selectable':错误的,});exchange=createNode([0,300,-400],[200,20,150],'H3C核心交换机','机型/机房/机柜相关/机柜设备6.json','symbols/机房/机柜组件1.json').s('label.t3',[0,0,-151]);//切换//五台不同功能的服务器service1=createNode([-400,140,0],[100,260,100],'Standby','models/机房/cabinet-related/cabinet2.json','symbols/机房/电阻cabinet.json');service2=createNode([-200,140,0],[100,260,100],'网站','型号/机房/机柜相关/cabinet2.json','symbols/机房/电阻柜.json');service3=createNode([0,140,0],[100,260,100],'OA','机型/机房/机柜相关/cabinet2.json','symbols/机房/电阻机柜.json');service4=createNode([200,140,0],[100,260,100],'广告','机型/机房/机柜相关/cabinet2.json','符号/机房/电阻机柜.json');service5=createNode([400,140,0],[100,260,100],'Acceptance','models/机房/cabinet-related/cabinet2.json','symbols/机房/resistancecabinet.json');vararr=[服务1、服务2、服务3、服务4、服务5];for(vari=0;i
