当前位置: 首页 > Web前端 > HTML5

WebGL3DTelecomRack实战数据绑定

时间:2023-04-05 20:53:10 HTML5

前言在前端,视图层和数据层需要进行单向或双向数据绑定。每个人都熟悉它。有时2D做得更流畅。我要挑战3D,不然总觉得手痒。我觉得这个3D架子的demo很有代表性。首先,3D机架的用途非常广泛,尤其是在电信行业。即使不是机架,3D模型和数据绑定在工业等行业的应用也非常广泛。毕竟现在工业物联网已经是大趋势了。效果图上方的动图中,闪烁的灯光不断变化。因为需要展示的效果更美更逼真,所以我拍的图比较完整,就是闪的部分有点看不清楚(cnblog放太多了明显的外链很容易被首页删掉!!!会发的稍后再试!)。代码实现上图gif中虽然一个是2D,一个是3D,但是构建步骤和需要的内容是一样的,所以本文只实现3D模型的代码。场景构建构建3D场景非常快,只需要三行代码:dm=newht.DataModel();//创建数据容器数据容器也可以通过g3d.getDataModel()获取g3d=newht.graph3d。Graph3dView(dm);//创建一个3D场景,将数据容器作为参数传入,使数据容器中的内容可以在3D场景中显示g3d.addToDOM();//将3D场景添加到body3Drackmodelconstruction虽然我可以要求设计师直接给我一个obj格式的模型,但是我觉得这是一个比较简单的答案,所以不要麻烦别人。..首先是创建一个六面体。模型上的贴图是我之前用的json格式文件,作为六面体的正面贴图。这些部分都写在json文件中。我先截取一小部分json内容,然后用js代码重现:{"c":"ht.Node",//anelementoftypeht.Node"i":1277,//id"p":{//通过set/get/获取元素的部分。如setPosition/getPosition"tag":"service",//设置元素标签为唯一标识"image":"symbols/cabinet.json",//设置节点图片"rotationX":1.5708,//设置节点X轴旋转角度"position":{//设置节点位置"x":0,"y":225},"anchor":{//设置节点锚点"x":0.5,"y":0.54},"anchorElevation":1,//设置节点y轴锚点"width":507,//设置节点宽度"height":980,//设置节点长度"tall":450,//设置节点height"elevation":451//控制Node图元中心所在的3D坐标系的y轴位置},"s":{//设置图元的样式,HT预定义的一些样式属性,通过node.s('all.color')获取并设置节点的样式"all.color":"#DDDDDD",//设置节点六边的颜色"top.image":"symbols/cabinet.json",//设置节点顶部图片"front.visible":true,//设置节点正面是否可见"back.visible":true,"left.visible":true,"right.visible":true,"bottom.visible":true}}这部分的json内容一般是创建一个ht.Node节点,然后为这个节点设置一些属性,包括节点坐标,node大小和一些样式设置。那么,如何使用代码来创建这样的节点呢?varnode=newht.Node();//创建一个ht.Node类型的节点node.setTag('service');//设置节点的标签node.setImage('symbols/cabinet.json');//设置节点图片node.setRotationX(Math.PI/2);//设置节点x轴旋转node.setPosition(0,225);//设置节点位置node.setAnchor(0.5,0.54);//设置节点锚点node.setAnchorElevation(1);//设置节点y轴方向的锚点node.setWidth(507);//设置节点的宽度node.setHeight(980);//设置节点的长度node.Tall(450);//设置节点的高度node.setElevation(451);//控制Node图元中心所在的3D坐标系的y轴位置node.s({//设置节点样式'all.color':'#ddd',//六边形颜色'top.image':'symbols/cabinet.json',//节点顶部的图像'front.visible':true,//设置节点的前面可见'back.visible':true,'left.visible'':true,'right.visible':true,'bottom.visible':true});事实上,整个json就是由多个这种类型的primitives组成的。让我们拆解它。整个3D机架实际上由十个图元组成。第一个是整体3D柜体(也就是我们在上面的json内容中创建的部分),剩下的九个是需要动态改变闪灯的设备,也就是我红框框起来的部分:http://www.hightopo.com/demo/...这些设备的创建方法和上面的3D架类似,只是对应的节点尺寸更小,贴图不同,坐标不同。但是下面九个节点的纹理好像有点不一样?上面有闪光灯,而且不止一个!如何动态获取它们?Vector-databinding不得不说到vector的概念。Vector是HTforWeb中矢量图形的缩写。常见的栅格位图如png、jpg等通过存储每个像素的颜色信息来描述图形。在拉伸和放大或缩小时,这样处理的图片会出现图形模糊、线条粗、线条锯齿等问题。矢量图像通过点、线、多边形来描述图形,因此在无限放大和缩小图像时仍能保持一致的精度。这些都是次要的,最重要的是这个vector可以进行数据绑定(这个数据绑定是绑定到节点上的),而且绑定方法非常简单!矢量以json格式描述,其用法与普通栅格位图相同。它通过node.setImage('hightopo.json')或node.setIcon('hightopo.json')设置为数据模型。vectorjson描述必须包含width、height和comps参数信息:width矢量图的width矢量图的heightheight矢量图的comps组件矢量图数组,每个数组对象都是一个独立的组件类型,数组的排列顺序就是其中的排列顺序componentsaredrawn由于这张图的绘制还是比较复杂,所以我把矩形部分的矢量绘制代码贴上数据绑定:{"width":48,//一个矢量图标必须的宽度矢量。详见HTforWeb矢量手册"height":262,//矢量图标必要的高度"comps":[//矢量图标必要的数组组件{//第一个元素arraycomponent"type":"rect",//类型为矩形"background":{//设置矩形的背景色"func":"attr@rectBg1",//HT将之前的参数值替换为anobjectwiththefuncattributeHereistheimplementationWherethedataisbound"value":"rgb(255,0,0)"//如果func值未定义或为null,则使用此值},"shadow":true,//设置“阴影”"shadowColor":{//"阴影"颜色"func":"attr@shadowColor1",//这里“阴影”也是数据绑定的,为了达到“发光”的效果"lights"value":"rgba(255,0,0,0.35)"//设置备选值},"shadowOffsetX":0,//设置阴影横轴偏移"shadowOffsetY":0,//设置阴影“rect”纵轴的偏移量:[//设置组件的宽高坐标4.38544,//x轴坐标23.52679,//y轴坐标14.46481,//width分量width6.1554//height分量height]}]}因为矢量图中有5个“闪烁的灯”,所以我加了5个分量,也就是在comps参数里加了5个元素,绑定的数据是不同的。为了省事,我把绑定的数据名设置为“rectBg”后面跟着一个数字,这些数字依次递增。我们设置这样一个矢量图作为节点的front.image作为节点的正面展示Image:node.s('front.image','symbols/internaldevice2.json')。JSON反序列化有人会好奇json文件中的内容是如何转化为3D模型的吗?说实话,步骤还是很简单的:ht.Default.xhrLoad('scene/service3d.json',function(text){//xhrLoad函数是一个异步加载文件的函数dm.deserialize(text);//Deserialize对数据容器进行解析,生成对应的Data对象加入到数据容器中,相当于将json文件中生成的ht.Node节点反序列化到数据容器中,这样数据容器中就有了这个节点});由于xhrLoad函数是一个异步加载函数,如果没有完成dm数据容器的反序列化,直接调用节点,会导致获取不到数据的结果,所以一般来说,我写一些逻辑代码在这个函数内部,或者给逻辑代码设置timeout来错开时间差。首先,由于数据存储在dm数据容器中(通过dm.add(node)添加),我们不仅可以通过id、tag等独立方法获取数据,还可以遍历数据容器获取多个元素:varinfos=[{shadowColor:'shadowColor1',background:'rectBg1'},{shadowColor:'shadowColor2',background:'rectBg2'},{shadowColor:'shadowColor3',background:'rectBg3'},{shadowColor:'shadowColor4',background:'rectBg4'},{shadowColor:'shadowColor5',background:'rectBg5'}];varlen=infos.length;//获取数组中的长度vardatas=dm.toDatas(function(d){returnd.getDisplayName()==='device';});//新建一个带过滤功能的元素集合,并返回(ht.Listarraytype)setInterval(function(){datas.forEach(function(data){varinfo=infos[Math.floor(Math.random()*len)];varshadowName=info.shadowColor;varbgName=info.background;if(data.a(shadowName)==='rgba(255,0,0,0.35)'){//如果节点业务属性“shadow”颜色为红色,则设置为绿色data.a(shadowName,'rgba(0,255,0,0.35)');}else{//如果节点业务属性“shadow”颜色为绿色,则设置为红色data.a(shadowNa我,'rgba(255,0,0,0.35)');}if(data.a(bgName)==='rgb(255,0,0)'){//如果节点业务属性的背景色为红色,则设置为绿色data.a(bgName,'rgb(0,255,0)');}else{//如果节点业务属性的背景色为绿色,则设置为红色data.a(bgName,'rgb(255,0,0)');}});},1000);结论总的来说,这个Demo还是挺有价值的,一是快速实现了3D柜子模型,二是给模型上的元素绑定了数据只是想让大家知道,画一个柜子并没有那么难画面清晰~3D世界没那么难~数据绑定也没那么难!我希望您也发现这并不难做到。