我们上一篇《基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)》主要讲解了如何搭建一个实时数据通讯服务器,客户端与服务端是如何通讯的,相信通过上一篇的讲解,再配合上数据库的数据储存,我们就可以实现一个简易版的 Web 聊天工具了,有空的朋友可以自己尝试下实现,那么我们今天的主要内容真的是实现 WebGL 3D 拓扑图实时数据通讯了,请大家接着往下看。
有了前面的知识储备,我们就可以来真正实现我们 3D 拓扑图组件上节点位置信息的实时数据同步了,毋庸置疑,节点的位置信息必须是在服务端统筹控制,才能达到实时数据同步,也就是说,我们必须在服务端创建 DataModel 来管理节点,创建 ForceLayout 弹力布局节点位置,并在节点位置改变的过程中,实时地将位置信息推送到客户端,让每个客户端都更新各自页面上面的节点位置。
在服务端我们该如何创建 HT 的 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 序列化的结果返回到客户端,让客户端反序列化,从而达到数据基本一致的效果。
那么客户端和服务端的节点是如何保持一一对应的呢?首先我们得了解 HT 在获取节点对象上提供了几个方法,熟悉的朋友应该知道,有 getDataById 和 getDataByTag 两个方法,其中 ID 是 HT 系统自己维护的属性,Tag 是提供给用户自己维护其唯一性的属性,一般不建议使用 ID 作为业务上面的唯一标识,因为在序列化和反序列化时候可能会有细微的差别,很难保证反序列话后的节点 ID 和序列化前的 ID 是一样的。因此在本文中,我们是通过 Tag 属性来控制服务器和客户端的节点一一对应的。
接下来我们来看看客户端的实现吧:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="/socket.io/socket.io.js"></script> <script src="/build/ht-debug.js"></script> <script> var socket = io(); var init = function() { var dm = window.dataModel = new ht.DataModel(), sm = dm.sm(), g3d = new ht.graph3d.Graph3dView(dm); g3d.setGridSize(100); g3d.setGridGap(100); g3d.setGridVisible(true); g3d.addToDOM(); var moveNodes = null; g3d.mi(function(evt){ if ( evt.kind === 'beginMove'){ moveNodes = sm.getSelection(); } else if (evt.kind === 'betweenMove'){ moveMap = {}; g3d.sm().each(function(data){ if(data instanceof ht.Node){ moveMap[data.getTag()] = data.p3(); console.info(data.p3()); } }); socket.emit('moveMap', moveMap); } else if (evt.kind === 'endMove') { moveNodes = null; } }); socket.on('ready', function(json) { dm.clear(); dm.deserialize(json); }); socket.on('result', function (result) { for(var id in result){ var data = dm.getDataByTag([id]); if (!data) continue; if (moveNodes && moveNodes.indexOf(data) >= 0) continue; data.p3(result[id]); } }); }; </script> </head> <body onload="init();"> </body> </html>
代码并不长,我来介绍下具体的实现。首先是创建 3D 拓扑图组件,并做一些设置,让场景上出现线条,然后就是监听拓扑图上面的操作,当监听到 betweenMove 时,或许当前被移动的节点位置信息,向服务器派发该信息;接下来是监听服务器的 ready 事件,在事件回调中做了反序列化的操作,但是在反序列化之前,为什么要将场景中的所有节点 Clear 掉呢?是因为页面有可能是断线重连,如果是断线重连的话,没有将场景中的节点都 Clear 掉的话,反序列化后就会有节点重叠了,而且 Tag 属性也不再是唯一的了,所以这时候操作节点的话,将会很混乱;最后呢,就是监听服务器的 result 事件,在事件的回调中,跟新回调参数中对应节点的位置信息,但是其中做了些过滤,这是过滤正在移动的节点,因为正在移动的节点位置是认为控制的,所有不需要更新其节点位置信息。
那么实时数据通讯系列到这里就介绍完了,如有什么问题,欢迎批评指正。
相关推荐
unity 项目使用websocket通讯 可以打包webGL 目前实测支持unity2021.3.38
基于WebSocket的车辆GPS信息实时推送系统的实现 在现代信息化社会中,人们对实时信息的需求日益增长,特别是在交通领域,对车辆实时信息的需求尤为迫切。本文旨在解决车辆管理系统中如何实时获取车辆GPS信息的问题...
【作品名称】:基于websocket实现浏览器端文本、视频、语音的即时通讯 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】...
为了在Web页面上实现数据的实时显示,我们需要在前端使用WebSocket API创建一个连接到后端服务的实例。当Java代码向RabbitMQ发送消息时,后端服务接收到消息后,可以通过WebSocket连接推送到Web页面。 实现这个功能...
UI01.HTML 页面,采用echarts折线图、柱状图、饼图、仪表盘等显示形式,展示后台发送的数据; 2、javascript websocket.js,websocket页面使用javascript文件,定义.onopen、onmessage、onclose、onerror函数,html...
在这个"dotnet-基于websocket实现的im实时通讯案例"中,开发者巧妙地结合了Redis的订阅与发布(Pub/Sub)功能,构建了一个高性能的IM系统。 首先,让我们深入了解WebSocket。WebSocket是HTML5引入的一种协议,旨在...
在基于WebSocket实现浏览器端文本、视频、语音的即时通讯中,我们可以深入理解以下几个关键知识点: 1. **WebSocket基本原理**:WebSocket协议是HTTP/1.1协议的一个扩展,它通过一次握手建立长连接,解决了HTTP协议...
总结来说,这个项目通过WebSocket、MySQL、Java 8和Tomcat 8的集成,实现了高效、实时的数据同步,让前端页面能够实时反映出后台数据库的动态变化,提高了用户体验。这在实时聊天、股票报价、在线游戏等需要实时数据...
WebSocket则为实现双向通信提供了可能,确保了数据的实时更新;SVG作为矢量图形技术,可以实现高清晰度且不损失质量的地图展示。接下来,我们将详细探讨这三个技术如何结合构建实时地图监控系统。 首先,Vue.js是...
Java基于WebSocket实现的视频聊天是一种实时通信(Real-Time Communication, RTC)的应用,它利用了WebSocket这一先进的网络协议来实现高效、双向的数据传输。WebSocket协议是HTML5的一个重要特性,为客户端与服务器...
这个项目中,开发者可能通过WebSocket实现了从服务器到客户端的视频数据实时推送,提供了流畅的观看体验。同时,这也只是一个基础的实现,实际的视频直播系统还会涉及到更多复杂的技术,如多码率适应、动态调度、流...
WebSocket是Web应用中实现实时通信的关键技术,它允许服务器与客户端之间建立长连接,从而实现实时、双向的数据传输。本项目是一个基于WebSocket的网页聊天室,具备私聊和多对多聊天功能,适合初学者理解和实践网络...
WebSocket协议被广泛应用于实时通信场景,例如在线游戏、聊天应用、股票交易系统等,使得Android客户端之间的实时通讯成为可能。 在Android中实现WebSocket通信,首先需要引入相关的库。Java中常见的WebSocket库有...
使用Java-WebSocket开源框架开发Android端即时通讯功能。主要功能: 1、与websocket建立长连接 2、与websocket进行即时通讯 3、Service和Activity之间通讯和UI更新 4、弹出消息通知(包括锁屏通知) 5、心跳检测和重...
WebSocket是一种在客户端和服务器之间建立长连接的协议,它允许双方进行全双工通信,即数据可以在两个方向上同时传输,极大地提高了实时性。在现代Web应用中,尤其是在需要实时更新、聊天、在线游戏或者股票交易等...
基于WebSocket和three.js的实时上位机, 用于显示STM32通过ESP8266发送来的数据波形图, 并绘制路径图.zip嵌入式优质项目,资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松copy复刻,拿到资料包后可...
【描述】:本文主要探讨了如何在Uniapp项目中集成GoEasy服务,以实现基于websocket的实时通讯功能。Uniapp作为一个跨平台的开发框架,允许开发者编写一次代码,即可应用于Android、iOS及多种小程序平台。GoEasy则是...
综上所述,使用Java实现WebSocket实现实时通讯涉及对WebSocket协议的理解、JSR 356 API的使用、连接生命周期的管理以及客户端和服务器端的交互逻辑。通过这些技术,开发者能够构建高效、实时的Web应用程序,满足即时...
Java课设基于WebSocket实现Web端聊天系统源码.zipJava课设基于WebSocket实现Web端聊天系统源码.zipJava课设基于WebSocket实现Web端聊天系统源码.zipJava课设基于WebSocket实现Web端聊天系统源码.zip 【1】项目代码...
基于WebSocket实现的Android和H5聊天通讯实例【附效果图附所有源码】使用的源码 博客地址:http://blog.csdn.net/lucherr/article/details/75673810