TWaver HTML5 + Node.js + express + socket.io + redis(四)
原文出处:http://twaver.servasoft.com/?p=3764
接上一回TWaver HTML5 + Node.js + express + socket.io + redis(三), 这一篇您将了解到
1. 如何保存更改后的拓扑数据 (包括新增的, 修改的, 删除的)
2. 如何广播更改后的拓扑数据 (仅仅广播更改的数据)
下面是mac和iphone上的效果图, mac或iphone上的修改都将及时互相同步:
一. 先来看后台如何实现
后台需要做两件事情: 保存修改以及广播修改; 其中修改又分为是新增, 修改, 还是删除. 保存修改很容易, 无非就是对数据库的增删改, 广播数据也很容易, 调用Socket.emit之前, 先设置广播标记就ok了: Socket.broadcast.emit. 而且这个广播只会通知其他客户端, 发送这个广播的客户端不会收到广播, 这正好是我们需要的, 所以后台代码就好写了:
添加保存数据的socket.io监听, 里面保存数据后, 广播之:
//保存数据 client.on('saveData', function (datas) { if (!datas) { return; } //保存新增网元 save(datas.add); //保存修改网元 save(datas.change); //删除网元 remove(datas.remove); //广播更新 client.broadcast.emit('broadcast', datas); });
保存数据的函数如下:
二. 前台实现
分两步: 监听数据的增删改并自动保存, 响应广播更新
1. 监听数据的增删改并自动保存
TWaver HTML5的数据模型提供了各种监听器, 以便在数据更改后做响应处理. 其中:
DataBox.addDataPropertyChangeListener用于监听数据容器里数据的属性变化, 也即对数据的修改, 其回调函数的参数包含属性: property(发生变化的属性), oldValue(旧值), newValue(新值), source(发生变化的数据)
DataBox.addDataBoxChangeListener用于监听数据容器的变化, 也即数据的添加, 删除以及清空, 其回调函数的参数包含属性: kind(容器变化类型, 可选值为add(新增), remove(删除), clear(清空)), data(新增或删除的数据), datas(清空的数据集合)
这里实现保存数据的思路是:
i> 如果有网元被修改, 则将被修改的网元加上change标记, 其中判断isChanging标志很重要, 因为需要用此标志区分是用户更改还是响应广播更新(也即程序更新)
ii> 如果有新增网元, 则将新增网元加上add标记, 如果有网元被删除, 则存入map中
//添加数据容器更改监听器 box.addDataBoxChangeListener( function (e) { //如果正在响应广播更新,则返回 if (isChanging) { return; } //设置保存数据标记 needSave = true; if (e.kind === 'add') { //将新增的节点置上add标记 e.data.setClient('add', true); } else if (e.kind === 'remove') { //如果网元没有新增标记, 则存储到被删除网元列表中 if (!e.data.getClient('add')) { //存储被删除网元 removedElements[e.data.getId()] = e.data; } } });
iii> 启动定时器, 保存更改
定时器代码如下:
保存数据代码如下, 需要注意的是, 得到要添加和被修改的网元后, 需要将其add和change标记置为false, 以避免重复保存:
//保存数据 function save () { //如果无数据添加、修改、删除,则直接返回 if(!needSave){ return; } var add = []; var change = []; var remove = []; isChanging = true; box.forEach(function(data){ //新增的网元 if(data.getClient('add')){ add.push(toData(data)); } //修改的网元 else if(data.getClient('change')){ change.push(toData(data)); } //清除网元新增和修改标记 data.setClient('add', false); data.setClient('change', false); }); isChanging = false; //删除的网元 for(var id in removedElements){ remove.push(toData(removedElements[id])); } if(add.length == 0 && change.length == 0 && remove.length == 0){ return; } //初始化待删除数据 removedElements = {}; //还原保存数据标记 needSave = false; //构造更新数据 var datas = {}; if(add.length != 0){ datas.add = add; } if(remove.length != 0){ datas.remove = remove; } if(change.length != 0){ datas.change = change; } socket.emit('saveData', datas); }
从网元获取要持久化的数据代码如下:
2. 响应广播更新
分为新增, 删除以及修改三种情况, 其中很重要的是在做这些事情之前先设置isChanging为true, 以防止重复广播更新
//响应广播更新 function onBroadcast (data) { if (!data) { return; } //设置响应广播更新标记,防止重复更新 isChanging = true; var i, c, add=data.add, change=data.change, remove=data.remove; //添加节点 if (add) { for (i=0,c=add.length; i<c; i++) { if (add[i].from) { addLink(add[i]); } else { addNode(add[i]); } } } //修改节点 if (change) { for (i=0,c=change.length; i<c; i++) { changeData(change[i]); } } //删除节点 if (remove) { for (i=0,c=remove.length; i<c; i++) { removeData(remove[i]); } } //还原更新广播数据 isChanging = false; }
增删改网元代码如下:
最后, 附上本文的完整demo:TWaverHTML5Demo