Gist contains a javaScript file svgDraw.js for connecting any two html elements with an SVG path in a pipe-like fashion. Also, index.html, and style.css are provided for demonstration purposes.
==
to-do: usage
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <link rel="stylesheet" type="text/css" href="style.css"> | |
| <title>Connect divs with SVG</title> | |
| <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="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> | |
| <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(); | |
| }); |