TWaver HTML伍 + Node.js + express + socket.io + redis(五)

接上一次TWaver HTML5 + Node.js +
express + socket.io +
redis(四)
,
这1篇您将精通到

  1. 什么保存更改后的拓扑数据 (包罗新增的, 修改的, 删除的)
  2. 如何广播更改后的拓扑数据 (仅仅广播更改的多少)

上面是mac和iphone上的职能图, mac或iphone上的修改都将霎时互动同步:

图片 1

图片 2

 

一. 先来看后台如何完结

后台要求做两件业务: 保存修改以及广播修改; 在那之中期维修改又分为是增创, 修改,
依旧删除. 保存修改很简单, 无非就是对数据库的增加和删除改, 广播数据也很不难,
调用Socket.emit从前, 先设置广播标记就ok了: Socket.broadcast.emit.
而且以此广播只会通报别的客户端, 发送那一个广播的客户端不会收到广播,
那刚刚是大家须要的, 所以往台代码就好写了:

增进保存数据的socket.io监听, 里面保存数据后, 广播之:

 1     //保存数据
 2     client.on('saveData', function (datas) {
 3         if (!datas) {
 4             return;
 5         }
 6         //保存新增网元
 7         save(datas.add);
 8         //保存修改网元
 9         save(datas.change);
10         //删除网元
11         remove(datas.remove);
12         //广播更新
13         client.broadcast.emit('broadcast', datas);
14     });

封存数据的函数如下:

 1 //保存网元
 2 function save (datas) {
 3     if(!datas){
 4         return;
 5     }
 6     var elements = {};
 7     for (var i=0,n=datas.length,data; i<n; i++) {
 8         data = datas[i];
 9         elements[data.id] = JSON.stringify(data);
10     }
11     redis.hmset('datas', elements);
12 };
13 
14 //删除网元
15 function remove (datas) {
16     if(!datas){
17         return;
18     }
19     var ids = [];
20     for (var i=0,n=datas.length; i<n; i++) {
21         ids.push(datas[i].id);
22     }
23     redis.hdel('datas', ids);
24 };

二. 前台完成

分两步: 监听数据的增加和删除改并机关保存, 响应广播更新

  1. 监听数据的增加和删除改并机关保存

TWaver HTML5的数据模型提供了种种监听器, 以便在数额变动后做响应处理.
当中:
DataBox.addDataPropertyChangeListener用于监听数据容器里多少的质量变化,
也即对数码的改动, 其回调函数的参数包罗属性: property(发生变化的习性),
oldValue(旧值), newValue(新值), source(爆发变化的数额)

DataBox.addDataBoxChangeListener用于监听数据容器的浮动, 也即数据的增进,
删除以及清空, 其回调函数的参数包蕴属性: kind(容器变化类型,
可选值为add(新增), remove(删除), clear(清空)), data(新增或删除的数量),
datas(清空的数量集合)

此间实现保存数据的思绪是:
i> 借使有网元被涂改, 则将被涂改的网元加上change标记,
当中判断isChanging标志很关键,
因为急需用此标志区分是用户更改可能响应广播更新(也即程序更新)

 1     //添加网元属性更改监听器
 2     box.addDataPropertyChangeListener(function (e) {
 3         //如果正在响应广播更新,则返回
 4         if (isChanging) {
 5             return;
 6         }
 7         //如果属性为add, change 则返回
 8         if (e.property === 'C:add' || e.property === 'C:change') {
 9             return;
10         }
11         //设置保存数据标记
12         needSave = true;
13         //将有属性更改的节点置上change标记
14         e.source.setClient('change', true);
15     });

ii> 若是有新增网元, 则将猛增网元加上add标记, 如若有网元被删除,
则存入map中

 1     //添加数据容器更改监听器
 2     box.addDataBoxChangeListener( function (e) {
 3         //如果正在响应广播更新,则返回
 4         if (isChanging) {
 5             return;
 6         }
 7         //设置保存数据标记
 8         needSave = true;
 9         if (e.kind === 'add') {
10             //将新增的节点置上add标记
11             e.data.setClient('add', true);
12         } else if (e.kind === 'remove') {
13             //如果网元没有新增标记, 则存储到被删除网元列表中
14             if (!e.data.getClient('add')) {
15                 //存储被删除网元
16                 removedElements[e.data.getId()] = e.data;
17             }
18         }
19     });

iii> 运行定时器, 保存更改
定时器代码如下:

 1 //自动保存
 2 function setAutoSave (value) {
 3     if(value){
 4         //定时器,每隔1秒钟保存修改
 5         timer = setInterval(function(){
 6             save();
 7         }, 1000);
 8     }else{
 9         window.clearTimeout(timer);
10     }
11 }

封存数据代码如下, 需求留意的是, 得到要增加和被修改的网元后,
供给将其add和change标记置为false, 以幸免双重保存:

 1 //保存数据
 2 function save () {
 3     //如果无数据添加、修改、删除,则直接返回
 4     if(!needSave){
 5         return;
 6     }
 7     
 8     var add = [];
 9     var change = [];
10     var remove = [];
11     isChanging = true;
12     box.forEach(function(data){
13         //新增的网元
14         if(data.getClient('add')){
15             add.push(toData(data));
16         }
17         //修改的网元
18         else if(data.getClient('change')){
19             change.push(toData(data));
20         }
21         //清除网元新增和修改标记
22         data.setClient('add', false);
23         data.setClient('change', false);
24     });
25     isChanging = false;
26     //删除的网元
27     for(var id in removedElements){
28         remove.push(toData(removedElements[id]));
29     }
30     
31     if(add.length == 0 && change.length == 0 && remove.length == 0){
32         return;
33     }
34     
35     //初始化待删除数据
36     removedElements = {};
37     //还原保存数据标记
38     needSave = false;
39     //构造更新数据
40     var datas = {};
41     if(add.length != 0){
42         datas.add = add;
43     }
44     if(remove.length != 0){
45         datas.remove = remove;
46     }
47     if(change.length != 0){
48         datas.change = change;
49     }
50     socket.emit('saveData', datas);
51 }

从网元获取要持久化的多少代码如下:

 1 //从网元获取持久化数据
 2 function toData (element) {
 3     if(element instanceof twaver.Node) {
 4         return {
 5             id: element.getId(),
 6             name: element.getName(),
 7             location: element.getLocation()
 8         };
 9     } else {
10         return {
11             id: element.getId(),
12             name: element.getName(),
13             from: element.getFromNode() ? element.getFromNode().getId() : null,
14             to: element.getToNode() ? element.getToNode().getId() : null
15         };
16     }
17 }
  1. 壹呼百应广播更新

分成新增, 删除以及修改二种情况,
在这之中很重大的是在做这一个工作以前先安装isChanging为true, 以防患重复播放更新

 1 //响应广播更新
 2 function onBroadcast (data) {
 3     if (!data) {
 4         return;
 5     }
 6     //设置响应广播更新标记,防止重复更新
 7     isChanging = true;
 8     var i, c, add=data.add, change=data.change, remove=data.remove;
 9     //添加节点
10     if (add) {
11         for (i=0,c=add.length; i<c; i++) {
12             if (add[i].from) {
13                 addLink(add[i]);
14             } else {
15                 addNode(add[i]);
16             }
17         }
18     }
19     //修改节点
20     if (change) {
21         for (i=0,c=change.length; i<c; i++) {
22             changeData(change[i]);
23         }
24     }
25     //删除节点
26     if (remove) {
27         for (i=0,c=remove.length; i<c; i++) {
28             removeData(remove[i]);
29         }
30     }
31     //还原更新广播数据
32     isChanging = false;
33 }

增加和删除改网东汉码如下:

 1 //添加节点
 2 function addNode (data) {
 3     //构造节点
 4     var node = new twaver.Node(data);
 5     //添加节点
 6     box.add(node);
 7 }
 8 
 9 //添加节点
10 function addLink (data) {
11     //查找from节点
12     var from = box.getDataById(data.from);
13     //查找to节点
14     var to = box.getDataById(data.to);
15     //构造连线
16     var link = new twaver.Link({id: data.id, name: data.name}, from, to);
17     //添加连线
18     box.add(link);
19 }
20 
21 //修改网元
22 function changeData (data) {
23     var element = box.getDataById(data.id);
24     //修改节点
25     if (element instanceof twaver.Node) {
26         element.setLocation(data.location.x, data.location.y);
27         element.setName(data.name);
28     }
29     //修改连线
30     else if (element instanceof twaver.Link) {
31         element.setName(data.name);
32         element.setFromNode(box.getDataById(data.from));
33         element.setToNode(box.getDataById(data.to));
34     }
35     //网元被删除
36     else {
37         //网元被删除, 无需修改
38     }
39 }
40 
41 //删除网元
42 function removeData (data) {
43     box.removeById(data.id);
44 }

 

最后,
附上本文的全体demo:TWaverHTML5Demo