基于 HT 实现锅炉火焰动画
前言
本文介绍的是用 HT 驱动 Canvas 实现的一个锅炉的可视化模型,目的在于以一种可视化的方式随时观测炉内燃烧情况。
代码实现
代码的主体部分是锅炉矢量图,锅炉火焰的数据绑定以及用 Animation 插件实现炉内火焰的动画。首先要生成数据容器和拓扑组件并将其添加到 body 中 。
dataModel = new ht.DataModel(); graphView = new ht.graph.GraphView(dataModel); view = graphView.getView(); document.body.appendChild(view);
首先我们先来生成底部的动态火焰效果,第一步我们先注册图片信息:
var image = []; // 这里加入图片的文件名 for(var i = 0; i < image.length; ++i) { ht.Default.setImage('fireNum' + i, image[i]); // 这里图片和 html 在同一路径下,如不在同一路径 ,加上前缀路径名 }
然后要实现静态火焰图片的动态效果,无非就是将图片连续循环播放,于是需要动态改变的就是图片的文件名了,于是火焰图片的数据绑定如下:(将这段代码加入到锅炉外观的注册代码中)
{ type: 'image', name: { func: function(data) {return data.a('imgNum');} // 绑定了一个方法,用以动态改变图片的 name 属性值 }, rect: [50, 325, 450, 280] // 设置火焰图片的位置和大小 }
要用 Animation 实现实现动画效果首先必须引入 ht-animation.js 文件:
<script src = "lib/ht-animation.js"></script>
然后数据模型调用 enableAnimation(interval) 启动动画定时器,让节点实现 Animation
dataModel.enableAnimation(); node.setAnimation({ flash: { // 自定义的任意方法名 from: 0, // 表示参数的开始值,从 0 开始 to: image.length - 1, // 到 image.length - 1 结束 onUpdate: function(value) { // 回调函数,动画的每一帧都会回调此函数。 this.a('imgNum', 'fireNum' + value); // 改变图片的文件名 }, frames: 69, // 动画的帧数,等于参数变化范围 - 1 (获得的参数刚好是整数),使得每一张图片都会被显示 easing: 'Linear', // 动画的方式,这里采用线性改变(保证参数刚好是整数) repeat: true // 上述过程是否重复 }, start: ["flash"] // 指定要启动的动画,里只定义了一个名为 flash 的动画,事实上,你可以定义任意多个 });
接下来我们把美工提供的锅炉外观信息注册成图片 fire ,并将火焰图片信息注册进锅炉外观
ht.Default.setImage('fire', { "width": 543, "height": 639, "comps": [ { "type": "shape", "background": "#7f7f7f", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 17.90813, 17.93993, 17.90813, 319.18021, 141.34629, 415.11661, 141.34629, 620.42049, 401.01413, 620.42049, 401.01413, 415.11661, 525.09187, 319.18021, 525.09187, 17.93993, 17.90813, 17.93993, 17.90813, 17.93993 ] }, { "type": "shape", "background": "#999999", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 58.20141, 17.93993, 58.20141, 319.18021, 161.81272, 415.11661, 161.81272, 620.42049, 379.90813, 620.42049, 379.90813, 415.11661, 483.51943, 319.18021, 483.51943, 17.93993, 58.20141, 17.93993, 58.20141, 17.93993 ] }, { "type": "shape", "background": "#b2b2b2", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 127.91519, 17.93993, 127.91519, 319.18021, 197.62898, 415.11661, 197.62898, 620.42049, 346.0106, 620.42049, 346.0106, 415.11661, 415.72438, 319.18021, 415.72438, 17.93993, 127.91519, 17.93993, 127.91519, 17.93993 ] }, { "type": "shape", "background": "#cccccc", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 209.78092, 17.93993, 209.78092, 319.18021, 241.12014, 415.11661, 241.12014, 620.42049, 304.43816, 620.42049, 304.43816, 415.11661, 333.85866, 319.18021, 333.85866, 17.93993, 209.78092, 17.93993, 209.78092, 17.93993 ] }, { "type": "shape", "borderWidth": 1.27915, "borderColor": "#000000", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 17.90813, 17.93993, 17.90813, 319.18021, 141.34629, 415.11661, 141.34629, 620.42049, 401.01413, 620.42049, 401.01413, 415.11661, 525.09187, 319.18021, 525.09187, 17.93993, 17.90813, 17.93993 ] }, { "type": "shape", "borderWidth": 1.27915, "borderColor": "#7f7f7f", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 141.98587, 223.24382, 401.65371, 223.24382 ] }, { "type": "shape", "borderWidth": 1.27915, "borderColor": "#7f7f7f", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 17.90813, 319.18021, 525.09187, 319.18021 ] }, { "type": "shape", "borderWidth": 1.27915, "borderColor": "#7f7f7f", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 264.14488, 291.67845, 264.14488, 223.24382 ] }, { "type": "shape", "background": "#336666", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 31.9788, 606.9894, 511.66078, 606.9894, 511.66078, 333.25088, 31.9788, 333.25088, 31.9788, 606.9894, 31.9788, 606.9894 ] }, { "type": "shape", "borderWidth": 1.27915, "borderColor": "#000000", "shadowColor": "#1ABC9C", "rotation": 3.14159, "points": [ 31.9788, 606.9894, 511.66078, 606.9894, 511.66078, 333.25088, 31.9788, 333.25088, 31.9788, 606.9894, 31.9788, 606.9894 ] }, { type: 'image', name: { func: function(data) {return data.a('imgNum');} // 绑定了一个方法,用以动态改变图片的 name 属性值 }, rect: [50,325,450,280] // 设置火焰图片的位置和大小 } });
而后要创建一个节点将图片 fire 添加进节点,并将节点添加进数据容器:
node = new ht.Node(); node.setImage('fire'); node.a({ 'imgNum': 'fireNum0' }); node.setPosition(200, 200); dataModel.add(node);
至此,模拟锅炉燃烧的模式就全部搭建完成,主体部分实际上是锅炉矢量图,锅炉火焰图的数据绑定以及用 Animation 插件实现炉内火焰的动画。
总结:这个 Demo 主要就是用 Animation 插件实现动画效果,其中 Animation 中有很多的参数,这里我们没有指定 property 和 accessType,因为图片名参数 imgNum 不是单纯的数字类型, 所以我们就用 onUpdate 回调函数,在动画的每一帧都动态的改变 imgNum 的值,使得其不断更换图片从而在视觉上造成一种动画的效果。