記錄一個利用jquery UI 和jquery jsPlumb插件完成的拖拽連線demo,效果以下:javascript
html及css樣式文件:css
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{ padding:0; margin:0; box-sizing: border-box; } #left{ height:600px; width:200px; border:1px solid #000; float: left; margin-left:100px; padding:0 10px; position:relative; } #main{ height:800px; width:1000px; border:1px solid #000; float: left; margin-left:100px; position:relative; } .item{ background: #ffffff; height:30px; width:178px; border:1px solid #5F9EDF; margin: 5px 0; font: 16px/30px "微軟雅黑"; text-align: center; border-radius: 15px; cursor: pointer; } .theGrey{ background:#ccc!important; } </style> </head> <body> <div id="left"> <div class="item" data-index="1">cf_訓練_data</div> <div class="item" data-index="2">cf_sql取購買行爲</div> <div class="item" data-index="3">協同過濾etrec_1</div> <div class="item" data-index="4">sql整理輸出格式</div> <div class="item" data-index="5">json-1</div> <div class="item" data-index="6">json-2</div> <div class="item" data-index="7">sql去重-1</div> <div class="item" data-index="8">sql去重-2</div> <div class="item" data-index="9">全表統計-1</div> <div class="item" data-index="10">全表統計-2</div> <div class="item" data-index="11">cf_結果_data</div> <div class="item" data-index="12">過濾與映射-1</div> </div> <div id="main"> </div> <button onclick="save()">保存</button> <br /> <br /> <input type="checkbox" id="onOff"/><label for="onOff">不可重複拖拽</label>
</body>
</html>
用到的js文件:html
<script src="http://www.jq22.com/jquery/jquery-1.10.2.js"></script>// <script src="http://www.jq22.com/jquery/jquery-ui-1.11.0.js"></script> <script src="js/jquery.jsPlumb-1.6.2-min.js" type="text/javascript" charset="utf-8"></script>
jquery實現拖拽、克隆、鏈接:java
<script type="text/javascript"> function deepCopy(p, c) { //克隆對象 var c = c || {}; for (var i in p) { if(! p.hasOwnProperty(i)){ continue; } if (typeof p[i] === 'object') { c[i] = (p[i].constructor === Array) ? [] : {}; deepCopy(p[i], c[i]); } else { c[i] = p[i]; } } return c; } function save() { var connects = [];//存儲連線的數組 var mainArr=[];//存儲元素的數組 $.each(jsPlumb.getAllConnections(), function (idx, connection) { connects.push({ ConnectionId: connection.id, start:$(connection.source).attr("data-index"), end:$(connection.target).attr("data-index"), originSign:$(connection.source).attr("data-sign"), destinationSign:$(connection.target).attr("data-sign"), }); }); $("#main .item").each(function(){ mainArr.push({ offset:$(this).position(), text:$(this).text(), index:$(this).attr("data-index"), sign:$(this).attr("data-sign"), }); }); console.log(connects); console.log(mainArr); sessionStorage.setItem("flowsheet",JSON.stringify({"connects":connects,"mainArr":mainArr})); } jsPlumb.ready(function() {//必定要加,不然你妹的老報錯 var connectorPaintStyle = {//基本鏈接線樣式 lineWidth: 1,//鏈接線寬度 strokeStyle: "#989898",//鏈接線顏色 joinstyle: "round", outlineColor: "white", outlineWidth: 0 }; var connectorHoverStyle = {// 鼠標懸浮在鏈接線上的樣式 lineWidth: 4, strokeStyle: "#989898", outlineColor: "white", outlineWidth: 0, }; var origin = {//起點 endpoint: ["Dot", { radius: 8 }], //端點的形狀 connectorStyle: connectorPaintStyle,//鏈接線的顏色,大小樣式 connectorHoverStyle: connectorHoverStyle, paintStyle: { strokeStyle: "#989898", fillStyle: "transparent", radius: 4, lineWidth: 1 }, //端點的顏色樣式 // anchor: "AutoDefault", isSource: true, //是否能夠拖動(做爲連線起點) connector: ["Bezier", { stub: [40, 60], gap: 10, cornerRadius: 5, alwaysRespectStubs: true }], //鏈接線的樣式種類有[Bezier],[Flowchart],[StateMachine ],[Straight ] isTarget: false, //是否能夠放置(連線終點) maxConnections:-1, // 設置鏈接點最多能夠鏈接幾條線,-1表示無限大 connectorOverlays: [["Arrow", { width: 10, length: 10, location: 1 }]] }; var destination = {//終點 endpoint: ["Dot", { radius: 5 }], //端點的形狀 connectorStyle: connectorPaintStyle,//鏈接線的顏色,大小樣式 connectorHoverStyle: connectorHoverStyle, paintStyle: {fillStyle: "#989898",}, //端點的顏色樣式 isSource: false, //是否能夠拖動(做爲連線起點) connector: ["Bezier", { stub: [40, 60], gap: 10, cornerRadius: 5, alwaysRespectStubs: true }], //鏈接線的樣式種類有[Bezier],[Flowchart],[StateMachine ],[Straight ] isTarget:true, //是否能夠放置(連線終點) maxConnections:-1, // 設置鏈接點最多能夠鏈接幾條線,-1表示無限大 connectorOverlays: [["Arrow", { width: 10, length: 10, location: 1 }]] }; $("#left").children().draggable({ helper: "clone", scope: "ss", }); var elementSign=0;//標誌元素惟一性 $("#main").droppable({ scope: "ss", drop: function (event, ui) {//在目標(target)容器上釋放鼠標 ,ui.draggable[0]爲開始拖拽的元素 elementSign++; var left = parseInt(ui.offset.left - $(this).offset().left); var top = parseInt(ui.offset.top - $(this).offset().top); var ele=$('<div class="item" data-sign="'+elementSign+'" data-index="'+$(ui.draggable[0]).attr("data-index")+'" >' + $(ui.helper).html() + '</div>');//$(ui.helper).html()取第一個JQ元素的文本 ele.css({"left":left,"top":top,position: "absolute",margin:0}); $(this).append(ele); jsPlumb.addEndpoint(ele, { anchors: "BottomCenter" }, origin);//起點 jsPlumb.addEndpoint(ele, { anchors: "TopCenter" }, destination);//終點 jsPlumb.draggable(ele,{containment: "parent"});//端點能夠拖動設置,而且將端點限制在父級內 $(ele).draggable({ //設置拖動到main區域中的元素還能夠拖拽 containment: "parent" //限制拖動不超過父級邊框 }); //禁止重複拖拽 if($("#onOff").prop("checked")){ $(ui.draggable[0]).addClass("theGrey").draggable("disable"); // 禁止其拖動功能 } } }); $("#main").on("mouseenter", ".item", function () { var ele=$('<span>X</span>'); ele.css({position:"absolute",left:"160px",top:"-15px"}); $(this).append(ele); }).on("mouseleave", ".item", function () { $("span").remove(); }).on("click", "span",function () { if (confirm("肯定刪除嗎?")) { jsPlumb.removeAllEndpoints($(this).parent().attr("id")); var index=$(this).parent().attr("data-index"); $(this).parent().remove(); $("#left .item").each(function(){ if($(this).attr("data-index")==index){ $(this).removeClass("theGrey").draggable("enable"); // 激活其拖動功能 } }); } }); jsPlumb.bind("click", function (conn, originalEvent) {//點擊線段刪除 if (confirm("肯定刪除嗎?")) jsPlumb.detach(conn); }); jsPlumb.bind("connection", function (connInfo, originalEvent) {//本身連本身管控 if (connInfo.connection.sourceId == connInfo.connection.targetId) { alert("不能鏈接本身!"); setTimeout(function(){ jsPlumb.detach(connInfo.connection); },100); } }); if(sessionStorage.getItem("flowsheet")){//判斷是否有保存過 var flowsheet=JSON.parse(sessionStorage.getItem("flowsheet")); var mainHTML="" for(var i=0;i<flowsheet.mainArr.length;i++){ if(elementSign<flowsheet.mainArr[i].sign){//若是已經保存過,即將標記更新 elementSign=flowsheet.mainArr[i].sign; } mainHTML+='<div class="item" data-sign="'+flowsheet.mainArr[i].sign+'" data-index="'+flowsheet.mainArr[i].index+'" style="left:'+flowsheet.mainArr[i].offset.left+'px;top:'+flowsheet.mainArr[i].offset.top+'px;position:absolute;margin:0" >' + flowsheet.mainArr[i].text + '</div>'; }; $("#main").append(mainHTML); $("#main .item").each(function(){ jsPlumb.addEndpoint(this, { anchors: "BottomCenter" }, deepCopy(origin, {uuid:$(this).attr("data-sign")+"origin"}));//起點 jsPlumb.addEndpoint(this, { anchors: "TopCenter" }, deepCopy(destination, {uuid:$(this).attr("data-sign")+"destination"}));//終點 jsPlumb.draggable(this,{containment: "parent"});//端點能夠拖動設置,而且將端點限制在父級內 $(this).draggable({ //設置拖動到main區域中的元素還能夠拖拽 containment: "parent" //限制拖動不超過父級邊框 }); }); //固定連線 for(var i=0;i<flowsheet.connects.length;i++){ jsPlumb.connect({uuids:[flowsheet.connects[i].originSign+"origin",flowsheet.connects[i].destinationSign+"destination"]}); }; } }); </script>