拖拽释放节点时如何动态通过SVG生成连线连接两个节点
实现思路
你只需要在现有代码基础上做4处调整,即可实现拖拽释放自动生成连线的效果:
- 第一步:调整现有DOM结构,在拖拽区域底层叠加专用SVG画布
在dropzone容器内新增一个和容器尺寸完全一致的绝对定位SVG元素,层级设为低于拖拽节点,专门用来绘制连线:
<div id="dropzone" style="border: 4px solid grey;height:28rem;position:relative;" draggable="true" ondragstart="{!c.drag}" ondrop="{!c.drop}" ondragover="{!c.allowDrop}"> <!-- 新增SVG连线画布 --> <svg id="linkSvg" style="position:absolute;top:0;left:0;width:100%;height:100%;z-index:0;"></svg> <!-- 原有节点内容放在上层,避免被SVG遮挡 --> <div style="position:relative;z-index:1;">Test</div> </div>
- 第二步:维护两套必要的数据
你需要在组件属性中新增两个数组存储关联数据:- 节点属性数组:存储每个已放入拖拽区的节点ID、相对于拖拽区的左上角坐标、宽高
- 连线关系数组:存储每组关联的父节点ID、子节点ID
- 第三步:改造drop事件,插入节点后触发连线绘制
drop: function (component, event, helper) { event.preventDefault(); var data = event.dataTransfer.getData("text"); const dragNode = document.getElementById(data); // 插入拖拽节点到上层内容区 event.target.querySelector('[z-index="1"]').appendChild(dragNode); dragNode.className = "nodeclass slds-card"; // 识别父节点(你当前场景是拖拽到Test1上方,父节点就是触发drop的Test1节点) const parentNode = event.target.closest('.nodeclass'); const dropRect = document.getElementById('dropzone').getBoundingClientRect(); // 计算父子节点相对于拖拽区的坐标 const parentRect = parentNode.getBoundingClientRect(); const parentInfo = { id: parentNode.id, x: parentRect.left - dropRect.left, y: parentRect.top - dropRect.top, width: parentRect.width, height: parentRect.height }; const childRect = dragNode.getBoundingClientRect(); const childInfo = { id: data, x: childRect.left - dropRect.left, y: childRect.top - dropRect.top, width: childRect.width, height: childRect.height }; // 调用工具方法绘制连线 helper.drawLink(component, parentInfo, childInfo); }
- 第四步:实现连线绘制工具方法,参考你找到的SVG路径规则生成圆角连线
// 写在helper中的drawLink方法 drawLink: function(component, parentInfo, childInfo) { const svg = document.getElementById('linkSvg'); // 计算父节点底部中点、子节点顶部中点作为连线起止点 const fromX = parentInfo.x + parentInfo.width / 2; const fromY = parentInfo.y + parentInfo.height; const toX = childInfo.x + childInfo.width / 2; const toY = childInfo.y; // 拼接带圆角的path路径,可自行调整圆角数值 const midY = (fromY + toY) / 2; const horizontalOffset = fromX > toX ? -8 : 8; const pathD = `M${fromX},${fromY} L${fromX},${midY - 8} Q${fromX},${midY} ${fromX + horizontalOffset},${midY} L${toX},${midY} Q${toX},${midY} ${toX},${midY + 8} L${toX},${toY}`; // 生成path元素插入SVG const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); path.setAttribute("d", pathD); path.setAttribute("stroke", "#aeaeae"); path.setAttribute("stroke-width", "1"); path.setAttribute("fill", "none"); path.setAttribute("stroke-linejoin", "round"); path.setAttribute("link-id", `[${parentInfo.id}][${childInfo.id}]`); svg.appendChild(path); }
如果后续需要支持节点拖拽移动后自动更新连线,只需要监听节点的拖拽事件,根据节点最新坐标更新对应link-id的path的d属性即可。
内容的提问来源于stack exchange,提问作者sfdc fox
相关产品推荐
相关产品推荐

