Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

882 - Chart Title Alignment #3276

Merged
merged 50 commits into from
Nov 29, 2018
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
6687034
Add test of current plot title alignment [882]
rmoestl Oct 30, 2018
a7e3a9d
Transition layout titles from being strings to be objects [882]
rmoestl Oct 30, 2018
50a1e9b
Support updating titles through `relayout` and `update` [882]
rmoestl Oct 31, 2018
4d21886
Deprecate `*.titlefont` attributes in favor of `*.title.font` [882]
rmoestl Nov 5, 2018
66a8154
Implement basic chart title alignment options [882]
rmoestl Nov 7, 2018
6f583a4
Add test to ensure current chart title position is still supported [882]
rmoestl Nov 8, 2018
185772b
Implement 'auto' values for title's `xanchor` and `yanchor` [882]
rmoestl Nov 12, 2018
ac3649b
Support deprecated axes titles syntax for multiple axes [882]
rmoestl Nov 13, 2018
493b6ec
Adapt axes tests to new `title` structure [882]
rmoestl Nov 14, 2018
4d7c4b3
Adapt axes auto-margin code to new `title` structure [882]
rmoestl Nov 14, 2018
96df782
Adapt `axes.swap` to new `title` attr structure [882]
rmoestl Nov 14, 2018
43da557
Adapt colorbar to new title attr structure [882]
rmoestl Nov 13, 2018
9e2cbfe
Adapt rangeslider to new title attr structure [882]
rmoestl Nov 14, 2018
f632a7d
Transition polar plot type to new title attr structure [882]
rmoestl Nov 15, 2018
b3367f1
Adapt legacy polar chart to new title attr structure [882]
rmoestl Nov 15, 2018
cf7f493
Transition ternary plot type to new title attr structure [882]
rmoestl Nov 15, 2018
573c90d
Deduplicate transitioning to new title structure in `cleanLayout` [882]
rmoestl Nov 15, 2018
ddf9c0b
Transition gl3d plot type to new title attr structure [882]
rmoestl Nov 15, 2018
0e144b6
Transition gl2d plot type to new title attr structure [882]
rmoestl Nov 15, 2018
984aa46
Expect new title syntax in legend, lib and further tests [882]
rmoestl Nov 15, 2018
58f402a
Reactivating editing plot title [882]
rmoestl Nov 15, 2018
5e16b02
Also call cleanLayout on `layout.template.layout` [882]
rmoestl Nov 16, 2018
7a81f27
Adjust hover template test to new title structure [882]
rmoestl Nov 20, 2018
e53e546
Adapt clonePlot function to new title attr structure [882]
rmoestl Nov 20, 2018
ca920ab
Implement padding for chart title alignment [882]
rmoestl Nov 20, 2018
37bb68c
Restrict title.y (and x) to a number between 0 and 1 [882]
rmoestl Nov 20, 2018
e438a3f
Edit attribute descriptions for new title attr structure [882]
rmoestl Nov 21, 2018
b37950d
Minor clean up in subroutines.js [882]
rmoestl Nov 21, 2018
0c2bfd7
Fix cleaning deprecated title structure on relayout/update [882]
rmoestl Nov 21, 2018
eda4f72
Fix `cleanLayout` bug [882]
rmoestl Nov 21, 2018
53ea94d
Remove small piece of obsolete code in gl3d's convert module [882]
rmoestl Nov 21, 2018
f896273
Still accept numbers as titles when defined in deprecated notation [882]
rmoestl Nov 22, 2018
f7b652b
Improve and simplify title compatibility code for relayout [882]
rmoestl Nov 22, 2018
1288121
Clear TODOs in gl3d axis_defaults.js and cloneplot.js [882]
rmoestl Nov 22, 2018
ee613bb
Streamline variable names in subroutines.js [882]
rmoestl Nov 23, 2018
678c2d9
Deprecate old title structure properly [882]
rmoestl Nov 23, 2018
598fc5f
Fix plotschema_test.js to embrace deprecated attribute containers [882]
rmoestl Nov 23, 2018
4efb546
Make explanatory comment in polar.js more clear [882]
rmoestl Nov 23, 2018
014548c
Skip overriding deprecated title attributes in polar [882]
rmoestl Nov 26, 2018
1117113
Reuse Lib.counterRegex to match deprecated title string attributes [882]
rmoestl Nov 26, 2018
c2b4c10
Pass back update data unmodified to plotly_relayout event handlers [882]
rmoestl Nov 26, 2018
86a88e2
Move legend's anchor_utils to Lib and use them in title alignment [882]
rmoestl Nov 23, 2018
5fb7b8f
Redeclare valType of title.y to be a 'number' [882]
rmoestl Nov 26, 2018
d600bbd
Merge branch 'master' into 882-chart-title-alignment
rmoestl Nov 27, 2018
a2f0543
Transition pie trace type to new title attr structure [882]
rmoestl Nov 27, 2018
a4e43a6
Transition color bar to new title attr structure [882]
rmoestl Nov 27, 2018
e4dbc5d
Transition carpet to new title attr structure [882]
rmoestl Nov 28, 2018
ef9e078
Refactor code to clean up deprecated title attr structure [882]
rmoestl Nov 28, 2018
e3bcf7c
Let '' be the default carpet axes title [882]
rmoestl Nov 28, 2018
2b26746
Reverse coerce logic for carpet axes titles [882]
rmoestl Nov 29, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/components/colorbar/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,15 @@ module.exports = function draw(gd, id) {
tickprefix: opts.tickprefix,
showticksuffix: opts.showticksuffix,
ticksuffix: opts.ticksuffix,
title: opts.title,
titlefont: opts.titlefont,

// Plot and axes titles have a different, nested attribute structure
// for defining title attributes. Since the `titles` component
// assumes that nested structure, let's adapt to it without breaking
// the existing colorbar API.
title: {
text: opts.title,
font: opts.titlefont
},
showline: true,
anchor: 'free',
side: 'right',
Expand Down Expand Up @@ -290,7 +297,7 @@ module.exports = function draw(gd, id) {
// when we squish the axis. This one only applies to
// top or bottom titles, not right side.
var x = gs.l + (opts.x + xpadFrac) * gs.w,
fontSize = cbAxisOut.titlefont.size,
fontSize = cbAxisOut.title.font.size,
y;

if(opts.titleside === 'top') {
Expand Down Expand Up @@ -460,7 +467,7 @@ module.exports = function draw(gd, id) {
},
function() {
if(['top', 'bottom'].indexOf(opts.titleside) === -1) {
var fontSize = cbAxisOut.titlefont.size,
var fontSize = cbAxisOut.title.font.size,
y = cbAxisOut._offset + cbAxisOut._length / 2,
x = gs.l + (cbAxisOut.position || 0) * gs.w + ((cbAxisOut.side === 'right') ?
10 + fontSize * ((cbAxisOut.showticklabels ? 1 : 0.5)) :
Expand Down
21 changes: 10 additions & 11 deletions src/components/legend/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ var FROM_BR = alignmentConstants.FROM_BR;
var getLegendData = require('./get_legend_data');
var style = require('./style');
var helpers = require('./helpers');
var anchorUtils = require('./anchor_utils');

var DBLCLICKDELAY = interactConstants.DBLCLICKDELAY;

Expand Down Expand Up @@ -154,17 +153,17 @@ module.exports = function draw(gd) {
lx = gs.l + gs.w * opts.x,
ly = gs.t + gs.h * (1 - opts.y);

if(anchorUtils.isRightAnchor(opts)) {
if(Lib.isRightAnchor(opts)) {
lx -= opts._width;
}
else if(anchorUtils.isCenterAnchor(opts)) {
else if(Lib.isCenterAnchor(opts)) {
lx -= opts._width / 2;
}

if(anchorUtils.isBottomAnchor(opts)) {
if(Lib.isBottomAnchor(opts)) {
ly -= opts._height;
}
else if(anchorUtils.isMiddleAnchor(opts)) {
else if(Lib.isMiddleAnchor(opts)) {
ly -= opts._height / 2;
}

Expand Down Expand Up @@ -699,18 +698,18 @@ function expandMargin(gd) {
opts = fullLayout.legend;

var xanchor = 'left';
if(anchorUtils.isRightAnchor(opts)) {
if(Lib.isRightAnchor(opts)) {
xanchor = 'right';
}
else if(anchorUtils.isCenterAnchor(opts)) {
else if(Lib.isCenterAnchor(opts)) {
xanchor = 'center';
}

var yanchor = 'top';
if(anchorUtils.isBottomAnchor(opts)) {
if(Lib.isBottomAnchor(opts)) {
yanchor = 'bottom';
}
else if(anchorUtils.isMiddleAnchor(opts)) {
else if(Lib.isMiddleAnchor(opts)) {
yanchor = 'middle';
}

Expand All @@ -730,10 +729,10 @@ function expandHorizontalMargin(gd) {
opts = fullLayout.legend;

var xanchor = 'left';
if(anchorUtils.isRightAnchor(opts)) {
if(Lib.isRightAnchor(opts)) {
xanchor = 'right';
}
else if(anchorUtils.isCenterAnchor(opts)) {
else if(Lib.isCenterAnchor(opts)) {
xanchor = 'center';
}

Expand Down
9 changes: 4 additions & 5 deletions src/components/rangeselector/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ var Drawing = require('../drawing');
var Lib = require('../../lib');
var svgTextUtils = require('../../lib/svg_text_utils');
var axisIds = require('../../plots/cartesian/axis_ids');
var anchorUtils = require('../legend/anchor_utils');

var alignmentConstants = require('../../constants/alignment');
var LINE_SPACING = alignmentConstants.LINE_SPACING;
Expand Down Expand Up @@ -218,21 +217,21 @@ function reposition(gd, buttons, opts, axName, selector) {
var ly = graphSize.t + graphSize.h * (1 - opts.y);

var xanchor = 'left';
if(anchorUtils.isRightAnchor(opts)) {
if(Lib.isRightAnchor(opts)) {
lx -= width;
xanchor = 'right';
}
if(anchorUtils.isCenterAnchor(opts)) {
if(Lib.isCenterAnchor(opts)) {
lx -= width / 2;
xanchor = 'center';
}

var yanchor = 'top';
if(anchorUtils.isBottomAnchor(opts)) {
if(Lib.isBottomAnchor(opts)) {
ly -= height;
yanchor = 'bottom';
}
if(anchorUtils.isMiddleAnchor(opts)) {
if(Lib.isMiddleAnchor(opts)) {
ly -= height / 2;
yanchor = 'middle';
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/rangeslider/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ module.exports = function(gd) {
placeholder: fullLayout._dfltTitle.x,
attributes: {
x: axisOpts._offset + axisOpts._length / 2,
y: y + opts._height + opts._offsetShift + 10 + 1.5 * axisOpts.titlefont.size,
y: y + opts._height + opts._offsetShift + 10 + 1.5 * axisOpts.title.font.size,
'text-anchor': 'middle'
}
});
Expand Down
2 changes: 1 addition & 1 deletion src/components/sliders/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ module.exports = overrideAll(templatedArray('slider', {
role: 'style',
description: 'Sets the x position (in normalized coordinates) of the slider.'
},
pad: extendDeepAll({}, padAttrs, {
pad: extendDeepAll(padAttrs({editType: 'arraydraw'}), {
description: 'Set the padding of the slider component along each side.'
}, {t: {dflt: 20}}),
xanchor: {
Expand Down
9 changes: 4 additions & 5 deletions src/components/sliders/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ var Color = require('../color');
var Drawing = require('../drawing');
var Lib = require('../../lib');
var svgTextUtils = require('../../lib/svg_text_utils');
var anchorUtils = require('../legend/anchor_utils');
var arrayEditor = require('../../plot_api/plot_template').arrayEditor;

var constants = require('./constants');
Expand Down Expand Up @@ -207,21 +206,21 @@ function findDimensions(gd, sliderOpts) {
dims.height = dims.currentValueTotalHeight + constants.tickOffset + sliderOpts.ticklen + constants.labelOffset + dims.labelHeight + sliderOpts.pad.t + sliderOpts.pad.b;

var xanchor = 'left';
if(anchorUtils.isRightAnchor(sliderOpts)) {
if(Lib.isRightAnchor(sliderOpts)) {
dims.lx -= dims.outerLength;
xanchor = 'right';
}
if(anchorUtils.isCenterAnchor(sliderOpts)) {
if(Lib.isCenterAnchor(sliderOpts)) {
dims.lx -= dims.outerLength / 2;
xanchor = 'center';
}

var yanchor = 'top';
if(anchorUtils.isBottomAnchor(sliderOpts)) {
if(Lib.isBottomAnchor(sliderOpts)) {
dims.ly -= dims.height;
yanchor = 'bottom';
}
if(anchorUtils.isMiddleAnchor(sliderOpts)) {
if(Lib.isMiddleAnchor(sliderOpts)) {
dims.ly -= dims.height / 2;
yanchor = 'middle';
}
Expand Down
16 changes: 9 additions & 7 deletions src/components/titles/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,21 @@ function draw(gd, titleClass, options) {
var group = options.containerGroup;

var fullLayout = gd._fullLayout;
var titlefont = cont.titlefont || {};
var font = titlefont.family;
var fontSize = titlefont.size;
var fontColor = titlefont.color;

var opacity = 1;
var isplaceholder = false;
var txt = (cont.title || '').trim();
var title = cont.title;
var txt = (title && title.text ? title.text : '').trim();

var font = title && title.font ? title.font : {};
var fontFamily = font.family;
var fontSize = font.size;
var fontColor = font.color;

// only make this title editable if we positively identify its property
// as one that has editing enabled.
var editAttr;
if(prop === 'title') editAttr = 'titleText';
if(prop === 'title.text') editAttr = 'titleText';
else if(prop.indexOf('axis') !== -1) editAttr = 'axisTitleText';
else if(prop.indexOf('colorbar' !== -1)) editAttr = 'colorbarTitleText';
var editable = gd._context.edits[editAttr];
Expand Down Expand Up @@ -137,7 +139,7 @@ function draw(gd, titleClass, options) {
titleEl.attr('transform', transformVal);

titleEl.style({
'font-family': font,
'font-family': fontFamily,
'font-size': d3.round(fontSize, 2) + 'px',
fill: Color.rgb(fontColor),
opacity: opacity * Color.opacity(fontColor),
Expand Down
2 changes: 1 addition & 1 deletion src/components/updatemenus/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ module.exports = overrideAll(templatedArray('updatemenu', {
].join(' ')
},

pad: extendFlat({}, padAttrs, {
pad: extendFlat(padAttrs({editType: 'arraydraw'}), {
description: 'Sets the padding around the buttons or dropdown menu.'
}),

Expand Down
9 changes: 4 additions & 5 deletions src/components/updatemenus/draw.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ var Color = require('../color');
var Drawing = require('../drawing');
var Lib = require('../../lib');
var svgTextUtils = require('../../lib/svg_text_utils');
var anchorUtils = require('../legend/anchor_utils');
var arrayEditor = require('../../plot_api/plot_template').arrayEditor;

var LINE_SPACING = require('../../constants/alignment').LINE_SPACING;
Expand Down Expand Up @@ -566,21 +565,21 @@ function findDimensions(gd, menuOpts) {
dims.ly = graphSize.t + graphSize.h * (1 - menuOpts.y);

var xanchor = 'left';
if(anchorUtils.isRightAnchor(menuOpts)) {
if(Lib.isRightAnchor(menuOpts)) {
dims.lx -= paddedWidth;
xanchor = 'right';
}
if(anchorUtils.isCenterAnchor(menuOpts)) {
if(Lib.isCenterAnchor(menuOpts)) {
dims.lx -= paddedWidth / 2;
xanchor = 'center';
}

var yanchor = 'top';
if(anchorUtils.isBottomAnchor(menuOpts)) {
if(Lib.isBottomAnchor(menuOpts)) {
dims.ly -= paddedHeight;
yanchor = 'bottom';
}
if(anchorUtils.isMiddleAnchor(menuOpts)) {
if(Lib.isMiddleAnchor(menuOpts)) {
dims.ly -= paddedHeight / 2;
yanchor = 'middle';
}
Expand Down
11 changes: 8 additions & 3 deletions src/constants/alignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,17 @@ module.exports = {
// multiple of fontSize to get the vertical offset between lines
LINE_SPACING: 1.3,

// multiple of fontSize to shift from the baseline to the midline
// multiple of fontSize to shift from the baseline
// to the cap (captical letter) line
// (to use when we don't calculate this shift from Drawing.bBox)
// To be precise this should be half the cap height (capital letter)
// of the font, and according to wikipedia:
// This is an approximation since in reality cap height can differ
// from font to font. However, according to Wikipedia
// an "average" font might have a cap height of 70% of the em
// https://en.wikipedia.org/wiki/Em_(typography)#History
CAP_SHIFT: 0.70,

// half the cap height (distance between baseline and cap line)
// of an "average" font (for more info see above).
MID_SHIFT: 0.35,

OPPOSITE_SIDE: {
Expand Down
62 changes: 62 additions & 0 deletions src/lib/anchor_utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Copyright 2012-2018, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/


'use strict';


/**
* Determine the position anchor property of x/y xanchor/yanchor components.
*
* - values < 1/3 align the low side at that fraction,
* - values [1/3, 2/3] align the center at that fraction,
* - values > 2/3 align the right at that fraction.
*/


exports.isLeftAnchor = function isLeftAnchor(opts) {
return (
opts.xanchor === 'left' ||
(opts.xanchor === 'auto' && opts.x <= 1 / 3)
);
};

exports.isCenterAnchor = function isCenterAnchor(opts) {
return (
opts.xanchor === 'center' ||
(opts.xanchor === 'auto' && opts.x > 1 / 3 && opts.x < 2 / 3)
);
};

exports.isRightAnchor = function isRightAnchor(opts) {
return (
opts.xanchor === 'right' ||
(opts.xanchor === 'auto' && opts.x >= 2 / 3)
);
};

exports.isTopAnchor = function isTopAnchor(opts) {
return (
opts.yanchor === 'top' ||
(opts.yanchor === 'auto' && opts.y >= 2 / 3)
);
};

exports.isMiddleAnchor = function isMiddleAnchor(opts) {
return (
opts.yanchor === 'middle' ||
(opts.yanchor === 'auto' && opts.y > 1 / 3 && opts.y < 2 / 3)
);
};

exports.isBottomAnchor = function isBottomAnchor(opts) {
return (
opts.yanchor === 'bottom' ||
(opts.yanchor === 'auto' && opts.y <= 1 / 3)
);
};
8 changes: 8 additions & 0 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,14 @@ lib.pathArc = anglesModule.pathArc;
lib.pathSector = anglesModule.pathSector;
lib.pathAnnulus = anglesModule.pathAnnulus;

var anchorUtils = require('./anchor_utils');
lib.isLeftAnchor = anchorUtils.isLeftAnchor;
lib.isCenterAnchor = anchorUtils.isCenterAnchor;
lib.isRightAnchor = anchorUtils.isRightAnchor;
lib.isTopAnchor = anchorUtils.isTopAnchor;
lib.isMiddleAnchor = anchorUtils.isMiddleAnchor;
lib.isBottomAnchor = anchorUtils.isBottomAnchor;

var geom2dModule = require('./geometry2d');
lib.segmentsIntersect = geom2dModule.segmentsIntersect;
lib.segmentDistance = geom2dModule.segmentDistance;
Expand Down
8 changes: 5 additions & 3 deletions src/lib/regex.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
* @param {Optional(string)} tail: a fixed piece after the id
* eg counterRegex('scene', '.annotations') for scene2.annotations etc.
* @param {boolean} openEnded: if true, the string may continue past the match.
* @param {boolean} matchBeginning: if false, the string may start before the match.
*/
exports.counter = function(head, tail, openEnded) {
exports.counter = function(head, tail, openEnded, matchBeginning) {
var fullTail = (tail || '') + (openEnded ? '' : '$');
var startWithPrefix = matchBeginning === false ? '' : '^';
if(head === 'xy') {
return new RegExp('^x([2-9]|[1-9][0-9]+)?y([2-9]|[1-9][0-9]+)?' + fullTail);
return new RegExp(startWithPrefix + 'x([2-9]|[1-9][0-9]+)?y([2-9]|[1-9][0-9]+)?' + fullTail);
}
return new RegExp('^' + head + '([2-9]|[1-9][0-9]+)?' + fullTail);
return new RegExp(startWithPrefix + head + '([2-9]|[1-9][0-9]+)?' + fullTail);
};
Loading