Skip to content

Commit a39a392

Browse files
Merge pull request #157 from keen/dlacheta-bar-percent-stacked-chart
dlacheta 100% stacked charts
2 parents 38db53e + 9dc9fca commit a39a392

File tree

5 files changed

+231
-43
lines changed

5 files changed

+231
-43
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,8 @@ Create a stacked chart, used to break down and compare parts of a whole.
574574
```javascript
575575
const chart = new KeenDataviz({
576576
container: '#some_container', // required
577-
stacked: true
577+
stacking: 'normal' // 'normal' - stacked chart
578+
// 'percent' - 100% stacked chart
578579
});
579580
```
580581

lib/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ export const Dataviz = function (options = {}) {
151151
this.config.type = convertChartTypes(this.config.type);
152152
}
153153

154+
// overwriting stacked when stacking added
155+
if (this.config.stacking) {
156+
this.config.stacked = true;
157+
}
158+
154159
// get DOM node by query
155160
if (this.config.container) {
156161
this.el(this.config.container);

lib/libraries/c3/extensions/tooltip-contents.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export default function (d, defaultTitleFormat, defaultValueFormat, color) {
1818
let name = nameFormat(d[i].name);
1919
let value = valueFormat(d[i].value, d[i].ratio, d[i].id, d[i].index);
2020
let bgcolor = this.levelColor ? this.levelColor(d[i].value) : color(d[i].id);
21-
if (value) {
21+
if (value && !isNaN(value)) {
2222
text += "<tr class='" + this.CLASS.tooltipName + "-" + d[i].id + "'>";
2323
if (name.indexOf('__tooltip_ignore_name_field__') === -1) {
2424
text += "<td class='name'><span style='background-color:" + bgcolor + "'></span>" + escapeHtml(name) + "</td>";

lib/libraries/index.js

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ function defineC3(){
107107
'horizontal-bar',
108108
'horizontal-line',
109109
'horizontal-step',
110-
'horizontal-spline'
110+
'horizontal-spline',
111111
];
112112

113113
const getPaddings = (element, paddingName) => {
@@ -185,6 +185,24 @@ function defineC3(){
185185
render: function(){
186186
const options = getDefaultOptions.call(this);
187187

188+
// 100% for charts
189+
const sumArray = calculateSumForPercents(this.dataset.matrix);
190+
let oldMatrix = [];
191+
if (options.stacking === 'percent' && (type === 'bar' || type === 'horizontal-bar' || type === 'area' || type === 'area-step' || type === 'area-spline')) {
192+
oldMatrix = this.dataset.matrix;
193+
this.dataset.matrix = [this.dataset.matrix[0], ...calculatePercents(this.dataset.matrix, sumArray)];
194+
options.axis = {
195+
y: {
196+
padding: {
197+
top: 0,
198+
},
199+
tick: {
200+
format: d => `${d}%`,
201+
},
202+
},
203+
};
204+
}
205+
188206
if (!!this.config.clearOnRender && options.data.columns.length > 0) {
189207
options.data.columns.splice(1);
190208
}
@@ -282,13 +300,13 @@ function defineC3(){
282300
if (results && results.length > 1) {
283301
const partialResultsRegion = {
284302
axis: 'x',
285-
start: new Date(results[results.length-2]),
303+
start: new Date(results[results.length - 2]),
286304
class: options.partialIntervalIndicator.className
287305
};
288306
options.regions = [...(options.regions || []), partialResultsRegion];
289307
}
290308
}
291-
309+
292310
if (
293311
!(options.tooltip && options.tooltip.show === false)
294312
&&
@@ -297,6 +315,7 @@ function defineC3(){
297315
&& options.legend.tooltip
298316
&& options.legend.tooltip.show)
299317
)) {
318+
300319
// Apply custom tooltip
301320
options.tooltip = {
302321
contents: c3TooltipContents,
@@ -307,6 +326,18 @@ function defineC3(){
307326
if (this.config.tooltip && this.config.tooltip.format && this.config.tooltip.format.value)
308327
{
309328
valueFormatted = this.config.tooltip.format.value.call(this, valueFormatted, ratio, id, index);
329+
// Restore value from percents calculation for stacking 100% charts
330+
if (options.stacking === 'percent' && (type === 'bar' || type === 'horizontal-bar' || type === 'area'
331+
|| type === 'area-step' || type === 'area-spline')) {
332+
valueFormatted = parseFloat(((valueFormatted / 100) * sumArray[index]).toFixed(2));
333+
}
334+
return valueFormatted;
335+
}
336+
// Restore value from percents calculation for stacking 100% charts
337+
if (options.stacking === 'percent' && (type === 'bar' || type === 'horizontal-bar' || type === 'area'
338+
|| type === 'area-step' || type === 'area-spline')) {
339+
valueFormatted = ((valueFormatted / 100) * sumArray[index]).toFixed(2);
340+
return parseFloat(valueFormatted);
310341
}
311342
return valueFormatted;
312343
}
@@ -422,3 +453,30 @@ function bindResizeListener(fn){
422453
window.attachEvent('onresize', fn);
423454
}
424455
}
456+
457+
function calculateSumForPercents(matrix) {
458+
const sumArray = [];
459+
matrix.slice(1).forEach((d, i) => {
460+
d.forEach((e) => {
461+
if (typeof e === 'number') {
462+
if (!sumArray[i]) {
463+
sumArray[i] = e;
464+
return sumArray[i];
465+
}
466+
sumArray[i] += e;
467+
}
468+
return sumArray[i];
469+
});
470+
});
471+
return sumArray;
472+
}
473+
474+
function calculatePercents(matrix, sumArray) {
475+
const newValues = matrix.slice(1).map((d, i) => d.map((e) => {
476+
if (typeof e === 'number') {
477+
return (e / sumArray[i]) * 100;
478+
}
479+
return e;
480+
}));
481+
return newValues;
482+
}

0 commit comments

Comments
 (0)