css 连接两个div的SVG Bezier路径

zf2sa74q  于 2023-11-19  发布在  其他
关注(0)|答案(1)|浏览(169)

我有两个div,这两个div的边框上有一个图标。我想使用SVG路径线连接icons
我已经尝试了一些解决方案,但由于某种原因,我似乎无法使它看起来很好。这条线从实际的div开始 * 远离 *。我相信我在计算过程中遇到了一些大问题。
我的项目是在Vue中,所以我不能给予一个适当的链接来显示复制,然而,这里是我使用的函数:

  1. function drawConnector() {
  2. if (divA.value && divB.value && svg.value) {
  3. const paths = svg.value
  4. let oldPaths = paths.children
  5. for (let a = oldPaths.length - 1; a >= 0; a--) {
  6. paths.removeChild(oldPaths[a])
  7. }
  8. let x1, y1, x4, y4, dx, x2, x3, path, boxA, boxB
  9. const bezierWeight = 0.8
  10. for (let a = 0; a < 1; a++) {
  11. // divA and divB are the icons
  12. boxA = divA.value
  13. boxB = divB.value
  14. x1 = getOffset(boxA).left + boxA.getBoundingClientRect().width / 2
  15. y1 = getOffset(boxA).top + (boxA.getBoundingClientRect().height - 100) / 2 // EDIT -100
  16. x4 = getOffset(boxB).left + boxB.getBoundingClientRect().width / 2
  17. y4 = getOffset(boxB).top + (boxB.getBoundingClientRect().height - 100)/ 2 // EDIT -100
  18. // Apply padding
  19. dx = Math.abs(x4 - x1) * bezierWeight
  20. if (x4 < x1) {
  21. x2 = x1 - dx
  22. x3 = x4 + dx
  23. } else {
  24. x2 = x1 + dx
  25. x3 = x4 - dx
  26. }
  27. const data = `M${x1} ${y1} C ${x2} ${y1} ${x3} ${y4} ${x4} ${y4}`
  28. path = document.createElementNS(SVG_URL, 'path')
  29. path.setAttribute('d', data)
  30. path.setAttribute('class', 'path')
  31. paths.appendChild(path)
  32. }
  33. }
  34. }
  35. function getOffset(element: HTMLDivElement) {
  36. if (!element.getClientRects().length) {
  37. return { top: 0, left: 0 }
  38. }
  39. let rect = element.getBoundingClientRect()
  40. let win = element.ownerDocument.defaultView
  41. return {
  42. top: rect.top + (win ? win.scrollY : 0),
  43. left: rect.left + (win ? win.scrollX : 0)
  44. }
  45. }

字符串
最终结果如下所示:


的数据
div本身是可拖动的,线会相应地重新绘制,但它会保持与端口的距离。如何确保连接从“输出端口”前面的图标开始,并在另一个输出端口正确结束?
还有,我应该使用什么样的贝塞尔曲线来使路径试图绕过div而不是从它下面?
任何指导将不胜感激。
编辑:我一直在篡改它,我在计算Y轴时添加了一个-100。我不知道为什么它会起作用,我尝试了不同的值,但100是最好的。



我仍然希望帮助关于这方面的工作,因为-100感觉像是一个侥幸,而不是一个适当的解决方案.此外,我的目标是让链接不去 * 下 * div,而是围绕它,如果你有任何关于这方面的建议,太,当然会很感激,否则我总是可以尝试解决它以后.

hsvhsicv

hsvhsicv1#

很难猜测这个问题是来自图像,但不知何故,你没有考虑SVG相对于区域的偏移或位置(这里我称之为板)。
我希望你能从这个例子中学到一些东西:

  1. const board = document.getElementById('board');
  2. const svg = board.querySelector('svg');
  3. const cardProps = {'width': 120, 'height': 80, 'offset': 65};
  4. updatePaths();
  5. function updatePaths() {
  6. let paths = svg.querySelectorAll('path');
  7. [...paths].forEach(path => {
  8. let from = board.querySelectorAll(`div.card`)[path.dataset.from];
  9. let to = board.querySelectorAll(`div.card`)[path.dataset.to];
  10. let fromPoint = {
  11. 'left': from.offsetLeft + cardProps.width,
  12. 'top': from.offsetTop + cardProps.offset
  13. };
  14. let toPoint = {
  15. 'left': to.offsetLeft,
  16. 'top': to.offsetTop + cardProps.offset
  17. };
  18. path.setAttribute('d', `M ${fromPoint.left} ${fromPoint.top}
  19. C ${fromPoint.left + 50} ${fromPoint.top} ${toPoint.left - 50} ${toPoint.top} ${toPoint.left} ${toPoint.top}`);
  20. });
  21. }
  22. board.addEventListener('mousedown', e => {
  23. switch (e.target.className) {
  24. case 'card':
  25. e.target.dataset.moving = "on";
  26. e.target.mouse = {
  27. left: e.layerX,
  28. top: e.layerY
  29. };
  30. break;
  31. }
  32. });
  33. board.addEventListener('mousemove', e => {
  34. let card = board.querySelector('div[data-moving="on"]');
  35. if (card) {
  36. card.style.left = `${e.clientX - card.mouse.left - board.offsetLeft}px`;
  37. card.style.top = `${e.clientY - card.mouse.top - board.offsetTop}px`;
  38. updatePaths();
  39. }
  40. });
  41. document.addEventListener('mouseup', e => {
  42. let cards = board.querySelectorAll('div[data-moving]');
  43. [...cards].forEach(card => card.dataset.moving = null);
  44. });
  1. #board {
  2. width: 100%;
  3. height: 400px;
  4. border: solid thin navy;
  5. position: relative;
  6. }
  7. .card {
  8. border: solid thin black;
  9. width: 120px;
  10. height: 80px;
  11. position: absolute;
  12. background-color: WhiteSmoke;
  13. }
  14. .card::before {
  15. content: "";
  16. width: 10px;
  17. height: 10px;
  18. border-radius: 5px;
  19. background-color: gray;
  20. position: absolute;
  21. left: -5px;
  22. top: 60px;
  23. }
  24. .card::after {
  25. content: "";
  26. width: 10px;
  27. height: 10px;
  28. border-radius: 5px;
  29. background-color: gray;
  30. position: absolute;
  31. right: -5px;
  32. top: 60px;
  33. }
  34. svg path {
  35. stroke-width: 2px;
  36. fill: none;
  37. }
  1. <div id="board">
  2. <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
  3. <path d="M 0 0 L 20 20" stroke="black" data-from="0" data-to="1" />
  4. </svg>
  5. <div class="card" style="left: 10px;top: 10px"></div>
  6. <div class="card" style="left: 200px;top: 50px"></div>
  7. </div>
展开查看全部

相关问题