blob: b5bbf0951946bffcbf6ac2b8398aba49ba8abc99 [file] [log] [blame]
import d3 from 'd3';
import { getColorFromScheme } from '../javascripts/modules/colors';
require('./histogram.css');
function histogram(slice, payload) {
const div = d3.select(slice.selector);
const draw = function (data, numBins) {
// Set Margins
const margin = {
top: 50,
right: 10,
bottom: 20,
left: 50,
};
const navBarHeight = 36;
const navBarBuffer = 10;
const width = slice.width() - margin.left - margin.right;
const height = slice.height() - margin.top - margin.bottom - navBarHeight - navBarBuffer;
// Set Histogram objects
const formatNumber = d3.format(',.0f');
const formatTicks = d3.format(',.00f');
const x = d3.scale.ordinal();
const y = d3.scale.linear();
const xAxis = d3.svg.axis()
.scale(x)
.orient('bottom')
.ticks(numBins)
.tickFormat(formatTicks);
const yAxis = d3.svg.axis()
.scale(y)
.orient('left')
.ticks(numBins);
// Calculate bins for the data
const bins = d3.layout.histogram().bins(numBins)(data);
// Set the x-values
x.domain(bins.map(d => d.x))
.rangeRoundBands([0, width], 0.1);
// Set the y-values
y.domain([0, d3.max(bins, d => d.y)])
.range([height, 0]);
// Create the svg value with the bins
const svg = div.selectAll('svg')
.data([bins])
.enter()
.append('svg');
// Make a rectangular background fill
svg.append('rect')
.attr('width', '100%')
.attr('height', '100%')
.attr('fill', '#f6f6f6');
// Transform the svg to make space for the margins
const gEnter = svg
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Add the bars and the x axis
gEnter.append('g').attr('class', 'bars');
gEnter.append('g').attr('class', 'x axis');
// Add width and height to the svg
svg.attr('width', slice.width())
.attr('height', slice.height());
// Create the bars in the svg
const bar = svg.select('.bars').selectAll('.bar').data(bins);
bar.enter().append('rect');
bar.exit().remove();
// Set the Height and Width for each bar
bar.attr('width', x.rangeBand())
.attr('x', d => x(d.x))
.attr('y', d => y(d.y))
.attr('height', d => y.range()[0] - y(d.y))
.style('fill', d => getColorFromScheme(d.length, slice.formData.color_scheme))
.order();
// Find maximum length to position the ticks on top of the bar correctly
const maxLength = d3.max(bins, d => d.length);
function textAboveBar(d) {
return d.length / maxLength < 0.1;
}
// Add a bar text to each bar in the histogram
svg.selectAll('.bartext')
.data(bins)
.enter()
.append('text')
.attr('dy', '.75em')
.attr('y', function (d) {
let padding = 0.0;
if (textAboveBar(d)) {
padding = 12.0;
} else {
padding = -8.0;
}
return y(d.y) - padding;
})
.attr('x', d => x(d.x) + (x.rangeBand() / 2))
.attr('text-anchor', 'middle')
.attr('font-weight', 'bold')
.attr('font-size', '15px')
.text(d => formatNumber(d.y))
.attr('fill', d => textAboveBar(d) ? 'black' : 'white')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
// Update the x-axis
svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(' + margin.left + ',' + (height + margin.top) + ')')
.text('values')
.call(xAxis);
// Update the Y Axis and add minor lines
svg.append('g')
.attr('class', 'axis')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.text('count')
.call(yAxis)
.selectAll('g')
.filter(function (d) { return d; })
.classed('minor', true);
};
const numBins = Number(slice.formData.link_length) || 10;
div.selectAll('*').remove();
draw(payload.data, numBins);
}
module.exports = histogram;