基于 HTML WebGL 的会展中心智能监控系统
2020-04-26 23:51
1281 查看
前言
随着近几年物联网、万物互联等诸多概念的大行其道,智慧城市的概念也早已经被人们耳熟能详,而作为城市的组成部分,智慧建筑也是重中之重,智慧园区,智慧小区等也如雨后春笋般的相继出现。
智慧建筑是指通过将建筑物的结构、系统、服务和管理根据用户的需求进行最优化组合,从而为用户提供一个高效、舒适、便利的人性化建筑环境,智慧建筑绝不仅仅只是智慧园区、智慧小区这种模式,这里我就通过 HT for Web 制作了一个以会展中心为主体的智慧建筑监控系统。
效果预览
代码实现
场景呈现
通过上面的效果预览,可以分辨出整个监控系统是分为 3 个层次的,分别是主体、楼内、展厅,如果是使用单个
graph3dView加载所有场景,通过
dm.clear()清除场景,
dm.deserieialize()加载新场景这种切换方式必然会有一个极短的渲染时间,使切换时不连贯,所以我这里就使用了 3 个
graph3dView,去呈现各自的层级模型,通过
notifier事件通知器监听场景切换,代码如下:
notifier.add((event) => { if (event.kind === 'sceneChange') { const oldSceneKey = event.oldScene, newSceneKey = event.newScene, oldScene = G[oldSceneKey], newScene = G[newSceneKey]; oldScene.removeFromDOM(); newScene.addToDOM(); if (newScene.graph2d.isAnimed) { newScene.graph3d.animByList(); } else { newScene.graph3d.animByList(newScene.graph2d.animByList, newScene.graph2d); } } });
其中
removeFromDOM是自行封装的一个方法
removeFromDOM() { const g3d = this.g3d, view = g3d.getView(); if (view.remove) { view.remove() } else { view.parentNode.removeChild(view) } this.notifier.fire({ kind: 'reset', }); }
但是这样还是有一个问题,
graph3dView默认如果不放到页面中,场景中的
obj等模型相关资源是不会请求和渲染的,这样对性能是十分友好的,但是当我第一次切换场景时,还是会有短暂的请求和渲染时间,所以这里我需要对资源进行预加载。
资源预加载
这里我通过在
body中添加一个不在窗口展示的与窗口等宽高的
div元素,通过把当前不展示的
graph3dView放到其中触发对相应
obj等模型资源的请求和渲染,完成预加载,代码如下:
const preloadDiv = document.createElement('div'); preloadDiv.style.position = 'absolute'; preloadDiv.style.bottom = '100%'; preloadDiv.style.width = '100%'; preloadDiv.style.height = '100%'; document.body.appendChild(preloadDiv); scene2.addToDOM(preloadDiv); scene3.addToDOM(preloadDiv);
模型加载完成后再执行动画
web 页面加载是依赖网速的,会展中心模型
obj等资源文件是有一定大小的,可能对于不同带宽网速的用户所需要加载的时间也不尽相同,这里就需要判断下
obj是否全部加载完成,加载完成后再执行动画效果,通过
ht.Default.handleModelLoaded监控是否所有模型都请求加载完成, 加载完成后开始执行动画,顺便释放之前预加载的
graph3dView,代码如下:
let modelSize = 0; ht.Default.handleModelLoaded = (name, model) => { modelSize++; if (modelSize === 62) { scene1.graph3d.enableShadow(); scene3.graph3d.enableShadow(); scene2.removeFromDOM(); scene3.removeFromDOM(); scene1.graph3d.animByList(scene1.graph2d.animByList, scene1.graph2d); } };
动画依参数顺序执行
我想要场景第一次加载时,视角拉近后左右两边的面板再一点一点的加载出来,动画效果是不完全线性顺序的去执行,所以我这里通过
ht.Default.startAnim方法封装了一套通过参数数组进行的动画的方法,代码如下:
animByList(callback, obj) { this.isAnimed = true; const animList = this.animList, self = this; let callAnim = (ind) => { const param = animList.get(ind); param && self.anim(param, () => { callAnim(ind + 1); const lastParam = animList.get(ind + 1); lastParam || callback && callback.call(obj || this); }); }; callAnim(0); } anim(animParam, callback) { const self = this, time = animParam['time'] || 1000, easing = animParam['easing'] || function (t) { return t * t; }, func = animParam['func']; this.__animObj = ht.Default.startAnim({ duration: time || 1000, easing: easing, action: function (v, t) { const V = v, T = t; function animFunc(param) { let v = V, t = T; if (param instanceof Function) { param(v, t); } else { const type = param['type'], object = param['object'], objectTag = param['objectTag'], key = param['key'], oldValue = param['oldValue'], newValue = param['newValue'], oneTime = param['time'], scope = param['scope']; if (scope) { v = v < scope[0] ? 0 : v > scope[1] ? 1 : (v - scope[0]) / (scope[1] - scope[0]); } else { v = !oneTime || oneTime > time ? v : v * time / oneTime < 1 ? v * time / oneTime : 1; } let obj, value; obj = object ? object : objectTag ? self.view.dm().getDataByTag(objectTag) : undefined; if (!obj) return; if (!isSameType(oldValue, newValue) || !isNumORNumArray(oldValue)) return; if (oldValue instanceof Array) { if (oldValue.length !== newValue.length) return; const darr = newValue.map((n, i) => { return n - oldValue[i]; }); value = oldValue.map((n, i) => { return n + darr[i] * v; }); } else { const d = newValue - oldValue; value = oldValue + d * v; } ht.Default.setPropertyValue(obj, type, key, value); } } if (animParam instanceof Array) { animParam.forEach(ele => { animFunc(ele); }); } else { animFunc(animParam); } }, finishFunc: function () { func && func(func); callback && callback(); }, }); }
参数格式如下:
// 视角移动 param = { object: g3d, type: undefined, key: 'eye', oldValue: [-118, 5130, 15858], newValue: [-26, 1130, 3494], time: 1000, } animList.add(); // 标题从左到右出现 param = { object: title, type: 'style', key: 'clip.percentage', oldValue: 0, newValue: 1, time: 1500, }; animList.add(param);
可点击部分高亮效果
为了突出可以点击的部分,我加了高亮效果,设置鼠标悬浮高亮模式,并通过
g3d.getHighlightHelper().setFetchTargetFunc方式筛选需要鼠标高亮的图元,代码如下:
g3d.setHighlightMode('mouseover'); g3d.getHighlightHelper().setFetchTargetFunc(function (nodes) { let sortList = new ht.List(nodes); return sortList.toArray(node => { return jumpList.contains(node); }); });
楼层视角跳转
因为整体的楼层比较大,而每个楼层中可选择的展区又比较小,所以这里我做了一个视角调整,可以使用单独移动视角到正视相应楼层的视角
flyTo,这里除了采用右侧边栏选中移动,也做了鼠标移入相应楼层右键改变视角的处理,使用了新建的类
messageView做交互提示。
g3d.flyTo(floor, { animation: true, direction: [0, 1, 2], center: floor.p3().map((n, i) => { return i !==1 ? n : n + floor.getTall() / 2; }), distance: distances[newFloor - 1], });
总结
随着科技的井喷式发展,智慧建筑将如雨后春笋般崛起,其应用的场景也会不断拓展,应运而生的数据可视化管理系统也应该配套升级,为其把数字信息变为直观的、以图形图像信息表示的信息,清晰的展现在客户的面前,这将是无可阻挡的时代大趋势。
还有更多的可视化案例可以参考:https://www.hightopo.com/demos/index.html
相关文章推荐
- 基于 HTML + WebGL 结合 23D 的疫情地图实时大屏 PC 版
- 基于 HTML + WebGL 结合 23D 的疫情地图实时大屏 PC 版【转载】
- BIM研究-基于HTML5/WebGL技术的BIM模型轻量化Web浏览解决方案
- 谷歌推出的基于WebGL下的鱼缸测试页面(用于网页速度测试)http://webglsamples.googlecode.com/hg/aquarium/aquarium.html
- 这将启动一个基于tornado的HTML笔记本服务器,它提供一个html5/ javascript笔记本客户端
- 基于HTML的使用(Beautifulsoup4实现)
- Html标签页的实现说明及结合JS基于对象特性的实现对比
- 基于 Web 的数据挖掘--自动抽取用 HTML、XML 和 Java 编写的信息
- 基于 HTML5 WebGL 的 3D “弹力”布局
- 基于html5+webview五分钟快速完成一个地图选址组件
- 基于HTML5和WebGL的3D网络拓扑结构图
- 基于 HTML5 + WebGL 的宇宙(太阳系) 3D 可视化系统
- 基于 HTML5 WebGL 的 3D 服务器与客户端的通信
- 基于webpack实现多html页面开发框架六 提取公共代码
- yii基于布局的子页面引入js和css文件,并放入布局文件中HTML的head中
- 编写基于outlook显示的html邮件需要注意的问题
- 利用HTML5+的Uploader模块API实现基于MUI的文件上传
- 在线富文本编辑器-基于Web的HTML编辑器大全(二)
- Java基于Socket文件传输示例 --- (http://www.blogjava.net/sterning/archive/2007/10/13/152508.html)
- 图片轮播插件-基于HTML5+CSS3+JavaSript的响应式图片轮播