|
//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(); |
|
}); |
If you have two elements side by side, you can use SVG line instead of SVG path. i.e, you can add condition like when startY and endY are equal, you can draw a line instead of drawing a path.