UNPKG

oecd-simple-charts

Version:

D3 charting library for creating pearl charts, stacked bar charts and box plots

274 lines (227 loc) 8.34 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>StackedChart.js - Documentation</title> <script src="scripts/prettify/prettify.js"></script> <script src="scripts/prettify/lang-css.js"></script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> </head> <body> <input type="checkbox" id="nav-trigger" class="nav-trigger" /> <label for="nav-trigger" class="navicon-button x"> <div class="navicon"></div> </label> <label for="nav-trigger" class="overlay"></label> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="BoxPlot.html">BoxPlot</a><ul class='methods'><li data-type='method'><a href="BoxPlot.html#update">update</a></li></ul></li><li><a href="PearlChart.html">PearlChart</a><ul class='methods'><li data-type='method'><a href="PearlChart.html#update">update</a></li></ul></li><li><a href="StackedChart.html">StackedChart</a><ul class='methods'><li data-type='method'><a href="StackedChart.html#update">update</a></li></ul></li></ul> </nav> <div id="main"> <h1 class="page-title">StackedChart.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>import { select as d3Select } from 'd3-selection'; import { scaleLinear as d3ScaleLinear } from 'd3-scale'; import { sum as d3Sum } from 'd3-array'; import OECDChart from './OECDChart'; /** * A stacked chart component * * @example * var StackedChartExample = new OECDCharts.StackedChart({ * container: '#StackedChartExample', * title: 'Stacked Bar Chart', * renderInfoButton: true, * data: [ * { * values: [1,2,3,4,5], * barLabels: ['0%', '100%'], * colors: ['#fddd5d', '#900c3f'], * stackLabels: ['I', 'II', 'III', 'IV', 'V'] * }, * { * values: [2,4,6,8,20], * barLabels: ['0%', '100%'], * colors: ['#fddd5d', '#189aa8'] * } * ] * }); * @constructor * @param {object} options - The options object for the stacked chart * @param {string} options.container - The DOM element to use as container * @param {string} options.title - The title to display * @param {bool} [options.renderInfoButton = false] - The info-Icon for the tooltip, renders after the title * @param {int} [options.fontSize = 14] - The font-size for the labels in px * @param {int} [options.marginTop = 15] - The space between the bars in px * @param {int} [options.barHeight = 30] -The height of a bar in px * @param {array} options.data - The data as array * @param {array} options.data.values - The values to display as stacked bar chart * @param {array} options.data.barLabels - The labels to display left and right to the chart * @param {array} options.data.colors - Colors for the min and max value of the stacked bar chart * @param {array} options.data.stackLabels - Labels for the stacked elements */ class StackedChart extends OECDChart { constructor(options = {}) { super(); this.defaultOptions = { container: null, extent: [0, 100], data: [], fontSize: 14, marginTop: 15, barHeight: 30, marginLeft: 30, marginRight: 45, labelOffset: 5 }; this.init(options); } render() { const { data, container, extent, marginTop, barHeight, fontSize, marginLeft, marginRight } = this.options; const d3Container = d3Select(container); const dimensions = d3Container.node().getBoundingClientRect(); const outerWidth = dimensions.width; const innerWidth = outerWidth - marginLeft - marginRight; const innerHeight = ((barHeight + marginTop) * data.length); this.removeSelections(['.stacked-chart__svg']); this.x = d3ScaleLinear().range([0, innerWidth]).domain(extent); this.colorScale = d3ScaleLinear(); const svg = d3Container .classed('OECDCharts__StackedChart', true) .append('svg') .classed('stacked-chart__svg', true) .attr('width', outerWidth) .attr('height', innerHeight); this.chartWrapper = svg.append('g') .attr('class', 'stacked-chart') .attr('transform', `translate(${marginLeft}, 0)`); this.update(data); } /** * @memberof StackedChart * @param {array} data - an array containing objects with the new data * @example * StackedChartExample.update([ * { * values: [1,10,3,4,5], * barLabels: ['0%', '100%'], * colors: ['#fddd5d', '#900c3f'], * stackLabels: ['1', '2', '3', '4', '5'] * }, * { * values: [2,4,10,15,20], * barLabels: ['0%', '100%'], * colors: ['#fddd5d', '#189aa8'] * } * ]); */ update(_data) { this.options.data = _data; const data = StackedChart.parseData(_data); StackedChart.validateData(_data); const chart = this.getChart(data); this.getBars(chart); this.getStackedLabels(chart); this.getBarLabels(chart); } getChart(_data) { const chart = this.chartWrapper.selectAll('.stacked-chart__bar') .data(_data, d => JSON.stringify(d)); chart.exit().remove(); return chart.enter() .append('g') .classed('stacked-chart__bar', true) .attr('transform', (d, i) => `translate(0, ${i * (this.options.barHeight + this.options.marginTop)})`); } getBars(chart) { chart.selectAll('.stacked-chart__rect') .data(data => data.values.map((value, i) => ({ value, offset: data.offset[i], colors: data.colors }))) .enter() .append('rect') .classed('stacked-chart__rect', true) .attr('width', d => this.x(d.value)) .attr('x', d => this.x(d.offset)) .attr('height', this.options.barHeight) .attr('fill', (d, i, nodes) => this.colorScale.domain([0, nodes.length]).range(d.colors)(i)); } getStackedLabels(chart) { chart.selectAll('.stacked-chart__stackedlabel') .data(data => data.stackLabels.map((stackLabel, i) => ({ stackLabel, offset: data.offset[i], value: data.values[i] }))) .enter() .append('text') .classed('stacked-chart__stackedlabel', true) .attr('y', this.options.barHeight / 2) .attr('x', d => this.x(d.offset + (d.value / 2))) .attr('text-anchor', 'middle') .attr('dy', '.35em') .attr('fill', '#fff') .text(d => d.stackLabel) .attr('font-size', this.options.fontSize); } getBarLabels(chart) { const { labelOffset, barHeight, fontSize } = this.options; chart.selectAll('.stacked-chart__barlabel') .data(d => d.barLabels) .enter() .append('text') .classed('stacked-chart__barlabel', true) .attr('y', barHeight / 2) .attr('x', (d, i, nodes) => (i === 0 ? 0 : nodes[i].parentNode.getBoundingClientRect().width)) .attr('dy', '.35em') .attr('dx', (d, i) => (i === 0 ? `-${labelOffset}px` : `${labelOffset}px`)) .attr('text-anchor', (d, i) => (i === 0 ? 'end' : 'start')) .text(d => d) .attr('font-size', fontSize); } static parseData(_data) { return _data.map((d) => { const factor = 100 / d.values.reduce((a, b) => a + b); d.values = d.values.map(value => value * factor); d.offset = d.values.map((value, i) => d3Sum(d.values.slice(0, i))); d.stackLabels = d.stackLabels || []; return d; }); } static validateData(_data) { const invalidData = _data.filter( d => (d.values.length !== d.stackLabels.length &amp;&amp; d.stackLabels.length) ); if (invalidData.length) { throw Error('invalid data: amount of stackLabels is not matching amount of values.'); } } } export default StackedChart; </code></pre> </article> </section> </div> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.5.5</a> using the <a href="https://github.com/clenemt/docdash">docdash</a> theme. </footer> <script>prettyPrint();</script> <script src="scripts/linenumber.js"></script> </body> </html>