Skip to content

Instantly share code, notes, and snippets.

@1wheel
Last active August 22, 2016 02:25
Show Gist options
  • Save 1wheel/d8994223339c9b546bf0 to your computer and use it in GitHub Desktop.
Save 1wheel/d8994223339c9b546bf0 to your computer and use it in GitHub Desktop.
tier-layout
{
"tiers": [
{"id": "TierI"},
{"id": "TierII"},
{"id": "TierIII"},
{"id": "TierVI"}
],
"groups": [
{"id": "gA", "tier": "TierI"},
{"id": "gB", "tier": "TierI"},
{"id": "gC", "tier": "TierII"},
{"id": "gD", "tier": "TierIII"},
{"id": "gE", "tier": "TierIII"},
{"id": "gF", "tier": "TierIII"},
{"id": "gG", "tier": "TierVI"},
{"id": "gH", "tier": "TierVI"}
],
"nodes": [
{"id": "n2", "group": "gA"},
{"id": "n3", "group": "gA"},
{"id": "n4", "group": "gA"},
{"id": "n5", "group": "gB"},
{"id": "n6", "group": "gB"},
{"id": "n7", "group": "gC"},
{"id": "n8", "group": "gC"},
{"id": "n9", "group": "gC"},
{"id": "n10", "group": "gC"},
{"id": "n11", "group": "gD"},
{"id": "n12", "group": "gD"},
{"id": "n13", "group": "gD"},
{"id": "n14", "group": "gD"},
{"id": "n15", "group": "gD"},
{"id": "n16", "group": "gD"},
{"id": "n17", "group": "gD"},
{"id": "n18", "group": "gD"},
{"id": "n19", "group": "gD"},
{"id": "n20", "group": "gE"},
{"id": "n21", "group": "gF"},
{"id": "n22", "group": "gF"},
{"id": "n23", "group": "gF"},
{"id": "n24", "group": "gF"},
{"id": "n25", "group": "gG"},
{"id": "n26", "group": "gG"},
{"id": "n27", "group": "gG"},
{"id": "n28", "group": "gH"},
{"id": "n29", "group": "gH"}
],
"links":[
{"source": "gA", "target": "gB"},
{"source": "gA", "target": "gC"},
{"source": "gB", "target": "gC"},
{"source": "gH", "target": "gF"},
{"source": "gH", "target": "gG"},
{"source": "gH", "target": "gE"},
{"source": "gD", "target": "gE"},
{"source": "gD", "target": "gC"}
]
}
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
position: relative;
margin: 0px auto;
color: rgb(105, 104, 104);
}
text{
fill: rgb(61, 61, 61);
}
.group-circle{
fill: white;
}
.node-circle{
stroke: darkgrey;
fill: lightgrey;
}
.group-text{
text-shadow: 0 3px 0 #fff, 3px 0 0 #fff, 0 -3px 0 #fff, -3px 0 0 #fff;
}
.link{
fill: none;
stroke: black;
stroke-width: 3px;
}
</style>
<body></body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
<script src="script.js"></script>
function f(str){ return function(obj){ return obj[str] }}
var width = 960,
height = 800
var margin = {top: 50, right: 10, bottom: 20, left: 100}
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
// svg.append('defs').append('marker')
// .attr({id: 'arrow', markerWidth: 13, marketHeight: 13, refx: 2, refy: 7, orient: 'auto'})
// .append('path')
// .attr('d', "M2,2 L2,13 L8,7 L2,2")
var svgBB = svg.node().getBoundingClientRect()
var linkG = svg.append('g')
d3.json('data.json', function(data){
var tiers = data.tiers,
groups = data.groups,
nodes = data.nodes,
links = data.links,
allIds = tiers.concat(groups).concat(nodes)
d3.nest()
.key(f('tier'))
.entries(groups)
.forEach(function(d){
var tier = _.findWhere(tiers, {id: d.key})
tier.values = d.values
tier.values.forEach(function(d){ d.tier = tier })
})
d3.nest()
.key(f('group'))
.entries(nodes)
.forEach(function(d){
var group = _.findWhere(groups, {id: d.key})
group.values = d.values
var root = Math.ceil(Math.sqrt(group.values.length))
group.values.forEach(function(d, i){
d.group = group
d.x = (i % root)*24
d.y = Math.floor(i/root)*24
})
})
links.forEach(function(d){
d.src = _.findWhere(allIds, {id: d.source})
d.tgt = _.findWhere(allIds, {id: d.target})
})
tiers.concat(groups).forEach(function(d){ if (!d.values) d.values = [] })
var tierGs = svg.selectAll('.tier')
.data(tiers).enter()
.append('g')
.attr('transform', function(d, i){
return 'translate(0,' + i/tiers.length*height + ')' })
tierGs.append('text').classed('tier-text', true)
.text(f('id'))
.attr({'dy': '-1.3em', dx: '0', 'font-weight': 'bold', 'font-size': '120%'})
.call(saveEl)
var groupGs = tierGs.selectAll('g')
.data(f('values')).enter()
.append('g')
.attr('transform', function(d, i){
return 'translate(' + (1 + i)/(1 + d.tier.values.length)*width + ',0)' })
groupGs.append('circle')
groupGs.append('text').classed('group-text', true)
.text(f('id'))
.attr({'dy': '-1.3em', dx: '-30'})
.call(saveEl)
groupGs.selectAll('circle').classed('group-circle', true)
.attr('cx', function(d){ return d.sbb.x + d.sbb.width/2 })
.attr('cy', function(d){ return d.sbb.y + d.sbb.height/2 })
.attr('r', 18)
var nodeGs = groupGs.selectAll('g')
.data(f('values')).enter()
.append('g')
.attr('transform', function(d, i){
return 'translate(' + d.x + ',' + d.y + ')' })
nodeGs.append('circle').classed('node-circle', true)
.attr('r', 10)
nodeGs.append('text').classed('node-text', true)
.text(f('id'))
.attr({dy: '.33em', 'text-anchor': 'middle', 'font-size': '60%'})
.call(saveEl)
var links = linkG.selectAll('path')
.data(links).enter()
.append('path').classed('link', true)
.attr('d', function(d){
return ['M', d.src.p, 'L', d.tgt.p].join(' ')
//beziers?
// var yDiff = d.src.p[1] - d.tgt.p[1]
// var c1 = d.src.p.slice()
// var c2 = d.tgt.p.slice()
// c1[1] += yDiff/5;
// c2[1] -= yDiff/5*4;
// return ['M', d.src.p, 'C', c1, c2, d.tgt.p].join(' ')
})
function saveEl(sel){
sel.each(function(d){
d.sel = d3.select(this)
d.sbb = d.sel.node().getBBox()
d.bb = offsetBB(d.sel.node().getBoundingClientRect())
d.p = [d.bb.left + d.bb.width/2, d.bb.top + d.bb.height/2]
})
}
})
function offsetBB(bb){
var obj = {width: bb.width, height: bb.height, left: bb.left, top : bb.top}
obj.left -= svgBB.left
obj.top -= svgBB.top
return obj
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment