Skip to content

Commit 3fd0d18

Browse files
committed
bar: change criteria for textposition: 'auto'
* With the new criteria, bar texts are drawn inside bars except in those cases that would require scaling down.
1 parent 7df4e09 commit 3fd0d18

File tree

1 file changed

+94
-75
lines changed

1 file changed

+94
-75
lines changed

src/traces/bar/plot.js

Lines changed: 94 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ var ErrorBars = require('../../components/errorbars');
2121

2222
var arraysToCalcdata = require('./arrays_to_calcdata');
2323

24+
// padding in pixels around text
25+
var TEXTPAD = 3;
2426

2527
module.exports = function plot(gd, plotinfo, cdbar) {
2628
var xa = plotinfo.xaxis,
@@ -147,6 +149,8 @@ function appendBarText(gd, bar, calcTrace, i, x0, x1, y0, y1) {
147149
text = traceText;
148150
}
149151

152+
if(!text) return;
153+
150154
// get text position
151155
var traceTextPosition = trace.textposition,
152156
textPosition;
@@ -160,21 +164,63 @@ function appendBarText(gd, bar, calcTrace, i, x0, x1, y0, y1) {
160164

161165
if(textPosition === 'none') return;
162166

163-
var barWidth = Math.abs(x1 - x0),
164-
barHeight = Math.abs(y1 - y0),
165-
barIsTooSmall = (barWidth < 8 || barHeight < 8),
167+
// get text font
168+
var traceTextFont = trace.textfont,
169+
textFont = (Array.isArray(traceTextFont)) ?
170+
traceTextFont[i] : traceTextFont;
171+
textFont = textFont || gd._fullLayout.font;
172+
173+
// get outside text font
174+
var traceOutsideTextFont = trace.outsidetextfont,
175+
outsideTextFont = (Array.isArray(traceOutsideTextFont)) ?
176+
traceOutsideTextFont[i] : traceOutsideTextFont;
177+
outsideTextFont = outsideTextFont || textFont;
178+
179+
// get inside text font
180+
var traceInsideTextFont = trace.insidetextfont,
181+
insideTextFont = (Array.isArray(traceInsideTextFont)) ?
182+
traceInsideTextFont[i] : traceInsideTextFont;
183+
insideTextFont = insideTextFont || textFont;
184+
185+
// append text node
186+
function appendTextNode(bar, text, textFont) {
187+
var textSelection = bar.append('text')
188+
// prohibit tex interpretation until we can handle
189+
// tex and regular text together
190+
.attr('data-notex', 1)
191+
.text(text)
192+
.attr({
193+
'class': 'bartext',
194+
transform: '',
195+
'data-bb': '',
196+
'text-anchor': 'middle',
197+
x: 0,
198+
y: 0
199+
})
200+
.call(Drawing.font, textFont);
201+
202+
textSelection.call(svgTextUtils.convertToTspans);
203+
textSelection.selectAll('tspan.line').attr({x: 0, y: 0});
204+
205+
return textSelection;
206+
}
166207

167-
barmode = gd._fullLayout.barmode,
208+
var barmode = gd._fullLayout.barmode,
168209
inStackMode = (barmode === 'stack'),
169210
inRelativeMode = (barmode === 'relative'),
170211
inStackOrRelativeMode = inStackMode || inRelativeMode,
171212

172213
calcBar = calcTrace[i],
173-
isOutmostBar = !inStackOrRelativeMode || calcBar._outmost;
214+
isOutmostBar = !inStackOrRelativeMode || calcBar._outmost,
174215

175-
if(textPosition === 'auto') {
176-
textPosition = (barIsTooSmall && isOutmostBar) ? 'outside' : 'inside';
177-
}
216+
barWidth = Math.abs(x1 - x0) - 2 * TEXTPAD, // padding excluded
217+
barHeight = Math.abs(y1 - y0) - 2 * TEXTPAD, // padding excluded
218+
barIsTooSmall = (barWidth <= 0 || barHeight <= 0),
219+
220+
textSelection,
221+
textBB,
222+
textWidth,
223+
textHeight;
178224

179225
if(textPosition === 'outside') {
180226
if(!isOutmostBar) textPosition = 'inside';
@@ -184,72 +230,46 @@ function appendBarText(gd, bar, calcTrace, i, x0, x1, y0, y1) {
184230
if(barIsTooSmall) return;
185231
}
186232

187-
188-
// get text font
189-
var textFont;
190-
191-
if(textPosition === 'outside') {
192-
var traceOutsideTextFont = trace.outsidetextfont;
193-
if(Array.isArray(traceOutsideTextFont)) {
194-
if(i >= traceOutsideTextFont.length) return;
195-
textFont = traceOutsideTextFont[i];
196-
}
197-
else {
198-
textFont = traceOutsideTextFont;
199-
}
200-
}
201-
else {
202-
var traceInsideTextFont = trace.insidetextfont;
203-
if(Array.isArray(traceInsideTextFont)) {
204-
if(i >= traceInsideTextFont.length) return;
205-
textFont = traceInsideTextFont[i];
206-
}
207-
else {
208-
textFont = traceInsideTextFont;
209-
}
210-
}
211-
212-
if(!textFont) {
213-
var traceTextFont = trace.textfont;
214-
if(Array.isArray(traceTextFont)) {
215-
if(i >= traceTextFont.length) return;
216-
textFont = traceTextFont[i];
217-
}
218-
else {
219-
textFont = traceTextFont;
233+
if(textPosition === 'auto') {
234+
if(isOutmostBar) {
235+
// draw text using insideTextFont and check if it fits inside bar
236+
textSelection = appendTextNode(bar, text, insideTextFont);
237+
238+
textBB = Drawing.bBox(textSelection.node()),
239+
textWidth = textBB.width,
240+
textHeight = textBB.height;
241+
242+
var textHasSize = (textWidth > 0 && textHeight > 0),
243+
fitsInside =
244+
(textWidth <= barWidth && textHeight <= barHeight),
245+
fitsInsideIfRotated =
246+
(textWidth <= barHeight && textHeight <= barWidth);
247+
if(textHasSize && (fitsInside || fitsInsideIfRotated)) {
248+
textPosition = 'inside';
249+
}
250+
else {
251+
textPosition = 'outside';
252+
textSelection.remove();
253+
textSelection = null;
254+
}
220255
}
256+
else if(!barIsTooSmall) textPosition = 'inside';
257+
else return;
221258
}
222259

223-
if(!textFont) {
224-
textFont = gd._fullLayout.font;
225-
}
260+
if(!textSelection) {
261+
textSelection = appendTextNode(bar, text,
262+
(textPosition === 'outside') ?
263+
outsideTextFont : insideTextFont);
226264

227-
// append bar text
228-
var textSelection = bar.append('text')
229-
// prohibit tex interpretation until we can handle
230-
// tex and regular text together
231-
.attr('data-notex', 1)
232-
.text(text)
233-
.attr({
234-
'class': 'bartext',
235-
transform: '',
236-
'data-bb': '',
237-
'text-anchor': 'middle',
238-
x: 0,
239-
y: 0
240-
})
241-
.call(Drawing.font, textFont);
242-
243-
textSelection.call(svgTextUtils.convertToTspans);
244-
textSelection.selectAll('tspan.line').attr({x: 0, y: 0});
245-
246-
// position bar text
247-
var textBB = Drawing.bBox(textSelection.node()),
265+
textBB = Drawing.bBox(textSelection.node()),
248266
textWidth = textBB.width,
249267
textHeight = textBB.height;
250-
if(!textWidth || !textHeight) {
251-
textSelection.remove();
252-
return;
268+
269+
if(textWidth <= 0 || textHeight <= 0) {
270+
textSelection.remove();
271+
return;
272+
}
253273
}
254274

255275
// compute translate transform
@@ -277,16 +297,15 @@ function getTransformToMoveInsideBar(x0, x1, y0, y1, textBB) {
277297
textY = (textBB.top + textBB.bottom) / 2;
278298

279299
// apply 3px target padding
280-
var targetWidth = barWidth - 6,
281-
targetHeight = barHeight - 6;
300+
var targetWidth = barWidth - 2 * TEXTPAD,
301+
targetHeight = barHeight - 2 * TEXTPAD;
282302

283303
return getTransform(
284304
textX, textY, textWidth, textHeight,
285305
barX, barY, targetWidth, targetHeight);
286306
}
287307

288308
function getTransformToMoveOutsideBar(x0, x1, y0, y1, textBB, orientation) {
289-
290309
// compute text and target positions
291310
var textWidth = textBB.width,
292311
textHeight = textBB.height,
@@ -298,14 +317,14 @@ function getTransformToMoveOutsideBar(x0, x1, y0, y1, textBB, orientation) {
298317
if(orientation === 'h') {
299318
if(x1 < x0) {
300319
// bar end is on the left hand side
301-
targetWidth = textWidth + 6; // 3px padding included
302-
targetHeight = Math.abs(y1 - y0) - 6;
320+
targetWidth = textWidth + 2 * TEXTPAD; // padding included
321+
targetHeight = Math.abs(y1 - y0) - 2 * TEXTPAD;
303322
targetX = x1 - targetWidth / 2;
304323
targetY = (y0 + y1) / 2;
305324
}
306325
else {
307-
targetWidth = textWidth + 6; // padding included
308-
targetHeight = Math.abs(y1 - y0) - 6;
326+
targetWidth = textWidth + 2 * TEXTPAD; // padding included
327+
targetHeight = Math.abs(y1 - y0) - 2 * TEXTPAD;
309328
targetX = x1 + targetWidth / 2;
310329
targetY = (y0 + y1) / 2;
311330
}

0 commit comments

Comments
 (0)