Skip to content

Instantly share code, notes, and snippets.

@binary10ve
Last active August 7, 2016 16:38
Show Gist options
  • Save binary10ve/1eef742d6c821a8f1d1920263ec1b18a to your computer and use it in GitHub Desktop.
Save binary10ve/1eef742d6c821a8f1d1920263ec1b18a to your computer and use it in GitHub Desktop.
Network graph
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Orbit Layout Modes</title>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<style>
body, html {
width: 100%;
margin: 0;
font-family: "Helvetica Neue", Helvetica, sans-serif;
font-size: 12px;
-webkit-backface-visibility: hidden;
}
body{
padding: 40px;
height: 1000px;
}
.node {
cursor: pointer; }
.node.leaf {
cursor: default; }
.node circle {
fill: lightsteelblue;
stroke: steelblue;
stroke-width: 1.5px; }
.node.leaf circle {
fill: #fff; }
.node text {
font-size: 11px; }
.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px; }
@-webkit-keyframes bounceIn {
0% {
opacity: 0;
-webkit-transform: scale(.3);
}
50% {
opacity: 1;
-webkit-transform: scale(1.05);
}
70% {
-webkit-transform: scale(.9);
}
100% {
-webkit-transform: scale(1);
}
}
@keyframes bounceIn {
0% {
opacity: 0;
transform: scale(.3);
}
50% {
opacity: 1;
transform: scale(1.05);
}
70% {
transform: scale(.9);
}
100% {
transform: scale(1);
}
}
.d3-tip.animate {
animation: bounceIn 0.2s ease-out;
-webkit-animation: bounceIn 0.2s ease-out;
}
.d3-tip span {
color: #ff00c7;
}
.domain {
display: none;
}
.axis line {
stroke-width: 1px;
stroke: #eee;
shape-rendering: crispedges;
}
.axis text {
fill: #888;
}
rect {
fill: #339cff;
fill-opacity: 0.7;
}
rect:hover {
fill-opacity: 1;
}
.user-panel {
padding: 10px;
background-color: white;
border:1px solid #E0E0E0;
border-radius: 8px;
}
.user-panel:before,
.user-panel:after {
display: table;
content: " ";
}
.user-panel:after {
clear: both;
}
.user-panel > .image > img {
width: 60px;
height: 60px;
}
.user-panel > .info {
padding: 5px 5px 5px 15px;
font-size: 14px;
line-height: 1;
}
.user-panel > .info > p {
margin-bottom: 9px;
}
.user-panel > .info > a {
text-decoration: none;
padding-right: 5px;
margin-top: 3px;
font-size: 11px;
font-weight: normal;
}
.user-panel > .info > a > .fa,
.user-panel > .info > a > .ion,
.user-panel > .info > a > .glyphicon {
margin-right: 3px;
}
.user-panel .info .title{
font-style: 16px;
}
.user-panel .info .description{
font-size: 12px;
color: #999;
}
.typeahead,
.tt-query,
.tt-hint {
width: 300px;
height: 30px;
padding: 8px 12px;
font-size: 16px;
border: 2px solid #ccc;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
outline: none;
}
.typeahead {
background-color: #fff;
}
.typeahead:focus {
border: 2px solid #0097cf;
}
.tt-query {
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
-moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
}
.tt-hint {
color: #999
}
.tt-menu {
width: 300px;
margin: 12px 0;
padding: 8px 0;
background-color: #fff;
border: 1px solid #ccc;
border: 1px solid rgba(0, 0, 0, 0.2);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
-webkit-box-shadow: 0 5px 10px rgba(0,0,0,.2);
-moz-box-shadow: 0 5px 10px rgba(0,0,0,.2);
box-shadow: 0 5px 10px rgba(0,0,0,.2);
}
.tt-suggestion {
padding: 3px 20px;
font-size: 18px;
line-height: 24px;
}
.tt-suggestion:hover {
cursor: pointer;
color: #fff;
background-color: #0097cf;
}
.tt-suggestion.tt-cursor {
color: #fff;
background-color: #0097cf;
}
.tt-suggestion p {
margin: 0;
}
svg .n1, svg .n2, svg .n3{
cursor: pointer;
}
.n2 text{
font-size: 0.8em;
}
</style>
</head>
<body>
<div id="network-grap-container" style="width:800px;margin: 0 auto;">
<div id="the-basics">
<input class="typeahead" type="text" placeholder="Search">
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.2.0/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"></script>
<script type="text/javascript">
var NetworkGraph = (function () {
var NG = {
canvas: null,
store: [],
init: init
};
var dimension = 650,zoom;
function setupCanvas() {
zoom = d3.behavior.zoom()
.scaleExtent([1, 8])
.on("zoom", zoomed);
NG.canvas = d3.select("#network-grap-container")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.call(zoom)
.append("g")
.attr("class", ".canvas")
}
function setUpPathHighlighter() {
NG.highlighter = NG.canvas.append("path")
.attr("stroke", "#9467bd")
.attr("stroke-width", "6")
.attr("fill", "none")
.style("visibility", "hidden");
}
function zoomed() {
var t = d3.event.translate,
s = d3.event.scale;
t[0] = Math.min(dimension / 2 * (s - 1), Math.max(dimension / 2 * (1 - s), t[0]));
t[1] = Math.min(dimension / 2 * (s - 1) + 230 * s, Math.max(dimension / 2 * (1 - s) - 230 * s, t[1]));
zoom.translate(t);
NG.canvas.attr("transform", "translate(" + t + ")scale(" + s + ")");
}
function hexagonPath() {
return d3.svg.line()
.x(function (d) {
return d.x;
})
.y(function (d) {
return d.y;
})
.interpolate("cardinal-closed")
.tension(1);
}
function drawHexagon(hexagonCorners) {
NG.canvas.append("path")
.attr("d", hexagonPath()(hexagonCorners))
.attr("stroke", "#FFC107")
.attr("stroke-width", 2)
.attr("fill", "none");
hexagonCorners.forEach(function (d) {
NG.canvas.append("path")
.attr("d", "M " + d.x + " " + d.y + " L " + dimension / 2 + " " + dimension / 2)
.attr("stroke", "#FFC107")
.attr("stroke-dasharray", "5,5")
.attr("stroke-width", 1)
.attr("class", "hexagon-path")
})
}
function setUpN1Container() {
var hexagonCorners = getHexagonPath();
this.attr("class", "n1-container")
.attr("x", function (d, i) {
var corner = hexagonCorners[i];
return corner.x;
})
.attr("y", function (d, i) {
var corner = hexagonCorners[i];
return corner.y;
})
.attr("transform", function (d, i) {
var corner = hexagonCorners[i];
d.path = [dimension / 2, dimension / 2, corner.x, corner.y];
NG.store.push({
name: d.name,
path: [dimension / 2, dimension / 2, corner.x, corner.y].join(',')
});
return "translate(" + corner.x + "," + corner.y + ")";
})
.attr("pathXY", function (d, i) {
return d.path.join(',');
})
}
function drawNetwork(_data) {
var hexagonCorners = getHexagonPath();
drawHexagon(hexagonCorners);
var n1Container = NG.canvas
.selectAll(".n1-container")
.data(_data.children)
.enter()
.append("g")
.call(setUpN1Container);
n1Container.call(drawN1);
var n2N3Container = n1Container
.selectAll(".n2-n3-container")
.data(function (d, i) {
return d.children.map(function (c) {
c.l = d.children.length;
return c;
});
})
.enter()
.append("g")
n2N3Container.call(setUpN2N3Container)
n2N3Container.each(drawN3);
n2N3Container.call(drawN2);
drawRootNode(_data);
NG.events.onLoad();
}
function setUpN2N3Container(){
this.attr("class", "n2-n3-container")
.attr("pathXY", function (d, i) {
var parent = d3.select(this.parentNode);
d.dx = NG.n1LoopScale(dimension) * Math.cos(2 * Math.PI * i / d.l);
d.dy = NG.n1LoopScale(dimension) * Math.sin(2 * Math.PI * i / d.l);
d.path = [parent.attr("pathXY"),
parseInt(parent.attr("x")) + parseInt(d.dx),
parseInt(parent.attr("y")) + parseInt(d.dy)].join(',');
NG.store.push({
name: d.name,
path: d.path
});
return d.path;
})
.attr("x", function (d, i) {
return d.dx;
})
.attr("y", function (d, i) {
return d.dy;
})
.transition()
.duration(1000)
.attr("transform", function (d, i) {
var parent = d3.select(this.parentNode);
d.path = [parent.attr("pathXY"), parseInt(parent.attr("x")) + d.dx, parseInt(parent.attr("y")) + d.dy].join(',');
NG.store.push({
name: d.name,
path: d.path
});
return "translate(" + d.dx + "," + d.dy + ")";
})
}
function drawN3(d) {
var _that = this;
if (d.children) {
var spaceScale = d3.scale.linear()
.range([0, 70])
.domain([1, 6]),
l = d.children.length,
theta = Math.atan2(d.dy, d.dx) * 180 / Math.PI,
degree = theta > 0 ? 360 - theta : Math.abs(theta),
degreeScale = d3.scale.linear()
.range([degree + spaceScale(l), degree - spaceScale(l)])
.domain([0, l - 1]);
d.children.forEach(function (d, i) {
d.cx = 35 * Math.cos(degreeScale(i) * (Math.PI / 180))
d.cy = -(35 * Math.sin(degreeScale(i) * (Math.PI / 180)))
});
d3.select(_that)
.selectAll(".n3-branch")
.data(d.children)
.enter()
.append("path")
.attr("class", "n3-branch")
.attr("stroke", "#F64F22")
.attr("stroke-width", 1)
.attr("d", function (d, i) {
return "M 0 0 L " + d.cx + " " + d.cy
})
var n3 = d3.select(_that)
.selectAll(".n3")
.data(d.children)
.enter()
.append("g")
.attr("class", "n3")
.attr("transform", function (b, i) {
var parent = d3.select(this.parentNode);
var grandParent = d3.select(this.parentNode.parentNode);
b.path = [parent.attr("pathXY"), parseInt(grandParent.attr("x")) + parseInt(parent.attr("x")) + b.cx, parseInt(grandParent.attr("y")) + parseInt(parent.attr("y")) + b.cy].join(',');
NG.store.push({
name: b.name,
path: b.path
});
return "translate(" + b.cx + "," + b.cy + ")";
})
.attr("pathXY", function (d, i) {
return d.path;
})
.attr("x", function (d, i) {
return d.cx;
})
.attr("y", function (d, i) {
return d.cy;
})
n3.append("circle")
.attr('fill', '#AFD097')
.attr('r', 8)
n3.append('text')
.attr("text-anchor", "middle")
.attr("fill", "white")
.attr("dy", ".3em")
.attr("font-size", "5")
.text(function (d, i) {
return initials(d.name)
});
}
}
function drawN2() {
var n2 = this
.append("g")
.attr("class", "n2");
n2.append("circle")
.attr('r', NG.n2RadiusScale(dimension))
.attr('fill', '#F64F22')
n2.append('text')
.attr("text-anchor", "middle")
.attr("fill", "white")
.attr("dy", ".3em")
.text(function (d, i) {
return initials(d.name)
});
n2.on('click', function () {
var parent = d3.select(this.parentNode),
path = parent.selectAll('path'),
lastNode = parent.selectAll('.n3');
lastNode
.style('visibility', lastNode.style('visibility') == 'hidden' ? 'visible' : 'hidden');
path
.style('visibility', path.style('visibility') == 'hidden' ? 'visible' : 'hidden');
})
}
function drawN1() {
var n1Container = this;
var n1 = n1Container
.append("g")
.attr("class", "n1")
.attr("expanded", 'true')
.on('click', function () {
var sn = d3.select(this.parentNode)
.selectAll('.n2-n3-container,.n1-loop,.n3-branch,.n3');
var expanded = d3.select(this).attr('expanded') == 'true'
sn.style('visibility', expanded ? 'hidden' : 'visible')
d3.select(this).attr('expanded', !expanded)
})
n1.append("circle")
.attr("r", NG.n1RadiusScale(dimension))
.attr("fill", "#23B3F4")
n1.append("text")
.attr("text-anchor", "middle")
.attr("fill", "white")
.attr("dy", ".3em")
.text(function (d, i) {
return initials(d.name)
})
n1Container
.append("circle")
.attr("class", "n1-loop")
.attr("fill", "none")
.attr("stroke", "#23B3F4")
.attr("stroke-dasharray", "3,3")
.transition()
.delay(700)
.attr('r', NG.n1LoopScale(dimension))
}
function drawRootNode(_data) {
var rootNode = NG.canvas.selectAll(".root-node")
.data([_data])
.enter()
.append("g")
.attr("class", "root-node")
.attr("transform", function (d) {
return "translate(" + dimension / 2 + "," + dimension / 2 + ")";
})
rootNode.append("circle")
.attr("r", " 30")
.attr("fill", "#FFC107")
rootNode.append("text")
.attr("text-anchor", "middle")
.attr("fill", "white")
.attr("dy", ".3em")
.text(initials(_data.name))
}
function getHexagonPath(config) {
var radius = dimension / 3,
xp = dimension / 2,
yp = xp,
h = (Math.sqrt(3) / 2);
return [
{"x": radius + xp, "y": yp},
{"x": radius / 2 + xp, "y": radius * h + yp},
{"x": -radius / 2 + xp, "y": radius * h + yp},
{"x": -radius + xp, "y": yp},
{"x": -radius / 2 + xp, "y": -radius * h + yp},
{"x": radius / 2 + xp, "y": -radius * h + yp}];
}
function highlight(node) {
if (node) {
NG.highlighter
.attr("d", "M " + node.path)
.style("visibility", "visible")
} else {
NG.highlighter
.style("visibility", "hidden")
}
}
function setDispatcher(config) {
if (config.events) {
NG.events = d3.dispatch(Object.keys(config.events).join(','));
Object.keys(config.events).forEach(function (event) {
NG.events.on(event, config.events[event]);
});
}
}
function setUpScales(config) {
var svgWidth = parseInt(d3.select(NG.canvas.node().parentNode).style('width'))
NG.n1LoopScale = d3.scale.linear().domain([400, Math.max(config.dimension || svgWidth, svgWidth)]).range([30, 70])
NG.n1RadiusScale = d3.scale.linear().domain([400, svgWidth]).range([15, 20]);
NG.n2RadiusScale = d3.scale.linear().domain([400, svgWidth]).range([10, 15]);
}
function init(config) {
dimension = config.dimension || dimension;
setDispatcher(config)
setupCanvas();
setUpScales(config)
setUpPathHighlighter();
drawNetwork(config.data);
}
function initials(name) {
var regex = /(\b[a-zA-Z0-9])[a-zA-Z0-9]* ?/g,
matches,
output = [];
while (matches = regex.exec(name)) {
output.push(matches[1]);
}
return output.join('');
}
return {
init: init,
highlight: highlight,
getStore: function () {
return NG.store;
}
};
}());
var SearchSuggestions = {};
(function(search){
search.init = init;
function init(){
var substringMatcher = function(strs) {
return function findMatches(q, cb) {
var matches, substringRegex,substrRegex;
// an array that will be populated with substring matches
matches = [];
// regex used to determine if a string contains the substring `q`
substrRegex = new RegExp(q, 'i');
// iterate through the pool of strings and for any string that
// contains the substring `q`, add it to the `matches` array
$.each(strs, function(i, str) {
if (substrRegex.test(str.name)) {
matches.push(str);
}
});
cb(matches);
};
};
$('#the-basics .typeahead').typeahead({ hint: true,
highlight: true,
minLength: 1},
{
source: substringMatcher(NetworkGraph.getStore()),
display : 'name'
})
.bind('typeahead:select', function(ev, suggestion) {
NetworkGraph.highlight(suggestion);
console.log( suggestion.name,'Selection: ' + suggestion.path);
})
.bind('keyup', function(){
if($(this).val() == ''){
NetworkGraph.highlight(false);
}
})
}
}(SearchSuggestions));
var Tooltip = {};
(function(tooltip){
tooltip.init = init;
tooltip.supplant = supplant;
function supplant(template, o) {
return template.replace(/{([^{}]*)}/g,
function (a, b) {
var r = o[b];
return typeof r === 'string' || typeof r === 'number' ? r : a;
}
);
}
function init(){
var tooltipMarkUp = d3.select("body")
.append("div")
.attr("class","tip")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden");
var template = document.getElementById('tooltip-template').innerHTML;
d3.selectAll(".root-node,.n1,.n2,.n3")
.on("mouseover", function (d) {
tooltipMarkUp.html(tooltip.supplant(template, d));
return tooltipMarkUp.style("visibility", "visible");
})
.on("mousemove", function () {
return tooltipMarkUp.style("top", (d3.event.pageY - 10) + "px").style("left", (d3.event.pageX + 10) + "px");
})
.on("mouseout", function () {
return tooltipMarkUp.style("visibility", "hidden");
});
}
}(Tooltip));
d3.json("https://gist.github.com/binary10ve/1eef742d6c821a8f1d1920263ec1b18a", function (data) {
NetworkGraph.init({
data : data,
dimension : 650,
events : {
onLoad : function(){
Tooltip.init();
SearchSuggestions.init();
}
}
});
});
</script>
<script type="text/x-template" id="tooltip-template">
<div class="user-panel">
<div class="pull-left image">
<img src="../../img/avatar3.png" class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
<p class="title">{name}</p>
<div class="description">
<p>ceaser.umbre@xyz.com</p>
<p>8805670639</p>
<p>Commission Earned : $100</p>
<p>Expected Commission : $100</p>
</div>
</div>
</div>
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment