基于Jtopo的网络拓扑编辑器初探
来源:互联网 发布:手机淘宝4.0.1 编辑:程序博客网 时间:2024/05/22 01:51
为了方便演示,我已经把一个静态DEMO部署到github,传送门
基本的操作可以看下面的GIF图,节点从左边图标栏拖拽至编辑区,通过单击节点图标,然后松开鼠标按键则可拖动一条连线。在目标节点单击,怎完成一次连线操作。左栏可以选择多种连线方式。
这个拓扑编辑器UI是easyUI做的布局,节点的编辑和连线则是基于jTopo二次开发的。jTopo提供了Stage、Scene、Node、Container以及对动画的支持,API使用相对简单易用。缺点是文档缺乏,但是我们可以通过作者提供的DEMO进行熟悉。一旦熟悉其源码,则十分便于二次开发。用来实现一些动画也是轻而易举的。由于是基于canvas的绘画,所以每次更改和操作其实都会重绘整个画布。当中还是有不少可以优化的地方。其实想D3.js也可以走到这样的效果,只是近期工作都在后端就没去探究了。
由于只是摘取个人开发项目的前端部分,由于公司许可原因只能开发这一部分了,有兴趣的可以去我的github上clone下来参考。核心部分代码都在editor.js,提供了节点拖拽、节点连线、布局等方法支持。这个是一个初始版本。代码粗糙,仅供参考。
下面摘取几个重要的地方稍微讲解:
1、编辑器初始化代码
//创建JTOP舞台屏幕对象 var canvas = document.getElementById('drawCanvas'); canvas.width = $("#contextBody").width(); canvas.height = $("#contextBody").height(); //加载空白的编辑器 if(stageJson == "-1"){ this.stage = new JTopo.Stage(canvas); this.stage.topoLevel = 1; this.stage.parentLevel = 0; this.modeIdIndex = 1; this.scene= new JTopo.Scene(this.stage); this.scene.totalLevel = 1; }else{ this.stage = JTopo.createStageFromJson(stageJson, canvas); this.scene = this.stage.childs[0]; }
我们可以调用JTopo.Stage(canvas)来初始化一个画图区域,接下来就可以使用API进行节点和动画的操作了。整个画图对象的JSON层次结构如下所示:
{ "version": "0.4.8", "deviceNum": "19", "wheelZoom": 0.95, "width": 864, "height": 569, "id": "ST172.19.105.52015100809430700001", "topoLevel": "1", "parentLevel": "0", "nextLevel": "0", "childs": [ { "elementType": "scene", "id": "S172.19.105.52015100809430700002", "topoLevel": "1", "parentLevel": "0", "nextLevel": "0", "translateX": 106.5, "translateY": 20, "scaleX": 1, "scaleY": 1, "totalLevel": "1", "childs": [ { "elementType": "node", "id": "", "topoLevel": 1, "parentLevel": "0", "nextLevel": "0", "x": 211.5, "y": 135, "width": 32, "height": 32, "visible": true, "rotate": 0, "scaleX": 1, "scaleY": 1, "zIndex": 3, "deviceId": "1404683827351.4666", "dataType": "VR", "nodeImage": "tpIcon_9.png", "text": "CS路由器", "textPosition": "Bottom_Center", "templateId": undefined } ] } ]}其结构为:
通常我们只需要一个 Scene对象即可管理所有的对象,当然如果要实现更复杂的分组对象管理则可以创建多个Scene对象进行单独管理。同时我们可以调用JTopo.createStageFromJson(stageJson, canvas)方法来讲一个保存好的拓扑结构重新渲染。
2、节点的拖拽
节点的拖拽使用的原生H5的drag&drop来实现
/** * 图元拖放功能实现 * @param modeDiv * @param drawArea */networkTopologyEditor.prototype.drag = function (modeDiv, drawArea, text) { if (!text) text = ""; var self = this; //拖拽开始,携带必要的参数 modeDiv.ondragstart = function (e) { e = e || window.event; var dragSrc = this; var backImg = $(dragSrc).find("img").eq(0).attr("src"); backImg = backImg.substring(backImg.lastIndexOf('/') + 1); var datatype = $(this).attr("datatype"); try { //IE只允许KEY为text和URL e.dataTransfer.setData('text', backImg + ";" + text + ";" + datatype); } catch (ex) { console.log(ex); } }; //阻止默认事件 drawArea.ondragover = function (e) { e.preventDefault(); return false; }; //创建节点 drawArea.ondrop = function (e) { e = e || window.event; var data = e.dataTransfer.getData("text"); var img, text,datatype; if (data) { var datas = data.split(";"); if (datas && datas.length == 3) { img = datas[0]; text = datas[1]; datatype = datas[2]; var node = new JTopo.Node(); node.fontColor = self.config.nodeFontColor; node.setBound((e.layerX ? e.layerX : e.offsetX) - self.scene.translateX - self.config.defaultWidth / 2, (e.layerY ? e.layerY : e.offsetY) - self.scene.translateY - self.config.defaultHeight / 2,self.config.defaultWidth,self.config.defaultHeight); //设备图片 node.setImage(context + 'post/web-topology/icon/' + img); //var cuurId = "device" + (++self.modeIdIndex); var cuurId = "" + new Date().getTime() * Math.random(); node.deviceId = cuurId; node.dataType = datatype; node.nodeImage = img; ++self.modeIdIndex; node.text = text; node.layout = self.layout; //节点所属层次 node.topoLevel = parseInt($("#selectLevel").find("option:selected").val()); //节点所属父层次 node.parentLevel = $("#parentLevel").val(); //子网连接点的下一个层,默认为0 node.nextLevel = "0"; self.scene.add(node); //加载属性面板 /* if(self.currDataType) self.clearOldPanels(self.currDataType) self.currDeviceId = cuurId; self.createNewPanels(datatype,self.templateId,self.currentModeId);*/ //self.currDataType = datatype; self.currentNode = node; } } if (e.preventDefault()) { e.preventDefault(); } if (e.stopPropagation()) { e.stopPropagation(); } }}在ondragstart回调方法中传递底图以及必要参数,然后在ondrop进行节点的创建
新建节点使用JTopo.Node()构造,设置好相关属性然后通过scene.add(node)加入到Stage。为何执行add操作在界面上就可以看到新的节点了呢?原因是Stage有一个frames属性,它定义了画布重绘频率1000/frames。
frames [属性]
设置当前舞台播放的帧数/秒
默认为:24
frames可以为0,表示:不自动绘制,由用户手工调用Stage对象的paint()方法来触发。
如果小于0意味着:只有键盘、鼠标有动作时才会重绘,例如:stage.frames = -24。
默认画面帧数为24帧,也就是每1000/24ms就会重绘屏幕。后台刷新的代码如下:
function() { 0 == stage.frames ? setTimeout(arguments.callee, 100) : stage.frames < 0 ? (stage.repaint(), setTimeout(arguments.callee, 1e3 / -stage.frames)) : (stage.repaint(), setTimeout(arguments.callee, 1e3 / stage.frames)) } ()
setTimeout会调用下面的重绘函数,
this.paint = function() { null != this.canvas && (this.graphics.save(), this.graphics.clearRect(0, 0, this.width, this.height), this.childs.forEach(function(a) { 1 == a.visible && a.repaint(stage.graphics) } ), 1 == this.eagleEye.visible && this.eagleEye.paint(this), this.graphics.restore()) } , this.repaint = function() { 0 != this.frames && (this.frames < 0 && 0 == this.needRepaint || (this.paint(), this.frames < 0 && (this.needRepaint = !1))) }
paint对遍历所有可见对象 ,依次调用repaint方法。
3、节点连线
if(self.lineType == "line"){ self.link = new JTopo.Link(self.tempNodeA, self.tempNodeZ); self.link.lineType = "line"; }else if(self.lineType == "foldLine"){ self.link = new JTopo.FoldLink(self.tempNodeA, self.tempNodeZ); self.link.lineType = "foldLine"; self.link.direction = self.config.direction; }else if(self.lineType == "flexLine"){ self.link = new JTopo.FlexionalLink(self.tempNodeA, self.tempNodeZ); self.link.direction = self.config.direction; self.link.lineType = "flexLine"; }else if(self.lineType == "curveLine"){ self.link = new JTopo.CurveLink(self.tempNodeA, self.tempNodeZ); self.link.lineType = "curveLine"; }
- 基于Jtopo的网络拓扑编辑器初探
- JTopo绘制网络拓扑图
- 网络拓扑图jTopo简介和入门
- 使用jTopo画网络拓扑图
- Jtopo 拓扑图
- 拓扑图框架Jtopo
- 基于Extjs3.0的网络拓扑
- 基于HTML5的网络拓扑图设计
- 基于HTML5的网络拓扑图
- 基于HTML5的拓扑图编辑器 - Graph.Editor
- 拓扑编辑器的编写
- 基于SNMP的网络拓扑结构自动发现研究
- 基于SNMP的网络拓扑结构自动发现研究
- java实现基于snmp的网络拓扑发现
- 基于HTML5的网络拓扑图 - 定制状态面板
- 基于 HTML5 的 3D 网络拓扑树呈现
- 基于HTML5的3D网络拓扑树呈现
- 基于HTML5的3D网络拓扑自动布局
- Android 标签数字自定义控件
- Codeforces 742B Arpa’s obvious problem and Mehrdad’s terrible solution
- 使用CSocket、CSocketFile及CArchive组合接收不到数据的一种原因
- chrome 浏览器主页被 360 篡改解决办法
- 通过Github与PM2部署Node应用
- 基于Jtopo的网络拓扑编辑器初探
- 解决ES数据偏移问题
- 一句代码检测app新版本
- Intent传值新技能
- Java CountDownLatch
- websphere重启方法
- 03.Sublime Text 3 快捷键
- iOS-申请邓白氏编码的超详细流程介绍--申请苹果公司开发者账号流程所需
- Android图片框架对比Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较