基于d3(v5.x)(主要用到选择器)或者jquery(也是主要用选择器)实现初步元素之间连线,因为在做流程图和思维导图用到的主要技术就是元素之间的连线,通过svg可以将dom元素连接起来。经过此次编写个人认为主要是坐标的计算。在通过svg里面的line或者path画线即可。
下面为实现的代码(代码里有注释)和示意图。仅供参考(如果能帮到别人当然更好)。
下图所示,左边的div里面的元素都可以拖动到右边的div里面(右边div自动过滤重复元素),并且两侧对应连线。
因为只实现js部分所以没有样式。看上去很low。。。。
<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>