HTML第三方组件种类繁多,小到按钮,工具栏,大到树图,表格,布局框架,以及各种图表,每种组件都有其优势,比如EasyUI的树和表格,Bootstrap的表单,Qunee的拓扑图等,一个应用需要整合多种组件,本文将以一个示例来介绍EasyUI与Qunee组件的同步使用
引入相关js和css文件
本例用到jquery, bootstrap, easyui和qunee,分别引入相关文件
<script type="text/javascript" src="http://demo.qunee.com/js/jquery/jquery.min.js"></script> <script type="text/javascript" src="http://demo.qunee.com/js/bootstrap/bootstrap.min.js?v=1.3"></script> <script type="text/javascript" src="http://demo.qunee.com/jquery-easyui-1.3.6/jquery.easyui.min.js"></script> <script src="http://demo.qunee.com/lib/qunee-min.js"></script> <script src="common.js"></script> <link rel="stylesheet" href="http://demo.qunee.com/js/bootstrap/bootstrap.min.css"/> <link rel="stylesheet" type="text/css" href="http://demo.qunee.com/jquery-easyui-1.3.6/themes/gray/easyui.css"> <link rel="stylesheet" type="text/css" href="http://demo.qunee.com/jquery-easyui-1.3.6/themes/icon.css">
使用EasyUI布局框架
EasyUI支持东南西北中区域布局,类似Java Swing中的BorderLayout,本例中,左侧放置树图,中间为拓扑图
<body class="easyui-layout"> <div data-options="region:'west',split:true" border="false" style="width:200px;padding-left: 10px;"> <h3 style="border-bottom:1px solid #ddd;padding:0 0 3px 5px;margin-top: 0px;">拓扑视图</h3> <ul id="tree" class="easyui-tree"></ul> </div> <div data-options="region:'north'" border="false" style="height:60px;"><h3 style="text-align: center;">Qunee + EasyUI 同步示例</h3></div> <div id="center_panel" data-options="region:'center'" style="padding-right: 10px;"> <div class="easyui-tabs" data-options="fit:true,border:false,plain:true"> <div title="网络视图" id="graph_panel" class="q-panel"> <div id="toolbar" class="q-toolbar"></div> <div id="canvas_panel" class="q-content"> <div id="canvas" class="q-canvas"></div> <div id="toolbox"></div> </div> </div> <div title="JSON" style="padding: 10px;" >JSON</div> </div> </div> <div id="footer" data-options="region:'south',border:false">Copyright © 2014 <a href="http://qunee.com">Qunee.com</a></div> </body>
配置风格样式
本人喜欢简洁风格,故而删除了大部分的边框和背景,并采用了灰色模板
<style> #graph_panel { height: 100%; } .tabs-panels .panel-body{ border-left: solid 1px #DDD; border-right: solid 1px #DDD; } .tree-node { height: 20px; } .q-panel { padding-top: 40px; position: relative; } .q-toolbar { padding: 5px; } .q-panel .q-toolbar { position: absolute; top: 0px; height: 40px; width: 100%; z-index: 1; } .q-panel .q-content { height: 100%; background-color: #FFF; overflow: hidden; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; position: relative; } .q-canvas { height: 100%; } #canvas_panel { position: relative; overflow: hidden; } #canvas { width: 100%; background-color: #FFF; outline: none; overflow: hidden; } #toolbar { background-color: #F8F8F8; border-bottom: solid 1px #DDD; padding: 5px; } #toolbar .btn, #toolbar .btn-group { margin-right: 5px; } #toolbar .btn-group .btn { margin-right: 0px; } #toolbox { position: absolute; top: 0px; background-color: #F8F8F8; padding: 5px; } #toolbox > img, #toolbox > button { display: block; padding: 8px 7px 0 7px; border-radius: 0px; } .layout-split-west { border-right: 5px solid rgba(255, 255, 255, 0); } #center_panel { border: none; } .panel { -webkit-box-shadow: none; box-shadow: none; } #footer { text-align: center; padding: 8px; border-top: solid 1px #DDD; background-color: #EEE; } .node_icon{ background: url('images/node_icon.png') no-repeat; background-size: 18px; background-position:center; } .edge_icon{ background: url('images/edge_icon.png') no-repeat; background-size: 18px; background-position:center; } </style>
界面效果
添加数据
这里采用了模拟数据,使用json格式,数据如下:
节点数据包含编号、名称以及父节点编号等属性,而连线数据则需要起始结束节点的编号
{ "nodes": [ { "id": 1, "name": "001" }, { "id": 2, "name": "R1", "parent": 1 }, ... ], "relations": [ { "from": 1, "to": 2 }, { "from": 1, "to": 3 }, ... ] }
加载数据
根据json数据,创建对应的图元数据和树节点数据
function initDatas(){ Q.loadJSON("testData.json", function(json){ var topoNodes = json.nodes; var relations = json.relations; initTopology(topoNodes,relations); graph.callLater(function(){ var layouter = new Q.TreeLayouter(graph); layouter.doLayout(); graph.moveToCenter(); }) var datas = []; var map = {}; graph.graphModel.forEachByBreadthFirst(function(d){ var name = d.name || d.type; var data = {text: name, id: d.id, iconCls: getTreeIcon(d)}; map[d.id] = data; var parent = d.parent; if(!parent){ datas.push(data); return; } parent = map[parent.id]; var children = parent.children; if(!children){ children = parent.children = []; } children.push(data); }); $('#tree').tree({ data: datas }); syncSelectionTreeAndGraph("tree", graph); syncDataTreeAndGraph("tree", graph); }); } function initTopology(topoNodes,topoRelations) { var map = {}; for(var i=0;i<topoNodes.length;i++) { var node = topoNodes[i]; var qNode = new Q.Node(); qNode.name=node.name; qNode.location = new Q.Point(node.x,node.y); graph.graphModel.add(qNode); map[node.id] = qNode; } for(var i=0;i<topoNodes.length;i++) { var node = topoNodes[i]; var parent = node.parent; if(parent){ parent = map[parent]; if(parent){ map[node.id].parent = parent; } } } for(var i=0;i<topoRelations.length;i++) { var relation = topoRelations[i]; var nodeFrom = map[relation.from]; var nodeTo = map[relation.to]; if(nodeFrom && nodeTo){ var edge = graph.createEdge(nodeFrom, nodeTo); edge.info = relation; } } }
到此时,界面已初步呈现了
组件状态同步
然后初始化工具栏,对树图和拓扑图填充数据,最后实现两组件的状态同步,包括选中同步和数据同步
首先数据同步
因为树图上不可编辑,所以这里只需要监听Graph组件图元的变化事件,在增加和删除图元时,分别对Tree组件进行处理
function syncDataTreeAndGraph(treeId, graph){ treeId = "#" + treeId; graph.listChangeDispatcher.addListener(function(evt){ var data = evt.data; switch (evt.kind) { case Q.ListEvent.KIND_ADD : var treeData = {data:[{id: data.id, text: data.name, iconCls: getTreeIcon(data)}]}; $(treeId).tree('append', treeData); break; case Q.ListEvent.KIND_REMOVE : Q.forEach(data, function(node){ var node = $(treeId).tree('find', node.id); if(node){ $(treeId).tree('remove', node.target); } }); break; case Q.ListEvent.KIND_CLEAR : break; } }); }
选中状态同步
需要分别监听Tree的"onSelect"事件,以及graph的selectionChangeDispatcher事件派发器,实现双向同步,有了监听器,一切变得容易
function syncSelectionTreeAndGraph(treeId, graph){ treeId = "#" + treeId; var selectionAjdusting; graph.selectionChangeDispatcher.addListener(function(evt){ if(selectionAjdusting){ return; } selectionAjdusting = true; var selection = []; graph.selectionModel.forEach(function(node){ var node = $(treeId).tree('find', node.id); if(node){ selection.push(node.target); } }); $(treeId).tree('select', selection); selectionAjdusting = false; }); $(treeId).tree({onSelect: function(){ if(selectionAjdusting){ return; } selectionAjdusting = true; var selected = $(treeId).tree("getSelected"); if(selected){ var node = graph.getElement(selected.id); graph.selectionModel.set(node); if(node){ ensureVisible(node); } } selectionAjdusting = false; }}); }
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。