【问题标题】:Svg draw connection line between two rectanglesSVG绘制两个矩形之间的连接线
【发布时间】:2018-05-09 11:17:17
【问题描述】:

我目前正在使用SVGjavascript 中编写图表编辑器。

我遇到了一个关于矩形之间连接的问题。我找到了很多资源来绘制圆之间的连接,但没有关于矩形。

所以现在我得到的是,我可以通过用鼠标拖动线在两个矩形之间绘制一条连接线,但连接显示在它们内部,因为我从矩形的中点计算连接。

正如您在下图中看到的那样,我自己做了一些想法,但我没有完成最后一步。

我只想画出红色标记的线。

稍后我想拖动矩形并更新线,但现在我只需要计算这条线。

有人有好的建议吗?

【问题讨论】:

  • 你有两个三角形,一个大的,顶点为 3,3 8,6 8,3,小一个为 3,3 5,3 5,y,因为它们的边角相同大小比例相同。从中您可以计算 y

标签: javascript svg connection rectangles


【解决方案1】:

假设你有两个矩形并且你知道它们的中心 (cx1, cy1) 和 (cx2, cy2)。您还有 除以 2 的宽度和高度(即从中心到两侧的距离):(w1, h1) 和 (w2, h2)。

它们之间的距离是:

var dx = cx2 - cx1;
var dy = cy2 - cy1;

然后你可以计算两个矩形的交点:

var p1 = getIntersection(dx, dy, cx1, cy1, w1, h1);
var p2 = getIntersection(-dx, -dy, cx2, cy2, w2, h2);

getIntersection 在哪里:

function getIntersection(dx, dy, cx, cy, w, h) {
  if (Math.abs(dy / dx) < h / w) {
    // Hit vertical edge of box1
    return [cx + (dx > 0 ? w : -w), cy + dy * w / Math.abs(dx)];
   } else {
    // Hit horizontal edge of box1
    return [cx + dx * h / Math.abs(dy), cy + (dy > 0 ? h : -h)];
    }
};

这是一个例子:

var rect1 = document.getElementById('rect1');
var rect2 = document.getElementById('rect2');
var cxn = document.getElementById('connection');

updateConnection();

function updateConnection() {
  // Top left coordinates
  var x1 = parseFloat(rect1.getAttributeNS(null, 'x'));
  var y1 = parseFloat(rect1.getAttributeNS(null, 'y'));
  var x2 = parseFloat(rect2.getAttributeNS(null, 'x'));
  var y2 = parseFloat(rect2.getAttributeNS(null, 'y'));

  // Half widths and half heights
  var w1 = parseFloat(rect1.getAttributeNS(null, 'width')) / 2;
  var h1 = parseFloat(rect1.getAttributeNS(null, 'height')) / 2;
  var w2 = parseFloat(rect2.getAttributeNS(null, 'width')) / 2;
  var h2 = parseFloat(rect2.getAttributeNS(null, 'height')) / 2;

  // Center coordinates
  var cx1 = x1 + w1;
  var cy1 = y1 + h1;
  var cx2 = x2 + w2;
  var cy2 = y2 + h2;

  // Distance between centers
  var dx = cx2 - cx1;
  var dy = cy2 - cy1;

  var p1 = getIntersection(dx, dy, cx1, cy1, w1, h1);
  var p2 = getIntersection(-dx, -dy, cx2, cy2, w2, h2);

  cxn.setAttributeNS(null, 'x1', p1[0]);
  cxn.setAttributeNS(null, 'y1', p1[1]);
  cxn.setAttributeNS(null, 'x2', p2[0]);
  cxn.setAttributeNS(null, 'y2', p2[1]);
}

function getIntersection(dx, dy, cx, cy, w, h) {
if (Math.abs(dy / dx) < h / w) {
  // Hit vertical edge of box1
  return [cx + (dx > 0 ? w : -w), cy + dy * w / Math.abs(dx)];
 } else {
  // Hit horizontal edge of box1
  return [cx + dx * h / Math.abs(dy), cy + (dy > 0 ? h : -h)];
  }
};

function makeDraggable(evt) {
  var svg = evt.target;
  svg.addEventListener('mousedown', startDrag);
  svg.addEventListener('mousemove', drag);
  svg.addEventListener('mouseup', endDrag);

  function getMousePosition(evt) {
    var CTM = svg.getScreenCTM();
    return {
      x: (evt.clientX - CTM.e) / CTM.a,
      y: (evt.clientY - CTM.f) / CTM.d
    };
  }

  var selectedElement, offset;

  function startDrag(evt) {
    if (evt.target.classList.contains('draggable')) {
      selectedElement = evt.target;
      offset = getMousePosition(evt);
      offset.x -= parseFloat(selectedElement.getAttributeNS(null, "x"));
      offset.y -= parseFloat(selectedElement.getAttributeNS(null, "y"));
    }
  }

  function drag(evt) {
    if (selectedElement) {
      var coord = getMousePosition(evt);
      selectedElement.setAttributeNS(null, "x", coord.x - offset.x);
      selectedElement.setAttributeNS(null, "y", coord.y - offset.y);
      updateConnection();
    }
  }

  function endDrag(evt) {
    selectedElement = null;
  }
}
.static {
  cursor: not-allowed;
}

.draggable {
  cursor: move;
  fill: #007bff;
  fill-opacity: 0.1;
  stroke: #007bff;
  stroke-width: 0.2;
}

#connection {
  stroke-width: 0.1;
  stroke: red;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 20" onload="makeDraggable(evt)" width="400" height="200">
    
  <rect id="rect1" class="draggable" x="4" y="5" width="4" height="3"/>
  <rect id="rect2" class="draggable" x="18" y="5" width="3" height="5"/>
  <line id="connection" />
</svg>

【讨论】:

  • 谢谢你这么完美的作品!非常感谢这个关于拖动的实现:)
猜你喜欢
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 2011-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-06
相关资源
最近更新 更多