Skip to content
Merged
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
1 change: 1 addition & 0 deletions draftlogs/7951_fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Fix issue where plot fails to render if unsupported MathJax version is present on page [[#7951](https://github.com/plotly/plotly.js/pull/7951)]
37 changes: 27 additions & 10 deletions src/lib/svg_text_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ exports.convertToTspans = function(_context, gd, _callback) {
// allow some elements to prohibit it by attaching 'data-notex' to the original
var tex = (!_context.attr('data-notex')) &&
gd && gd._context.typesetMath &&
(typeof MathJax !== 'undefined') &&
matchTex(str);

// Only complain about MathJax version once we know there's actually math to render
if(tex && !isMathJaxVersionSupported()) tex = null;

var parent = d3.select(_context.node().parentNode);
if(parent.empty()) return;
var svgClass = (_context.attr('class')) ? _context.attr('class').split(' ')[0] : 'text';
Expand Down Expand Up @@ -204,18 +206,33 @@ function cleanEscapesForTex(s) {
// and reused for subsequent calls.
var mathjaxSVGDocument = null;

function texToSVG(_texString, _config, _callback) {
const MathJaxVersion = parseInt(
(MathJax.version || '').split('.')[0]
);
// Function which returns the major version of MathJax as an integer,
// or null if MathJax is undefined or MathJax.version is falsy.
const mathJaxMajorVersion = () => (typeof MathJax !== 'undefined' && MathJax.version) ? parseInt(MathJax.version.split('.')[0]) : null;

if(
MathJaxVersion !== 3 &&
MathJaxVersion !== 4
) {
// Only warn once per page about each of these conditions
var warnedMissingMathJax = false;
var warnedUnsupportedMathJax = false;

// plotly.js is only compatible with MathJax v3 and v4.
function isMathJaxVersionSupported() {
const version = mathJaxMajorVersion();
if(version === 3 || version === 4) return true;

if(version === null) {
if(!warnedMissingMathJax) {
warnedMissingMathJax = true;
Lib.warn('MathJax is not loaded. Math equations will not be rendered.');
}
} else if(!warnedUnsupportedMathJax) {
warnedUnsupportedMathJax = true;
Lib.warn('Unsupported MathJax version:', MathJax.version);
return;
}
return false;
}

function texToSVG(_texString, _config, _callback) {
const MathJaxVersion = mathJaxMajorVersion();

var tmpDiv;

Expand Down
44 changes: 44 additions & 0 deletions test/jasmine/bundle_tests/mathjax_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,4 +159,48 @@ describe('Test MathJax v' + mathjaxVersion + ':', function() {
.then(done, done.fail);
});
});

describe('Test tex rendering:', function() {
var gd;

beforeEach(function() {
gd = createGraphDiv();
});

afterEach(destroyGraphDiv);

it('should hand tex titles and tick labels off to MathJax', function(done) {
Plotly.newPlot(gd, {
data: [{
x: ['$\\phi$', '$\\nabla \\cdot \\vec{F}$'],
y: [1, 2]
}],
layout: {
title: { text: '$E = mc^2$' }
}
})
.then(function() {
var gd3 = d3Select(gd);

// '.gtitle-math-group' is only added once MathJax has typeset the
// string, so its presence is what tells us the tex was rendered
expect(gd3.selectAll('.gtitle-math-group').size()).toBe(1, 'title math group');

// tick label math groups carry the default 'text-math-group' class
expect(gd3.selectAll('.text-math-group').size()).toBe(2, 'tick label math groups');

var rendered = [];
gd3.selectAll('[class*=-math-group]').each(function() {
expect(this.getAttribute('data-math')).toBe('Y');
rendered.push(this.getAttribute('data-unformatted'));
});
expect(rendered.sort()).toEqual([
'$E = mc^2$',
'$\\nabla \\cdot \\vec{F}$',
'$\\phi$'
]);
})
.then(done, done.fail);
});
});
});
41 changes: 41 additions & 0 deletions test/jasmine/tests/svg_text_utils_test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
var d3Select = require('../../strict-d3').select;
var d3SelectAll = require('../../strict-d3').selectAll;

var Plotly = require('../../../lib/index');
var util = require('../../../src/lib/svg_text_utils');

var createGraphDiv = require('../assets/create_graph_div');
var destroyGraphDiv = require('../assets/destroy_graph_div');


describe('svg+text utils', function() {
'use strict';
Expand Down Expand Up @@ -619,3 +623,40 @@ describe('sanitizeHTML', function() {
expect(innerHTML).toEqual('<a href="https://example.com/?q=date%20%3E=%202018-01-01">click</a>');
});
});

// regression test for https://github.com/plotly/plotly.js/issues/7926
describe('convertToTspans with an unsupported MathJax version', function() {
'use strict';

var gd;
var mathJaxBefore;

beforeEach(function() {
gd = createGraphDiv();
mathJaxBefore = window.MathJax;
// Fake the presence of MathJax v2 by clearing window.MathJax
// and setting window.MathJax.version to a v2.x version string
window.MathJax = {version: '2.7.9'};
});

afterEach(function() {
if(mathJaxBefore === undefined) delete window.MathJax;
else window.MathJax = mathJaxBefore;
destroyGraphDiv();
});

it('draws the plot with the tex left unevaluated', function(done) {
Plotly.newPlot(gd, [{y: [1, 2, 3]}], {title: {text: '$x^2$'}})
.then(function() {
// whole plot should render except for tex string
expect(d3SelectAll('.scatterlayer .trace').size()).toBe(1, 'trace');
expect(d3SelectAll('.xtick').size()).toBeGreaterThan(0, 'x ticks');

var title = d3Select('.gtitle');
expect(title.size()).toBe(1, 'title');
expect(title.text()).toBe('$x^2$', 'raw tex as title');
expect(title.node().style.display).not.toBe('none', 'title is visible');
})
.then(done, done.fail);
});
});