Skip to content

Instantly share code, notes, and snippets.

@denjn5
Last active September 23, 2017 20:14
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 denjn5/c27756b9fdadfa1a6490578331596906 to your computer and use it in GitHub Desktop.
Save denjn5/c27756b9fdadfa1a6490578331596906 to your computer and use it in GitHub Desktop.
Animated Sticky Note Hierarchy
license: gpl-3.0
height: 600
border: no
id parentId round
cars 1
owned cars 1
pilot owned 1
325ci owned 1
accord owned 1
traded cars 1
chevette traded 1
learned cars 1
odyssey learned 1
maxima learned 1
trailers are heavy odyssey 3
left turns can be dangerous maxima 3
<!DOCTYPE html>
<meta charset='utf-8'>
<head>
<title>Animated Sticky Note Hierarchy</title>
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<style>
rect.main {
stroke: #05668D;
fill: white;
stroke-width: 2px;
}
rect.second {
fill: white;
opacity: 0;
}
path {
fill: none;
stroke: #05668D;
stroke-width: 2px;
}
text {
font-family: "Comic Sans MS", Verdana, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
font-size: 12px;
fill: black;
}
</style>
<button id="phase">Next</button>
<svg>
<g></g>
</svg>
<script>
var vWidth = 350;
var vHeight = 600;
var vRad = 25;
var vColor = ['#feff9c', '#7afcff', '#ff7eb9'];
var vRects;
var vLines;
var vPhase = 1;
// Prepare our physical space
var g = d3.select('svg').attr('width', vWidth).attr('height', vHeight)
.select('g').attr('transform', 'translate(40, 20)');
// Declare d3 layout
var vLayout = d3.tree().size([vHeight * 0.9, vWidth * 0.7]);
// Get the data from our JSON file
d3.csv('data.csv', function(error, vCsvData) {
if (error) throw error;
vCsvData = vCsvData.filter( function(node) { return node.round === "1"; });
vData = d3.stratify()(vCsvData);
drawTree(vData);
});
/**
* Draw our sunburst
* Time: 0
* @param {object} data - Hierarchical data
*/
function drawTree(data) {
// Layout + Data
var vRoot = d3.hierarchy(data);
var vNodes = vRoot.descendants();
var vLinks = vLayout(vRoot).links();
// Draw on screen
vLines = g.selectAll('path').data(vLinks).enter().append('path')
.attr('d', d3.linkHorizontal()
.x(function(d) { return d.y; })
.y(function(d) { return d.x; }));
// Add <g>s
vRects = g.selectAll('g').data(vNodes).enter().append('g')
.attr('transform', function (d) { return 'translate(' + (d.y - vRad) + ',' + (d.x - vRad) + ')'; });
// Draw <rect>s
vRects.append('rect').attr('class','main').attr('width', vRad * 2).attr('height', vRad * 2)
.attr('rx', vRad)
.attr('transform', 'rotate(5)')
.each( function(d) { d.data.color = vColor[d.depth]});
}
/**
* Animation 1: Move from tree diagram to sticky notes in tree shape
* End: 2500 (vDelay + (2 * vDuration))
*/
function animateTree1() {
var vDelay = 250;
var vDuration = 1000;
// Clear lines
vLines.transition().delay(vDelay).duration(vDuration * 2).style('opacity', 0);
// Circles to sticky notes
vRects.selectAll('rect.main')
.transition().delay( function(d) { return ripple(vDelay, d.depth); }).duration(vDuration)
.attr('rx', 0).attr('width', vRad * 2).attr('height', vRad * 2).style('fill', function(d) { return d.data.color; })
.style('stroke', function(d) { return d.data.color; }).style('opacity', 1);
// Add <text>s and labels
vRects.append('text')
.attr('text-anchor', 'middle')
.attr("dominant-baseline", "central")
.attr('transform', function (d) { return 'translate(' + (vRad - 3) + ',' + vRad + ')'; })
.text(function(d) { return d.data.id }).style('opacity', 0)
.transition().delay( function(d) { return ripple(vDelay, d.depth); }).duration(vDuration)
.style('opacity', 1);
}
/**
* Animation 2: Move from sticky notes in tree shape to sticky notes in tabular shape
* End:
*/
function animateTree2() {
var vDelay = 250; // 3000;
var vDuration = 1000;
vRad = 25;
// Move <g>s to Tabular Location
vRects.transition().delay(vDelay).duration(vDuration)
.attr('transform', function(d, i) { return 'translate(40, ' + (i * 50 + 15) + ')'; } );
vRects.selectAll('.main').transition().delay(vDelay).duration(vDuration)
.attr('width', vRad * 2).attr('height', vRad * 2);
// Add 2nd column of <rect>s
vRects.append('rect').attr('class', 'second')
.attr('transform', function (d) { return 'translate(60, 0) rotate(5)'; })
.attr('width', vRad * 2).attr('height', vRad * 2).attr('rx', vRad).attr('rx', 0)
.transition().delay( function(d) { return ripple(vDelay, d.depth); }).duration(vDuration)
.style('fill', function(d) { return d.parent ? d.parent.data.color : 'white'; })
.style('stroke', function(d) { return d.parent ? d.parent.data.color : 'white'; })
.style('opacity', 1);
// Add 2nd column <text>s
vRects.append('text').attr('class', 'second')
.attr('text-anchor', 'middle')
.attr("dominant-baseline", "central")
.attr('transform', function (d) { return 'translate(' + (57 + vRad) + ', ' + vRad + ')'; })
.text(function(d) { return d.parent ? d.parent.data.id : ''; }).style('opacity', 0)
.transition().delay( function(d) { return ripple(vDelay, d.depth); }).duration(vDuration)
.style('opacity', 1);
// Add labels at top
g.append('text').attr('text-anchor', 'middle').attr('class', 'second')
.attr('transform', function (d) { return 'translate(65, 0)'; })
.transition().delay(vDelay).text('id');
g.append('text').attr('text-anchor', 'middle').attr('class','second')
.attr('transform', function (d) { return 'translate(130, 0)'; })
.transition().delay(vDelay).text('parentId');
}
/**
* Animation 3: Get back to our original tree diagram
*/
function resetTree() {
var vDelay = 250; // 6000;
var vDuration = 1000;
vRad = 30;
vLines.transition().delay(vDelay * 3).duration(vDuration).style('opacity', 1);
vRects.transition().delay( function(d) { return ripple(vDelay, d.depth); }).duration(vDuration)
.attr('transform', function (d) { return 'translate(' + (d.y - vRad) + ',' + (d.x - vRad) + ')'; })
.selectAll('rect').attr('rx', vRad)
.style('fill', 'white')
.style('stroke', '#05668D').style('opacity', 1);
vRects.selectAll('.second').transition().delay(vDelay).duration(vDuration).style('opacity', 0);
d3.selectAll('text').transition().delay(vDelay).duration(vDuration).style('opacity', 0);
}
function ripple(baseDelay, groupNumber) {
return ((groupNumber + 1) * 250) + baseDelay;
}
d3.select('button#phase').on('click', function() {
switch (vPhase) {
case 1:
animateTree1();
vPhase = 2;
break;
case 2:
animateTree2();
vPhase = 3;
break;
case 3:
resetTree();
vPhase = 1;
break;
}});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment