基于 HTML5 WebGL 的楼宇智能化集成系统(三)



// 通过 moveCamera 改变 eye 和 center 来移动场景视角为大楼的正视面
moveCamera(g3d, [134, 399, 1617], [7, 40, 144], {
duration: 2000,
easing: t => t * t,
finishFunc: () => {
// 开启场景大楼模型的可透明为 true
this.building.eachChild(c => {
c.s({
'shape3d.transparent': true,
});
});
// 大楼模型线框的颜色变化
tweenColor(this.building, 'wf.color', 'rgba(72,149,232,1)', 'rgba(56,156,255,0.03)', {
duration: 2000,
easing: t => t
});
// 大楼模型整体染色的颜色变化
tweenColor(this.building, 'shape3d.blend', 'rgba(120,180,255,1)', 'rgba(120,180,255,0)', {
duration: 2000,
easing: t => t,
finishFunc: () => {
// 楼层设置为可见
this.floor.eachChild(c => {
setNodeVisible(c, true);
});
this.floorLighting = 1;
// 显示大楼建筑信息的动画
this.showBuilding();
}
});
}
});
- node:改变颜色的图元节点;
- startColor:起始颜色的 rgba 值;
- endColor:变化后颜色的 rgba 值;
- animParams:过渡动画参数;
tweenColor(node, property, startColor, endColor, animParams) {
animParams = animParams || {};
if (!animParams.frames && !animParams.duration)
animParams.duration = 5000;
if (!animParams.easing)
animParams.easing = t => t;
startColor = ht.Default.toColorData(startColor);
endColor = ht.Default.toColorData(endColor);
const dx = endColor[0] - startColor[0];
const dy = endColor[1] - startColor[1];
const dz = endColor[2] - startColor[2];
const da = endColor[3] - startColor[3];
const postAction = animParams.postAction;
animParams.action = (v, t) => {
const x = startColor[0] + v * dx;
const y = startColor[1] + v * dy;
const z = startColor[2] + v * dz;
const a = (startColor[3] + v * da) / 255;
node.s(property, ('rgba(' + ([x, y, z, a]).join(', ')) + ')');
if (postAction) postAction(('rgba(' + ([x, y, z, a]).join(', ')) + ')');
}
return ht.Default.startAnim(animParams);
}

// 面板显示
showPanel(data) {
ht.Default.startAnim({
duration: 1000,
easing: t => t,
action: (v,t) => {
data.setScaleX(data.getScaleX() + (1 - data.getScaleX()) * v);
}
});
} // 面板隐藏
hidePanel(data) {
ht.Default.startAnim({
duration: 1000,
easing: t => t,
action: (v,t) => {
data.setScaleX(data.getScaleX() + (0 - data.getScaleX()) * v);
}
});
}

elevatorAnimation(data) {
const g3d = this.g3d;
const tag = data.getTag();
const e = data.getElevation();
const label = data.getChildAt(0);
// 判断现在所处楼层
let now = Math.ceil(e / 50);
// 下一层楼层取1~7随机数
let next = randomNumber(1, 7);
// 根据现在的楼层和下一个楼层,判断电梯运行的范围
let range = numBetween(now, next);
this.animationElevatorMap[tag] = ht.Default.startAnim({
duration: range * 800,
easing: t => t,
action: (v, t) => {
// 电梯运行位置设定
data.setElevation(now < next ? (e + (range * 50) * v) : (e - (range * 50) * v));
// 设置电梯楼层面板显示并根据电梯位置设定
if (!label) return;
const floor = Math.ceil(data.getElevation() / 50);
if (floor === label.a('text')) return;
label.a('text', floor);
// 手动刷新电梯面板信息
g3d.invalidateShape3dCachedImage(label);
},
finishFunc: () => {
// 销毁电梯间隔动画
delete this.timeoutElevatorMap[tag];
// 执行电梯间隔动画后回调电梯运行动画
this.timeoutElevatorMap[tag] = setTimeout(() => {
this.elevatorAnimation1(data);
}, Math.floor(Math.random() * 5000) + 2000);
}
});
}

park(car, key = 'Path', finishFunc) {
const dm = car.dm();
const tag = car.getTag();
const forwardPath = dm.getDataByTag(tag + '_forward' + key);
const backwardPath = dm.getDataByTag(tag + '_backward' + key);
this.animationMap[tag] = move(car, forwardPath, 'forward', undefined, 24, {
pathEndFunc: () => {
this.animationMap[tag].stop();
this.animationMap[tag] = move(car, backwardPath, 'backward', undefined, undefined, {
pathEndFunc: () => {
this.animationMap[tag].stop();
delete this.animationMap[tag];
if (finishFunc) finishFunc();
return true;
}
});
return true;
}
});
}
move 是节点沿着路径平滑移动的封装函数,主要参数为:
- node:动画节点;
- path:运行路径;
- direction:节点朝向 forward | backward;
- animParams:动画参数;
通过绘制一条运行路线的管道,ht.Default.getLineCacheInfo() 得到这条管道的点位和分割信息 cache,然后管道信息通过 ht.Default.getLineLength() 得到管道的长度,并且通过 ht.Default.getLineOffset() 来获取连线或者管道指定比例的偏移信息,从而达到移动的效果,注意的是,这里还设定了 direction 来规定动画节点的朝向,主要是为了通过 node.lookAtX() 来获取节点下一个面对的朝向的位置信息,并设置节点此时的位置,从而达到节点沿着路径平滑移动的效果。
move(node, path, direction, step = 6, interval = 75, animParams) {
let cache = path.__cache__;
if (!cache)
cache = path.__cache__ = ht.Default.getLineCacheInfo(path.getPoints(), path.getSegments());
const len = ht.Default.getLineLength(cache);
animParams = animParams || {};
const face = direction === 'forward' ? 'front' : direction === 'backward' ? 'back' : direction;
let currentLen = 0;
const pathEndFunc = animParams.pathEndFunc;
const action = animParams.action;
animParams.action = (v, t) => {
if (currentLen >= len) {
// 档 pathEndFunc 返回 true 是,认为是要结束动画, 不执行后面档 action
if (pathEndFunc && pathEndFunc())
return;
}
currentLen = currentLen % len;
const offset = ht.Default.getLineOffset(cache, currentLen);
const point = offset.point;
node.lookAtX([point.x, node.getElevation(), point.z], face);
node.p3(point.x, node.getElevation(), point.z);
currentLen = currentLen + step;
if (action) action();
};
return loop(animParams.action, interval);
}
与此同时,我们还可以看到车辆行驶到车位或者离开时,车位上方的红绿灯则表示着这个车位的停放信息,是根据车辆的情况实时设定车位的状况,通过改变其信号灯 image 的 json 图标并手动刷新缓存来实现的。而缓存机制对于整体场景的流畅度是至关重要的,对于一些不必要实时刷新的面板信息,我们可以采取缓存的方式,并且在下一次更新的时候调用 Graph3dView.invalidateShape3dCachedImage(node)来手动刷新这个节点,从而大大提高了场景的性能,有关 3D 面板的属性可以参考 <HT 的 3D 手册 billboard 公告板>。
updateLight(view, light, color) {
light.s('shape3d.image', 'symbols/parking/' + color + 'Light.json');
view.invalidateShape3dCachedImage(light);
}

基于 HTML5 WebGL 的楼宇智能化集成系统(三)的更多相关文章
- 基于 HTML5 WebGL 的楼宇智能化集成系统(一)
前言 随着现代通信技术.计算机技术.控制技术的飞速发展,智能建筑已经成为现代建筑发展的主流.智能建筑是以建筑物为平台,兼备信息设施系统.信息化应用系统.建筑设备管理系统.公共安全系统等.集 ...
- 基于 HTML5 WebGL 的楼宇智能化集成系统(二)
前言 一套完整的可视化操作交互上,必不可少 2D/3D 的融合,在上期我们介绍了有关 3D 场景的环视漫游.巡视漫游以及动画效果,还包括了冷站场景.热站场景以及智慧末端的实现原理,本期主要 ...
- 基于 HTML5 + WebGL 实现 3D 挖掘机系统
前言 在工业互联网以及物联网的影响下,人们对于机械的管理,机械的可视化,机械的操作可视化提出了更高的要求.如何在一个系统中完整的显示机械的运行情况,机械的运行轨迹,或者机械的机械动作显得尤为的重要,因 ...
- 基于 HTML5 WebGL 的 CPU 监控系统
前言 科技改变生活,科技的发展带来了生活方式的巨大改变.随着通信技术的不断演进,5G 技术应运而生,随时随地万物互联的时代已经来临.5G 技术不仅带来了更快的连接速度和前所未有的用户体验,也为制造业, ...
- 基于 HTML5 + WebGL 的 3D 太阳系系统
前言 近年来随着引力波的发现.黑洞照片的拍摄.火星上存在水的证据发现等科学上的突破,以及文学影视作品中诸如<三体>.<流浪地球>.<星际穿越>等的传播普及,宇宙空间 ...
- 基于 HTML5 WebGL 的医疗物流系统
前言 物联网( IoT ),简单的理解就是物体之间通过互联网进行链接.世界上的万事万物,都可以通过数据的改变进行智能化管理.ioT 的兴起在医疗行业中具有拯救生命的潜在作用.不断的收集用户信息并且实时 ...
- 基于 HTML5 + WebGL 实现的垃圾分类系统
前言 垃圾分类,一般是指按一定规定或标准将垃圾分类储存.分类投放和分类搬运,从而转变成公共资源的一系列活动的总称.分类的目的是提高垃圾的资源价值和经济价值,力争物尽其用.垃圾在分类储存阶段属于公众的私 ...
- 基于 HTML5 WebGL 的地铁站 3D 可视化系统
前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...
- 基于 HTML5 + WebGL 实现 3D 可视化地铁系统
前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...
随机推荐
- .Net Framework 工具Mpgo.exe与Ngen.exe
首先放出官方MSDN的文档地址 Mpgo.exe 主要用于分析程序集启动时需要哪些东西,然后将信息反馈给NGen.exe 来更好的优化本机映像,使得应用程序启动更快,工作集缩小.准备发布时,用MPGO ...
- 【问题记录】记一次ConnectionTimeout问题排查
最近做性能测试时,发现连接第三方系统时会有约1%的交易提示如下错误 nested exception is org.apache.commons.httpclient.ConnectTimeoutEx ...
- C# 在DataGridView中,点击单元格调出 TreeView控件 或 ListBox控件
1.调出 TreeView控件 或 ListBox控件 private void deductGrid1_CellClick(object sender, DataGridViewCellEvent ...
- Redis源码分析: String(SDS)容量调整分析
整体思路: 1 惰性缩容.不释放空间,留给到期释放等机制释放. 2 加倍扩容.在需要空间达1M之前按新空间两倍分配空间,否则按新空间大小+1M分配.注意,1M=1024*1024*Char.Char可 ...
- mysql系列-⼀条SQL查询语句是如何执⾏的?
⼀条SQL查询语句是如何执⾏的? ⼤体来说,MySQL 可以分为 Server 层和存储引擎层两部分 Server 层 Server 层包括连接器.查询缓存.分析器.优化器.执⾏器等,涵盖 MySQL ...
- 老板说,Vim宏都不会用,你的工作效率太低啦~
工作中,对于文本文件的编辑我们经常有这样的需求: 多次重复输入一段相同文本: 生成一段序列化的文本: 每行文本插入一句相同的文本. 除此之外,还有很多需要重复操作的动作.对于这些需求,如果我们人工去操 ...
- 吴恩达最新TensorFlow专项课程开放注册,你离TF Boy只差这一步
不需要 ML/DL 基础,不需要深奥数学背景,初学者和软件开发者也能快速掌握 TensorFlow.掌握人工智能应用的开发秘诀. 以前,吴恩达的机器学习课程和深度学习课程会介绍很多概念与知识,虽然也会 ...
- python中面向对象&装饰器
类的定义 基本形式: class ClassName(object): Statement 1.class定义类的关键字 2.ClassName类名,类名的每个单词的首字母大写. 3.object是父 ...
- python文件封装成*.exe
python文件封装成*.exe文件(单文件和多文件) 环境:win10 64位 python3.7 原文: https://www.cnblogs.com/jackzz/p/9431923.html ...
- dp例题03. 最大子矩阵和
题目Description: 给出一个矩阵, 求子矩阵(可以是其本身)数之和的最大值 Input: 第一行 为行数n和列数m (n≤500, m≤500) 接下来为一个n行m列的矩阵 (每 ...