Chinaunix首页 | 论坛 | 博客
  • 博客访问: 951113
  • 博文数量: 110
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1997
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-15 22:39
个人简介

HT for Web 3D. HT for modern web and mobile app development. www.hightopo.com

文章分类

全部博文(110)

文章存档

2020年(1)

2018年(28)

2017年(21)

2016年(10)

2015年(28)

2014年(19)

2013年(3)

我的朋友

分类: HTML5

2014-02-20 19:21:17

上篇将3D弹力布局的算法运行在Web Workers后台,这篇我们将进一步折腾,将算法运行到真正的后台:Node.js,事先申明Node.js篇和Web Workers篇一样,在这个应用场景下并不能提高性能,纯粹为了折腾好玩,当然也不会白玩,人生就在折腾中,只有折腾才能真正成长。


 

核心实现代码和Web Workers篇基本一致,唯一区别在于前后台交互的方式上,worker通过postMessage和addEventListener('message' 就可以发送和接收消息,对于真正分离前后台的Node.js自然没那么简单了,我采用了Socket.io通信框架,Socket.io让长连接通信变得无比简单,和Web Workers的通信几乎一样的容易了,Socket.io的用法下图一目了然:


 

Node.js后台代码如下,通过require引入和Socket.io相关类库,io = require('socket.io').listen(8036)构建出一个监听在8036端口的服务,通过io.sockets.on('connection'等着客户端页面来建立的socket通信,通过socket.on('moveMap',监听客户端发过来的图片节点拖拽变化信息进行同步,通过 socket.emit('result', result);发送自动布局算法的运算结果push到客户端。

 

Js代码  收藏代码
  1. io = require('socket.io').listen(8036);  
  2. ht = require('ht.js').ht;  
  3. require("ht-forcelayout.js");  
  4. reloadModel = require("util.js").reloadModel;      
  5.   
  6. io.sockets.on('connection'function (socket) {      
  7.     var dataModel = new ht.DataModel(),  
  8.         forceLayout = new ht.layout.Force3dLayout(dataModel);  
  9.   
  10.     forceLayout.onRelaxed = function(){      
  11.         var result = {};  
  12.         dataModel.each(function(data){  
  13.            if(data instanceof ht.Node){  
  14.                result[data._id] = data.p3();  
  15.            }   
  16.         });  
  17.         socket.emit('result', result);  
  18.     };  
  19.     forceLayout.start();  
  20.   
  21.     socket.on('moveMap'function (moveMap) {  
  22.         dataModel.sm().cs();  
  23.         for(var id in moveMap){  
  24.             var data = dataModel.getDataById(id);  
  25.             if(data){  
  26.                 data.p3(moveMap[id]);  
  27.                 dataModel.sm().as(data);  
  28.             }  
  29.         }       
  30.     });  
  31.     socket.on('reload'function (data) {  
  32.         reloadModel(dataModel, data);     
  33.     });             
  34. });  

 客户端的代码需要通过引入Socket.io客户端类库,通过socket = io.connect('')链接服务器获得握手链接socket对象,剩下的代码就是同socket.emit发送客户端拖拽信息,以及socket.on监听服务器推送过来的自动布局结果:

Js代码  收藏代码
  1. g3d.mi(function(evt){  
  2.     if(evt.kind === 'betweenMove'){                  
  3.         moveMap = {};  
  4.         g3d.sm().each(function(data){  
  5.             if(data instanceof ht.Node){  
  6.                 moveMap[data._id] = data.p3();  
  7.             }  
  8.         });  
  9.         socket.emit('moveMap', moveMap);                  
  10.     }  
  11. });   
  12.   
  13. socket = io.connect('');                                
  14. socket.on('result'function (result) {  
  15.     for(var id in result){  
  16.         var data = dataModel.getDataById([id]);  
  17.         if(data && !g3d.isSelected(data)){  
  18.             data.p3(result[id]);  
  19.         }                  
  20.     }   
  21. });  

 

几个注意点:

 

1、首选和Web Workers一样,跑在Node.js的类库肯定不能操作window和document之类的页面特定元素对象,从这点说很多考虑不周全的类库会把自己限制死只能在页面主线程运行,这点考虑得很周到,不仅ht.js包括所有ht-forcelayout.js插件都是可运在Web Workers和Node.js的非GUI环境,因为我也常需要ht.js运行在后台直接将DataModel的数据和前台进行JSON的数据格式转换存储。

 

2、Util.js定义的reloadModel函数我增加了this.reloadModel = reloadModel;的逻辑,这样才能在Node.js后台代码reloadModel = require("util.js").reloadModel; 这样的方式得到该函数进行调用,细节可以参考 的章节

 

3、这个例子是有缺陷的,以下播放过程你会发现,我打开了两个页面,这样就会有两个socket分别连接后台Node.js,而Node.js默认是单线程的,如果正在一个请求函数密集运算处理,则其他请求只能排队等待处理,这也是视频中我拖拽一个页面布局是,另一个页面无法操作的原因。当然你可以改进demo,采用的cluster方式,实现真正的后台多核任务处理

操作视频如下:

阅读(2879) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~