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

基于H5和WebGL的低碳工业园区3D监控系统

时间:2023-04-04 23:24:15 HTML5

前言低碳工业园区的建设与推广是我国推进低碳产业转型的重要举措。低碳产业园区能源与碳排放管控平台是建设的关键环节。如何对园区企业的碳排放量进行采集、测算、计算,以及如何对能耗和碳排放量进行实时动态监测等,涉及多个技术领域,专业性很强。它的数据不仅要求准确,还要求真实可靠(即可验证、可追溯)。这是低碳产业园区“管控平台”建设的核心任务,也是我国产业园区建设中亟待解决的主要问题之一。http://www.hightopo.com/demo/HTBuilding/index.html此gif展示了结合2D和3D的低碳工业园区能源监控系统。实时监控用电量。用代码实现创建3D低碳工业园场景并不难,但是如何在同一个界面上同时显示2D和3D场景呢?如果你想做出炫酷的效果,这个方法在很多情况下是非常有用的。整个低碳产业园的场景都是二维搭建的。我们知道,HTML只能使用传统的光栅位图为DOM元素设置图片。json格式的矢量图最好实现。当光栅位图被拉伸和放大或缩小时,图形会变得模糊,线条会变粗并呈锯齿状。矢量图像通过点、线、多边形来描述图形,因此在无限放大和缩小图像时仍能保持一致的精度。首先,我搭建了一个2D场景来放置我们的json矢量图,使用ht.Default.xhrLoad函数反序列化json矢量图背景图,显示在gv上。除了作为背景的节点之外,这张json矢量背景图还有另外两个节点,如下图,红线框出的较大节点用于安装3D场景,较小的节点框在右边用来放另外一个gv(还没用,后面需要加一个类似form的功能,所以需要一个固定的位置):ht.Default.xhrLoad('displays/background.json',function(text){dm.deserialize(text);//将数据反序列化到数据模型gv.addToDOM();//添加2D场景到body});这个2D场景设置为背景部分,我们来看看如何在2D场景的基础上放上3D场景。将3D场景添加到2D将3D添加到2D也非常容易。问题是如何让3D场景根据2D场景的缩放和平移自适应变化,让3D场景始终保持在2D场景中的固定位置?我监听gv的属性变化事件,监听zoom、translate等属性,对3D场景进行自动布局操作:varg3dInfo=create3D('g3dNode');gv.mp(function(e){//monitorgvproperty更改事件if(e.property==='zoom'||e.property==='translateX'||e.property==='translateY'){layout(g3dInfo);}});functionlayout(info){varrect=info.no??de.getRect(),//获取场景依赖的节点的矩形区域zoom=gv.getZoom(),//获取当前gv的缩放值tx=gv.tx(),//获取当前gv的水平平移值ty=gv.ty();//获取当前gv的垂直平移值//依赖节点的大小根据缩放值缩放rect.x\*=zoom,rect.y\*=zoom,rect.width\*=zoom,rect.height\*=zoom;varx=rect.x+tx,y=rect.y+ty;//设置场景自动布局if(info.g3d)info.g3d.layout(x,y,rect.width,rect.height);}眼尖的同学应该注意到我没有写create3D函数的声明.就展示的效果而言,这个方法只是将场景转为json绘图反序列化为3D场景,并添加了一个objectinfo,传递了3D场景所依赖的节点和3D场景变量在:函数create3D(标签){varg3d=newht.graph3d.Graph3dView();//3D组件vardataModel=g3d.dm();//获取3D场景的数据容器gv.getView().appendChild(g3d.getView());//将3D场景添加到2D场景中ht.Default.xhrLoad('scenes/electricclouddimension.json',function(text){//加载3D场景的json矢量图dataModel.deserialize(text);//将数据反序列化为数据模型});//停止事件的传播并防止它被分派到其他文档节点g3d.getView().addEventListener('mousedown',function(e){e.stopPropagation()});g3d.getView().addEventListener('mousewheel',function(e){e.stopPropagation()});if(isFirefox=navigator.userAgent.indexOf("Firefox")>0){g3d.getView().addEventListener('DOMMouseScroll',function(e){e.stopPropagation()});}varinfo={g3d:g3d,node:dm.getDataByTag(tag),};returninfo;}2D和3D在鼠标事件点上有很多相似之处,但是我们不希望在操作3D场景的同时改变2D场景,所以上面的代码禁止了鼠标按下和滚轮的事件传播。将建筑物显示的视线移动到更合适的位置,建筑物顶部显示一个面板,显示当前建筑物的信息。这里我直接创建了一个节点。通过将节点的shape3d属性设置为billboard,可以将其显示为“surface”。该面板非常易于使用。首先,它只有一个表面。推荐使用这种billboard类型,非常节省性能。//在建筑物上创建显示面板varbillboard=newht.Node();billboard.setScaleX(2);//X轴节点放大2倍billboard.setScaleTall(2);//Y轴节点放大2倍billboard.s({'shape3d':'billboard',//这个类型是一个patch'shape3d.image':'symbols/nodeForm.json',//设置patch的显示图像为矢量图'shape3d.autorotate':true,//始终面向相机'shape3d.vector.dynamic':true,//设置矢量图形'3d.visible':false//不可见});billboard.setTag('billboard');//设置节点标签的唯一属性dataModel.add(billboard);//将节点添加到数据容器中,通过点击不同的建筑物,在当前点击的建筑物上方显示信息面板,根据不同的选择勾选广告牌显式和隐式控制:dataModel.sm().ms(function(e){//监听选中的变化事件if(e.kind==='set'||e.kind==='append'){//Setselectedandaddselectedbillboard.s('3d.visible',true);vardata=dataModel.sm().ld();//获取当前选中的最后一个节点if(!data)return;billboard.p3(data.getPosition().x,data.getTall()+200,data.getPosition().y);//设置billboard的位置在当前选中节点的上方}elseif(e.kind==='remove'){//选择移除vardata=dataModel.sm().ld();//获取当前最后选中的节点if(data){billboard.setPosition(data.getPosition().x,data.getPosition().y);广告牌.setElevation(data.getTall()+200);}elsebillboard.s('3d.visible',false);}elseif(e.kind==='clear')billboard.s('3d.visible',false);//清除所有选中的项目并将广告牌设置为不可见});(参考其他例子)http://www.hightopo.com/demo/large-screen-photovoltaic/关于点击建筑物,flyTo函数用于从当前视线位置推送到节点位置。该函数在6.2.2版本中具有三个参数。第一个参数是目标节点。第二个参数是是否动画,第三个参数是计算眼睛到目标节点中心的距离。例如下面的代码设置为0.5,表示眼睛动态计算上述方向的距离,使目标适配屏幕。当前点击的建筑物的名称,我在设计3D场景的绘图时,为对应的建筑物设置了displayName属性,当前显示是根据这个displayName来显示的。g3d.mi(function(e){//添加交互式事件监听器if(e.kind==='clickData'){g3d.flyTo(e.data,true,0.5);//从当前位置设置眼睛和中心“飞到”目标节点的位置,如果第二个参数为1,则占满屏幕。6.2.2及以上版本有这个方法varname=e.data.getDisplayName();//由于3D不能合并模型,所以我使用加选的方式解决dataModel.each(function(node){if(node.getDisplayName()!==name)return;//我设置了相同类型的节点要相同dataModel.sm().appendSelection(node);})}});那么,只有一个广告牌,我们如何让这个广告牌根据不同的建筑物显示不同的信息呢?这时候,矢量图标还有另外一个优势。通过数据绑定到矢量图标的某一部分,可以动态改变数据。在这里,我三言两语并不完整。我将简单地提及如何实现它。其他的可以去官网的数据绑定手册查看相关资料和具体实现。前面为billboard设置了一个shape3d.image属性,设置的图片为nodeForm.json。这个json里面有四行文字显示,最上面的文字是用来显示当前点击的建筑物的名称。根据手册,我们知道数据绑定的格式分为两种,一种是绑定函数类型,一种是绑定字符串类型,如下:也就是说如果我们需要的属性HT或矢量图中没有定义如果有多个相同的属性需要改成不同的值,可以使用attr自定义属性。我这里使用的是这种方法:"text":{"func":"attr@buildingName","value":"赛普健身学院学生宿舍"}数据绑定完成后,我们只需要更改业务属性即可当前根据绑定数据引用此json矢量图标的节点://不同建筑物显示的内容是不同的广告牌。a('buildingName',name);billboard.a('electricUsage',(Math.random()\*300).toFixed(2));billboard.a('waterUsage',(Math.random()\*300).toFixed(2));billboard.a('gasUsage',(Math.random()\*300).toFixed(2));右侧的数据显示3D场景已创建。添加右侧的两个数据显示面板?这里我在之前2Djson场景中已经排好的节点上又增加了一个2D场景来展示整体的场景数据。因为这个gv上有两个信息面板,所以我直接在graphView中添加了两个节点,将节点添加到graphView的dataModel数据容器中。其他部分我就不解释了,都是基本代码:functioncreateGV(tag){varg2d=newht.graph.GraphView();//二维拓扑场景vardataModel=g2d.dm();//获取当前拓扑场景的数据容器gv.getView().appendChild(g2d.getView());//将这个拓扑场景添加到底层背景图片中g2d.setInteractors(\[\]);//清除这个上的交互component//在拓扑场景中添加两个节点varnode=newht.Node();node.setImage('symbols/form.json');节点.setPosition(0,0);dataModel.add(节点);varnode1=newht.Node();node1.setImage('symbols/form1.json');node1.setPosition(0,dm.getDataByTag(tag).getHeight()/3);dataModel.add(node1);g2d.fitContent();setInterval(function(){//Form表单数据动态变化node.a('electricUse',(Math.random()\*300).toFixed(2));node.a('waterUse',(Math.random()\*300).toFixed(2));node.a('gasUse',(Math.random()\*300).toFixed(2));node.a('tempUse',(RandomNumBoth(10,40))+'');node.a('wetUse',(Math.floor((Math.random()\*100)))+'');},3000);varinfo={g2d:g2d,node:dm.getDataByTag(tag)}returninfo;}以上,整个低碳产业园的监控系统实现就全部结束了。如果您有任何问题或建议,可以给我留言,或直接访问官网(http://hightopo.com/)查看相应信息