Skip to content

Commit ea8e6d1

Browse files
authored
Merge pull request #6454 from plotly/add-text-to-shapes
Support adding text labels to lines and shapes
2 parents 1d21d64 + d927b6a commit ea8e6d1

17 files changed

+890
-17
lines changed

draftlogs/6454_add.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
- Add `label` attribute to shapes [[#6454](https://github.com/plotly/plotly.js/pull/6454)], with thanks to
2+
the [Volkswagen](https://www.volkswagenag.com) Center of Excellence for Battery Cells for sponsoring development!

src/components/shapes/attributes.js

+81-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
var annAttrs = require('../annotations/attributes');
4+
var fontAttrs = require('../../plots/font_attributes');
45
var scatterLineAttrs = require('../../traces/scatter/attributes').line;
56
var dash = require('../drawing/attributes').dash;
67
var extendFlat = require('../../lib/extend').extendFlat;
@@ -224,6 +225,85 @@ module.exports = templatedArray('shape', {
224225
'`config.editable` or `config.edits.shapePosition`.'
225226
].join(' ')
226227
},
227-
228+
label: {
229+
text: {
230+
valType: 'string',
231+
dflt: '',
232+
editType: 'arraydraw',
233+
description: 'Sets the text to display with shape.'
234+
},
235+
font: fontAttrs({
236+
editType: 'calc+arraydraw',
237+
colorEditType: 'arraydraw',
238+
description: 'Sets the shape label text font.'
239+
}),
240+
textposition: {
241+
valType: 'enumerated',
242+
values: [
243+
'top left', 'top center', 'top right',
244+
'middle left', 'middle center', 'middle right',
245+
'bottom left', 'bottom center', 'bottom right',
246+
'start', 'middle', 'end',
247+
],
248+
editType: 'arraydraw',
249+
description: [
250+
'Sets the position of the label text relative to the shape.',
251+
'Supported values for rectangles, circles and paths are',
252+
'*top left*, *top center*, *top right*, *middle left*,',
253+
'*middle center*, *middle right*, *bottom left*, *bottom center*,',
254+
'and *bottom right*.',
255+
'Supported values for lines are *start*, *middle*, and *end*.',
256+
'Default: *middle center* for rectangles, circles, and paths; *middle* for lines.',
257+
].join(' ')
258+
},
259+
textangle: {
260+
valType: 'angle',
261+
dflt: 'auto',
262+
editType: 'calc+arraydraw',
263+
description: [
264+
'Sets the angle at which the label text is drawn',
265+
'with respect to the horizontal. For lines, angle *auto*',
266+
'is the same angle as the line. For all other shapes,',
267+
'angle *auto* is horizontal.'
268+
].join(' ')
269+
},
270+
xanchor: {
271+
valType: 'enumerated',
272+
values: ['auto', 'left', 'center', 'right'],
273+
dflt: 'auto',
274+
editType: 'calc+arraydraw',
275+
description: [
276+
'Sets the label\'s horizontal position anchor',
277+
'This anchor binds the specified `textposition` to the *left*, *center*',
278+
'or *right* of the label text.',
279+
'For example, if `textposition` is set to *top right* and',
280+
'`xanchor` to *right* then the right-most portion of the',
281+
'label text lines up with the right-most edge of the',
282+
'shape.',
283+
].join(' '),
284+
},
285+
yanchor: {
286+
valType: 'enumerated',
287+
values: ['top', 'middle', 'bottom'],
288+
editType: 'calc+arraydraw',
289+
description: [
290+
'Sets the label\'s vertical position anchor',
291+
'This anchor binds the specified `textposition` to the *top*, *middle*',
292+
'or *bottom* of the label text.',
293+
'For example, if `textposition` is set to *top right* and',
294+
'`yanchor` to *top* then the top-most portion of the',
295+
'label text lines up with the top-most edge of the',
296+
'shape.',
297+
].join(' ')
298+
},
299+
padding: {
300+
valType: 'number',
301+
dflt: 3,
302+
min: 0,
303+
editType: 'arraydraw',
304+
description: 'Sets padding (in px) between edge of label and edge of shape.'
305+
},
306+
editType: 'arraydraw'
307+
},
228308
editType: 'arraydraw'
229309
});

src/components/shapes/defaults.js

+21
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut) {
1515
});
1616
};
1717

18+
function dfltLabelYanchor(isLine, labelTextPosition) {
19+
// If shape is a line, default y-anchor is 'bottom' (so that text is above line by default)
20+
// Otherwise, default y-anchor is equal to y-component of `textposition`
21+
// (so that text is positioned inside shape bounding box by default)
22+
return isLine ? 'bottom' :
23+
labelTextPosition.indexOf('top') !== -1 ? 'top' :
24+
labelTextPosition.indexOf('bottom') !== -1 ? 'bottom' : 'middle';
25+
}
26+
1827
function handleShapeDefaults(shapeIn, shapeOut, fullLayout) {
1928
function coerce(attr, dflt) {
2029
return Lib.coerce(shapeIn, shapeOut, attributes, attr, dflt);
@@ -116,4 +125,16 @@ function handleShapeDefaults(shapeIn, shapeOut, fullLayout) {
116125
if(noPath) {
117126
Lib.noneOrAll(shapeIn, shapeOut, ['x0', 'x1', 'y0', 'y1']);
118127
}
128+
129+
// Label options
130+
var isLine = shapeType === 'line';
131+
var labelText = coerce('label.text');
132+
if(labelText) {
133+
coerce('label.textangle');
134+
var labelTextPosition = coerce('label.textposition', isLine ? 'middle' : 'middle center');
135+
coerce('label.xanchor');
136+
coerce('label.yanchor', dfltLabelYanchor(isLine, labelTextPosition));
137+
coerce('label.padding');
138+
Lib.coerceFont(coerce, 'label.font', fullLayout.font);
139+
}
119140
}

src/components/shapes/display_outlines.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ module.exports = function displayOutlines(polygons, outlines, dragOptions, nCall
3636
// recursive call
3737
displayOutlines(polygons, outlines, dragOptions, nCalls++);
3838

39-
if(pointsOnEllipse(polygons[0])) {
39+
if(pointsOnEllipse(polygons[0]) || dragOptions.hasText) {
4040
update({redrawing: true});
4141
}
4242
}

0 commit comments

Comments
 (0)