Fix tex hover label name truncation and rotated label placement by SergeyAxiomatic · Pull Request #8138 · plotly/plotly.js · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions draftlogs/8138_fix.md
6 changes: 4 additions & 2 deletions src/components/fx/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -2650,8 +2650,10 @@ function spikesChanged(gd, oldspikepoints) {
}

function plainText(s, len) {
return svgTextUtils.plainText(s || '', {
len: len,
s = s || '';
return svgTextUtils.plainText(s, {
// truncating a tex expression drops its closing $, so it would no longer be typeset
len: svgTextUtils.isPureTex(s) ? undefined : len,
allowedTags: ['br', 'sub', 'sup', 'b', 'i', 'em', 's', 'u']
});
}
Expand Down
33 changes: 30 additions & 3 deletions src/lib/svg_text_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,30 @@ const isPureTex = (str) => {
};
exports.isPureTex = isPureTex;

/**
* Size of the typeset glyphs in their own coordinate system when an ancestor
* is rotated (e.g. a hover label in hovermode 'y'), where getBoundingClientRect
* would report the larger screen-space box of the rotated shape.
*
* @param {d3 selection} newSvg: the typeset <svg>
* @param {d3 selection} g: the <g> inside newSvg that holds the glyphs
* @return {?{width: number, height: number}} null if no ancestor is rotated
*/
function getUnrotatedSize(newSvg, g) {
var svgNode = newSvg.node();
var ctm = svgNode.getScreenCTM();
if(!ctm || (Math.abs(ctm.b) < 1e-6 && Math.abs(ctm.c) < 1e-6)) return null;

var bbox = g.node().getBBox();
var viewBox = svgNode.viewBox.baseVal;
// the glyphs are letterboxed, so they scale by the smaller of the two ratios
var scale = Math.min(
svgNode.width.baseVal.value / viewBox.width,
svgNode.height.baseVal.value / viewBox.height
);
return {width: bbox.width * scale, height: bbox.height * scale};
}

/**
* Positions a MathJax-typeset group against its source <text> node's x/y
* and text-anchor.
Expand All @@ -50,10 +74,13 @@ exports.isPureTex = isPureTex;
* @param {number} [width0]: the SVG's own reported width, to detect the
* Firefox v82+ overflow bug (see link below); omit to skip that check
* @param {number} [height0]: same, for height
* @param {boolean} [unrotated]: measure in the group's own coordinates when an
* ancestor is rotated. Off by default so convertToTspans' other callers keep
* the screen-space measurement they were laid out with
*/
function positionMathGroup(_context, svgClass, mathjaxGroup, newSvg, textAnchor, fontSize, width0, height0) {
function positionMathGroup(_context, svgClass, mathjaxGroup, newSvg, textAnchor, fontSize, width0, height0, unrotated) {
var g = newSvg.select('g');
var bb = g.node().getBoundingClientRect();
var bb = (unrotated && getUnrotatedSize(newSvg, g)) || g.node().getBoundingClientRect();
var w = bb.width;
var h = bb.height;
var w0 = width0 === undefined ? w : width0;
Expand Down Expand Up @@ -260,7 +287,7 @@ exports.repositionMathGroup = function(_context) {

var textAnchor = _context.attr('text-anchor');
var fontSize = parseInt(_context.node().style.fontSize, 10);
positionMathGroup(_context, svgClass, mathjaxGroup, newSvg, textAnchor, fontSize);
positionMathGroup(_context, svgClass, mathjaxGroup, newSvg, textAnchor, fontSize, undefined, undefined, true);
};

/**
Expand Down
141 changes: 141 additions & 0 deletions test/jasmine/bundle_tests/mathjax_test.js
Loading