bar chart showing values split around a pivot line i.e. people left on the left and people remaining on the right (length of bar is total)
Last active
September 10, 2018 14:06
-
-
Save eesur/4d0e2d9390bfbb414ec3e517b1497c72 to your computer and use it in GitHub Desktop.
d3 | split bar chart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit | |
height: 500 | |
border: no |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body,text{font-family:'Space Mono',monospace}*{box-sizing:border-box}body{font-size:11px}text{fill:#35342f}.axis-left line,.axis-left path{stroke:#f45844}.axis-left text{fill:#f45844}.axis-right line,.axis-right path{stroke:#e6c700}.axis-right text{fill:#e6c700;font-family:Consolas,monaco,monospace} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
!function(n){function t(g){if(a[g])return a[g].exports;var e=a[g]={i:g,l:!1,exports:{}};return n[g].call(e.exports,e,e.exports,t),e.l=!0,e.exports}var a={};t.m=n,t.c=a,t.i=function(n){return n},t.d=function(n,a,g){t.o(n,a)||Object.defineProperty(n,a,{configurable:!1,enumerable:!0,get:g})},t.n=function(n){var a=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(a,"a",a),a},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=1)}([function(module,exports,__webpack_require__){"use strict";eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = [{ label: 'set-1', right: rInt(100, 300), left: rInt(20, 100) }, { label: 'set-2', right: rInt(100, 250), left: rInt(20, 80) }, { label: 'set-3', right: rInt(30, 150), left: rInt(5, 30) }, { label: 'set-4', right: rInt(2, 100), left: rInt(0, 50) }, { label: 'set-5', right: rInt(2, 50), left: rInt(0, 20) }];\n\n\nfunction rInt(min, max) {\n return Math.floor(d3.randomUniform(min, max)());\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMC5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy9zYW1wbGVEYXRhLmpzPzM5N2YiXSwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGRlZmF1bHQgW1xuICB7bGFiZWw6ICdzZXQtMScsIHJpZ2h0OiBySW50KDEwMCwgMzAwKSwgbGVmdDogckludCgyMCwgMTAwKX0sXG4gIHtsYWJlbDogJ3NldC0yJywgcmlnaHQ6IHJJbnQoMTAwLCAyNTApLCBsZWZ0OiBySW50KDIwLCA4MCl9LFxuICB7bGFiZWw6ICdzZXQtMycsIHJpZ2h0OiBySW50KDMwLCAxNTApLCBsZWZ0OiBySW50KDUsIDMwKX0sXG4gIHtsYWJlbDogJ3NldC00JywgcmlnaHQ6IHJJbnQoMiwgMTAwKSwgbGVmdDogckludCgwLCA1MCl9LFxuICB7bGFiZWw6ICdzZXQtNScsIHJpZ2h0OiBySW50KDIsIDUwKSwgbGVmdDogckludCgwLCAyMCl9XG5dXG5cbmZ1bmN0aW9uIHJJbnQgKG1pbiwgbWF4KSB7XG4gIHJldHVybiBNYXRoLmZsb29yKGQzLnJhbmRvbVVuaWZvcm0obWluLCBtYXgpKCkpXG59XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8gc2FtcGxlRGF0YS5qcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFNQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///0\n")},function(module,exports,__webpack_require__){"use strict";eval("\n\nvar _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };\n\nvar _sampleData = __webpack_require__(0);\n\nvar _sampleData2 = _interopRequireDefault(_sampleData);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar d3 = window.d3;\n\nfunction splitBar(bind, data, config) {\n config = _extends({\n margin: { top: 80, right: 10, bottom: 10, left: 10 },\n width: 960,\n // height: 400, // calc height via datums so we don't get ugly size rects\n barFillRight: '#e6c700', // colour of right bars\n barFillLeft: '#f45844', // colour of left+ bars\n lineStroke: '#35342f',\n lineStrokeWidth: 4,\n // be able to change the keys in data\n leftKey: 'left',\n rightKey: 'right',\n labelKey: 'label'\n }, config);\n var _config = config,\n margin = _config.margin,\n width = _config.width,\n leftKey = _config.leftKey,\n rightKey = _config.rightKey;\n\n var height = data.length * 30 + margin.top + margin.bottom;\n var w = width - margin.left - margin.right;\n var h = height - margin.top - margin.bottom;\n\n // calc max value for whole data set\n var maxValues = [d3.max(data, function (d) {\n return d[leftKey];\n }), d3.max(data, function (d) {\n return d[rightKey];\n })];\n // const minValues = [\n // d3.min(data, d => d[leftKey]),\n // d3.min(data, d => d[rightKey])\n // ]\n\n // access labels\n var labels = data.map(function (d) {\n return d[config.labelKey];\n });\n\n // set up scales\n var bandScale = d3.scaleBand().domain(labels).range([10, h]).paddingInner(0.2);\n // scale for bars and right axis\n var barWidth = d3.scaleLinear().domain([0, d3.max(maxValues)]).range([0, w / 2]);\n // scale for left axis\n var leftAxisScale = d3.scaleLinear().domain([0, d3.max(maxValues)]).range([w / 2, 0]);\n\n var svg = d3.select(bind).append('svg').attr('width', width).attr('height', height).append('g').attr('transform', function (d) {\n return 'translate(' + margin.left + ', ' + margin.top + ')';\n });\n\n var axisRight = svg.append('g').attr('class', 'axis-right').attr('transform', function (d) {\n return 'translate(' + w / 2 + ', ' + -margin.top / 2 + ')';\n });\n var axisLeft = svg.append('g').attr('class', 'axis-left').attr('transform', function (d) {\n return 'translate(' + 0 + ', ' + -margin.top / 2 + ')';\n });\n\n var g = svg.selectAll('.bar').data(data).enter().append('g').attr('class', 'bar').attr('transform', function (d) {\n return 'translate(' + w / 2 + ', ' + bandScale(d[config.labelKey]) + ')';\n });\n // append left bars\n g.append('rect').attr('class', 'bar-left').attr('x', 0).attr('width', 0).attr('height', bandScale.bandwidth()).style('fill', config.barFillLeft).transition().ease(d3.easeSinOut).delay(1000).duration(1000).attr('x', function (d) {\n return -barWidth(d[leftKey]);\n }).attr('width', function (d) {\n return barWidth(d[leftKey]);\n });\n // append right bars\n g.append('rect').attr('class', 'bar-right').attr('width', 0).attr('height', bandScale.bandwidth()).style('fill', config.barFillRight).transition().ease(d3.easeSinOut).duration(1500).attr('width', function (d) {\n return barWidth(d[rightKey]);\n });\n // create a pivot line (around zero)\n svg.append('line').attr('x1', w / 2).attr('y1', 0).attr('x2', w / 2).attr('y2', h).style('stroke', config.lineStroke).style('stroke-width', config.lineStrokeWidth);\n // append a label\n g.append('text').attr('x', 5).attr('y', 15).text(function (d) {\n return d.label;\n });\n // render an axis for each side\n // can use the bar scale for the right\n var xAxisRight = d3.axisBottom().scale(barWidth).ticks(4);\n // need the left to be reversed\n var xAxisLeft = d3.axisBottom().scale(leftAxisScale).ticks(4);\n axisRight.call(xAxisRight);\n axisLeft.call(xAxisLeft);\n // hide the right zero (so no overlap)\n svg.select('.axis-right g.tick').style('display', 'none');\n}\n\n// run the chart\nsplitBar('body', _sampleData2.default);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMS5qcyIsInNvdXJjZXMiOlsid2VicGFjazovLy9zY3JpcHQuanM/OWE5NSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgc2FtcGxlRGF0YSBmcm9tICcuL3NhbXBsZURhdGEnXG5jb25zdCBkMyA9IHdpbmRvdy5kM1xuXG5mdW5jdGlvbiBzcGxpdEJhciAoYmluZCwgZGF0YSwgY29uZmlnKSB7XG4gIGNvbmZpZyA9IHtcbiAgICBtYXJnaW46IHt0b3A6IDgwLCByaWdodDogMTAsIGJvdHRvbTogMTAsIGxlZnQ6IDEwfSxcbiAgICB3aWR0aDogOTYwLFxuICAgIC8vIGhlaWdodDogNDAwLCAvLyBjYWxjIGhlaWdodCB2aWEgZGF0dW1zIHNvIHdlIGRvbid0IGdldCB1Z2x5IHNpemUgcmVjdHNcbiAgICBiYXJGaWxsUmlnaHQ6ICcjZTZjNzAwJywgLy8gY29sb3VyIG9mIHJpZ2h0IGJhcnNcbiAgICBiYXJGaWxsTGVmdDogJyNmNDU4NDQnLCAvLyBjb2xvdXIgb2YgbGVmdCsgYmFyc1xuICAgIGxpbmVTdHJva2U6ICcjMzUzNDJmJyxcbiAgICBsaW5lU3Ryb2tlV2lkdGg6IDQsXG4gICAgLy8gYmUgYWJsZSB0byBjaGFuZ2UgdGhlIGtleXMgaW4gZGF0YVxuICAgIGxlZnRLZXk6ICdsZWZ0JyxcbiAgICByaWdodEtleTogJ3JpZ2h0JyxcbiAgICBsYWJlbEtleTogJ2xhYmVsJyxcbiAgICAuLi5jb25maWdcbiAgfVxuICBjb25zdCB7bWFyZ2luLCB3aWR0aCwgbGVmdEtleSwgcmlnaHRLZXl9ID0gY29uZmlnXG4gIGNvbnN0IGhlaWdodCA9IChkYXRhLmxlbmd0aCAqIDMwKSArIG1hcmdpbi50b3AgKyBtYXJnaW4uYm90dG9tXG4gIGNvbnN0IHcgPSB3aWR0aCAtIG1hcmdpbi5sZWZ0IC0gbWFyZ2luLnJpZ2h0XG4gIGNvbnN0IGggPSBoZWlnaHQgLSBtYXJnaW4udG9wIC0gbWFyZ2luLmJvdHRvbVxuXG4gIC8vIGNhbGMgbWF4IHZhbHVlIGZvciB3aG9sZSBkYXRhIHNldFxuICBjb25zdCBtYXhWYWx1ZXMgPSBbXG4gICAgZDMubWF4KGRhdGEsIGQgPT4gZFtsZWZ0S2V5XSksXG4gICAgZDMubWF4KGRhdGEsIGQgPT4gZFtyaWdodEtleV0pXG4gIF1cbiAgLy8gY29uc3QgbWluVmFsdWVzID0gW1xuICAvLyAgIGQzLm1pbihkYXRhLCBkID0+IGRbbGVmdEtleV0pLFxuICAvLyAgIGQzLm1pbihkYXRhLCBkID0+IGRbcmlnaHRLZXldKVxuICAvLyBdXG5cbiAgLy8gYWNjZXNzIGxhYmVsc1xuICBjb25zdCBsYWJlbHMgPSBkYXRhLm1hcChkID0+IGRbY29uZmlnLmxhYmVsS2V5XSlcblxuICAvLyBzZXQgdXAgc2NhbGVzXG4gIGNvbnN0IGJhbmRTY2FsZSA9IGQzLnNjYWxlQmFuZCgpXG4gICAgLmRvbWFpbihsYWJlbHMpXG4gICAgLnJhbmdlKFsxMCwgaF0pXG4gICAgLnBhZGRpbmdJbm5lcigwLjIpXG4gIC8vIHNjYWxlIGZvciBiYXJzIGFuZCByaWdodCBheGlzXG4gIGNvbnN0IGJhcldpZHRoID0gZDMuc2NhbGVMaW5lYXIoKVxuICAgIC5kb21haW4oWzAsIGQzLm1heChtYXhWYWx1ZXMpXSlcbiAgICAucmFuZ2UoWzAsIHcgLyAyXSlcbiAgLy8gc2NhbGUgZm9yIGxlZnQgYXhpc1xuICBjb25zdCBsZWZ0QXhpc1NjYWxlID0gZDMuc2NhbGVMaW5lYXIoKVxuICAgIC5kb21haW4oWzAsIGQzLm1heChtYXhWYWx1ZXMpXSlcbiAgICAucmFuZ2UoW3cgLyAyLCAwXSlcblxuICBjb25zdCBzdmcgPSBkMy5zZWxlY3QoYmluZCkuYXBwZW5kKCdzdmcnKVxuICAgIC5hdHRyKCd3aWR0aCcsIHdpZHRoKVxuICAgIC5hdHRyKCdoZWlnaHQnLCBoZWlnaHQpXG4gICAgLmFwcGVuZCgnZycpXG4gICAgLmF0dHIoJ3RyYW5zZm9ybScsIGQgPT4gYHRyYW5zbGF0ZSgke21hcmdpbi5sZWZ0fSwgJHttYXJnaW4udG9wfSlgKVxuXG4gIGNvbnN0IGF4aXNSaWdodCA9IHN2Zy5hcHBlbmQoJ2cnKVxuICAgIC5hdHRyKCdjbGFzcycsICdheGlzLXJpZ2h0JylcbiAgICAuYXR0cigndHJhbnNmb3JtJywgZCA9PiBgdHJhbnNsYXRlKCR7dyAvIDJ9LCAkey1tYXJnaW4udG9wIC8gMn0pYClcbiAgY29uc3QgYXhpc0xlZnQgPSBzdmcuYXBwZW5kKCdnJylcbiAgICAuYXR0cignY2xhc3MnLCAnYXhpcy1sZWZ0JylcbiAgICAuYXR0cigndHJhbnNmb3JtJywgZCA9PiBgdHJhbnNsYXRlKCR7MH0sICR7LW1hcmdpbi50b3AgLyAyfSlgKVxuXG4gIGNvbnN0IGcgPSBzdmcuc2VsZWN0QWxsKCcuYmFyJylcbiAgICAuZGF0YShkYXRhKVxuICAgIC5lbnRlcigpLmFwcGVuZCgnZycpXG4gICAgLmF0dHIoJ2NsYXNzJywgJ2JhcicpXG4gICAgLmF0dHIoJ3RyYW5zZm9ybScsIGQgPT4gYHRyYW5zbGF0ZSgke3cgLyAyfSwgJHtiYW5kU2NhbGUoZFtjb25maWcubGFiZWxLZXldKX0pYClcbiAgLy8gYXBwZW5kIGxlZnQgYmFyc1xuICBnLmFwcGVuZCgncmVjdCcpXG4gICAgLmF0dHIoJ2NsYXNzJywgJ2Jhci1sZWZ0JylcbiAgICAuYXR0cigneCcsIDBcbiAgICAgIClcbiAgICAuYXR0cignd2lkdGgnLCAwKVxuICAgIC5hdHRyKCdoZWlnaHQnLCBiYW5kU2NhbGUuYmFuZHdpZHRoKCkpXG4gICAgLnN0eWxlKCdmaWxsJywgY29uZmlnLmJhckZpbGxMZWZ0KVxuICAgIC50cmFuc2l0aW9uKClcbiAgICAuZWFzZShkMy5lYXNlU2luT3V0KVxuICAgIC5kZWxheSgxMDAwKVxuICAgIC5kdXJhdGlvbigxMDAwKVxuICAgIC5hdHRyKCd4JywgZCA9PiAtKGJhcldpZHRoKGRbbGVmdEtleV0pKSlcbiAgICAuYXR0cignd2lkdGgnLCBkID0+IGJhcldpZHRoKGRbbGVmdEtleV0pKVxuICAvLyBhcHBlbmQgcmlnaHQgYmFyc1xuICBnLmFwcGVuZCgncmVjdCcpXG4gICAgLmF0dHIoJ2NsYXNzJywgJ2Jhci1yaWdodCcpXG4gICAgLmF0dHIoJ3dpZHRoJywgMClcbiAgICAuYXR0cignaGVpZ2h0JywgYmFuZFNjYWxlLmJhbmR3aWR0aCgpKVxuICAgIC5zdHlsZSgnZmlsbCcsIGNvbmZpZy5iYXJGaWxsUmlnaHQpXG4gICAgLnRyYW5zaXRpb24oKVxuICAgIC5lYXNlKGQzLmVhc2VTaW5PdXQpXG4gICAgLmR1cmF0aW9uKDE1MDApXG4gICAgLmF0dHIoJ3dpZHRoJywgZCA9PiBiYXJXaWR0aChkW3JpZ2h0S2V5XSkpXG4gIC8vIGNyZWF0ZSBhIHBpdm90IGxpbmUgKGFyb3VuZCB6ZXJvKVxuICBzdmcuYXBwZW5kKCdsaW5lJylcbiAgICAuYXR0cigneDEnLCB3IC8gMilcbiAgICAuYXR0cigneTEnLCAwKVxuICAgIC5hdHRyKCd4MicsIHcgLyAyKVxuICAgIC5hdHRyKCd5MicsIGgpXG4gICAgLnN0eWxlKCdzdHJva2UnLCBjb25maWcubGluZVN0cm9rZSlcbiAgICAuc3R5bGUoJ3N0cm9rZS13aWR0aCcsIGNvbmZpZy5saW5lU3Ryb2tlV2lkdGgpXG4gIC8vIGFwcGVuZCBhIGxhYmVsXG4gIGcuYXBwZW5kKCd0ZXh0JylcbiAgICAuYXR0cigneCcsIDUpXG4gICAgLmF0dHIoJ3knLCAxNSlcbiAgICAudGV4dChkID0+IGQubGFiZWwpXG4gIC8vIHJlbmRlciBhbiBheGlzIGZvciBlYWNoIHNpZGVcbiAgLy8gY2FuIHVzZSB0aGUgYmFyIHNjYWxlIGZvciB0aGUgcmlnaHRcbiAgY29uc3QgeEF4aXNSaWdodCA9IGQzLmF4aXNCb3R0b20oKS5zY2FsZShiYXJXaWR0aCkudGlja3MoNClcbiAgLy8gbmVlZCB0aGUgbGVmdCB0byBiZSByZXZlcnNlZFxuICBjb25zdCB4QXhpc0xlZnQgPSBkMy5heGlzQm90dG9tKCkuc2NhbGUobGVmdEF4aXNTY2FsZSkudGlja3MoNClcbiAgYXhpc1JpZ2h0LmNhbGwoeEF4aXNSaWdodClcbiAgYXhpc0xlZnQuY2FsbCh4QXhpc0xlZnQpXG4gIC8vIGhpZGUgdGhlIHJpZ2h0IHplcm8gKHNvIG5vIG92ZXJsYXApXG4gIHN2Zy5zZWxlY3QoJy5heGlzLXJpZ2h0IGcudGljaycpLnN0eWxlKCdkaXNwbGF5JywgJ25vbmUnKVxufVxuXG4vLyBydW4gdGhlIGNoYXJ0XG5zcGxpdEJhcignYm9keScsIHNhbXBsZURhdGEpXG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8gc2NyaXB0LmpzIl0sIm1hcHBpbmdzIjoiOzs7O0FBQUE7QUFDQTs7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFYQTtBQURBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQWVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBSUE7QUFDQTtBQUdBO0FBQ0E7QUFDQTtBQUdBO0FBSUE7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUFBO0FBQ0E7QUFFQTtBQUFBO0FBQ0E7QUFDQTtBQUlBO0FBQUE7QUFDQTtBQUNBO0FBV0E7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBUUE7QUFBQTtBQUNBO0FBQ0E7QUFPQTtBQUNBO0FBR0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///1\n")}]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<title>blockup</title> | |
<link href='dist.css' rel='stylesheet' /> | |
<link href="https://fonts.googleapis.com/css?family=Space+Mono" rel="stylesheet"> | |
<body> | |
<script src='https://d3js.org/d3.v4.min.js'></script> | |
<script src='dist.js'></script> | |
</body> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"standard": { | |
"globals": [ | |
"d3" | |
] | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default [ | |
{label: 'set-1', right: rInt(100, 300), left: rInt(20, 100)}, | |
{label: 'set-2', right: rInt(100, 250), left: rInt(20, 80)}, | |
{label: 'set-3', right: rInt(30, 150), left: rInt(5, 30)}, | |
{label: 'set-4', right: rInt(2, 100), left: rInt(0, 50)}, | |
{label: 'set-5', right: rInt(2, 50), left: rInt(0, 20)} | |
] | |
function rInt (min, max) { | |
return Math.floor(d3.randomUniform(min, max)()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sampleData from './sampleData' | |
const d3 = window.d3 | |
function splitBar (bind, data, config) { | |
config = { | |
margin: {top: 80, right: 10, bottom: 10, left: 10}, | |
width: 960, | |
// height: 400, // calc height via datums so we don't get ugly size rects | |
barFillRight: '#e6c700', // colour of right bars | |
barFillLeft: '#f45844', // colour of left+ bars | |
lineStroke: '#35342f', | |
lineStrokeWidth: 4, | |
// be able to change the keys in data | |
leftKey: 'left', | |
rightKey: 'right', | |
labelKey: 'label', | |
...config | |
} | |
const {margin, width, leftKey, rightKey} = config | |
const height = (data.length * 30) + margin.top + margin.bottom | |
const w = width - margin.left - margin.right | |
const h = height - margin.top - margin.bottom | |
// calc max value for whole data set | |
const maxValues = [ | |
d3.max(data, d => d[leftKey]), | |
d3.max(data, d => d[rightKey]) | |
] | |
// const minValues = [ | |
// d3.min(data, d => d[leftKey]), | |
// d3.min(data, d => d[rightKey]) | |
// ] | |
// access labels | |
const labels = data.map(d => d[config.labelKey]) | |
// set up scales | |
const bandScale = d3.scaleBand() | |
.domain(labels) | |
.range([10, h]) | |
.paddingInner(0.2) | |
// scale for bars and right axis | |
const barWidth = d3.scaleLinear() | |
.domain([0, d3.max(maxValues)]) | |
.range([0, w / 2]) | |
// scale for left axis | |
const leftAxisScale = d3.scaleLinear() | |
.domain([0, d3.max(maxValues)]) | |
.range([w / 2, 0]) | |
const svg = d3.select(bind).append('svg') | |
.attr('width', width) | |
.attr('height', height) | |
.append('g') | |
.attr('transform', d => `translate(${margin.left}, ${margin.top})`) | |
const axisRight = svg.append('g') | |
.attr('class', 'axis-right') | |
.attr('transform', d => `translate(${w / 2}, ${-margin.top / 2})`) | |
const axisLeft = svg.append('g') | |
.attr('class', 'axis-left') | |
.attr('transform', d => `translate(${0}, ${-margin.top / 2})`) | |
const g = svg.selectAll('.bar') | |
.data(data) | |
.enter().append('g') | |
.attr('class', 'bar') | |
.attr('transform', d => `translate(${w / 2}, ${bandScale(d[config.labelKey])})`) | |
// append left bars | |
g.append('rect') | |
.attr('class', 'bar-left') | |
.attr('x', 0 | |
) | |
.attr('width', 0) | |
.attr('height', bandScale.bandwidth()) | |
.style('fill', config.barFillLeft) | |
.transition() | |
.ease(d3.easeSinOut) | |
.delay(1000) | |
.duration(1000) | |
.attr('x', d => -(barWidth(d[leftKey]))) | |
.attr('width', d => barWidth(d[leftKey])) | |
// append right bars | |
g.append('rect') | |
.attr('class', 'bar-right') | |
.attr('width', 0) | |
.attr('height', bandScale.bandwidth()) | |
.style('fill', config.barFillRight) | |
.transition() | |
.ease(d3.easeSinOut) | |
.duration(1500) | |
.attr('width', d => barWidth(d[rightKey])) | |
// create a pivot line (around zero) | |
svg.append('line') | |
.attr('x1', w / 2) | |
.attr('y1', 0) | |
.attr('x2', w / 2) | |
.attr('y2', h) | |
.style('stroke', config.lineStroke) | |
.style('stroke-width', config.lineStrokeWidth) | |
// append a label | |
g.append('text') | |
.attr('x', 5) | |
.attr('y', 15) | |
.text(d => d.label) | |
// render an axis for each side | |
// can use the bar scale for the right | |
const xAxisRight = d3.axisBottom().scale(barWidth).ticks(4) | |
// need the left to be reversed | |
const xAxisLeft = d3.axisBottom().scale(leftAxisScale).ticks(4) | |
axisRight.call(xAxisRight) | |
axisLeft.call(xAxisLeft) | |
// hide the right zero (so no overlap) | |
svg.select('.axis-right g.tick').style('display', 'none') | |
} | |
// run the chart | |
splitBar('body', sampleData) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* | |
box-sizing border-box | |
body | |
font-family: 'Space Mono', monospace | |
font-size: 11px | |
text | |
font-family: 'Space Mono', monospace | |
fill: #35342f | |
.axis-left path, .axis-left line | |
stroke: #f45844 | |
.axis-left text | |
fill: #f45844 | |
.axis-right path, .axis-right line | |
stroke: #e6c700 | |
.axis-right text | |
fill: #e6c700 | |
font-family: Consolas, monaco, monospace |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment