- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
序:
这几年观察下来,大部分做物联网三维可视化解决方案的企业或个人, 基本都绕不开3D机房。包括前面也讲过这样的案例 《使用webgl(three.js)创建自动化抽象化3D机房,3D机房模块详细介绍(抽象版一)》 《 使用webgl(three.js)创建科技版3D机房,3D机房微模块详细介绍(升级版三)—— 1》 。
随着技术的快速发展,机房的数量和规模也在不断扩大。然而,传统的数据中心管理方式已经无法满足现代社会的需求。在这种情况下,3D机房数据中心应运而生.
顾名思义,三维机房数据中心是指利用三维仿真技术,将数据中心的空间信息、设备信息、人员流动信息等各类信息集成在三维模型中,实现数据中心的全面可视化。这种新型的数据中心管理方式,能够提高管理效率,降低运营成本,提升数据中心的可靠性.
但是,三维机房解决方案已经发展了好多年,逃不开建模,数据连接,个性化定制。一个机房项目,开发周期长,研发成本高。不说如何颠覆一下这部分行业应用,也得想想如何提升一下效率.
综述,低代码模式的三维机房解决方案呼之欲出。当然还是基于three.js(webgl)引擎架构 。
我们还是闲话少叙,切入正题.
前言:
首先,我们要确定目标与需求.
目标: 低代码生成三维机房系统.
全套完备的三维数据中心系统,目标任务过于繁重,所以先得将目标切割,先完成低代码模式下的单个机房或者是微模块的前端三维方案。这就符合了自我效能理论,分割事务,及时得到正向反馈,不断完成小目标,看到成效,最终才能做出结果.
需求: 通过上面的目标分割,我们可以简单概述出需求。简单一句话,通过配置,快速生成3D机房,包括其常用的业务逻辑.
这里我们明确了包含常用业务逻辑,而个性化特殊化的业务需求我们可以在完成这部分后,基于现有系统做叠加与拓展。为了方便拓展,先用简易系统要考虑到合理性与延续性.
综上所述,我们要做一个通过简单配置即可自动生成一个3D机房前端系统。后续我们再通过做一个工具,通过工具拖拉拽来代替写配置这一步.
1、效果展示 。
1.1、机房效果 。
通过简单配置生成一个带有微模块、单排柜以及动环设备的机房模型 。
。
。
根据数据自动生成机柜内部设备 。
。
。
1.2、json配置 。
分析行业需求,提炼配置信息 。
房间建筑 :长宽高属性,以及门窗属性。这里必须且必要省掉墙的皮肤属性、不规则房间特性等等 。
设备 :类型、位置,尺寸、关联数据id、这里要放弃设备细节。考虑的越多,越不容易完成目标 。
通过上面分析,我们可以基本得出一个简单的配置信息 。
1.2.1、建筑房间配置:
。
。
。
{ "type": "wall" , "name": "wall_4", // 名称 "size" : { "x": 8000, // 墙长度 "z": 100, // 墙厚度 "y": 1000 // 墙体高度 }, // 墙的起始点位置 "startPosition": { // 墙体的起始位置 默认是墙体的左下角 "x": -4000 , "y": 0 , "z": 2700 }, "doorHoles": [ // 门 { "id": "door_001", // 门禁设备id "type": 2, // 0 x方向单门 1 x反方向单门 2 双门 3表示窗户洞 "start": 400, // 相对于尺寸参数的x 离0多长 比如400 表示门洞离x 0点400 "width": 600, // 门洞宽 "height": 700, // 门洞高 "thickness": 40 // 门厚度 }, { "type": 3 , "start": 2600 , "width": 2000 , "height": 700 , "rideHeight": 100, // 窗户离墙的底边高度 "thickness": 10 // 窗的厚度 } ], },
1.2.2、机柜配置 。
a、冷通道配置 。
。
{ "id": "101", // 冷通道id 唯一 "type": "minRoom", // 冷通道类型 "dataId": "101", // 数据id 唯一 "position": { // 冷通道位置 是指冷通道中心点在场景中的位置 "x": -2000 , "y": 0 , "z": 0 }, "rotationDir": "Z", // 冷通道门对准的方向 X 表示坐标系x轴方向 Z表示坐标系z方向 "rackLength": 9, // 冷通道单边机柜的个数 "children": [ // 冷通道内设备 { "id": "1_1", // 设备id "type": "ljkt", // 设备类型 取值范围:ljkt ltg rack 分别表示列间空调 列头柜 机柜 "dataId": "1_1", // 数据id "row": "1", // 表示在冷通道哪一排 取值1或者2 在第一排 或者第二排 "col": "1", // 表示在某排第几个 "width": 0.5 // 占用宽度比例 }, ] .......... },
b、单排柜配置 。
。
{ "id": "1_1", // 机柜id 自定义 唯一性 建议跟数据库资产id保持一致 "type": "rack", // 类型 "name": "rack_1_1", // 机柜模型名称 唯一性 "dataId": "1_1", // 机柜数据id 这里是指数据库存储的机柜资产id "position": { // 机柜位置 是指机柜中心点在场景中的位置 "x": -2550 , "y": 450 , "z": 1315 }, }
1.2.3、设备配置 。
。
。
。
{ // 温湿度传感器 "type": "wdcgq", // 设备类型 "id": "2", // id 保持全局唯一 "dataId": "wd1", // 数据id "position": { // 模型中心点在场景中的位置 "x": 0 , "y": 1200 , "z": 0 }, "scale": { // 缩放 所有值不可为0 "x": 1 , "y": 1 , "z": 1 } }
1.3、业务逻辑 。
上面的配置,机房模型已经生成,接下来就是基于模型与数据,生成功能逻辑 。
例如、利用率、温度云图、承重、告警等等 。
。
温度云图 。
承重、功耗 。
。
2、代码解析 。
2.1、合理封装 。
封装分为两部分 。
第一部分是模型封装,更加不同类型 以及属性生成模型 / 。
例如:
* 创建普通地板 * @param {any} name 名称 floor * @param {any} size 尺寸 {x:8000,z:5000,y:100} 长 宽 厚 * @param {any} CenterPosition 中心点位置 {x:0,z:-60,y:0} * @param {any} rotation 旋转 {x:0,y:0,z:0} 角度用 */ function createFloor(name, size, CenterPosition, rotation) { ...... return model; } /* * * 创建机房空气地板 * @param {any} name 名称 floor * @param {any} size 尺寸 {x:8000,z:5000,y:100} 长 宽 厚 * @param {any} CenterPosition 中心点位置 {x:0,z:-60,y:0} * @param {any} rotation 旋转 {x:0,y:0,z:0} 角度用 */ function createDataCenterFloor(name, size, CenterPosition, rotation) { ...... return model; } /* * * 创建墙体 * @param {any} name 名称 wall_4 * @param {any} size 尺寸{x:8000,z:100,y:1000} 长 厚 高 * @param {any} startPosition 起始点位置 { "x": -4858.313, "y": 0, "z": 1264.35 } * @param {any} doorHoles 门洞 [ { type:2 ,//0 x方向单门 1 x反方向单门 2 双门 3窗户 start: 400,//相对于尺寸参数的x 离0多长 比如400 表示门洞离x 0点400 width:600,//门洞宽 height:700,//门洞高 thickness:40,//门洞厚度 rideHeight:100//离地高度 } ] * @param {any} rotation 旋转 {x:0,y:0,z:0} */ function createWall(name,type, size, startPosition, doorHoles, rotation) { ...... return buildwall; }
第二部分是封装业务逻辑 。
将每部分业务逻辑单独封装到方法类中 。
例如:温度云图 。
// =======================================================温度======================================================= function Tempture() { } Tempture.prototype.temptureSpaceState = 0 ; // 温度显示 Tempture.prototype.showTemptureMap = function (callBack) { var _this = this ; if (_this.temptureSpaceState == 0 ) { $( "#backBtn" ).fadeIn(); layer.closeAll(); $( "#toolbar" ).fadeOut(); _this.temptureSpaceState = 1 ; _this.createHeatMapModels( "temptureObj" , callBack); _this.hideAllMsg(); } else { _this.temptureSpaceState = 0 ; _this.hideAllTemptureMapObjs(); } } Tempture.prototype.hideAllTemptureMapObjs = function () { WT3DObj.destoryObj( "temptureObj" ); for ( var i = 0; i < 20; i++ ) { WT3DObj.destoryObj( "temptureObj_" + i); } } // 创建热力图 Tempture.prototype.createHeatMapModels = function (name, callBack) { var _this = this ; var scaleRate = 1 ; if (roomConfig.buildData.baseConfig && roomConfig.buildData.baseConfig.normRackSize) { scaleRate = roomConfig.buildData.baseConfig.normRackSize.width / 350 ; } _this.getHeatMapDataValue( function (_data) { var modeljson = ...; WT3DObj.InitAddObject(modeljson); for ( var i = 0; i < 10; i++ ) { modeljson.position.y += (roomConfig.maxheight / 10) / scaleRate; modeljson.name = name + "_" + i; modeljson.values = _data.data; WT3DObj.InitAddObject(modeljson); } }, callBack); }; Tempture.prototype.getHeatMapDataValue = function (suc, callBack) { webapi.getTemptureValue( function (result) { var heatMapData = {}; $.each(result, function (_reindex, _reobj) { heatMapData[ "d_" + _reobj.id] = _reobj; }); ... var rdata = { max: 100 , data: datas }; if (suc) { suc(rdata); } if (callBack) { callBack(mtemp); } }); }
。
。
2.2、业务隔离 。
switch (id) { case "div_btn_1": // 异常设备 { clearInterval(_this.alarmSetintervalIndex); $( "#btn_1").fadeTo(100, 1 ); if ($("#btn_1").attr("title") == "告警监控" ) { $( "#btn_1").attr("title", "关闭告警闪动" ); $( "#btn_1").attr("src", "../img/pageimg2/ycsbclose.png" ); modelBussiness.closeAlarm(); } else { _this.flashAlarmBtn(); modelBussiness.startAlarm(); $( "#btn_1").attr("src", "../img/pageimg2/ycsb.png" ); $( "#btn_1").attr("title", "告警监控" ); } } break ; case "div_btn_2": // 空间 { modelBussiness.currentState = 22 ; modelBussiness.showSpaceRate(); } break ; case "div_btn_3": // U位 { modelBussiness.currentState = 23 ; modelBussiness.showUsageMap(); } break ; case "div_btn_4" : { modelBussiness.currentState = 24 ; modelBussiness.showTemptureMap(); } // 温度 break ; case "div_btn_5": // 承重 { modelBussiness.currentState = 25 ; modelBussiness.showBearing(); } break ; case "div_btn_6": // 功率 { modelBussiness.currentState = 26 ; modelBussiness.showEnergyRate(); } break ; } });
。
3、主要难点 。
3.1、如何封装模型、提炼参数 。
3.2、如何在生成的不同房间模型下,还能展现业务功能 。
3.3、如何做数据分离 。
统一webapi数据文件,这里主要处理获取数据,数据过滤 。
/* 数据接口 */ function WebAPI() { this .serverHead = ""; // idc/ this .roomid = getQueryString("room") ? getQueryString("room") : "1" ; this .CabInfosCache = null ; // 机柜数据缓存 this .OtherDevsCache = null ; // 所有设备缓存 this .ServerDevsCache = {}; // 所有设备缓存 this .AllDevsCache = null ; // 所有设备缓存 this .alarmCache = []; // 告警缓存 this .modelAlarmCache = {}; // 模型对应告警缓存 this .wsSocket = null ; // 告警闪动对应的颜色 this .alarmColors = { "L1": 0xff0000 , "L2": 0xff6600 , "L3": 0xffff00 , "L4": 0x0096ff , } this .urls = { enables: "/dataDemo/enable.json", // 功能开启关闭接口 buildData: "/dataDemo/buildData.json", // 创建模型接口 racks: "/dataDemo/racks.json", // 机柜信息 useRates:"/dataDemo/useRates.json", // 机柜利用率 temperatures: "/dataDemo/tempTureData.json", // 温度数据 bearing: "/dataDemo/beringRate.json", // 承重 euRate: "/dataDemo/euRate.json", // 功耗 uvInfos: "/dataDemo/uDetail.json", // u位信息 otherDevs: "/dataDemo/otherDev.json", // 其它动环设备 DevData: "/dataDemo/otherDevValue.json", // 动环设备实时数据 queryInfos: "/dataDemo/search.json", // 查询接口 alarms: "/dataDemo/alarm.json", // 告警 wsurl: "xxxx", // websocket地址 } } WebAPI.prototype.getEnables = function () { var _this = this ; var url = this .serverHead + this .urls.enables + "?roomId=" + this .roomid; url += "&r=" + Math.random(); var enables = null ; httpGetSyn(url, function (response) { if (response && response.data) { enables = response.data; } }, function (err) { console.log(err); }); return enables; } .......
。
由于篇幅原因,我们本节课先到这里,后面我们更新如何创建一个可编辑工具完成配置 。
。
其它相关文章:
如何使用webgl(three.js)实现煤矿隧道、井下人员定位、掘进面、纵采面可视化解决方案——第十九课(一) 。
如何使用webgl(three.js)实现3D消防、3D建筑消防大楼、消防数字孪生、消防可视化解决方案——第十八课(一) 。
webgl(three.js)3D光伏,3D太阳能能源,3D智慧光伏、光伏发电、清洁能源三维可视化解决方案——第十六课 。
如何用webgl(three.js)搭建一个3D库房,3D仓库3D码头,3D集装箱,车辆定位,叉车定位可视化孪生系统——第十五课 。
webgl(three.js)实现室内三维定位,3D定位,3D楼宇bim、实时定位三维可视化解决方案——第十四课(定位升级版) 。
使用three.js(webgl)搭建智慧楼宇、设备检测、数字孪生——第十三课 。
如何用three.js(webgl)搭建3D粮仓、3D仓库、3D物联网设备监控-第十二课 。
如何用webgl(three.js)搭建处理3D隧道、3D桥梁、3D物联网设备、3D高速公路、三维隧道桥梁设备监控-第十一课 。
如何用three.js实现数字孪生、3D工厂、3D工业园区、智慧制造、智慧工业、智慧工厂-第十课 。
使用webgl(three.js)创建3D机房,3D机房微模块详细介绍(升级版二) 。
如何用webgl(three.js)搭建一个3D库房-第一课 。
如何用webgl(three.js)搭建一个3D库房,3D密集架,3D档案室,-第二课 。
使用webgl(three.js)搭建一个3D建筑,3D消防模拟——第三课 。
使用webgl(three.js)搭建一个3D智慧园区、3D建筑,3D消防模拟,web版3D,bim管理系统——第四课 。
如何用webgl(three.js)搭建不规则建筑模型,客流量热力图模拟 。
使用webgl(three.js)搭建一个3D智慧园区、3D建筑,3D消防模拟,web版3D,bim管理系统——第四课(炫酷版一) 。
如何用webgl(three.js)搭建处理3D园区、3D楼层、3D机房管线问题(机房升级版)-第九课(一) 。
。
最后此篇关于如何基于three.js(webgl)引擎架构,研发一套通过配置就能自动生成的3D机房系统的文章就讲到这里了,如果你想了解更多关于如何基于three.js(webgl)引擎架构,研发一套通过配置就能自动生成的3D机房系统的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想做的是,如果鼠标位于“下一个”按钮上,它会以慢速向右滚动,如果鼠标没有位于“下一个”按钮上,它会停止滚动? 这是我的尝试http://jsfiddle.net/mdanz/nCCRy/14/ $(
StyleCop 是一个很棒的视觉工作室小插件。但它不会向您显示实时提示或提供任何自动修复。 随之而来的是 reSharper 和 StyleCop for reSharper,这是理想的解决方案,但
我为我的MatchQuery使用了模糊性选项,但是我想将模糊性值设置为auto。有什么办法吗? 另外,对于完成建议程序,您可以将其设置为支持unicode,对于我的MatchQuery,有什么方法可以
我想从表中获取一行[字符串名称,字符串密码,int 某些内容]并将其映射到一个 User 对象,该对象具有 3 个属性,如上面的 getter 和 setter有什么方法可以自动完成吗?我考虑过反射,
我有一个像这样的方法:void m1(string str) 并且有一个像这样的类: public class MyClass { public bool b1 { set; get; }
我正在尝试使用 $rootScope 从一个 Controller 向另一个 Controller $broadcast 一些数据。 如果我使用像 ng-click 这样的触发器来运行将广播的功能,它
我考虑了很多关于是要使用完全自动化的缓存还是手动缓存。 我们的自动方法是一种解决方案,它可以挖掘数据库、查询和格式化每个潜在和 future 的数据请求,并将其保存到适当的缓存存储(内存缓存或基于磁盘
我的 CSS 必须使用过渡来更改,直到现在我都使用 div:hover 来实现。 当您单击另一个 div 时需要激活过渡,而不是当您将鼠标悬停在必须移动/更改的 div 上时。 我该怎么做? 谢谢 永
在我的应用程序中,我需要一些动画,但如果它已经设置了动画,则不需要持续时间。但我的问题是它会自动添加持续时间。 在这里你可以看到 2 个函数,第二个没有持续时间但它确实有持续时间(可能从 1 秒开始)
两年前,我需要制作一个工具,通过 POST 自动将 txt/csv 文件上传到我的 Web 服务器,然后使用 cronjob 通过 PHP 对其进行解析。 这有两次在每天午夜自动发生。尽管这行得通,但
请阅读下面程序中的评论: #include void test(char c[]) { c=c+2; //why does this work ? c--; printf("%
也许是个幼稚的问题,但是...... 确认或拒绝: 自动和静态存储持续时间的对象/变量的内存的存在是在编译时确定的,程序运行时失败的可能性绝对为零,因为没有足够的内存用于自动对象。 自然地,当自动对象
有没有什么方法可以自动获得类中属性更改的通知,而不必在每个 setter 中都编写 OnPropertyChanged? (我有数百个属性,我想知道它们是否已更改)。 安东建议 dynamic pro
我们在使用 Azure DevOps 的项目中采用了 gitflow 流程。我有以下场景: 当功能分支合并到 Develop 时,我想在完成拉取请求的同时执行压缩合并策略 当 Release 分支定期
我的网站上有一个评论部分,我将 html 编码的评论保存在我的数据库中。所以我添加了这条评论- "testing" `quotes` \and backslashes\ and html 并将其保存在
是否存在“ checkin 前 TFS 自动 checkout ”这样的功能,以便在我说“ checkin ”之前我不会 checkout 任何文件,例如以防我只是临时更改文件 - 这一直发生。 换句
我有一个运行在 Linux/Apache/Tomcat 堆栈上的网站,它需要每隔几个月自动脱机以进行服务器维护,这将持续任意时间。有哪些选项可以让 Apache 建立和取消“服务器维护”页面? 我需要
我经常在工作中创建文档,在公司内部,由于我们使用的首字母缩写词和缩写词的数量,我们几乎拥有自己的语言。因此,我厌倦了在发布文档之前手动创建首字母缩写词和缩写表,并且快速的谷歌搜索发现了一个可以有效地为
我希望在用户或宏将计算模式从自动更改为手动或手动更改为自动时运行代码。是否有为此触发的事件? (属性是 Application.Calculation 在 Excel 互操作中。) 使用 Excel
这个问题在这里已经有了答案: Repeat command automatically in Linux (13 个回答) 6年前关闭。 我想创建一个脚本来获取另一个文件夹中的所有文件夹名称。并为这些
我是一名优秀的程序员,十分优秀!