利用jQuery-UI和jsPlumb实现拖拽连接模型
简介
之前公司需要做一个自定义数据搜索模型的功能,大体是这样的:左边显示的每一个模型对应于数据库中的一个表,把左边的模型拉入右边的容器内,会显示这个模型(也就是表)下的列信息,然后通过连线确定各独立的模型之间的关系(对应于数据库中的多表链接查询),然后保存数据到后台执行。由于保存模型就是对容器中的模型的一个解析,这里就不做展示了,这个demo主要处理模型的展示以及如何链接。
话不多说,先上图:
需要用到的东西
这个功能主要用到的是jQuery UI的拖拽功能以及jsPlumb连线插件。
jsPlumb插件是一个js插件,其主要功能是对网页上任意两个元素,都可以通过为他们添加endPoint节点来实现在这两个元素之间建立一个连接(就是画一条线)。这个插件有收费版、和社区版,收费版可能功能更强大,在这里用的是社区版,只要能处理我们的需求就可以了。用这个插件只需要jsPlumb-x.x.x.js即可,官网地址:https://jsplumbtoolkit.com/
下面介绍我的demo:
完整demo下载地址:http://download.csdn.net/download/csdn_xuexiaoqiang/9784381
在这个demo里,样式和HTML我写在了demo.html,js我写在了demo.js,用到的示例数据我写在了metadata.js,是一个数组。其他主要的东西还有:jquery-2.1.4.min.js、jquery-ui.min.js、jquery-ui.custom.min.css、jsPlumb-2.2.8.js剩下的bootstrap相关的都是为了页面美观我才加进去的,和核心功能无关。
至于jsPlumb的用法,在demo.js中我都有标记。
数据处理的例子
这是我之前做的一个模块,里面有怎么保存模型数据的方法,仅供参考。
jsp页面,页面本身没什么,而且是镶嵌在框架里面的,主要是页面下面的js,有主要的处理逻辑
1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 3 <% 4 String path = request.getContextPath(); 5 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path; 6 %> 7 <c:set var="ctx" value="<%=basePath%>"></c:set> 8 <html> 9 <head> 10 <title>模型定义</title> 11 <link rel="stylesheet" href="${ctx }/bootstrap/css/bootstrap.min.css" /> 12 <link rel="stylesheet" 13 href="${ctx }/bootstrap/css/jquery-ui.custom.min.css" /> 14 <link rel="stylesheet" href="${ctx }/zTree/css/zTreeStyle/zTreeStyle.css "> 15 <script type="text/javascript" src="${ctx }/js/jquery-2.1.4.min.js"></script> 16 <script type="text/javascript" src="${ctx }/js/jquery-ui.min.js"></script> 17 <script type="text/javascript" src="${ctx }/js/jsPlumb-2.2.8.js"></script> 18 <script src="${ctx }/bootstrap/js/bootstrap.min.js"></script> 19 <script src="${ctx }/bootstrap/js/bootbox.js"></script> 20 <script src="${ctx }/zTree/js/jquery.ztree.core.js"></script> 21 <script src="${ctx }/zTree/js/jquery.ztree.exedit.js"></script> 22 <style type="text/css"> 23 .navRight li a { 24 font-size: 12px!important; 25 } 26 .footer { 27 height: auto; 28 margin-top: 10px; 29 text-align: center; 30 width: auto; 31 font: 12px/1.5 tahoma,arial,simsun,sans-serif; 32 padding-top: 0; 33 } 34 .userHandle a,span { 35 box-sizing: content-box; 36 } 37 .userHandle { 38 box-sizing: content-box; 39 } 40 body { 41 background-color: #cbdde4; 42 } 43 /*ztree*/ 44 .ztree li span.button.noline_open { 45 background: url(${ctx }/zTree/images/tree_close.png) no-repeat!important; 46 width: 10px!important; 47 height: 10px!important; 48 vertical-align: middle!important; 49 margin: 9px 9px 9px 0px!important; 50 } 51 .ztree li span.button.noline_close { 52 background: url(${ctx }/zTree/images/tree_open.png) no-repeat!important; 53 width: 10px!important; 54 height: 10px!important; 55 vertical-align: middle!important; 56 margin: 9px 9px 9px 0px!important; 57 } 58 .ztree li a span.button.ico_open { 59 background: url(${ctx }/zTree/images/tree_level2.png) no-repeat!important; 60 } 61 .ztree li a span.button.ico_close { 62 background: url(${ctx }/zTree/images/tree_level2.png) no-repeat!important; 63 } 64 .ztree>li>a>span.button.ico_open { 65 background: url(${ctx }/zTree/images/tree_level1.png) no-repeat!important; 66 } 67 .ztree>li>a>span.button.ico_close { 68 background: url(${ctx }/zTree/images/tree_level1.png) no-repeat!important; 69 } 70 .ztree li a span.button.ico_docu { 71 background: url(${ctx }/zTree/images/tree_level3.png) no-repeat!important; 72 } 73 .ztree *{ 74 font-family: SimHei!important; 75 font-size: 18px!important; 76 color: #666666!important; 77 } 78 .ztree li a { 79 margin-bottom: 5px!important; 80 height: 28px!important; 81 line-height: 28px!important; 82 } 83 .ztree li a.curSelectedNode { 84 border: 1px solid #2983cf!important; 85 background: #d5ecf9!important; 86 } 87 .ztree li span.button { 88 height: 28px!important; 89 width: 20px!important; 90 line-height: 28px!important; 91 text-align: center; 92 vertical-align: middle!important; 93 } 94 .ztree>li{ 95 margin-bottom: 4px!important; 96 } 97 .ztree ul { 98 padding-left: 28px!important; 99 } 100 .ztree li span.button.chk { 101 width: 13px!important; 102 height: 13px!important; 103 } 104 .ztree li span{ 105 z-index: 1; 106 } 107 /*ztree-end*/ 108 109 #container { 110 min-height: 800px; 111 position: relative; 112 border: 1px solid #666666; 113 background-color: #ffffff; 114 border-radius: 5px; 115 z-index: 0; 116 overflow: auto; 117 } 118 #container .model table { 119 border: 1px solid #ddd; 120 border-radius: 5px; 121 margin-bottom: 0; 122 } 123 #container .model table thead th{ 124 background-color: #3E7E9C; 125 text-align: center; 126 background-image: none; 127 } 128 #container .model table tbody{ 129 background-color: #CBEAE1; 130 } 131 .jtk-endpoint, .endpointTargetLabel, .endpointSourceLabel { 132 cursor: pointer; 133 } 134 </style> 135 </head> 136 <body> 137 <div class="container-fluid"> 138 <div class="row"> 139 <div class="col-xs-2" style="min-height: 800px;background-color: #84ACB3;border-radius:5px;padding-top: 12px;"> 140 <div class="content_wrap" style="width: 100%;"> 141 <div class="zTreeDemoBackground left" style="width: 100%;"> 142 <ul id="leftMenu" class="ztree" style="height: 800px;overflow: auto;width: 100%;"></ul> 143 </div> 144 </div> 145 </div> 146 <div class="col-xs-10"> 147 <div id="container"></div> 148 </div> 149 </div> 150 </div> 151 <div style="padding-top: 10px;"> 152 模型名称:<input type="text" value='' id="modelName" style="height: 32px;margin-right:5px;"/> 153 模型描述:<input type="text" value='' id="modelDesc" style="height: 32px;margin-right:5px;"/> 154 <button class="btn btn-white btn-info" type="button" onclick="save()" style="display: inline-block;"> 155 <i class="ace-icon fa fa-check bigger-120 blue"></i> 保存</button> 156 </div> 157 <div id="myModal" class="modal fade" aria-labelledby="myModalLabel" aria-hidden="true"> 158 <div class="modal-dialog"> 159 <div class="modal-content"> 160 <div class="modal-header"> 161 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> 162 <h4 class="modal-title" id="myModalLabel">请选择模型联系条件</h4> 163 </div> 164 <div class="modal-body"> 165 连线类型:<select id="twoWay"> 166 <option value="false">单向</option> 167 <option value="true">双向</option> 168 </select> 169 条件:<select id="select_sourceList"> 170 </select> 171 <select id="select_comparison" > 172 <option value="=" selected="selected">=</option> 173 </select> 174 <select id="select_targetList"> 175 </select> 176 </div> 177 <div class="modal-footer"> 178 <button id="submit_label" type="button" class="btn btn-primary" data-dismiss="modal">确定</button> 179 </div> 180 </div> 181 </div> 182 </div> 183 184 <!-- javascript --> 185 <script type="text/javascript" src="${ctx }/js/model/addModel.js"></script> 186 187 <script type="text/javascript"> 188 $(document).ready(function(){ 189 190 getDataSet("${ctx }/ajaxGetDataSet.do"); 191 192 //监听新的连接 193 instance.bind("connection", function (connInfo, originalEvent) { 194 init(connInfo.connection); 195 }); 196 // listen for clicks on connections, and offer to delete connections on click. 197 instance.bind("dblclick", function (conn, originalEvent) { 198 if (confirm("要删除从 " + conn.source.getElementsByTagName("th")[0].innerHTML 199 + " 到 " + conn.target.getElementsByTagName("th")[0].innerHTML + " 的连接么?")){ 200 instance.detach(conn); 201 } 202 }); 203 }); 204 function save(){ 205 //下面两个只是到后台执行相关业务逻辑的链接,在后面的js中会用到,所以弄了一个变量,传到saveToDb方法中 206 var ajaxToVerifySql = "这里只是一个异步保存并执行所产生的SQL语句的链接"; 207 var ajaxToSaveModel = "这个是保存模型相关数据的链接"; 208 //保存到数据库 209 saveToDb(ajaxToVerifySql,ajaxToSaveModel); 210 } 211 </script> 212 </body> 213 </html>
下面就是页面引用的addModel.js,整个js都在这里:
1 /** 2 * 添加自定义模型 3 */ 4 var model_counter=0; 5 var dataSet; 6 var mData; 7 var treeObj; 8 9 //初始化一个jsPlumb实例 10 var instance = jsPlumb.getInstance({ 11 DragOptions: { cursor: "pointer", zIndex: 2000 }, 12 ConnectionOverlays: [ 13 [ "Arrow", { 14 location: 1, 15 visible:true, 16 width:11, 17 length:11, 18 direction:1, 19 id:"arrow_forwards" 20 } ], 21 [ "Arrow", { 22 location: 0, 23 visible:true, 24 width:11, 25 length:11, 26 direction:-1, 27 id:"arrow_backwards" 28 } ], 29 [ "Label", { 30 location: 0.5, 31 id: "label", 32 cssClass: "aLabel" 33 }] 34 ], 35 Container: "container" 36 }); 37 instance.importDefaults({ 38 ConnectionsDetachable:true, 39 ReattachConnections:true 40 }); 41 42 //创建模型 43 function CreateModel(ui, selector) { 44 //添加html模型 45 var modelid = $(ui.draggable).attr("id").split("_span")[0]; 46 model_counter++; 47 var id = modelid + "_model_" + model_counter; 48 var type = treeObj.getNodeByTId(modelid).id; 49 var add_html = getModelTable(ui, type); 50 $(selector).append('<div class="model" id="' 51 + id +'" modelType="' + type 52 + '" >'+add_html+'</div>'); 53 var left = parseInt(ui.offset.left - $(selector).offset().left); 54 var top = parseInt(ui.offset.top - $(selector).offset().top); 55 $("#"+id).css("position", "absolute").css("left", left).css("top", top); 56 //添加连接点 57 instance.addEndpoint(id, { anchors: "RightMiddle" }, hollowCircle); 58 instance.addEndpoint(id, { anchors: "LeftMiddle" }, hollowCircle); 59 instance.addEndpoint(id, { anchors: "TopCenter" }, hollowCircle); 60 instance.addEndpoint(id, { anchors: "BottomCenter" }, hollowCircle); 61 //instance.draggable(id); 62 //注册实体可draggable 63 $("#" + id).draggable({ 64 containment: "parent", 65 drag: function (event, ui) { 66 instance.repaintEverything(); 67 }, 68 stop: function () { 69 instance.repaintEverything(); 70 } 71 }); 72 return id; 73 } 74 //基本连接线样式 75 var connectorPaintStyle = { 76 stroke: "#84ACB3", 77 strokeWidth: 2 78 }; 79 //鼠标悬浮在连接线上的样式 80 var connectorHoverStyle = { 81 strokeWidth: 3, 82 stroke: "#84ACB3", 83 outlineWidth: 2, 84 outlineStroke: "#84ACB3" 85 }; 86 //端点样式设置 87 var hollowCircle = { 88 endpoint: ["Dot",{ cssClass: "endpointcssClass"}], //端点形状 89 connectorStyle: connectorPaintStyle, 90 // connectorHoverStyle: connectorHoverStyle, 91 paintStyle: { 92 fill: "#84ACB3", 93 radius: 6 94 }, //端点的颜色样式 95 isSource: true, //是否可拖动(作为连接线起点) 96 connector: ["Flowchart", {stub: 30, gap: 0, coenerRadius: 0, alwaysRespectStubs: true, midpoint: 0.5 }], 97 isTarget: true, //是否可以放置(连接终点) 98 maxConnections: -1 99 }; 100 //获得对应模型名称的模型 101 function getModelTable(ui, type) 102 { 103 var thead = $(ui.helper).html(); 104 var list_tr = ""; 105 for(var i = 0; i < dataSet.length;i++){ 106 var data = dataSet[i]; 107 if(data.key == type){ 108 for(var y = 0;y < data.content.length;y++){ 109 var col = data.content[y]; 110 list_tr += '<tr><td>' + '<input type="checkbox" value="' + col.field + '">' 111 + col.label 112 + '</td><td></td></tr>'; 113 } 114 } 115 } 116 var table = '<table class="table">' 117 + '<thead><th>' +thead+ '</th><th><a href="javascript:void(0)" onclick="removeElement(this);" style="color:black;">X</a></th></thead>' 118 + '<tbody>' 119 + list_tr 120 + '</tbody>' 121 + '</table>'; 122 return table; 123 } 124 //设置连接Label的label 125 function init(conn) 126 { 127 var label_text; 128 $("#select_sourceList").empty(); 129 $("#select_targetList").empty(); 130 var sourceName = $("#" + conn.sourceId).attr("modelType"); 131 var targetName = $("#" + conn.targetId).attr("modelType"); 132 for(var i = 0; i < dataSet.length; i++){ 133 if(dataSet[i].key == sourceName){ 134 for(var y = 0;y < dataSet[i].content.length; y++){ 135 var text = '<option value="'+dataSet[i].value + '.' + dataSet[i].content[y].label +'">'+dataSet[i].value + '.' + dataSet[i].content[y].label + '</option>'; 136 $("#select_sourceList").append(text); 137 } 138 }else if(dataSet[i].key == targetName){ 139 for(var y = 0;y < dataSet[i].content.length; y++){ 140 var text = '<option value="'+dataSet[i].value + '.' + dataSet[i].content[y].label +'">' +dataSet[i].value + '.' + dataSet[i].content[y].label + '</option>'; 141 $("#select_targetList").append(text); 142 } 143 } 144 } 145 $("#submit_label").unbind("click"); 146 $("#submit_label").on("click",function(){ 147 setlabel(conn); 148 }); 149 $("#myModal").modal(); 150 //connection.getOverlay("label").setLabel("点击此处添加模型关联条件"); 151 } 152 //setlabel 153 function setlabel(conn) 154 { 155 conn.getOverlay("label").setLabel($("#select_sourceList").val() 156 + ' ' 157 + $("#select_comparison").val() 158 + ' ' 159 + $("#select_targetList").val()); 160 if($("#twoWay").val()=="true"){ 161 conn.setParameter("twoWay",true); 162 }else{ 163 conn.setParameter("twoWay",false); 164 conn.hideOverlay("arrow_backwards"); 165 } 166 } 167 //删除节点 168 function removeElement(obj) 169 { 170 var element = $(obj).parents(".model"); 171 if(confirm("确定删除该模型?")) 172 instance.remove(element); 173 } 174 //获取原始数据 175 function getDataSet(uri) 176 { 177 $.ajax({ 178 type: "post", 179 url: uri, 180 success: function(data){ 181 dataSet = data.dSet; 182 mData = data.mData; 183 getLeftMenuList(dataSet); 184 }, 185 error:function(data){ 186 myalert("内部错误"); 187 } 188 }); 189 } 190 //设置左边模型列表 191 function getLeftMenuList(dataList) 192 { 193 var setting = { 194 data: { 195 simpleData: { 196 enable: true, 197 idKey: "id", 198 pIdKey: "pId", 199 rootPId: "root" 200 } 201 }, 202 callback: { 203 onNodeCreated: zTreeOnNodeCreated 204 }, 205 view : { 206 showLine: false 207 } 208 }; 209 //初始化一级节点 210 var zNodes = [ 211 {id:"dns",pId:"root",name:"DNS",isParent:true}, 212 {id:"vpn",pId:"root",name:"VPN",isParent:true}, 213 {id:"url",pId:"root",name:"URL",isParent:true}, 214 {id:"terminal",pId:"root",name:"终端ID",isParent:true}, 215 {id:"remoteControl",pId:"root",name:"远程控制",isParent:true}, 216 {id:"netDisk",pId:"root",name:"网盘",isParent:true}, 217 {id:"mail",pId:"root",name:"邮箱",isParent:true}, 218 {id:"ip",pId:"root",name:"IP地址",isParent:true}, 219 {id:"instantMessage",pId:"root",name:"即时通讯",isParent:true}, 220 {id:"fiveTule",pId:"root",name:"五元组",isParent:true}, 221 {id:"defence",pId:"root",name:"突防工具",isParent:true}, 222 {id:"cookie",pId:"root",name:"COOKIE",isParent:true}, 223 {id:"adsl",pId:"root",name:"Radius",isParent:true}, 224 {id:"accountPassword",pId:"root",name:"账号口令",isParent:true}, 225 {id:"newTable",pId:"root",name:"自定义",isParent:true} 226 ]; 227 228 for(var i=0; i < dataList.length; i++){ 229 var node = new Object(); 230 if((dataList[i].oriName != "")&&(dataList[i].oriName != null)){ 231 node.pId = dataList[i].oriName; 232 }else{ 233 node.pId = "newTable"; 234 } 235 node.id = dataList[i].key; 236 node.name = dataList[i].value; 237 zNodes.push(node); 238 } 239 //初始化 240 treeObj = $.fn.zTree.init($("#leftMenu"), setting, zNodes); 241 } 242 //拖拽设置 243 function zTreeOnNodeCreated() 244 { 245 //左边区域的draggable事件 246 $("#leftMenu .node_name").draggable({ 247 helper: "clone", 248 scope: "plant" 249 }); 250 //中间拖拽去的drop事件 251 $("#container").droppable({ 252 scope: "plant", 253 drop: function (event, ui) { 254 //创建模型到拖拽区 255 CreateModel(ui, $(this)); 256 } 257 }); 258 } 259 //保存模型 260 function saveToDb(ajaxToVerifySql,ajaxToSaveModel) 261 { 262 var flag = true; 263 var ary = new Array(); 264 $("input[type=checkbox]:checked").each(function(){ 265 var val = this.value.toLocaleLowerCase(); 266 ary.push(val); 267 }); 268 flag = mm(ary); 269 if(!flag){ 270 if(!checkOn()){ 271 var modelName = $("#modelName").val(); 272 var modelDesc = $("#modelDesc").val(); 273 var result = exportData(); 274 var result_sql = exportSQL(result); 275 276 if(modelName.length == 0){ 277 myalert("请输入模型名称"); 278 }else if(modelDesc.length == 0){ 279 myalert("请输入模型描述"); 280 }else { 281 var items = new Array(); // 保存model涉及到的表名称 282 var jItems = new Array(); // 保存表以及对应的列名称 283 var kItems = new Array(); // 保存表以及对应的列名称 284 285 var nodes = result.nodes; 286 for(var property in nodes){ 287 var dataSetJSON = nodes[property].data; 288 items.push(dataSetJSON.key+ "!" + nodes[property].name); 289 } 290 291 uniqueArray(items); 292 for(var i=0;i<items.length;i++){ 293 var alias = items[i].split("!")[1]; 294 var tableName = items[i].split("!")[0]; 295 for(var j=0;j<mData.length;j++){ 296 if(tableName == mData[j]['tableName']){ 297 mData[j]["alias"] = alias; 298 jItems.push(JSON.stringify(mData[j])); 299 break; 300 } 301 } 302 } 303 for(var i=0;i<jItems.length;i++){ 304 kItems.push(JSON.parse(jItems[i])); 305 } 306 307 var submitData = {"modelName":modelName,"modelDesc":modelDesc,"modelJson":JSON.stringify(result),"modelSql":result_sql,"modelTable":JSON.stringify(kItems)}; 308 var sqlData = {"modelSql":result_sql}; 309 $.ajax({ 310 type:"post", 311 url:ajaxToVerifySql, 312 data:sqlData, 313 success:function(data){ 314 if(data == "success"){ 315 $.ajax({ 316 type:"post", 317 url:ajaxToSaveModel, 318 data:submitData, 319 success:function(data){ 320 if(data.status == "success"){ 321 myalert("保存成功"); 322 }else{ 323 myalert("保存失败"); 324 } 325 }, 326 error:function(data){ 327 myalert("保存失败"); 328 } 329 }); 330 }else{ 331 myalert("请检查模型连线是否正确以及是否有选择模型的列"); 332 } 333 }, 334 error:function(data){ 335 myalert("保存失败"); 336 } 337 }); 338 } 339 }else{ 340 myalert("请选择连接条件"); 341 } 342 }else{ 343 myalert("不能选择重复的列名称"); 344 } 345 } 346 //把模型导出到一个变量中 347 function exportData() 348 { 349 var retStr = '{"nodes":{'; 350 351 if($("#container").children().length > 0){ 352 $("#container .model").each(function(i){ 353 var nodeStr = ""; 354 nodeStr += '"' + $(this).attr("id") + '":{"name":"' + $(this).attr("id") + '"' 355 + ',' + '"left":"' + $(this).css("left") + '"' 356 + ',' + '"top":"' + $(this).css("top") + '"' 357 + ',' + '"type":"' + $(this).attr("modelType") + '"' 358 + ','; 359 var data = new Object(); 360 var key = $(this).attr("modelType"); 361 var value; 362 var content; 363 for(var y = 0;y < dataSet.length; y++){ 364 var ds = dataSet[y]; 365 if(ds.key == key){ 366 value = ds.value; 367 content = ds.content; 368 } 369 } 370 $(this).find("input:checked").each(function(n){ 371 var field = $(this).val(); 372 for(var y = 0;y < content.length; y++){ 373 var col = content[y]; 374 if(col.field == field) 375 col.checked = true; 376 } 377 }); 378 data.value = value; 379 data.key = key; 380 data.content = content; 381 nodeStr += "\"data\":" + JSON.stringify(data) + "}"; 382 if((i+1) < $("#container .model").length) 383 nodeStr += ',' 384 retStr += nodeStr; 385 }); 386 retStr += '},'; 387 //连接 388 var connections = instance.getAllConnections(); 389 if(connections.length > 0){ 390 var lineStr = '"lines":{'; 391 for(var i = 0; i < connections.length; i++){ 392 var sourceId = connections[i].sourceId; 393 var targetId = connections[i].targetId; 394 var label = connections[i].getOverlay("label").label; 395 var twoWay = connections[i].getParameter("twoWay"); 396 var str = '"demo_line_' + i + '":{' 397 + '"from":"' + sourceId + '"' 398 + ',' + '"to":"' + targetId + '"' 399 + ',' + '"label":"' + label + '"' 400 + ',' + '"twoWay":' + twoWay 401 + '}'; 402 if((i+1) < connections.length) 403 str += ','; 404 lineStr += str; 405 } 406 lineStr += '}'; 407 retStr += lineStr; 408 }else{ 409 myalert("请检查模型连线是否正确"); 410 return false; 411 } 412 }else{ 413 myalert("请选择模型"); 414 } 415 retStr += '}'; 416 var retObj = JSON.parse(retStr); 417 return retObj; 418 } 419 //生成SQL 420 function exportSQL(retObj) 421 { 422 var fields = ""; 423 var join = ""; 424 var nodeData = retObj.nodes; 425 var lineData = retObj.lines; 426 var num = 0; 427 for(var k in lineData){ 428 var lf = lineData[k].from; 429 var lt = lineData[k].to; 430 var ll = lineData[k].label; 431 var twoWay = lineData[k].twoWay; 432 var f_node = nodeData[lf]; 433 var t_node = nodeData[lt]; 434 435 var f_d = f_node.data; 436 var f_node_name = f_node.name; 437 var t_d = t_node.data; 438 var t_node_name = t_node.name; 439 440 var from_table_name = f_d.value; 441 var from_table = f_d.key; 442 var to_table_name = t_d.value; 443 var to_table = t_d.key; 444 445 for(var i=0; i<f_d.content.length; i++){ 446 var f_field = f_d.content[i]; 447 if(f_field.checked){ 448 var fld = f_node_name+"."+f_field.field + " as " + "A" + num++ +"_" + f_field.field; 449 if(fields.indexOf(fld)<0){ 450 fields+=fld + ","; 451 } 452 } 453 } 454 455 for(var i=0; i<t_d.content.length; i++){ 456 var t_field = t_d.content[i]; 457 if(t_field.checked){ 458 var fld = t_node_name+"."+t_field.field + " as " + "B" + num++ +"_" + t_field.field; 459 if(fields.indexOf(fld)<0){ 460 fields+=fld+","; 461 } 462 } 463 } 464 465 var j_array = ll.split("="); 466 var j_from_table_name = $.trim(j_array[0].split(".")[0]); 467 var j_from_table_filed = $.trim(j_array[0].split(".")[1]); 468 var j_to_table_name = $.trim(j_array[1].split(".")[0]); 469 var j_to_table_filed = $.trim(j_array[1].split(".")[1]); 470 471 j_from_table_name = j_from_table_name.replace(from_table_name,f_node_name); 472 j_from_table_filed = getFieldByLabel(f_d.content,j_from_table_filed); 473 j_to_table_name = j_to_table_name.replace(to_table_name,t_node_name); 474 j_to_table_filed = getFieldByLabel(t_d.content,j_to_table_filed); 475 var on = j_from_table_name + "." + j_from_table_filed + "=" + j_to_table_name + "." + j_to_table_filed; 476 if(twoWay){ 477 if("" == join) 478 join += from_table + " " + f_node_name + " inner join " +to_table+ " " + t_node_name + " on "+on; 479 else 480 join += " inner join " + to_table + " " + t_node_name + " on " +on; 481 }else{ 482 if("" == join) 483 join += from_table+" " + f_node_name + " left join "+to_table+ " " + t_node_name+" on "+on+" "; 484 else 485 join += " left join "+to_table+ " " + t_node_name+" on "+on+" "; 486 } 487 } 488 if(fields.length>0) 489 fields = fields.substring(0,fields.length-1); 490 491 return ("select " + fields + " from " +join); 492 } 493 //根据label获取field 494 function getFieldByLabel(obj,label) 495 { 496 var field; 497 for(var i=0; i<obj.length; i++){ 498 if(obj[i].label == label) 499 field = obj[i].field; 500 } 501 return field; 502 } 503 //去除重复数据 504 function uniqueArray(data) 505 { 506 data = data || []; 507 var a = {}; 508 for (var i=0; i<data.length; i++) { 509 var v = data[i]; 510 if (typeof(a[v]) == 'undefined'){ 511 a[v] = 1; 512 } 513 }; 514 data.length=0; 515 for (var i in a){ 516 data[data.length] = i; 517 } 518 return data; 519 } 520 //判断数组元素是否重复,重复返回ture 521 function mm(a) 522 { 523 return /(\x0f[^\x0f]+)\x0f[\s\S]*\1/.test("\x0f"+a.join("\x0f\x0f") +"\x0f"); 524 } 525 //检查连线是否有连接条件 526 function checkOn(){ 527 var flag = false; 528 $(".aLabel").each(function(){ 529 if("" == $(this).text()){ 530 flag = true; 531 return false; 532 } 533 }); 534 return flag; 535 } 536 //弹窗 537 function myalert(info) { 538 bootbox.dialog({ 539 "message" : info, 540 "buttons" : { 541 "success" : { 542 "label" : "OK", 543 "className" : "btn-sm btn-primary" 544 } 545 } 546 }); 547 }
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%><% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path; %><c:set var="ctx" value="<%=basePath%>"></c:set><html><head><title>模型定义</title><link rel="stylesheet" href="${ctx }/bootstrap/css/bootstrap.min.css" /><link rel="stylesheet" href="${ctx }/bootstrap/css/jquery-ui.custom.min.css" /><link rel="stylesheet" href="${ctx }/zTree/css/zTreeStyle/zTreeStyle.css "><script type="text/javascript" src="${ctx }/js/jquery-2.1.4.min.js"></script><script type="text/javascript" src="${ctx }/js/jquery-ui.min.js"></script><script type="text/javascript" src="${ctx }/js/jsPlumb-2.2.8.js"></script><script src="${ctx }/bootstrap/js/bootstrap.min.js"></script><script src="${ctx }/bootstrap/js/bootbox.js"></script><script src="${ctx }/zTree/js/jquery.ztree.core.js"></script><script src="${ctx }/zTree/js/jquery.ztree.exedit.js"></script><style type="text/css"> .navRight li a { font-size: 12px!important; } .footer { height: auto; margin-top: 10px; text-align: center; width: auto; font: 12px/1.5 tahoma,arial,simsun,sans-serif; padding-top: 0; } .userHandle a,span { box-sizing: content-box; } .userHandle { box-sizing: content-box; } body { background-color: #cbdde4; } /*ztree*/ .ztree li span.button.noline_open { background: url(${ctx }/zTree/images/tree_close.png) no-repeat!important; width: 10px!important; height: 10px!important; vertical-align: middle!important; margin: 9px 9px 9px 0px!important; } .ztree li span.button.noline_close { background: url(${ctx }/zTree/images/tree_open.png) no-repeat!important; width: 10px!important; height: 10px!important; vertical-align: middle!important; margin: 9px 9px 9px 0px!important; } .ztree li a span.button.ico_open { background: url(${ctx }/zTree/images/tree_level2.png) no-repeat!important; } .ztree li a span.button.ico_close { background: url(${ctx }/zTree/images/tree_level2.png) no-repeat!important; } .ztree>li>a>span.button.ico_open { background: url(${ctx }/zTree/images/tree_level1.png) no-repeat!important; } .ztree>li>a>span.button.ico_close { background: url(${ctx }/zTree/images/tree_level1.png) no-repeat!important; } .ztree li a span.button.ico_docu { background: url(${ctx }/zTree/images/tree_level3.png) no-repeat!important; } .ztree *{ font-family: SimHei!important; font-size: 18px!important; color: #666666!important; } .ztree li a { margin-bottom: 5px!important; height: 28px!important; line-height: 28px!important; } .ztree li a.curSelectedNode { border: 1px solid #2983cf!important; background: #d5ecf9!important; } .ztree li span.button { height: 28px!important; width: 20px!important; line-height: 28px!important; text-align: center; vertical-align: middle!important; } .ztree>li{ margin-bottom: 4px!important; } .ztree ul { padding-left: 28px!important; } .ztree li span.button.chk { width: 13px!important; height: 13px!important; } .ztree li span{ z-index: 1; } /*ztree-end*/ #container { min-height: 800px; position: relative; border: 1px solid #666666; background-color: #ffffff; border-radius: 5px; z-index: 0; overflow: auto; } #container .model table { border: 1px solid #ddd; border-radius: 5px; margin-bottom: 0; } #container .model table thead th{ background-color: #3E7E9C; text-align: center; background-image: none; } #container .model table tbody{ background-color: #CBEAE1; } .jtk-endpoint, .endpointTargetLabel, .endpointSourceLabel { cursor: pointer; } </style></head><body><div class="container-fluid"><div class="row"><div class="col-xs-2" style="min-height: 800px;background-color: #84ACB3;border-radius:5px;padding-top: 12px;"><div class="content_wrap" style="width: 100%;"><div class="zTreeDemoBackground left" style="width: 100%;"><ul id="leftMenu" class="ztree" style="height: 800px;overflow: auto;width: 100%;"></ul></div></div></div><div class="col-xs-10"><div id="container"></div></div></div></div><div style="padding-top: 10px;"> 模型名称:<input type="text" value='' id="modelName" style="height: 32px;margin-right:5px;"/> 模型描述:<input type="text" value='' id="modelDesc" style="height: 32px;margin-right:5px;"/><button class="btn btn-white btn-info" type="button" onclick="save()" style="display: inline-block;"><i class="ace-icon fa fa-check bigger-120 blue"></i> 保存</button></div><div id="myModal" class="modal fade" aria-labelledby="myModalLabel" aria-hidden="true"><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button><h4 class="modal-title" id="myModalLabel">请选择模型联系条件</h4></div><div class="modal-body"> 连线类型:<select id="twoWay"><option value="false">单向</option><option value="true">双向</option></select> 条件:<select id="select_sourceList"></select><select id="select_comparison" ><option value="=" selected="selected">=</option></select><select id="select_targetList"></select></div><div class="modal-footer"><button id="submit_label" type="button" class="btn btn-primary" data-dismiss="modal">确定</button></div></div></div></div><!-- javascript --><script type="text/javascript" src="${ctx }/js/model/addModel.js"></script><script type="text/javascript"> $(document).ready(function(){ getDataSet("${ctx }/ajaxGetDataSet.do"); //监听新的连接 instance.bind("connection", function (connInfo, originalEvent) { init(connInfo.connection); }); // listen for clicks on connections, and offer to delete connections on click. instance.bind("dblclick", function (conn, originalEvent) { if (confirm("要删除从 " + conn.source.getElementsByTagName("th")[0].innerHTML + " 到 " + conn.target.getElementsByTagName("th")[0].innerHTML + " 的连接么?")){ instance.detach(conn); } }); }); function save(){ //下面两个只是到后台执行相关业务逻辑的链接,在后面的js中会用到,所以弄了一个变量,传到saveToDb方法中 var ajaxToVerifySql = "这里只是一个异步保存并执行所产生的SQL语句的链接"; var ajaxToSaveModel = "这个是保存模型相关数据的链接"; //保存到数据库 saveToDb(ajaxToVerifySql,ajaxToSaveModel); } </script></body></html>