• jQuery+d3绘制流程图OK


    jQuery+d3绘制流程图

    2017年11月06日 16:27:02 Brent-CCNU 阅读数:10193

    jQuery + d3绘制流程图

    运行效果

    这里写图片描述

    代码

    HTML代码

    <!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;  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;  100%">
              <a class="btn btn-link" href="#"><i class="fa fa-play-circle-o" aria-hidden="true"></i>&nbsp;运行</a>
              <a class="btn btn-link" href="#"><i class="fa fa-cloud-upload" aria-hidden="true"></i>&nbsp;部署</a>
              <a class="btn btn-link" href="#"><i class="fa fa-share-alt" aria-hidden="true"></i>&nbsp;分享</a>
            </div>
          </div>
          <div class="right-wrapper">
            <h4>实验属性</h4>
          </div>
        </div>
    </body>
    <script type="text/javascript" src="index.js"></script>
    </html>

    CSS代码

    .left-wrapper {
         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;
         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 {
        180px; 
        height:36px;
        cursor: pointer;
        stroke: #333;
        stroke-2;
        fill: #fff;
    }
    
    .bpmn .node.active rect,
    .bpmn .node.active circle {
        stroke: lightblue;
    }
    
    .bpmn .node circle {
        stroke: #333;
        stroke- 2px;
        fill: #fff;
        cursor: crosshair;
    }
    
    .bpmn .node circle.end {
        fill: orange;
    }
    
    .bpmn .cable {
        stroke: #333;
        stroke- 2px;
        fill: none;
    }

    JavaScript

    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;
    }
  • 相关阅读:
    layaAir引擎制作游戏的图集动画、时间轴动画、和骨骼动画总结二
    layaAir引擎制作游戏的图集动画、时间轴动画、和骨骼动画总结一
    Flask 生成验证码 支持干扰线、噪点
    数组操作
    css_权威指南_选择符
    css权威指南_特指度
    *arg **kwargs
    一日一库—importlib
    一日一库—itertools
    FLask 流程图、上下文、上下文隔离原理
  • 原文地址:https://www.cnblogs.com/grj001/p/12224060.html
Copyright © 2020-2023  润新知