基于d3(v5.x)/jquery和svg,初步实现流程图和思维导图

时间:2022-11-20 18:09:20

基于d3(v5.x)(主要用到选择器)或者jquery(也是主要用选择器)实现初步元素之间连线,因为在做流程图和思维导图用到的主要技术就是元素之间的连线,通过svg可以将dom元素连接起来。经过此次编写个人认为主要是坐标的计算。在通过svg里面的line或者path画线即可。

下面为实现的代码(代码里有注释)和示意图。仅供参考(如果能帮到别人当然更好)。

下图所示,左边的div里面的元素都可以拖动到右边的div里面(右边div自动过滤重复元素),并且两侧对应连线。

因为只实现js部分所以没有样式。看上去很low。。。。

基于d3(v5.x)/jquery和svg,初步实现流程图和思维导图

基于d3(v5.x)/jquery和svg,初步实现流程图和思维导图

基于d3(v5.x)/jquery和svg,初步实现流程图和思维导图



<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
<script src="https://d3js.org/d3.v5.js"></script>
    <title>my-project</title>
</head>
<body>
<script>
 var data = [
        {
          number: "num1",
          numberChild: [
            { child: "child1" },
            { child: "child2" },
            { child: "child3" }
          ]
        },
        { number: "num2" },
        { number: "num3" }
      ];


      // console.log(data);
      //画图区域
      var basefram ="<div class='basefram' id='basefram' style='width:100%;height:400px;position:relative;top:0;left:0;z-index:1;border:1px solid #ccc;background:#ccc;'></div>";
      d3.select("body").html(basefram);

      //创建第一个div(添加元素拖动)
      initmain(data);

      //创建第二个div
      initsecond(data);

      function initmain(array) {
        var parent = document.getElementById("basefram"); //添加 div
        var div = document.createElement("div"); //设置 div 属性,如 id
        div.setAttribute("id", "first");
        div.setAttribute("class", "first");
        div.setAttribute(
          "style",
          "width:100px;height:200px;border:1px solid black;float:left;"
        );
        parent.appendChild(div);
        //添加列表内容
        array.forEach(function(v, i) {
          var parent = document.getElementById("first"); //添加 div
          var div = document.createElement("text"); //设置 div 属性,如 id
          div.setAttribute("id", "text_" + i);
          div.setAttribute("class", "text_" + i);
          div.setAttribute("draggable", "true");
          div.ondragstart = function(event, index) {
            //用户开始拖动元素时触发
            // console.log("开始拖动元素");
            event.dataTransfer.setData("id", event.target.id);        //dataTransfer属性只有在拖动事件(包括开始和结束)期间存在,事件结束该属性销毁。
            var obj = {
              offsetX: event.target.offsetLeft + event.target.offsetWidth,
              offsetY: event.target.offsetTop + event.target.offsetHeight,
              offsetHeight: event.target.offsetHeight,
              index: index
            };
            event.dataTransfer.setData("obj", JSON.stringify(obj));
            // console.log( event.offsetX)
          };
          // div.ondrag = function(event) {
          //   //元素正在拖动时触发
          //   // console.log("元素正在拖动。。。。");
          //   // event.target.style.cursor = "pointer";
          //   // div.style.cursor = "pointer";
          // };
          // div.ondrop = function(event) {
          //   // 在一个拖动过程中,释放鼠标键时触发此事件
          //   console.log("释放鼠标键时触发此事件");
          // };
          div.setAttribute(
            "style",
            "display:inline-block;height:20px;text-align:center;width:100px;background:red;"
          );
          div.innerHTML = v.number;
          parent.appendChild(div);
        });
        document.addEventListener("dragover", function(event) {
          event.preventDefault();
        });
      }


      function initsecond(array) {
        var parent = document.getElementById("basefram"); //添加 div
        var div = document.createElement("div"); //设置 div 属性,如 id
        div.setAttribute("id", "secondiv");
        div.setAttribute("class", "secondiv");
        // div.ondragover = function() {
        //   //当某被拖动的对象在另一对象容器范围内拖动时触发此事件
        //   console.log("当某被拖动的对象在另一对象容器范围内拖动时触发此事件");
        //   event.preventDefault();
        // };
        div.style.width = "100px";
        div.style.height = "100px";
        div.style.border = "1px solid blue";
        div.style.float = "left";
        div.style.position = "relative";
        div.style.left = "200px";
        div.style.top = "100px";
        // div.style.transform = "translate(50%,50%)";
        div.ondrop = function(event) {
          // 在一个拖动过程中,释放鼠标键时触发此事件
          // console.log("释放鼠标键时触发此事件");
          event.preventDefault();
          // var obj = jsonData(event);
          var id = event.dataTransfer.getData("id");
          var clone = document.getElementById(id).cloneNode(true);
          //去重
      
          var child=event.target.parentNode.children;
          if (child.length > 0) {
            var flag = false;
            for (var j = 0; j < child.length; j++) {
              if (child[j].id == id) {
                flag = true;
                break;
              }
            }
            if (!flag) {
              event.target.appendChild(clone);
              // 连线坐标
              var obj = jsonData(event, id);
              // 划线;
              line(obj, event);
            }
          } else {
            event.target.appendChild(clone);
            // 连线坐标
            var obj = jsonData(event, id);
            // 划线;
            line(obj, event);
          }
        };
        parent.appendChild(div);
      }


      function line(obj, event) {
        d3
          .selectAll(".basefram")
          .append("svg")
          // .attr("width", obj.x2-obj.x1)
          // .attr("height", obj.y2-obj.y1)
          .attr("width", "100%")
          .attr("height", "400px")
          .attr("id", "svg")
          // .attr("style","position:absolute;left:"+obj.x1+";top:"+obj.y1+"")
          .attr("style", "position:absolute;left:0;top:0;z-index:-1")
          .append("line")
          .attr("stroke", "blue")
          .attr("x1", obj.x1)
          .attr("y1", obj.y1 - obj.offsetHeight / 2)
          .attr("x2", obj.x2)
          .attr("y2", obj.y2 + obj.offsetHeight / 2);
      }


      function jsonData(event, id) {
        var obj = {
          id: id
        };
        obj.offsetHeight = JSON.parse(
          event.dataTransfer.getData("obj")
        ).offsetHeight;
        obj.x1 = JSON.parse(event.dataTransfer.getData("obj")).offsetX;
        obj.y1 = JSON.parse(event.dataTransfer.getData("obj")).offsetY;
        obj.y2 =
          event.target.getElementsByClassName(obj.id)[0].offsetTop +
          Number(getElementViewTop(event.target));


        obj.x2 = getElementViewLeft(event.target);


        // }else{
        //   obj.x2 = getElementViewLeft(event.target);
        //   obj.y2 = getElementViewTop(event.target);
        // }
        return obj;
      }


      function getElementViewLeft(element) {
        // debugger;
        var actualLeft = element.offsetLeft;
        var current = element.offsetParent;
        while (current !== null) {
          actualLeft += current.offsetLeft;
          current = current.offsetParent;
        }
        if (document.compatMode == "BackCompat") {
          var elementScrollLeft = document.body.scrollLeft;
        } else {
          var elementScrollLeft = document.documentElement.scrollLeft;
        }
        return actualLeft - elementScrollLeft;
      }
      function getElementViewTop(element) {
        var actualTop = element.offsetTop;
        var current = element.offsetParent;
        while (current !== null) {
          actualTop += current.offsetTop;
          current = current.offsetParent;
        }
        if (document.compatMode == "BackCompat") {
          var elementScrollTop = document.body.scrollTop;
        } else {
          var elementScrollTop = document.documentElement.scrollTop;
        }
        return actualTop - elementScrollTop;
      }
</script>
</body>
</html>