Skip to content

Commit ca920ab

Browse files
committed
Implement padding for chart title alignment [882]
1 parent e53e546 commit ca920ab

File tree

7 files changed

+301
-62
lines changed

7 files changed

+301
-62
lines changed

src/components/sliders/attributes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ module.exports = overrideAll(templatedArray('slider', {
133133
role: 'style',
134134
description: 'Sets the x position (in normalized coordinates) of the slider.'
135135
},
136-
pad: extendDeepAll({}, padAttrs, {
136+
pad: extendDeepAll(padAttrs({editType: 'arraydraw'}), {
137137
description: 'Set the padding of the slider component along each side.'
138138
}, {t: {dflt: 20}}),
139139
xanchor: {

src/components/updatemenus/attributes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ module.exports = overrideAll(templatedArray('updatemenu', {
162162
].join(' ')
163163
},
164164

165-
pad: extendFlat({}, padAttrs, {
165+
pad: extendFlat(padAttrs({editType: 'arraydraw'}), {
166166
description: 'Sets the padding around the buttons or dropdown menu.'
167167
}),
168168

src/plot_api/subroutines.js

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ var enforceAxisConstraints = axisConstraints.enforce;
2727
var cleanAxisConstraints = axisConstraints.clean;
2828
var doAutoRange = require('../plots/cartesian/autorange').doAutoRange;
2929

30+
var SVG_TEXT_ANCHOR_START = 'start';
31+
var SVG_TEXT_ANCHOR_MIDDLE = 'middle';
32+
var SVG_TEXT_ANCHOR_END = 'end';
33+
3034
exports.layoutStyles = function(gd) {
3135
return Lib.syncOrAsync([Plots.doAutoMargin, lsInner], gd);
3236
};
@@ -450,45 +454,62 @@ function findCounterAxisLineWidth(ax, side, counterAx, axList) {
450454
exports.drawMainTitle = function(gd) {
451455
var fullLayout = gd._fullLayout;
452456

457+
var textAnchor = getMainTitleTextAnchor(fullLayout);
458+
var dy = getMainTitleDy(fullLayout);
459+
453460
Titles.draw(gd, 'gtitle', {
454461
propContainer: fullLayout,
455462
propName: 'title.text',
456463
placeholder: fullLayout._dfltTitle.plot,
457464
attributes: {
458-
x: getMainTitleX(fullLayout),
459-
y: getMainTitleY(fullLayout),
460-
'text-anchor': getMainTitleTextAnchor(fullLayout),
461-
dy: getMainTitleDy(fullLayout)
465+
x: getMainTitleX(fullLayout, textAnchor),
466+
y: getMainTitleY(fullLayout, dy),
467+
'text-anchor': textAnchor,
468+
dy: dy
462469
}
463470
});
464471
};
465472

466-
function getMainTitleX(fullLayout) {
473+
function getMainTitleX(fullLayout, textAnchor) {
467474
var title = fullLayout.title;
468475
var _size = fullLayout._size;
476+
var hPadShift = 0;
477+
478+
if(textAnchor === SVG_TEXT_ANCHOR_START) {
479+
hPadShift = title.pad.l;
480+
} else if(textAnchor === SVG_TEXT_ANCHOR_END) {
481+
hPadShift = -title.pad.r;
482+
}
469483

470484
switch(title.xref) {
471485
case 'paper':
472-
return _size.l + _size.w * title.x;
486+
return _size.l + _size.w * title.x + hPadShift;
473487
case 'container':
474488
default:
475-
return fullLayout.width * title.x;
489+
return fullLayout.width * title.x + hPadShift;
476490
}
477491
}
478492

479-
function getMainTitleY(fullLayout) {
493+
function getMainTitleY(fullLayout, dy) {
480494
var title = fullLayout.title;
481495
var _size = fullLayout._size;
496+
var vPadShift = 0;
497+
498+
if(dy === '0em' || !dy) {
499+
vPadShift = -title.pad.b;
500+
} else if(dy === alignmentConstants.CAP_SHIFT + 'em') {
501+
vPadShift = title.pad.t;
502+
}
482503

483504
if(title.y === 'auto') {
484505
return _size.t / 2;
485506
} else {
486507
switch(title.yref) {
487508
case 'paper':
488-
return _size.t + _size.h - _size.h * title.y;
509+
return _size.t + _size.h - _size.h * title.y + vPadShift;
489510
case 'container':
490511
default:
491-
return fullLayout.height - fullLayout.height * title.y;
512+
return fullLayout.height - fullLayout.height * title.y + vPadShift;
492513
}
493514
}
494515
}
@@ -500,22 +521,22 @@ function getMainTitleTextAnchor(fullLayout) {
500521
case 'auto':
501522
return calcTextAnchor(fullLayout.title.x);
502523
case 'left':
503-
return 'start';
524+
return SVG_TEXT_ANCHOR_START;
504525
case 'right':
505-
return 'end';
526+
return SVG_TEXT_ANCHOR_END;
506527
case 'center':
507528
default:
508-
return 'middle';
529+
return SVG_TEXT_ANCHOR_MIDDLE;
509530
}
510531

511532
function calcTextAnchor(x) {
512533
if(x < 1 / 3) {
513-
return 'start';
534+
return SVG_TEXT_ANCHOR_START;
514535
} else if(x > 2 / 3) {
515-
return 'end';
536+
return SVG_TEXT_ANCHOR_END;
516537
}
517538

518-
return 'middle';
539+
return SVG_TEXT_ANCHOR_MIDDLE;
519540
}
520541
}
521542

src/plots/layout_attributes.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
var fontAttrs = require('./font_attributes');
1212
var colorAttrs = require('../components/color/attributes');
13+
var padAttrs = require('./pad_attributes');
14+
var extendFlat = require('../lib/extend').extendFlat;
1315

1416
var globalFont = fontAttrs({
1517
editType: 'calc',
@@ -102,6 +104,16 @@ module.exports = {
102104
'docu', // TODO document
103105
].join(' ')
104106
},
107+
pad: extendFlat(padAttrs({editType: 'layoutstyle'}), {
108+
description: [
109+
'Sets the padding of the title.',
110+
'Each padding value only applies when the corresponding',
111+
'xanchor / yanchor value is set accordingly. E.g. for left',
112+
'padding to take effect, xanchor must be set to left.',
113+
'The same rule applies if xanchor/yanchor is determined automatically.',
114+
'Padding is muted if respective anchor value is middle/center.'
115+
].join(' ')
116+
}),
105117
editType: 'layoutstyle'
106118
},
107119
autosize: {

src/plots/pad_attributes.js

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,46 @@
88

99
'use strict';
1010

11-
// This is used exclusively by components inside component arrays,
12-
// hence the 'arraydraw' editType. If this ever gets used elsewhere
13-
// we could generalize it as a function ala font_attributes
14-
module.exports = {
15-
t: {
16-
valType: 'number',
17-
dflt: 0,
18-
role: 'style',
19-
editType: 'arraydraw',
20-
description: 'The amount of padding (in px) along the top of the component.'
21-
},
22-
r: {
23-
valType: 'number',
24-
dflt: 0,
25-
role: 'style',
26-
editType: 'arraydraw',
27-
description: 'The amount of padding (in px) on the right side of the component.'
28-
},
29-
b: {
30-
valType: 'number',
31-
dflt: 0,
32-
role: 'style',
33-
editType: 'arraydraw',
34-
description: 'The amount of padding (in px) along the bottom of the component.'
35-
},
36-
l: {
37-
valType: 'number',
38-
dflt: 0,
39-
role: 'style',
40-
editType: 'arraydraw',
41-
description: 'The amount of padding (in px) on the left side of the component.'
42-
},
43-
editType: 'arraydraw'
11+
/**
12+
* Creates a set of padding attributes.
13+
*
14+
* @param {object} opts
15+
* @param {string} editType:
16+
* the editType for all pieces of this padding definition
17+
*
18+
* @return {object} attributes object containing {t, r, b, l} as specified
19+
*/
20+
module.exports = function(opts) {
21+
var editType = opts.editType;
22+
return {
23+
t: {
24+
valType: 'number',
25+
dflt: 0,
26+
role: 'style',
27+
editType: editType,
28+
description: 'The amount of padding (in px) along the top of the component.'
29+
},
30+
r: {
31+
valType: 'number',
32+
dflt: 0,
33+
role: 'style',
34+
editType: editType,
35+
description: 'The amount of padding (in px) on the right side of the component.'
36+
},
37+
b: {
38+
valType: 'number',
39+
dflt: 0,
40+
role: 'style',
41+
editType: editType,
42+
description: 'The amount of padding (in px) along the bottom of the component.'
43+
},
44+
l: {
45+
valType: 'number',
46+
dflt: 0,
47+
role: 'style',
48+
editType: editType,
49+
description: 'The amount of padding (in px) on the left side of the component.'
50+
},
51+
editType: editType
52+
};
4453
};

src/plots/plots.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,10 @@ plots.supplyLayoutGlobalDefaults = function(layoutIn, layoutOut, formatObj) {
13381338
coerce('title.y'); // TODO restrict to [-2, 3]?
13391339
coerce('title.xanchor');
13401340
coerce('title.yanchor');
1341+
coerce('title.pad.t');
1342+
coerce('title.pad.r');
1343+
coerce('title.pad.b');
1344+
coerce('title.pad.l');
13411345

13421346
// Make sure that autosize is defaulted to *true*
13431347
// on layouts with no set width and height for backward compatibly,

0 commit comments

Comments
 (0)