2017年11月06日 16:27:02 Brent-CCNU 閱讀數:10193javascript
<!DOCTYPE html> <html style="overflow: hidden;"> <head> <title>流程設計工具</title> <link href="https://cdn.bootcss.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> <link href="https://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.min.css" rel="stylesheet"> <link rel="stylesheet" type="text/css" href="index.css"> <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/popper.js/1.12.5/umd/popper.min.js"></script> <script src="https://cdn.bootcss.com/bootstrap/4.0.0-beta/js/bootstrap.min.js"></script> <script src="https://cdn.bootcss.com/jqueryui/1.12.1/jquery-ui.min.js"></script> <script src="https://cdn.bootcss.com/d3/4.11.0/d3.min.js"></script> <script src="https://cdn.bootcss.com/d3-transform/1.0.4/d3-transform.min.js"></script> </head> <body> <div class="container-fuild"> <div id="left-wrapper" class="left-wrapper"> <ul class="sidebar-nav"> <li> <a class="open"> <i class="fa fa-folder-o"></i> <span>源/目標</span> </a> <ul> <li class="node" data-id="101"> <a href=""> <i class="fa fa-database"></i> <span>讀數據</span> </a> </li> <li class="node" data-id="102"> <a href=""> <i class="fa fa-database"></i> <span>寫數據</span> </a> </li> </ul> </li> <li> <a> <i class="fa fa-folder-o"></i> <span>數據預處理</span> </a> <ul> <li class="node" data-id="211"> <a href=""> <i class="fa fa-crosshairs" aria-hidden="true"></i> <span>類型轉換</span> </a> </li> <li class="node" data-id="212"> <a href=""> <i class="fa fa-crosshairs" aria-hidden="true"></i> <span>拆分</span> </a> </li> <li class="node" data-id="213"> <a href=""> <i class="fa fa-crosshairs" aria-hidden="true"></i> <span>缺失值填充</span> </a> </li> <li class="node" data-id="214"> <a href=""> <i class="fa fa-crosshairs" aria-hidden="true"></i> <span>歸一化</span> </a> </li> <li class="node" data-id="215"> <a href=""> <i class="fa fa-crosshairs" aria-hidden="true"></i> <span>標準化</span> </a> </li> </ul> </li> <li> <a> <i class="fa fa-folder-o"></i> <span>特徵工程</span> </a> </li> <li> <a> <i class="fa fa-folder-o"></i> <span>機器學習</span> </a> <ul> <li> <a> <i class="fa fa-folder-o"></i> <span>二分類</span> </a> <ul> <li class="node"> <a href=""> <i class="fa fa-circle-o"></i> <span>GBDT二分類</span> </a> </li> <li class="node"> <a href=""> <i class="fa fa-circle-o"></i> <span>PS-SMART</span> </a> </li> <li class="node"> <a href=""> <i class="fa fa-circle-o"></i> <span>線性支持向量機</span> </a> </li> <li class="node"> <a href=""> <i class="fa fa-circle-o"></i> <span>邏輯迴歸二分類</span> </a> </li> </ul> </li> <li> <a> <i class="fa fa-folder-o"></i> <span>聚類</span> </a> <ul> <li class="node"> <a href=""> <i class="fa fa-circle-o"></i> <span>K均值聚類</span> </a> </li> </ul> </li> <li> <a> <i class="fa fa-folder-o"></i> <span>迴歸</span> </a> <ul> <li class="node"> <a href=""> <i class="fa fa-circle-o"></i> <span>GBDT迴歸</span> </a> </li> <li class="node"> <a href=""> <i class="fa fa-circle-o"></i> <span>線性迴歸</span> </a> </li> <li class="node"> <a href=""> <i class="fa fa-circle-o"></i> <span>PS_SMART迴歸</span> </a> </li> <li class="node"> <a href=""> <i class="fa fa-circle-o"></i> <span>PS線性迴歸</span> </a> </li> </ul> </li> </ul> </li> </ul> </div> <div class="middle-wrapper"> <h4>實驗名稱</h4> <div id="idsw-bpmn" class="bpmn" style="position: relative; width: 100%; height: 100%;"> <svg width="100%" height="100%"> <defs> <marker id="arrowhead" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="6" markerHeight="6" orient="auto"> <path d="M 0 0 L 10 5 L 0 10 z" stroke-width="0" stroke="#333"></path> </marker> </defs> </svg> </div> <div style="height: 40px; border-top: solid 1px #e7e7e7; text-align: center; line-height: 40px; position: absolute;bottom: 2px; width: 100%"> <a class="btn btn-link" href="#"><i class="fa fa-play-circle-o" aria-hidden="true"></i> 運行</a> <a class="btn btn-link" href="#"><i class="fa fa-cloud-upload" aria-hidden="true"></i> 部署</a> <a class="btn btn-link" href="#"><i class="fa fa-share-alt" aria-hidden="true"></i> 分享</a> </div> </div> <div class="right-wrapper"> <h4>實驗屬性</h4> </div> </div> </body> <script type="text/javascript" src="index.js"></script> </html>
.left-wrapper { width: 250px; position: absolute; top:0px; bottom: 0px; left: 0px; background: #f0f0f0; border-right: solid 1px #e7e7e7; } .middle-wrapper { position: absolute; top: 0px; bottom: 0px; left: 250px; right: 250px; } .right-wrapper { position: absolute; width: 250px; top: 0px; bottom: 0px; right: 0px; background: #f5f5f5; border-left: solid 1px #e7e7e7; } .sidebar-nav, .sidebar-nav ul { list-style: none; padding: 0px; } .sidebar-nav > li:nth-child(odd), .sidebar-nav ul li:nth-child(odd) { background: #f0f0f0; } .sidebar-nav > li:nth-child(even), .sidebar-nav ul > li:nth-child(even) { background: #fff; } .sidebar-nav li { text-indent: 4px; line-height: 30px; } .sidebar-nav li li { text-indent: 15px; } .sidebar-nav li li li { text-indent: 25px; } .sidebar-nav li a { display: block; text-decoration: none; color: #333; } .sidebar-nav li.active a { background-color: #3e99ff; } .sidebar-nav li a>i+span { margin-left: 3px; } .sidebar-nav li a:hover { text-decoration: none; background: rgba(255, 255, 255, 0.2); } .sidebar-nav li a:active, .sidebar-nav li a:focus { text-decoration: none; } .middle-wrapper h4, .right-wrapper h4 { font-size: 1em; height: 40px; border-bottom: solid 1px #e7e7e7; text-align: center; line-height: 40px } .bpmn .node rect { width:180px; height:36px; cursor: pointer; stroke: #333; stroke-width:2; fill: #fff; } .bpmn .node.active rect, .bpmn .node.active circle { stroke: lightblue; } .bpmn .node circle { stroke: #333; stroke-width: 2px; fill: #fff; cursor: crosshair; } .bpmn .node circle.end { fill: orange; } .bpmn .cable { stroke: #333; stroke-width: 2px; fill: none; }
var workflow = { nodes: {} }; $(function() { var svg = d3.select("svg"); // 綁定拖拽 $('#left-wrapper .node').draggable({ helper: "clone", addClass: false, connectToSortable: "#idsw-bpmn", start: function (e, ui) { ui.helper.addClass("ui-draggable-helper"); }, stop: function (e, ui) { var node = { id: new Date().getTime(), dataId: ui.helper.attr('data-id'), x: ui.position.left - 250, y: ui.position.top - 40, text: ui.helper.text(), inputs: 1, outputs: 2 }; if(node.dataId == 101) { node.inputs = 0; node.outputs = 1; } else if(node.dataId == 102) { node.inputs = 1; node.outputs = 0; } else { node.inputs = 1; node.outputs = 1; } // 計算節點編號 if(workflow.nodes[node.dataId]) { workflow.nodes[node.dataId] += 1; } else { workflow.nodes[node.dataId] = 1; } var g = addNode(svg, node); g.call( d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended) ); g.selectAll("circle.output").call( d3.drag() .on("start", linestarted) .on("drag", linedragged) .on("end", lineended) ); g.selectAll("circle.input") .on("mouseover", function() { if(drawLine) { d3.selectAll("circle.end").classed("end", false); d3.select(this).classed("end", true); } }); } }); }); var activeLine = null; var points = []; var translate = null; var drawLine = false; function linestarted() { drawLine = false; // 當前選中的circle var anchor = d3.select(this); // 當前選中的節點 var node = d3.select(this.parentNode); var rect = node.node().getBoundingClientRect(); var dx = rect.width / (+anchor.attr("output") + 1); var dy = rect.height; var transform = node.attr("transform"); translate = getTranslate(transform); points.push([dx + translate[0], dy + translate[1]]); activeLine = d3.select("svg") .append("path") .attr("class", "cable") .attr("from", node.attr("id")) .attr("start", dx + ", " + dy) .attr("output", d3.select(this).attr("output")) .attr("marker-end", "url(#arrowhead)"); } function linedragged() { drawLine = true; points[1] = [d3.event.x + translate[0], d3.event.y + translate[1]]; activeLine.attr("d", function() { return "M" + points[0][0] + "," + points[0][1] + "C" + points[0][0] + "," + (points[0][1] + points[1][1]) / 2 + " " + points[1][0] + "," + (points[0][1] + points[1][1]) / 2 + " " + points[1][0] + "," + points[1][1]; }); } function lineended(d) { drawLine = false; var anchor = d3.selectAll("circle.end"); if(anchor.empty()) { activeLine.remove(); } else { var pNode = d3.select(anchor.node().parentNode); var input = pNode.node().getBoundingClientRect().width / (+anchor.attr("input") + 1); anchor.classed("end", false); activeLine.attr("to", pNode.attr("id")); activeLine.attr("input", anchor.attr("input")); activeLine.attr("end", input + ", 0"); } activeLine = null; points.length = 0; translate = null; } function getTranslate(transform) { var arr = transform.substring(transform.indexOf("(")+1, transform.indexOf(")")).split(","); return [+arr[0], +arr[1]]; } var dx = 0; var dy = 0; var dragElem = null; function dragstarted() { var transform = d3.select(this).attr("transform"); var translate = getTranslate(transform); dx = d3.event.x - translate[0]; dy = d3.event.y - translate[1]; dragElem = d3.select(this); } function dragged() { dragElem.attr("transform", "translate(" + (d3.event.x - dx) + ", " + (d3.event.y - dy) + ")"); updateCable(dragElem); } function updateCable(elem) { var bound = elem.node().getBoundingClientRect(); var width = bound.width; var height = bound.height; var id = elem.attr("id"); var transform = elem.attr("transform"); var t1 = getTranslate(transform); // 更新輸出線的位置 d3.selectAll('path[from="' + id + '"]') .each(function() { var start = d3.select(this).attr("start").split(","); start[0] = +start[0] + t1[0]; start[1] = +start[1] + t1[1]; var path = d3.select(this).attr("d"); var end = path.substring(path.lastIndexOf(" ") + 1).split(","); end[0] = +end[0]; end[1] = +end[1]; d3.select(this).attr("d", function() { return "M" + start[0] + "," + start[1] + " C" + start[0] + "," + (start[1] + end[1]) / 2 + " " + end[0] + "," + (start[1] + end[1]) / 2 + " " + end[0] + "," + end[1]; }); }); // 更新輸入線的位置 d3.selectAll('path[to="' + id + '"]') .each(function() { var path = d3.select(this).attr("d"); var start = path.substring(1, path.indexOf("C")).split(","); start[0] = +start[0]; start[1] = +start[1]; var end = d3.select(this).attr("end").split(","); end[0] = +end[0] + t1[0]; end[1] = +end[1] + t1[1]; d3.select(this).attr("d", function() { return "M" + start[0] + "," + start[1] + " C" + start[0] + "," + (start[1] + end[1]) / 2 + " " + end[0] + "," + (start[1] + end[1]) / 2 + " " + end[0] + "," + end[1]; }); }); } function dragended() { dx = dy = 0; dragElem = null; } function addNode(svg, node) { var g = svg.append("g") .attr("class", "node") .attr("data-id", node.dataId) .attr("id", node.id) .attr("transform", 'translate(' + node.x + ', ' + node.y + ')'); var rect = g.append("rect") .attr("rx", 5) .attr("ry", 5) .attr("stroke-width", 2) .attr("stroke", "#333") .attr("fill", "#fff"); var bound = rect.node().getBoundingClientRect(); var width = bound.width; var height = bound.height; // text g.append("text") .text(node.text) .attr("x", width / 2) .attr("y", height / 2) .attr("dominant-baseline", "central") .attr("text-anchor", "middle"); // left icon g.append('text') .attr("x", 18) .attr("y", height / 2) .attr("dominant-baseline", "central") .attr("text-anchor", "middle") .attr('font-family', 'FontAwesome') .text('\uf1c0'); // right icon g.append('text') .attr("x", width - 18) .attr("y", height / 2) .attr("dominant-baseline", "central") .attr("text-anchor", "middle") .attr('font-family', 'FontAwesome') .text('\uf00c'); // input circle var inputs = node.inputs || 0; g.attr("inputs", inputs); for(var i = 0; i < inputs; i++) { g.append("circle") .attr("class", "input") .attr("input", (i + 1)) .attr("cx", width * (i + 1) / (inputs + 1)) .attr("cy", 0) .attr("r", 5); } // output circle var outputs = node.outputs || 0; g.attr("outputs", outputs); for(i = 0; i < outputs; i++) { g.append("circle") .attr("output", (i + 1)) .attr("class", "output") .attr("cx", width * (i + 1) / (outputs + 1)) .attr("cy", height) .attr("r", 5); } return g; }