Skip to content

Instantly share code, notes, and snippets.

@enactdev
Forked from mbostock/.block
Last active January 13, 2022 23:01
Show Gist options
  • Save enactdev/a647e60b209e67602304 to your computer and use it in GitHub Desktop.
Save enactdev/a647e60b209e67602304 to your computer and use it in GitHub Desktop.
Responsive D3 chart

This is basic responsive D3 chart example. It is a fork from Mike Bostock's bar chart "Wrapping Long Labels." This NPR article was also useful.

Changes from Mike Bostock's original in the order they were applied:

  • Add default width and height
  • Use those defaults to calculate non-repsonsive width and height
  • Create the set_vars() function to re-calculate width and height when needed. Call it immediately to correctly set width and height
  • Put the code that draws the chart in a function, drawGraphic. Basically, the code from "var x..." through "svg.selectAll("rect")..."
  • Create the window.onresize funcion

In the future be able to create breakpoints to draw slightly different graphs if space is constrained.

name value
Mom keeps commenting on friend's baby photos .17
Putin just sent a friend request .19
Ex is having too much fun with new beau .10
Only using Instagram .15
Discovered books .27
Too much politics .12
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.bar {
fill: steelblue;
}
.bar:hover {
fill: brown;
}
.title {
font: bold 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.axis {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set default width and height, calculate ratio
var default_width = 960;
var default_height = 500;
var default_ratio = default_width / default_height;
// Current (non-responsive) width and height are calcuated from the default, minus the margins
var margin = {top: 80, right: 180, bottom: 80, left: 180},
width = default_width - margin.left - margin.right,
height = default_height - margin.top - margin.bottom;
// Determine current size, which determines vars
function set_vars() {
//alert('setting vars')
current_width = window.innerWidth;
current_height = window.innerHeight;
current_ratio = current_width / current_height;
// Check if height is limiting factor
if ( current_ratio > default_ratio ){
h = current_height;
w = h * default_ratio;
// Else width is limiting
} else {
w = current_width;
h = w / default_ratio;
}
// Set new width and height based on graph dimensions
width = w - margin.left - margin.right;
height = h - margin.top - margin.bottom;
};
set_vars();
function drawGraphic() {
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1, .3);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(8, "%");
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 + ")");
d3.tsv("data.tsv", type, function(error, data) {
x.domain(data.map(function(d) { return d.name; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
svg.append("text")
.attr("class", "title")
.attr("x", x(data[0].name))
.attr("y", -26)
.text("Why Are We Leaving Facebook?");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll(".tick text")
.call(wrap, x.rangeBand());
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.name); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); });
}); // End d3.tsv
}; // End drawGraphic function
drawGraphic();
// Use a timer so the chart is not constantly redrawn while window is being resized.
var resizeTimer;
window.onresize = function(event) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function()
{
var s = d3.selectAll('svg');
s = s.remove();
set_vars();
drawGraphic();
}, 100);
}
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
function type(d) {
d.value = +d.value;
return d;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment