Skip to content

Instantly share code, notes, and snippets.

@olimay
Last active June 11, 2016 22:42
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 olimay/41d1fcacfd208263fa09b8d7db3273d0 to your computer and use it in GitHub Desktop.
Save olimay/41d1fcacfd208263fa09b8d7db3273d0 to your computer and use it in GitHub Desktop.
Bar Chart Example
license: mpl-2.0
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: A simple bar chart</title>
<script type="text/javascript" src="https://d3js.org/d3.v3.min.js"></script>
<style type="text/css">
rect:hover {
fill: orange;
}
#tooltip {
position: absolute;
width: 200px;
height: auto;
padding: 10px;
background-color: white;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
pointer-events: none;
}
#tooltip.hidden {
display: none;
}
#tooltip p {
margin: 0;
font-family: sans-serif;
font-size: 16px;
line-height: 20px;
}
</style>
</head>
<body>
<div class="graph">
<div id="tooltip" class="hidden">
<p><strong>Important Label Heading</strong></p>
<p><span id="value">100</span>%</p>
</div>
</div>
<div id="controls"></div>
<script type="text/javascript">
// Margins, width, height
var margin = { top: 0, bottom: 0, left: 0, right: 0 };
var w = 650 - margin.left - margin.right;
var h = 250 - margin.top - margin.bottom;
var barPadding = 1;
var dynamicData = function dynamicData (n, max) {
var data = [];
for (var i = 0; i < n; i++) {
data.push(Math.round(Math.random() * max));
}
return data;
}
var maxvalue = 100;
var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,
11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
// Transition defaults
var tinyDuration = 100;
var tinyDelay = 10;
var smallDuration = 500;
var smallDelay = 50;
var medDuration = 1000;
var medDelay = 100;
var longDuration = 2000;
var longDelay = 200;
var defaultDuration = tinyDuration;
var defaultDelay = tinyDelay;
//Create SVG element
var svg;
var createSVG = function () {
svg = d3.select('.graph')
.append('svg')
.attr('width', w + margin.left + margin.right)
.attr('height', h + margin.top + margin.bottom)
.append('g')
.attr('class', 'graph')
.attr('transform',
'translate(' + margin.left + ',' + margin.top + ')');
};
// Scales
var xscale = d3.scale.ordinal();
var yscale = d3.scale.linear()
var barColorScale = d3.scale.linear()
var updateXScale = function updateXScale() {
xscale.domain(d3.range(dataset.length))
.rangeRoundBands([0, w], 0.05);
};
var updateYScale = function updateYScale() {
yscale.domain([0, d3.max(dataset)])
.rangeRound([0, h]);
yscale.clamp();
};
var updateColorScale = function updateColorScale() {
barColorScale.domain([0,d3.max(dataset)])
.rangeRound([0, 255])
.clamp();
};
var updateScales = function () {
updateXScale();
updateYScale();
updateColorScale();
}
// Bars
function barColor(d) {
return 'rgb(0,0,' + barColorScale(d) + ')';
}
/** Update */
var updateBars = function (animate, duration, delay) {
if (!animate) {
duration = 0;
delay = 0;
} else {
if (null == duration) {
duration = defaultDuration;
}
if (null == delay) {
delay = defaultDelay;
}
}
svg.selectAll('rect')
.data(dataset)
.enter()
.append('rect')
.attr('class', 'bar')
.attr('fill', function (d) {
return barColor(d);
})
.attr('width', w / dataset.length - barPadding)
.attr('height', function (d) {
return yscale(d);
})
.attr('y', function (d) {
return h - yscale(d);
})
/* horizontal animation */
.attr('x', xscale(0))
.transition()
.delay(function (d, i) {
console.log(delay);
return i * delay;
})
.duration(duration)
.attr('x', function (d, i) {
return xscale(i);
});
}; // Update bars
// Labels
var updateLabels = function (animate, duration, delay) {
console.log('Update labels');
if (!animate) {
duration = 0;
delay = 0;
}
svg.selectAll('text')
.data(dataset)
.enter()
.append('text')
.attr('class', 'bar-label')
.text(function (d) {
return d;
})
.attr('text-anchor', 'middle')
.attr('x', function (d, i) {
return xscale(i) + xscale.rangeBand() / 2;
})
.attr('y', h + 14 )
.transition()
.delay(function (d, i) {
return i * delay;
})
.duration(duration)
.attr('y', function (d) {
return h - yscale(d) + 14;
})
.attr('font-family', 'sans-serif')
.attr('font-size', '11px')
.attr('fill', 'white');
};
// Animations
var easetype = 'cubic-in-out';
var alleasetypes = ['linear', 'circle', 'elastic', 'bounce'];
d3.select('#ease-type')
.text(easetype);
var durationms = 300;
var delay = durationms * 0.8;
// Hide/Unhide Labels
var labelsHidden = false;
var toggleLabels = function removeLabels (delay, duration) {
d3.selectAll('.bar-label')
.transition()
.delay(function (d, i) {
return i * delay;
})
.duration(duration)
.attr('y', function (d, i) {
console.log('label:' + d);
if (labelsHidden) {
console.log('Unhide labels');
return h - yscale(d);
} else {
console.log('Hide labels');
return h + 14;
}
});
labelsHidden = !labelsHidden;
};
// Interaction
// Bar mousing
var setBarMousing = function setBarMousing () {
var barMouseOutDuration = 300;
var barMouseDelay = 10;
d3.selectAll('rect.bar')
.on('click', function (d, i) {
console.log(d);
})
.on('mouseover', function (d, i) {
// console.log('mouseover [' + i + '] ' + d);
var xPos = parseFloat(d3.select(this).attr('x')) + xscale.rangeBand()/2;
var yPos = parseFloat(d3.select(this).attr('y')) / 2 + h / 2;
// set tooltip position and text
d3.select('#tooltip')
.style('left', xPos + 'px')
.style('top', yPos + 'px')
.select('#value')
.text(d);
// toggle hidden off
d3.select('#tooltip').classed('hidden', false);
})
.on('mouseout', function (d, i) {
// console.log('mouseout [' + i + '] ' + d);
d3.select('#tooltip').classed('hidden', true);
});
};
/** UI */
var initUI = function () {
var easeButton, dataButton, sortButton;
var dataButton = d3.select('#controls')
.append('button')
.attr('class', 'data-reload');
var easeButton = d3.select('#controls')
.append('button')
.attr('class', 'ease-type');
var sortButton = d3.select('#controls')
.append('button')
.attr('class', 'sort-type');
// Cycle through ease types
easeButton.on('click', function () {
alleasetypes.push(easetype);
easetype = alleasetypes.shift();
easeButton.text(easetype);
});
// Randomly generate new data
var sayings = ['hey yo', 'yo yo', 'yo yo'];
var barChangeDur = 200;
var barChangeDelay = 20;
dataButton.
on('click', function () {
dataset = dynamicData(dataset.length, maxvalue);
console.log('Regenerating dataset:'); console.log(dataset);
updateYScale();
// Bars
svg.selectAll('rect')
.data(dataset)
.transition()
.delay(function (d, i) {
return i * barChangeDelay;
})
.duration(barChangeDur)
.ease(easetype)
.attr('x', function (d, i) {
return xscale(i);
})
.attr('y', function (d) {
return h - yscale(d);
})
.attr('width', w / dataset.length - barPadding)
.attr('height', function (d) {
return yscale(d);
})
.attr('fill', function (d) {
return barColor(d);
});
// Labels
svg.selectAll('text')
.data(dataset)
.transition()
.delay(function (d, i) {
return i * barChangeDelay;
})
.duration(barChangeDur)
.ease(easetype)
.text(function (d) {
return d;
})
.attr('text-anchor', 'middle')
.attr('x', function (d, i) {
return xscale(i) + xscale.rangeBand() / 2;
})
.attr('y', function (d) {
return h - yscale(d) + 14;
})
.attr('font-family', 'sans-serif')
.attr('font-size', '11px')
.attr('fill', 'white');
});
// Sort bars
var barSortDuration = 1000;
var barSortDelay = 0;
var sortOrder = false;
var sorttype = 'Ascending';
var sortAll = function sortAll() {
}
var sortBars = function sortBars() {
d3.selectAll('rect')
.sort(function (a,b) {
if (sortOrder) {
return d3.ascending(a, b);
} else {
return d3.descending(a, b);
}
})
.transition()
.duration(1000)
.attr('x', function(d, i) {
return xscale(i);
});
};
var sortLabels = function sortLabels(animate, duration, delay) {
console.log('sort labels');
if (!animate) {
duration = 0;
delay = 0;
} else {
if (null == duration) duration = defaultDuration;
if (null == delay) delay = defaultDelay;
}
d3.selectAll('.bar-label')
.sort(function (a, b) {
if (sortOrder) {
return d3.ascending(a, b);
} else {
return d3.descending(a, b);
}
})
.attr('x', function (d, i) {
return xscale(i) + xscale.rangeBand() / 2;
})
.attr('y', function (d) {
return h - yscale(d) + 14;
});
};
sortButton.on('click', function () {
sortOrder = !sortOrder;
// toggleLabels(true, medDuration, medDelay);
sortBars();
sortLabels();
// toggleLabels(true, medDuration, medDelay);
// update sort button text
d3.select('button.sort')
.text(function () {
if (sortOrder) {
return 'Descending';
}
return 'Ascending';
});
});
dataButton.text('Reload Data')
easeButton.text(easetype);
sortButton.text('Ascending');
};
// Run
function updateChart() {
createSVG();
initUI();
updateScales();
updateBars(true, medDuration, medDelay);
setBarMousing();
updateLabels(true, longDuration, medDelay);
}
updateChart();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment