Skip to content

Instantly share code, notes, and snippets.

@JonnoFTW
Forked from alojzije/connectHTMLelements_SVG.png
Created February 25, 2019 05:07
Show Gist options
  • Save JonnoFTW/f5c0207f69d385f07cba7d14740616f7 to your computer and use it in GitHub Desktop.
Save JonnoFTW/f5c0207f69d385f07cba7d14740616f7 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();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment