Skip to content

Commit e6343d9

Browse files
authored
Merge pull request #3443 from plotly/sub-sup-in-extra-hover-label
Add support for <sub> and <sup> in "extra" hover label
2 parents 0251a0c + 6c7b0ed commit e6343d9

File tree

4 files changed

+271
-139
lines changed

4 files changed

+271
-139
lines changed

src/components/fx/hover.js

+16-18
Original file line numberDiff line numberDiff line change
@@ -925,15 +925,10 @@ function createHoverText(hoverData, opts, gd) {
925925
if(d.nameOverride !== undefined) d.name = d.nameOverride;
926926

927927
if(d.name) {
928-
// strip out our pseudo-html elements from d.name (if it exists at all)
929-
name = svgTextUtils.plainText(d.name || '');
930-
931-
var nameLength = Math.round(d.nameLength);
932-
933-
if(nameLength > -1 && name.length > nameLength) {
934-
if(nameLength > 3) name = name.substr(0, nameLength - 3) + '...';
935-
else name = name.substr(0, nameLength);
936-
}
928+
name = svgTextUtils.plainText(d.name || '', {
929+
len: d.nameLength,
930+
allowedTags: ['br', 'sub', 'sup', 'b', 'i', 'em']
931+
});
937932
}
938933

939934
if(d.zLabel !== undefined) {
@@ -995,6 +990,7 @@ function createHoverText(hoverData, opts, gd) {
995990

996991
var tx2 = g.select('text.name');
997992
var tx2width = 0;
993+
var tx2height = 0;
998994

999995
// secondary label for non-empty 'name'
1000996
if(name && name !== text) {
@@ -1006,18 +1002,20 @@ function createHoverText(hoverData, opts, gd) {
10061002
.attr('data-notex', 1)
10071003
.call(svgTextUtils.positionText, 0, 0)
10081004
.call(svgTextUtils.convertToTspans, gd);
1009-
tx2width = tx2.node().getBoundingClientRect().width + 2 * HOVERTEXTPAD;
1010-
}
1011-
else {
1005+
1006+
var t2bb = tx2.node().getBoundingClientRect();
1007+
tx2width = t2bb.width + 2 * HOVERTEXTPAD;
1008+
tx2height = t2bb.height + 2 * HOVERTEXTPAD;
1009+
} else {
10121010
tx2.remove();
10131011
g.select('rect').remove();
10141012
}
10151013

1016-
g.select('path')
1017-
.style({
1018-
fill: numsColor,
1019-
stroke: contrastColor
1020-
});
1014+
g.select('path').style({
1015+
fill: numsColor,
1016+
stroke: contrastColor
1017+
});
1018+
10211019
var tbb = tx.node().getBoundingClientRect();
10221020
var htx = d.xa._offset + (d.x0 + d.x1) / 2;
10231021
var hty = d.ya._offset + (d.y0 + d.y1) / 2;
@@ -1028,7 +1026,7 @@ function createHoverText(hoverData, opts, gd) {
10281026

10291027
d.ty0 = outerTop - tbb.top;
10301028
d.bx = tbb.width + 2 * HOVERTEXTPAD;
1031-
d.by = tbb.height + 2 * HOVERTEXTPAD;
1029+
d.by = Math.max(tbb.height + 2 * HOVERTEXTPAD, tx2height);
10321030
d.anchor = 'start';
10331031
d.txwidth = tbb.width;
10341032
d.tx2width = tx2width;

src/lib/svg_text_utils.js

+60-6
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,6 @@ var ZERO_WIDTH_SPACE = '\u200b';
264264
*/
265265
var PROTOCOLS = ['http:', 'https:', 'mailto:', '', undefined, ':'];
266266

267-
var STRIP_TAGS = new RegExp('</?(' + Object.keys(TAG_STYLES).join('|') + ')( [^>]*)?/?>', 'g');
268-
269267
var NEWLINES = /(\r\n?|\n)/g;
270268

271269
var SPLIT_TAGS = /(<[^<>]*>)/;
@@ -315,10 +313,66 @@ function getQuotedMatch(_str, re) {
315313

316314
var COLORMATCH = /(^|;)\s*color:/;
317315

318-
exports.plainText = function(_str) {
319-
// strip out our pseudo-html so we have a readable
320-
// version to put into text fields
321-
return (_str || '').replace(STRIP_TAGS, ' ');
316+
/**
317+
* Strip string of tags
318+
*
319+
* @param {string} _str : input string
320+
* @param {object} opts :
321+
* - maxLen {number} max length of output string
322+
* - allowedTags {array} list of pseudo-html tags to NOT strip
323+
* @return {string}
324+
*/
325+
exports.plainText = function(_str, opts) {
326+
opts = opts || {};
327+
328+
var len = (opts.len !== undefined && opts.len !== -1) ? opts.len : Infinity;
329+
var allowedTags = opts.allowedTags !== undefined ? opts.allowedTags : ['br'];
330+
331+
var ellipsis = '...';
332+
var eLen = ellipsis.length;
333+
334+
var oldParts = _str.split(SPLIT_TAGS);
335+
var newParts = [];
336+
var prevTag = '';
337+
var l = 0;
338+
339+
for(var i = 0; i < oldParts.length; i++) {
340+
var p = oldParts[i];
341+
var match = p.match(ONE_TAG);
342+
var tagType = match && match[2].toLowerCase();
343+
344+
if(tagType) {
345+
// N.B. tags do not count towards string length
346+
if(allowedTags.indexOf(tagType) !== -1) {
347+
newParts.push(p);
348+
prevTag = tagType;
349+
}
350+
} else {
351+
var pLen = p.length;
352+
353+
if((l + pLen) < len) {
354+
newParts.push(p);
355+
l += pLen;
356+
} else if(l < len) {
357+
var pLen2 = len - l;
358+
359+
if(prevTag && (prevTag !== 'br' || pLen2 <= eLen || pLen <= eLen)) {
360+
newParts.pop();
361+
}
362+
363+
if(len > eLen) {
364+
newParts.push(p.substr(0, pLen2 - eLen) + ellipsis);
365+
} else {
366+
newParts.push(p.substr(0, pLen2));
367+
}
368+
break;
369+
}
370+
371+
prevTag = '';
372+
}
373+
}
374+
375+
return newParts.join('');
322376
};
323377

324378
/*

0 commit comments

Comments
 (0)