On Github Golodhros / golodhros.github.io
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
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 + ")");
Reference: Margin Convention
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
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(10, "%");
Reference: Scales tutorial
// Loads Data
d3.tsv("data.tsv", type, function(error, data) {
if (error) throw error;
// Chart Code here
});
// Cleans Data
function type(d) {
d.frequency = +d.frequency;
return d;
}
// Rest of the scales
x.domain(data.map(function(d) { return d.letter; }));
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
// Draws X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Draws Y axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); });
return function module(){
// @param {D3Selection} _selection A d3 selection that represents
// the container(s) where the chart(s) will be rendered
function exports(_selection){
// @param {object} _data The data to generate the chart
_selection.each(function(_data){
// Assigns private variables
// Builds chart
});
}
// @param {object} _x Margin object to get/set
// @return { margin | module} Current margin or Bar Chart module to chain calls
exports.margin = function(_x) {
if (!arguments.length) return margin;
margin = _x;
return this;
};
return exports;
}
// Creates bar chart component and configures its margins
barChart = chart()
.margin({top: 5, left: 10});
container = d3.select('.chart-container');
// Calls bar chart with the data-fed selector
container.datum(dataset).call(barChart);
container = d3.select('.test-container');
dataset = [
{ letter: 'A',
frequency: .08167
},{
letter: 'B',
frequency: .01492
},...
];
barChart = barChart();
container.datum(dataset).call(barChart);
it('should render a chart with minimal requirements', function(){
expect(containerFixture.select('.bar-chart').empty()).toBeFalsy();
});
return function module(){
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960, height = 500,
svg;
function exports(_selection){
_selection.each(function(_data){
var chartWidth = width - margin.left - margin.right,
chartHeight = height - margin.top - margin.bottom;
if (!svg) {
svg = d3.select(this)
.append('svg')
.classed('bar-chart', true);
}
});
};
return exports;
}
Reference: Towards Reusable Charts
it('should render container, axis and chart groups', function(){
expect(containerFixture.select('g.container-group').empty()).toBeFalsy();
expect(containerFixture.select('g.chart-group').empty()).toBeFalsy();
expect(containerFixture.select('g.x-axis-group').empty()).toBeFalsy();
expect(containerFixture.select('g.y-axis-group').empty()).toBeFalsy();
});
function buildContainerGroups(){
var container = svg.append("g").attr("class", "container-group");
container.append("g").attr("class", "chart-group");
container.append("g").attr("class", "x-axis-group axis");
container.append("g").attr("class", "y-axis-group axis");
}
it('should render an X and Y axes', function(){
expect(containerFixture.select('.x-axis-group.axis').empty()).toBeFalsy();
expect(containerFixture.select('.y-axis-group.axis').empty()).toBeFalsy();
});
function buildScales(){
xScale = d3.scale.ordinal()
.domain(data.map(function(d) { return d.letter; }))
.rangeRoundBands([0, chartWidth], .1);
yScale = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.frequency; })])
.range([chartHeight, 0]);
}
function buildAxis(){
xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10, "%");
}
function drawAxis(){
svg.select('.x-axis-group')
.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + chartHeight + ")")
.call(xAxis);
svg.select(".y-axis-group")
.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
}
it('should render a bar for each data entry', function(){
var numBars = dataset.length;
expect(containerFixture.selectAll('.bar').size()).toEqual(numBars);
});
function drawBars(){
// Setup the enter, exit and update of the actual bars in the chart.
// Select the bars, and bind the data to the .bar elements.
var bars = svg.select('.chart-group').selectAll(".bar")
.data(data);
// If there aren't any bars create them
bars.enter().append('rect')
.attr("class", "bar")
.attr("x", function(d) { return xScale(d.letter); })
.attr("width", xScale.rangeBand())
.attr("y", function(d) { return yScale(d.frequency); })
.attr("height", function(d) { return chartHeight - yScale(d.frequency); });
}
Reference: Thinking with joins, General Update Pattern
it('should provide margin getter and setter', function(){
var defaultMargin = barChart.margin(),
testMargin = {top: 4, right: 4, bottom: 4, left: 4},
newMargin;
barChart.margin(testMargin);
newMargin = barChart.margin();
expect(defaultMargin).not.toBe(testMargin);
expect(newMargin).toBe(testMargin);
});
exports.margin = function(_x) {
if (!arguments.length) return margin;
margin = _x;
return this;
};
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
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(10, "%");
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.letter; }));
y.domain([0, d3.max(data, function(d) { return d.frequency; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Frequency");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.letter); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.frequency); })
.attr("height", function(d) { return height - y(d.frequency); });
});
function type(d) {
d.frequency = +d.frequency;
return d;
}
return function module(){
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960, height = 500,
chartWidth, chartHeight,
xScale, yScale,
xAxis, yAxis,
data, svg;
function exports(_selection){
_selection.each(function(_data){
chartWidth = width - margin.left - margin.right;
chartHeight = height - margin.top - margin.bottom;
data = _data;
buildScales();
buildAxis();
buildSVG(this);
drawBars();
drawAxis();
});
}
function buildContainerGroups(){ ... }
function buildScales(){ ... }
function buildAxis(){ ... }
function drawAxis(){ ... }
function drawBars(){ ... }
// Accessors to all configurable attributes
exports.margin = function(_x) { ... };
return exports;
};