Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jirick1/e57d3a7f14ed18aef10f3faf8a590326 to your computer and use it in GitHub Desktop.
Save jirick1/e57d3a7f14ed18aef10f3faf8a590326 to your computer and use it in GitHub Desktop.
Connect two elements / draw a path between two elements with SVG path (using jQuery)

connect html elements with SVG path

Gist contains a javaScript file svgDraw.js for connecting any two html elements with an SVG path in a pipe-like fashion. It connects the bottom-middle point of the "higher" element with the top-middle point ot the "lower" element. preview

Also, index.html, and style.css are provided for demonstration purposes.

==

USAGE:

In odrer to connect any two elements, they need an ID. For the purposes of this demonstration, we shall id them as "Mary" and "Tom". Style with CSS as you normally would.

 <div id="Mary"></div>
 <p id="Tom"></p>

Next, (also in your .html) we need to add a path with which to connect our Mary and Tom elements. We do that by appending a child <path> element to <svg>. Note that they also have unique IDs, "myNewPath" and "svg1", respectively .

<svg id="svg1" width="0" height="0" >
       <path
            id="myNewPath"
            d="M0 0"             
            stroke-width="0.3em"
            style="stroke:#555; fill:none;  "/>
</svg>

And now for the fun part. The actual connecting! In svgDraw.js locate function connectAll() and add your connection like so:

function connectAll() {
    // connect all the paths you want!
    connectElements($("#svg1"), $("#myNewPath"), $("#Mary"),  $("#Tom"));
    ...
    connectElements($("#svg1"), $("#someOtherPath"), $("#purple"), $("#teal")  );
    connectElements($("#svg1"), $("#yetAnotherPath"), $("#Tom"), $("#teal")  );
}

aand... you're done!
You can repeat these steps any number of times connecting any number of different elements ( or connecting any one element with any number of different elements, for that matter :))
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Connect divs with SVG</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
<div id="svgContainer" style="margin: 50px 50px;">
<svg id="svg1" width="0" height="0" >
<path
id="path1"
d="M0 0"
stroke="#000"
fill="none"
stroke-width="12px";/>
<path
id="path2"
d="M0 0"
stroke="#000"
fill="none"
stroke-width="12px";/>
<path
id="path3"
d="M0 0"
stroke-width="8px"
style="stroke:#000; fill:none;"/>
<path
id="path4"
d="M0 0"
stroke-width="12px"
style="stroke:#000; fill:none; stroke-width: 12px;" />
<path
id="path5"
d="M0 0"
stroke-width="10px"
style="stroke:#000; fill:none;"/>
<path
id="path6"
d="M0 0"
stroke-width="10px"
style="stroke:#000; fill:none;"/>
</svg>
</div>
<div id= "outer">
<div id="teal"></div>
<div id="red"></div>
<div id="green"></div>
<div id="purple"></div>
<div id="orange"></div>
<div id="aqua"></div>
</div>
<script src="svgDraw.js"></script>
</body>
</html>
body{ background-color:gray; }
#svgContainer {
z-index: -10;
position:absolute;
background-color:silver;
opacity: 0.5;
}
div{ opacity: 0.6; }
#outer{
margin:0 auto;
width: 80%;
}
#teal{
width: 6em;
height: 6em;
background-color:teal;
margin-left: 10%;
}
#orange{
height: 4em;
width: 35%;
padding: 2em 8em;
margin-left: 8em;
margin-top: 6em;
background-color: orange;
}
#red{
width:6em;
height: 4em;
margin-left: 30%;
padding:4em 3em;
background-color:red;
}
#aqua{
width: 5em;
height: 5em;
margin-left:15%;
background-color:aqua;
}
#purple{
width: 15em;
height: 5em;
background-color:purple;
}
#green{
width: 5em;
height: 7em;
margin-top: 2em;
margin-left: 50%;
background-color: green;
}
//helper functions, it turned out chrome doesn't support Math.sgn()
function signum(x) {
return (x < 0) ? -1 : 1;
}
function absolute(x) {
return (x < 0) ? -x : x;
}
function drawPath(svg, path, startX, startY, endX, endY) {
// get the path's stroke width (if one wanted to be really precize, one could use half the stroke size)
var stroke = parseFloat(path.attr("stroke-width"));
// check if the svg is big enough to draw the path, if not, set heigh/width
if (svg.attr("height") < endY) svg.attr("height", endY);
if (svg.attr("width" ) < (startX + stroke) ) svg.attr("width", (startX + stroke));
if (svg.attr("width" ) < (endX + stroke) ) svg.attr("width", (endX + stroke));
var deltaX = (endX - startX) * 0.15;
var deltaY = (endY - startY) * 0.15;
// for further calculations which ever is the shortest distance
var delta = deltaY < absolute(deltaX) ? deltaY : absolute(deltaX);
// set sweep-flag (counter/clock-wise)
// if start element is closer to the left edge,
// draw the first arc counter-clockwise, and the second one clock-wise
var arc1 = 0; var arc2 = 1;
if (startX > endX) {
arc1 = 1;
arc2 = 0;
}
// draw tha pipe-like path
// 1. move a bit down, 2. arch, 3. move a bit to the right, 4.arch, 5. move down to the end
path.attr("d", "M" + startX + " " + startY +
" V" + (startY + delta) +
" A" + delta + " " + delta + " 0 0 " + arc1 + " " + (startX + delta*signum(deltaX)) + " " + (startY + 2*delta) +
" H" + (endX - delta*signum(deltaX)) +
" A" + delta + " " + delta + " 0 0 " + arc2 + " " + endX + " " + (startY + 3*delta) +
" V" + endY );
}
function connectElements(svg, path, startElem, endElem) {
var svgContainer= $("#svgContainer");
// if first element is lower than the second, swap!
if(startElem.offset().top > endElem.offset().top){
var temp = startElem;
startElem = endElem;
endElem = temp;
}
// get (top, left) corner coordinates of the svg container
var svgTop = svgContainer.offset().top;
var svgLeft = svgContainer.offset().left;
// get (top, left) coordinates for the two elements
var startCoord = startElem.offset();
var endCoord = endElem.offset();
// calculate path's start (x,y) coords
// we want the x coordinate to visually result in the element's mid point
var startX = startCoord.left + 0.5*startElem.outerWidth() - svgLeft; // x = left offset + 0.5*width - svg's left offset
var startY = startCoord.top + startElem.outerHeight() - svgTop; // y = top offset + height - svg's top offset
// calculate path's end (x,y) coords
var endX = endCoord.left + 0.5*endElem.outerWidth() - svgLeft;
var endY = endCoord.top - svgTop;
// call function for drawing the path
drawPath(svg, path, startX, startY, endX, endY);
}
function connectAll() {
// connect all the paths you want!
connectElements($("#svg1"), $("#path1"), $("#teal"), $("#orange"));
connectElements($("#svg1"), $("#path2"), $("#red"), $("#orange"));
connectElements($("#svg1"), $("#path3"), $("#teal"), $("#aqua") );
connectElements($("#svg1"), $("#path4"), $("#red"), $("#aqua") );
connectElements($("#svg1"), $("#path5"), $("#purple"), $("#teal") );
connectElements($("#svg1"), $("#path6"), $("#orange"), $("#green") );
}
$(document).ready(function() {
// reset svg each time
$("#svg1").attr("height", "0");
$("#svg1").attr("width", "0");
connectAll();
});
$(window).resize(function () {
// reset svg each time
$("#svg1").attr("height", "0");
$("#svg1").attr("width", "0");
connectAll();
});
@old-cory
Copy link

old-cory commented Jul 1, 2019

How can this be modified to have the path start and end at the right edge of the div instead of the bottom?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment