Skip to content

Instantly share code, notes, and snippets.

@micahstubbs
Last active March 27, 2016 22:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save micahstubbs/0d74dca6457cacee52e6 to your computer and use it in GitHub Desktop.
Save micahstubbs/0d74dca6457cacee52e6 to your computer and use it in GitHub Desktop.
custom tree layout sketch
license: CC0-1.0
height: 1440
border: no

an artisan hand-coded sketch of a custom tree layout. this very likely could be shaped into a proper custom tree layout that would be useful for the deeper tree structures found in wild-caught data.

based on a bespoke felt-marker-on-graph-paper design, reproduced below.

sketch

further research may lead to an bl.ock that builds on these examples:

Pedigree Tree "Elbow" Dendrogram Variable Offset Animated Links Tree Layout Orientations

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>custom tree layout sketch</title>
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
<style>
</style>
</head>
<body>
<script>
// Extract the width and height that was computed by CSS.
var chartDiv = document.getElementById("vis");
var width = 960;
var height = 1440;
var nodeRadius = 6;
var linkWidth = '3px';
// Use the extracted size to set the size of an SVG element.
var svg = d3.select('body').append("svg")
.attr("width", width)
.attr("height", height);
var background = svg.append('rect')
.classed('background', true)
.attr({
'x': 0,
'y': 0,
'rx': 10,
'ry': 10,
'height': height,
'width': width
})
.style({
'fill': '#EEF1F6',
'stroke': 'gray',
'stroke-width': '0px'
});
var nodes = [
{
'id': 0,
'x': 75,
'y': 75
},
{
'id': 1,
'x': 885,
'y': 72
},
{
'id': 2,
'x': 885,
'y': 247
},
{
'id': 3,
'x': 885,
'y': 840
},
{
'id': 4,
'x': 885,
'y': 1014
},
{
'id': 5,
'x': 885,
'y': 1189
},
{
'id': 6,
'x': 885,
'y': 1363
},
{
'id': 7,
'hidden': true,
'x': 308,
'y': 75
},
{
'id': 8,
'hidden': true,
'x': 308,
'y': 247
}
];
/////////////////////////////////////////////////////////////////////////////////
///// draw the hidden nodes /////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
// do this first, so that our hiddden nodes
// ghost circles appear below our link paths
d3.select('svg').selectAll('.hiddenNodes')
.data(nodes.filter(function(d) {
return d.hidden === true;
}))
.enter()
.append('g')
.classed('hiddenNodes', true)
.classed('nodes', true)
.append('circle')
.attr('r', nodeRadius)
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.style({
'fill': '#CFD7E6',
'fill-opacity': .8
});
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
var links = [
{
'source': 7,
'target': 8,
'color': '#7F8DE1',
'id': 0
},
{
'source': 8,
'target': 2,
'color': '#7F8DE1',
'id': 1
},
{
'source': 0,
'target': 1,
'color': '#4BC076',
'id': 2
},
{
'source': 0,
'target': 3,
'color': '#F88962',
'id': 3
},
{
'source': 0,
'target': 4,
'color': '#F88962',
'id': 4
},
{
'source': 0,
'target': 5,
'color': '#F88962',
'id': 5
},
{
'source': 0,
'target': 6,
'color': '#EF7EAD',
'id': 6
}
]
/////////////////////////////////////////////////////////////////////////////////
////// draw the links ///////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
d3.select('svg').selectAll('.links')
.data(links)
.enter()
.append('g')
.classed('links', true)
.append('path')
.attr('d', function(d) {
return generateLinkPath(d);
})
.style('stroke', function(d) {
return d.color;
})
.style('stroke-width', linkWidth)
.style({
'fill': 'none',
'stroke-linecap': 'square'
})
function generateLinkPath(link) {
// a d3 path generator to draw a nice
// bezier curve
var bezierCurve = d3.svg.line()
.x(function(d) { return d[0]; })
.y(function(d) { return d[1]; })
.interpolate('basis');
var sourceId = link['source'];
var targetId = link['target'];
var xS = nodes[sourceId]['x'];
var yS = nodes[sourceId]['y'];
var xT = nodes[targetId]['x'];
var yT = nodes[targetId]['y'];
switch (link.id) {
case 6:
return bezierCurve([
[xS, yS],
[Math.abs(xS-.6*xT), Math.abs(yS-yT)],
[xT, yT]
]);
default:
var path = 'M ' + xS + ' ' + yS + ' ' + xT + ' ' + yT;
return path;
}
}
/////////////////////////////////////////////////////////////////////////////////
///// draw the nodes ////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
// do this second, so that our node circles appear
// above our link paths
d3.select('svg').selectAll('.visibleNodes')
.data(nodes.filter(function(d) {
return d.hidden == undefined;
}))
.enter()
.append('g')
.classed('visibleNodes', true)
.classed('nodes', true)
.append('circle')
.attr('r', nodeRadius)
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.style({'fill': '#00396B'});
/////////////////////////////////////////////////////////////////////////////////
// draw the labels for the nodes ////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
d3.selectAll('.nodes')
.append('text')
.attr('x', function(d) {
return d.x;
})
.attr('y', function(d) {
return d.y;
})
.attr('dx', function(d) {
if(d.id === 0) return '-1.2em';
if(d.id === 7) return '-.25em';
if(d.id === 8) return '.35em';
return '.7em';
})
.attr('dy', function(d) {
if(d.id === 7) return '-.5em';
if(d.id === 8) return '-.35em';
return '.35em';
})
.style('stroke', 'none')
.style('fill', '#A7B8D1')
.text(function(d) { return d.id });
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment