博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(二)
阅读量:6640 次
发布时间:2019-06-25

本文共 4223 字,大约阅读时间需要 14 分钟。

我们上一篇《》主要讲解了如何搭建一个实时数据通讯服务器,客户端与服务端是如何通讯的,相信通过上一篇的讲解,再配合上数据库的数据储存,我们就可以实现一个简易版的 Web 聊天工具了,有空的朋友可以自己尝试下实现,那么我们今天的主要内容真的是实现 WebGL 3D 拓扑图实时数据通讯了,请大家接着往下看。

 

有了前面的知识储备,我们就可以来真正实现我们 3D 组件上节点位置信息的实时数据同步了,毋庸置疑,节点的位置信息必须是在服务端统筹控制,才能达到实时数据同步,也就是说,我们必须在服务端创建 DataModel 来管理节点,创建 ForceLayout 弹力布局节点位置,并在节点位置改变的过程中,实时地将位置信息推送到客户端,让每个客户端都更新各自页面上面的节点位置。

在服务端我们该如何创建 的 DataModel 和 ForceLayout 呢?其实也很简单,我们可以看看下面的代码:

var ht = global.ht = this.ht = require('../../../build/ht-debug.js').ht,    dataModel = new ht.DataModel(),    reloadModel = require("../util.js").reloadModel;reloadModel(dataModel, { A: 3, B: 5 });require("../../../build/ht-forcelayout-debug.js");var forceLayout = new ht.layout.Force3dLayout(dataModel);forceLayout.onRelaxed = function() {    var result = {};    dataModel.each(function(data) {        if (data instanceof ht.Node) {            result[data.getTag()] = data.p3();        }    });    io.emit('result', result);};forceLayout.start();

我们通过 require 将非 Node.js 模块包引入到程序中,并加以使用。在上面的代码中,我们确实创建了 HT 的拓扑节点,是通过 util.js 文件中的 relowdModel 方法创建的节点,那这个文件中到底是怎么实现创建 HT 拓扑节点的呢?接下来就来看看具体的实现:

function createNode(dataModel, id){    var node = new ht.Node();    node.setId(id);    node.setTag(id);    node.s3(40, 40, 40);    node.s({        'shape3d': 'sphere',        'note': id,        'note.position': 17,        'note.background': 'yellow',        'note.color': 'black',        'note.autorotate': true,        'note.face': 'top'    });    dataModel.add(node);    return node;}function createEdge(dataModel, source, target){    var edge = new ht.Edge(source, target);    edge.s({        'edge.width': 10,        'shape3d.color': '#E74C3C',        'edge.3d': true    });    dataModel.add(edge);    return edge;}function reloadModel(dataModel, info){    dataModel.clear();    var ip = "192.168.1.";    var count = 0;    var root = createNode(dataModel, ip + count++);    for (var i = 0; i < info.A; i++) {        var iNode = createNode(dataModel, ip + count++);        createEdge(dataModel, root, iNode);        for (var j = 0; j < info.B; j++) {            var jNode = createNode(dataModel, ip + count++);            createEdge(dataModel, iNode, jNode);        }    }}this.reloadModel = reloadModel;

在这个文件中,封装了创建节点的方法 createNode,和创建连线的方法 createEdge,最后是通过 reloadModel 方法将前面的两个方法连接起来,在这个文件的最后,我们可以看到,只公开了 reloadModel 的函数接口。

当然光这些是不够的,这些还不能够达成实时数据通讯的功能,我们还需要监听和派发一些事件才能够达到效果,那么我们都监听了什么借口,派发了什么事件呢?

io.on('connection', function(socket) {    socket.emit('ready', dataModel.serialize(0));    console.log('a user connected');    socket.on('disconnect', function() {        console.log('user disconnected');    });    socket.on('moveMap', function(moveMap) {        dataModel.sm().cs();        for (var id in moveMap) {            var data = dataModel.getDataByTag(id);            if (data) {                data.p3(moveMap[id]);                dataModel.sm().as(data);            }        }    });});

 

上面那串代码是我们的事件监听,我们通过监听 moveMap 的事件,并获取从客户端传递上来的移动的节点坐标信息,根据参数的内容,我们将其改变服务端的 DataModel 中对应节点的坐标,改变后 ForceLayout 就会根据当前的状态去调整整个拓扑上所有节点的位置。那么在调节的过程中,我们是怎么知道 ForceLayout 是正在调整的呢?在前面介绍如何在 Node.js 上面创建 HT 相关的组件时贴出来的代码中就告诉我么怎么做了。 

在创建 ForceLayout 组件的代码后面,紧跟着就是重载 ForceLayout 组件的 onRelaxed 方法,每次布局玩后,都会调用这个方法,这样我们就可以在这个方法中,编辑获取到 DataModel 中的所有节点的当前位置,并通过 io.emit 方法通知给所有的客户端,让客户端去实时更新对应节点的坐标位置。

但是还有一个问题,我们要怎么样让客户端显示的节点和服务端上的节点一一对应呢?首先不能让客户端自己创建节点,我们的做法其实也很简单,虽然不能保证客户端的节点 ID 会和服务端的节点 ID 一模一样,但是我们可以保证其他关键属性是一样,因为我们利用了 HT 的序列化功能,当有客户端连接到服务器时,就会向客户端派发 ready 事件,将 DataModel 序列化的结果返回到客户端,让客户端反序列化,从而达到数据基本一致的效果。

那么客户端和服务端的节点是如何保持一一对应的呢?首先我们得了解 在获取节点对象上提供了几个方法,熟悉的朋友应该知道,有 getDataById 和 getDataByTag 两个方法,其中 ID 是 HT 系统自己维护的属性,Tag 是提供给用户自己维护其唯一性的属性,一般不建议使用 ID 作为业务上面的唯一标识,因为在序列化和反序列化时候可能会有细微的差别,很难保证反序列话后的节点 ID 和序列化前的 ID 是一样的。因此在本文中,我们是通过 Tag 属性来控制服务器和客户端的节点一一对应的。

接下来我们来看看客户端的实现吧:

 

            

代码并不长,我来介绍下具体的实现。首先是创建 3D 组件,并做一些设置,让场景上出现线条,然后就是监听拓扑图上面的操作,当监听到 betweenMove 时,或许当前被移动的节点位置信息,向服务器派发该信息;接下来是监听服务器的 ready 事件,在事件回调中做了反序列化的操作,但是在反序列化之前,为什么要将场景中的所有节点 Clear 掉呢?是因为页面有可能是断线重连,如果是断线重连的话,没有将场景中的节点都 Clear 掉的话,反序列化后就会有节点重叠了,而且 Tag 属性也不再是唯一的了,所以这时候操作节点的话,将会很混乱;最后呢,就是监听服务器的 result 事件,在事件的回调中,跟新回调参数中对应节点的位置信息,但是其中做了些过滤,这是过滤正在移动的节点,因为正在移动的节点位置是认为控制的,所有不需要更新其节点位置信息。

那么实时数据通讯系列到这里就介绍完了,如有什么问题,欢迎批评指正。

 

转载地址:http://dzlvo.baihongyu.com/

你可能感兴趣的文章
设计模式-命令模式
查看>>
C#的几个基本概念
查看>>
JavaScript对象的几种创建方式
查看>>
Linux进程间通信——使用信号量
查看>>
xpath提取多个html标签text
查看>>
android中webservce获取soapObject数据的解析问题
查看>>
[120_移动开发Android]004_android开发之单元测试
查看>>
Java加密算法(二)——对称加密算法DES&AES
查看>>
最少换乘
查看>>
centos 7 安装MySql
查看>>
LeetCode: Adding two numbers (by list)
查看>>
Hibernate查询 内连接和外连接区别
查看>>
1068. [SCOI2007]压缩【区间DP】
查看>>
下载远程(第三方服务器)文件、图片,保存到本地(服务器)的方法、保存抓取远程文件、图片...
查看>>
Docker四种网络模式
查看>>
c:url标签
查看>>
Silverlight-Validation服务器端异步数据验证
查看>>
最新VIN(车辆识别码)解析
查看>>
ubuntu下出现的问题-控制台更新源失败
查看>>
获得user account的SID,GUID
查看>>