利用jQuery-UI和jsPlumb实现拖拽连接模型

Posted ysx_小鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用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">&times;</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">&times;</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>








以上是关于利用jQuery-UI和jsPlumb实现拖拽连接模型的主要内容,如果未能解决你的问题,请参考以下文章

jsPlumb开发入门教程(实现html5拖拽连线)

利用插件(jQuery-ui.js)实现表格行的拖拽排序

使用jsPlumb插件实现动态连线功能

jquery-ui拖拽对齐线位置不对的操作

jquery-ui sortable 使用实例

jsplumbWithVue实现流程编排