Created
February 14, 2014 00:14
-
-
Save jedwood/8986724 to your computer and use it in GitHub Desktop.
Tiny helper for connecting two elements with SVG lines. Assumes jQuery (for now). Original by @johndilworth
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>SVG Lines</title> | |
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script> | |
<script src="belay.js"></script> | |
<link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"> | |
<style> | |
body{ | |
background: #eee; | |
} | |
.grid{ | |
padding: 30px; | |
} | |
.fact,.source, .child, .parent{ | |
background: #fff; | |
margin: 10px 0px; | |
border-radius: 4px; | |
min-height: 30px; | |
padding: 10; | |
} | |
ol{ | |
margin: 0; | |
padding: 0; | |
} | |
li{ | |
list-style:none; | |
padding: 0; | |
} | |
h1,h2,h3{ | |
margin-top:0; | |
} | |
li p{margin-bottom:0;} | |
</style> | |
</head> | |
<body> | |
<div class="grid"> | |
<div class="row"> | |
<h1>On Belay!</h1> | |
</div> | |
<div class="row"> | |
<div class="col-sm-5"> | |
<ol id="wives"> | |
<li class="parent" id="parent-1"> | |
<h3>Kendall</h3> | |
</li> | |
<li class="parent" id="parent-2"> | |
<h3>Dave</h3> | |
</li> | |
<li class="parent" id="parent-3"> | |
<h3>Tana</h3> | |
</li> | |
</ol> | |
</div> | |
<div class="col-sm-2"></div> | |
<div class="col-sm-5"> | |
<ol id="children"> | |
<li class="child parent-1">John</li> | |
<li class="child parent-1">Jed</li> | |
<li class="child parent-1">Josh</li> | |
<li class="child parent-1">Kory</li> | |
<li class="child parent-1">Bonnie</li> | |
<li class="child parent-2">Rob</li> | |
<li class="child parent-3">Freestone</li> | |
</ol> | |
</div> | |
</div> | |
</div> | |
</body> | |
<script> | |
function drawConnectors(){ | |
//Draws a line from the wife to her children, based on each child having a class that is the id of the parent. | |
$(".parent").each(function(){ | |
var theID = this.id; | |
$("."+theID).each(function(i,e){ | |
var rand = Math.random() * .7 + .3; | |
Belay.set('animationDuration', rand) | |
Belay.on($("#"+theID), e) | |
}); | |
}) | |
} | |
// redraw if window is resized | |
$(window).resize(function(){ | |
Belay.off(); | |
drawConnectors(); | |
}); | |
Belay.init({strokeWidth: 1}); | |
Belay.set('strokeColor', '#999'); | |
drawConnectors(); | |
</script> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Belay = (function(){ | |
var settings = { | |
strokeColor : '#fff', | |
strokeWidth : 2, | |
opacity : 1, | |
fill : 'none', | |
animate : true, | |
animationDirection: 'right', | |
animationDuration : .75 | |
}; | |
var me = {}; | |
me.init = function(initObj) { | |
if (initObj) { | |
$.each(initObj, function(index, value) { | |
//TODO validation on settings | |
settings[index] = value; | |
}); | |
} | |
} | |
me.set = function(prop, val){ | |
//TODO validate | |
settings[prop] = val; | |
} | |
me.on = function(el1, el2){ | |
var $el1 = $(el1); | |
var $el2 = $(el2); | |
if ($el1.length && $el2.length) { | |
var svgheight | |
,p | |
,svgleft | |
,svgtop | |
,svgwidth | |
var el1pos = $(el1).offset(); | |
var el2pos = $(el2).offset(); | |
var el1H = $(el1).outerHeight(); | |
var el1W = $(el1).outerWidth(); | |
var el2H = $(el2).outerHeight(); | |
var el2W = $(el2).outerWidth(); | |
svgleft = Math.round(el1pos.left + el1W); | |
svgwidth = Math.round(el2pos.left - svgleft); | |
var curvinessFactor, cpt; | |
////Determine which is higher/lower | |
if( (el2pos.top+(el2H/2)) <= ( el1pos.top+(el1H/2))){ | |
// console.log("low to high"); | |
svgheight = Math.round((el1pos.top+el1H/2) - (el2pos.top+el2H/2)); | |
svgtop = Math.round(el2pos.top + el2H/2) - settings.strokeWidth; | |
cpt = Math.round(svgwidth*Math.min(svgheight/300, 1)); | |
p = "M0,"+ (svgheight+settings.strokeWidth) +" C"+cpt+","+(svgheight+settings.strokeWidth)+" "+(svgwidth-cpt)+"," + settings.strokeWidth + " "+svgwidth+"," + settings.strokeWidth; | |
}else{ | |
// console.log("high to low"); | |
svgheight = Math.round((el2pos.top+el2H/2) - (el1pos.top+el1H/2)); | |
svgtop = Math.round(el1pos.top + el1H/2) - settings.strokeWidth; | |
cpt = Math.round(svgwidth*Math.min(svgheight/300, 1)); | |
p = "M0," + settings.strokeWidth + " C"+ cpt +",0 "+ (svgwidth-cpt) +","+(svgheight+settings.strokeWidth)+" "+svgwidth+","+(svgheight+settings.strokeWidth); | |
} | |
//ugly one-liner | |
$ropebag = $('#ropebag').length ? $('#ropebag') : $('body').append($( "<div id='ropebag' />" )).find('#ropebag'); | |
var svgnode = document.createElementNS('http://www.w3.org/2000/svg','svg'); | |
var newpath = document.createElementNS('http://www.w3.org/2000/svg',"path"); | |
newpath.setAttributeNS(null, "d", p); | |
newpath.setAttributeNS(null, "stroke", settings.strokeColor); | |
newpath.setAttributeNS(null, "stroke-width", settings.strokeWidth); | |
newpath.setAttributeNS(null, "opacity", settings.opacity); | |
newpath.setAttributeNS(null, "fill", settings.fill); | |
svgnode.appendChild(newpath); | |
//for some reason, adding a min-height to the svg div makes the lines appear more correctly. | |
$(svgnode).css({left: svgleft, top: svgtop, position: 'absolute',width: svgwidth, height: svgheight + settings.strokeWidth*2, minHeight: '20px' }); | |
$ropebag.append(svgnode); | |
if (settings.animate) { | |
// THANKS to http://jakearchibald.com/2013/animated-line-drawing-svg/ | |
var pl = newpath.getTotalLength(); | |
// Set up the starting positions | |
newpath.style.strokeDasharray = pl + ' ' + pl; | |
if (settings.animationDirection == 'right') { | |
newpath.style.strokeDashoffset = pl; | |
} else { | |
newpath.style.strokeDashoffset = -pl; | |
} | |
// Trigger a layout so styles are calculated & the browser | |
// picks up the starting position before animating | |
// WON'T WORK IN IE. If you want that, use requestAnimationFrame to update instead of CSS animation | |
newpath.getBoundingClientRect(); | |
newpath.style.transition = newpath.style.WebkitTransition ='stroke-dashoffset ' + settings.animationDuration + 's ease-in-out'; | |
// Go! | |
newpath.style.strokeDashoffset = '0'; | |
} | |
} | |
} | |
me.off = function(){ | |
$("#ropebag").empty(); | |
} | |
return me; | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment