Skip to content

Commit f99ee3b

Browse files
committed
[Bars] Add possibility to display totals for bars
Contributes to plotly#85
1 parent 6656ca3 commit f99ee3b

File tree

3 files changed

+61
-2
lines changed

3 files changed

+61
-2
lines changed

src/traces/bar/layout_attributes.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -63,5 +63,17 @@ module.exports = {
6363
'Sets the gap (in plot fraction) between bars of',
6464
'the same location coordinate.'
6565
].join(' ')
66-
}
66+
},
67+
displaytotal: {
68+
valType: 'boolean',
69+
dflt: false,
70+
role: 'style',
71+
description: 'Display the total value of each bar.'
72+
},
73+
totaltemplate: {
74+
valType: 'string',
75+
dflt: '%{total}',
76+
role: 'style',
77+
description: 'Template to display the total value of each bar.'
78+
},
6779
};

src/traces/bar/layout_defaults.js

+2
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,6 @@ module.exports = function(layoutIn, layoutOut, fullData) {
5555

5656
coerce('bargap', (shouldBeGapless && !gappedAnyway) ? 0 : 0.2);
5757
coerce('bargroupgap');
58+
coerce('displaytotal');
59+
coerce('totaltemplate');
5860
};

src/traces/bar/plot.js

+46-1
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ function plot(gd, plotinfo, cdModule, traceLayer, opts, makeOnCompleteCallback)
251251
}
252252

253253
appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, opts, makeOnCompleteCallback);
254+
if(fullLayout.displaytotal) {
255+
appendBarTotal(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, opts, makeOnCompleteCallback);
256+
}
254257

255258
if(plotinfo.layerClipId) {
256259
Drawing.hideOutsideRangePoint(di, bar.select('text'), xa, ya, trace.xcalendar, trace.ycalendar);
@@ -275,7 +278,7 @@ function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, opts, makeOnCom
275278
var textPosition;
276279

277280
function appendTextNode(bar, text, font) {
278-
var textSelection = Lib.ensureSingle(bar, 'text')
281+
var textSelection = Lib.ensureSingle(bar, 'text', 'bartext-' + textPosition)
279282
.text(text)
280283
.attr({
281284
'class': 'bartext bartext-' + textPosition,
@@ -443,6 +446,48 @@ function appendBarText(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, opts, makeOnCom
443446
.attr('transform', Lib.getTextTransform(transform));
444447
}
445448

449+
// total for stacked bars
450+
function appendBarTotal(gd, plotinfo, bar, cd, i, x0, x1, y0, y1, opts, makeOnCompleteCallback) {
451+
var fullLayout = gd._fullLayout;
452+
// get trace attributes
453+
var trace = cd[0].trace;
454+
var isHorizontal = (trace.orientation === 'h');
455+
var inStackOrRelativeMode =
456+
opts.mode === 'stack' ||
457+
opts.mode === 'relative';
458+
var calcBar = cd[i];
459+
var isOutmostBar = !inStackOrRelativeMode || calcBar._outmost;
460+
461+
if(isOutmostBar) {
462+
var layoutFont = fullLayout.font;
463+
var font = style.getOutsideTextFont(trace, i, layoutFont);
464+
var totalTemplate = fullLayout.totaltemplate;
465+
var obj = {total: isHorizontal ? calcBar.x : calcBar.y};
466+
var totalText = Lib.texttemplateString(totalTemplate, obj, fullLayout._d2locale, {}, obj, trace._meta || {});
467+
var totalSelection = Lib.ensureSingle(bar, 'text', 'bartext-outside')
468+
.text(totalText)
469+
.attr({
470+
'class': 'bartext bartext-outside',
471+
'text-anchor': 'middle',
472+
// prohibit tex interpretation until we can handle
473+
// tex and regular text together
474+
'data-notex': 1
475+
})
476+
.call(Drawing.font, font)
477+
.call(svgTextUtils.convertToTspans, gd);
478+
479+
var textBB = Drawing.bBox(totalSelection.node());
480+
var transform = toMoveOutsideBar(x0, x1, y0, y1, textBB, {
481+
isHorizontal: isHorizontal,
482+
constrained: false,
483+
angle: trace.textangle
484+
});
485+
486+
transition(totalSelection, fullLayout, opts, makeOnCompleteCallback)
487+
.attr('transform', Lib.getTextTransform(transform));
488+
}
489+
}
490+
446491
function getRotateFromAngle(angle) {
447492
return (angle === 'auto') ? 0 : angle;
448493
}

0 commit comments

Comments
 (0)