diff --git a/htdocs/index.html b/htdocs/index.html index cf6847e2e..6f12df0e2 100644 --- a/htdocs/index.html +++ b/htdocs/index.html @@ -44,6 +44,9 @@

Area Chart

Bar Chart

+ + Bar chart with spaces + Bar chart with ordinary data diff --git a/htdocs/samples/chart_bar_space.html b/htdocs/samples/chart_bar_space.html new file mode 100644 index 000000000..00e48a945 --- /dev/null +++ b/htdocs/samples/chart_bar_space.html @@ -0,0 +1,28 @@ + + + + + +
+ + + + + + diff --git a/spec/shape.bar-spec.js b/spec/shape.bar-spec.js index 838625c6f..f8f6b3c15 100644 --- a/spec/shape.bar-spec.js +++ b/spec/shape.bar-spec.js @@ -174,4 +174,156 @@ describe('c3 chart shape bar', function () { }); + describe('bar spacing', function() { + + var createArgs = function(spacing) { + return { + size: { + width: 500 + }, + data: { + columns: [ + ['data1', 30, 200, 100], + ['data2', 50, 20, 10], + ['data3', 150, 120, 110], + ['data4', 12, 24, 20 ] + ], + type: 'bar', + groups: [ + [ 'data1', 'data4' ] + ] + }, + bar: { + space: spacing + } + }; + }; + + var getBBox = function(selector) { + return d3.select(selector).node().getBBox(); + }; + + var getBarContainerWidth = function() { + return parseInt(getBBox('.c3-chart-bars').width); + }; + + var getBarContainerOffset = function() { + return parseInt(getBBox('.c3-chart-bars').x); + }; + + var getBarBBox = function(name, idx) { + return getBBox('.c3-target-' + name + ' .c3-bar-' + (idx || 0)); + }; + + var getBarWidth = function(name, idx) { + return parseInt(getBarBBox(name, idx).width); + }; + + var getBarOffset = function(name1, name2, idx) { + var bbox1 = getBarBBox(name1, idx); + var bbox2 = getBarBBox(name2, idx); + return parseInt(bbox2.x - (bbox1.x + bbox1.width)); + }; + + it('should set bar spacing to 0', function () { + args = createArgs(0); + expect(true).toBeTruthy(); + }); + + it('should display the bars without any spacing', function () { + // all bars should have the same width + expect(getBarWidth('data1', 0)).toEqual(30); + expect(getBarWidth('data2', 0)).toEqual(30); + expect(getBarWidth('data3', 0)).toEqual(30); + expect(getBarWidth('data1', 1)).toEqual(30); + expect(getBarWidth('data2', 1)).toEqual(30); + expect(getBarWidth('data3', 1)).toEqual(30); + expect(getBarWidth('data1', 2)).toEqual(30); + expect(getBarWidth('data2', 2)).toEqual(30); + expect(getBarWidth('data3', 2)).toEqual(30); + + // all offsets should be the same + expect(getBarOffset('data1', 'data2', 0)).toEqual(0); + expect(getBarOffset('data2', 'data3', 0)).toEqual(0); + expect(getBarOffset('data1', 'data2', 1)).toEqual(0); + expect(getBarOffset('data2', 'data3', 1)).toEqual(0); + expect(getBarOffset('data1', 'data2', 2)).toEqual(0); + expect(getBarOffset('data2', 'data3', 2)).toEqual(0); + + // default width/offset of the container for this chart + expect(getBarContainerWidth()).toEqual(396); + expect(getBarContainerOffset()).toEqual(31); + }); + + it('should set bar spacing to 0.25', function () { + args = createArgs(0.25); + expect(true).toBeTruthy(); + }); + + it('should display the bars with a spacing ratio of 0.25', function () { + // with bar_space of 0.25, the space between bars is + // expected to be 25% of the original bar's width + // which is ~7 + + // expect all bars to be the same width + expect(getBarWidth('data1', 0)).toEqual(22); + expect(getBarWidth('data2', 0)).toEqual(22); + expect(getBarWidth('data3', 0)).toEqual(22); + expect(getBarWidth('data1', 1)).toEqual(22); + expect(getBarWidth('data2', 1)).toEqual(22); + expect(getBarWidth('data3', 1)).toEqual(22); + expect(getBarWidth('data1', 2)).toEqual(22); + expect(getBarWidth('data2', 2)).toEqual(22); + expect(getBarWidth('data3', 2)).toEqual(22); + + // all offsets should be the same + expect(getBarOffset('data1', 'data2', 0)).toEqual(7); + expect(getBarOffset('data2', 'data3', 0)).toEqual(7); + expect(getBarOffset('data1', 'data2', 1)).toEqual(7); + expect(getBarOffset('data2', 'data3', 1)).toEqual(7); + expect(getBarOffset('data1', 'data2', 2)).toEqual(7); + expect(getBarOffset('data2', 'data3', 2)).toEqual(7); + + // expect the container to shrink a little because of + // the offsets from the first/last chart + // we add/subtract 1 because of approximation due to rounded values + expect(getBarContainerWidth()).toEqual(396 - 7 - 1); + expect(getBarContainerOffset()).toEqual(31 + (parseInt(7 / 2) + 1)); + }); + + it('should set bar spacing to 0.5', function () { + args = createArgs(0.5); + expect(true).toBeTruthy(); + }); + + it('should display the bars with a spacing ratio of 0.5', function () { + // with bar_space of 0.5, the space between bars is + // expected to be 50% of the original bar's width + // which is ~15 + + // expect all bars to be the same width + expect(getBarWidth('data1', 0)).toEqual(15); + expect(getBarWidth('data2', 0)).toEqual(15); + expect(getBarWidth('data3', 0)).toEqual(15); + expect(getBarWidth('data1', 1)).toEqual(15); + expect(getBarWidth('data2', 1)).toEqual(15); + expect(getBarWidth('data3', 1)).toEqual(15); + expect(getBarWidth('data1', 2)).toEqual(15); + expect(getBarWidth('data2', 2)).toEqual(15); + expect(getBarWidth('data3', 2)).toEqual(15); + + // all offsets should be the same + expect(getBarOffset('data1', 'data2', 0)).toEqual(15); + expect(getBarOffset('data2', 'data3', 0)).toEqual(15); + expect(getBarOffset('data1', 'data2', 1)).toEqual(15); + expect(getBarOffset('data2', 'data3', 1)).toEqual(15); + expect(getBarOffset('data1', 'data2', 2)).toEqual(15); + expect(getBarOffset('data2', 'data3', 2)).toEqual(15); + + // expect the container to shrink a little because of + // the offsets from the first/last chart + expect(getBarContainerWidth()).toEqual(396 - 15); + expect(getBarContainerOffset()).toEqual(31 + parseInt(15 / 2)); + }); + }); }); diff --git a/src/config.js b/src/config.js index 14565bf85..d95e2eced 100644 --- a/src/config.js +++ b/src/config.js @@ -170,6 +170,7 @@ c3_chart_internal_fn.getDefaultConfig = function () { bar_width_ratio: 0.6, bar_width_max: undefined, bar_zerobased: true, + bar_space: 0, // area area_zerobased: true, area_above: false, diff --git a/src/shape.bar.js b/src/shape.bar.js index 7bf538f0c..e71f89f82 100644 --- a/src/shape.bar.js +++ b/src/shape.bar.js @@ -97,6 +97,7 @@ c3_chart_internal_fn.generateGetBarPoints = function (barIndices, isSub) { barX = $$.getShapeX(barW, barTargetsNum, barIndices, !!isSub), barY = $$.getShapeY(!!isSub), barOffset = $$.getShapeOffset($$.isBarType, barIndices, !!isSub), + barSpaceOffset = barW * ($$.config.bar_space / 2), yScale = isSub ? $$.getSubYScale : $$.getYScale; return function (d, i) { var y0 = yScale.call($$, d.id)(0), @@ -108,10 +109,10 @@ c3_chart_internal_fn.generateGetBarPoints = function (barIndices, isSub) { } // 4 points that make a bar return [ - [posX, offset], - [posX, posY - (y0 - offset)], - [posX + barW, posY - (y0 - offset)], - [posX + barW, offset] + [posX + barSpaceOffset, offset], + [posX + barSpaceOffset, posY - (y0 - offset)], + [posX + barW - barSpaceOffset, posY - (y0 - offset)], + [posX + barW - barSpaceOffset, offset] ]; }; };