Skip to content

Instantly share code, notes, and snippets.

@ne8il
Last active December 15, 2015 01:59
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 ne8il/5184165 to your computer and use it in GitHub Desktop.
Save ne8il/5184165 to your computer and use it in GitHub Desktop.
D3 Example 5 : Transitions! Exits!

Going overboard on features

<!DOCTYPE html>
<meta charset="utf-8">
<head>
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
padding:20px;
position: relative;
}
ul {
list-style: none;
}
.peopleDiv {
display:inline-block;
position:relative;
height:30px;
line-height:30px;
width:100px;
text-align:center;
}
svg {
padding:20px;
}
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
#formArea {
border:1px solid #c3c3c3;
background-color:#f1f1f1;
border-radius:5px;
width:200px;
padding:10px;
margin:10px;
float:left;
height:240px;
}
#formArea input{
display:block;
margin: 10px 0px;
}
button {
border:1px solid #a3a3a3;
background-color:#d3d3d3;
padding:5px;
width:100px;
border-radius:10px;
cursor: pointer;
}
button:hover {
background-color:#c3c3c3;
}
button:active {
background-color:#a3a3a3;
}
</style>
</head>
<body>
<div id="svgArea"></div>
<div class="forms">
<div id="formArea">
<ul>
<li><label>Name<input type="text" id="nameInput"/></label></li>
<li><label>Weight<input type="number" min="100" max="500" id="weightInput"/></label></li>
<li><label>Color<input type="color" id="colorInput"/></label></li>
<li> <button id="addButton">Add</button></li>
</ul>
</div>
<div id="formArea">
<ul>
<li><label>Name<select id="removeSelect"/>
</select></label></li>
<li> <button id="removeButton">Remove</button></li>
</ul>
</div>
<div id="formArea">
<ul>
<li> <button id="shuffleButton">Shuffle</button></li>
<li> <button id="ascButton">Ascending</button></li>
<li> <button id="descButton">Descending</button></li>
</ul>
</div>
</div>
</body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var people = [{'name' : 'Frank', 'color' : 'blue', 'weight' : 180},
{'name' : 'Tom', 'color' : 'red', 'weight' : 230},
{'name' : 'Peter', 'color' : 'green', 'weight' : 190},
{'name' : 'Mary', 'color' : 'purple', 'weight' : 150}];
var chartWidth = 800,
chartHeight = 250,
padding = 30,
duration = 1000; //transition length (in ms)
var svg = d3.select('#svgArea')
.append('svg')
.attr('width', chartWidth)
.attr('height', chartHeight);
/*
* Append our axis groups before rendering chart
*/
var yAxisGroup = svg.append("g")
.classed('axis', true)
.classed('y-axis', true)
.attr("transform", "translate(" + padding + ",0)")
var xAxisGroup = svg.append("g")
.classed('axis', true)
.attr('transform', 'translate(' + padding + ', ' + chartHeight + ')');
var buildChart = function(){
/** SCALES */
var min = d3.min(people, function(d){return d['weight']});
var max = d3.max(people, function(d){return d['weight']});
var yScale = d3.scale.linear()
.domain([0, max])
.rangeRound([0, chartHeight]);
//populate an array of names to use for our ordinal scale
var nameCats = people.map(function(d){ return d['name']});
var xScale = d3.scale.ordinal()
.domain(nameCats)
.rangeBands([0, chartWidth]);
var rect = svg.selectAll("rect")
.data(people, function(d) {
return d['name']
});
var xAxis = d3.svg.axis()
.scale(xScale)
.orient('bottom');
xAxisGroup
.transition()
.duration(duration)
.call(xAxis);
rect.enter()
.insert('rect')
.classed('chartBlock', true)
.style('fill', function(d){
return d['color']
})
.attr('x', function(d, i){
return xScale(d['name']) - .5 + 2.5 + padding;
})
.attr('y', function(d){
return (chartHeight - yScale(d['weight']))
})
.attr('height', function(d){
return yScale(d['weight']);
})
.attr('width', chartWidth / people.length - 5);
//remove anything we've deleted
rect.exit()
.remove();
//when transitioning, we don't have to worry about the color
//but everything else could have changed
rect.transition()
.duration(duration)
.attr("x", function(d, i) {
return xScale(d['name']) - .5 + 2.5 + padding;
})
.attr('y', function(d){
return (chartHeight - yScale(d['weight']))
})
.attr('height', function(d){
return yScale(d['weight']);
})
.attr('width', chartWidth / people.length - 5);
var yAxisScale = d3.scale.linear()
.domain([0, max])
.rangeRound([chartHeight, 0]);
var yAxis = d3.svg.axis()
.scale(yAxisScale)
.orient('left')
.ticks(10);
yAxisGroup.transition()
.duration(duration)
.call(yAxis);
}
/** Event Handlers and Functions */
/**
* Add person to chart
* Name is required
*/
var addPerson = function(){
var nameInput = d3.select('#nameInput').node();
var weightInput = d3.select('#weightInput').node();
var colorInput = d3.select('#colorInput').node();
if(nameInput.value == '') return;
var weight = Math.min(Math.max(weightInput.value, 100), 500);
var newPerson = {
'name' : nameInput.value,
'color' : colorInput.value,
'weight' : weight
}
people.push(newPerson);
populateRemoveSelect();
//clear out inputs
nameInput.value = '';
weightInput.value = '';
colorInput.value = '';
//refresh chart
buildChart();
}
/**
* remove selected person
*/
var removePerson = function(){
var removeInput = d3.select('#removeSelect').node();
var name = removeInput.value;
//easiest way to splice this person out
people = people.filter(function(person){
return person['name'] != name;
});
populateRemoveSelect();
buildChart();
}
/**
* Fills in remove select with our names
*/
var populateRemoveSelect = function(){
var removeInput = d3.select('#removeSelect').node();
//clear existing options
removeInput.options.length = 0;
people.forEach(function(name){
var display = name['name'];
removeInput.add(new Option(display, display));
});
}
/**
* Randomly shuffles our people and rebuilds chart
*/
var shuffle = function(){
sortAndBuild(function(a, b){
var chance = !!Math.round(Math.random() * 1);
return chance ? 1 : -1;
});
}
/**
* sort in ascending order
*/
var asc = function(){
sortAndBuild(function(a, b){
return a['weight'] > b['weight'];
});
}
/**
* Randomly shuffles our people and rebuilds chart
*/
var desc = function(){
sortAndBuild(function(a, b){
return a['weight'] < b['weight'];
});
}
var sortAndBuild = function(sortFunction){
people.sort(sortFunction);
populateRemoveSelect();
buildChart();
}
//event listener to add a new person
d3.select('#addButton')
.on('click', addPerson);
d3.select('#removeButton')
.on('click', removePerson);
d3.select('#shuffleButton')
.on('click', shuffle);
d3.select('#ascButton')
.on('click', asc);
d3.select('#descButton')
.on('click', desc);
populateRemoveSelect();
//initial render of chart
buildChart();
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment