记录一个利用jquery UI 和jquery jsPlumb插件完成的拖拽连线demo,效果如下:
html及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文件:
<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实现拖拽、克隆、连接:
<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>