diff --git a/README.md b/README.md index 68a51412ccf..96e23654268 100644 --- a/README.md +++ b/README.md @@ -95,17 +95,23 @@ While non-minified source files may contain characters outside UTF-8, it is reco > Please note that as of v2 the "plotly-latest" outputs (e.g. https://cdn.plot.ly/plotly-latest.min.js) will no longer be updated on the CDN, and will stay at the last v1 patch v1.58.5. Therefore, to use the CDN with plotly.js v2 and higher, you must specify an exact plotly.js version. ### MathJax -You can load either version two or version three of MathJax files. For example: +plotly.js supports using MathJax v3 or v4 to render mathematical expressions within plots. + +MathJax is not included in the plotly.js bundle, so it must be loaded separately as a script on the webpage. + +For MathJax v4: ```html - + ``` +For MathJax v3: ```html ``` -> When using MathJax version 3, it is also possible to use `chtml` output on the other parts of the page in addition to `svg` output for the plotly graph. -Please refer to `devtools/test_dashboard/index-mathjax3chtml.html` to see an example. +When MathJax is available, any string contained within `$..$` signs will be rendered using the MathJax engine. This applies to plot titles, axis labels, tick label text, and annotations. + +plotly.js's use of the MathJax `svg` renderer should not prevent using other MathJax renderers elsewhere on the page, nor will it affect the global MathJax config. See `devtools/test_dashboard/index-mathjax3chtml.html` for an example of a webpage which uses the MathJax `chtml` renderer in the main page, and also displays Plotly charts containing MathJax equations rendered as `svg`. ### Need to have several WebGL graphs on a page? You may simply load the [virtual-webgl](https://github.com/greggman/virtual-webgl) script for WebGL 1 (not WebGL 2) before loading other scripts. diff --git a/devtools/test_dashboard/index-mathjax3.html b/devtools/test_dashboard/index-mathjax3.html index 510e839fa7f..9dd126ba155 100644 --- a/devtools/test_dashboard/index-mathjax3.html +++ b/devtools/test_dashboard/index-mathjax3.html @@ -38,7 +38,7 @@

no MathJax: Apple: $2, Orange: $3

}; - + diff --git a/devtools/test_dashboard/index-mathjax3chtml.html b/devtools/test_dashboard/index-mathjax3chtml.html index 795c5688703..815d5b3d349 100644 --- a/devtools/test_dashboard/index-mathjax3chtml.html +++ b/devtools/test_dashboard/index-mathjax3chtml.html @@ -49,12 +49,7 @@ options.format = svgDocument.inputJax[0].name; return svgDocument.convert(math, options); }; - /* - MathJax.tex2svgPromise = (math, options = {}) => { - options.format = svgDocument.inputJax[0].name; - return mathjax.handleRetriesFor(() => svgDocument.convert(math, options)); - }; - */ + MathJax.svgStylesheet = () => svgOutput.styleSheet(svgDocument); } } @@ -62,7 +57,7 @@ - + diff --git a/devtools/test_dashboard/index.html b/devtools/test_dashboard/index.html index de0841cc650..521077098c0 100644 --- a/devtools/test_dashboard/index.html +++ b/devtools/test_dashboard/index.html @@ -27,7 +27,7 @@ - + diff --git a/draftlogs/7898_change.md b/draftlogs/7898_change.md new file mode 100644 index 00000000000..fc7e2927bc8 --- /dev/null +++ b/draftlogs/7898_change.md @@ -0,0 +1 @@ +- Add support for MathJax v4, and **drop support for v2** [[#7898](https://github.com/plotly/plotly.js/pull/7898)] diff --git a/package-lock.json b/package-lock.json index 33b6740c070..f08cad23e78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,8 +54,8 @@ }, "devDependencies": { "@biomejs/biome": "2.2.0", - "@plotly/mathjax-v2": "npm:mathjax@2.7.5", - "@plotly/mathjax-v3": "npm:mathjax@^3.2.2", + "@plotly/mathjax-v3": "npm:mathjax@3.2.2", + "@plotly/mathjax-v4": "npm:mathjax@^4.1.2", "@types/d3": "3.5.34", "@types/node": "^24.10.0", "amdefine": "^1.0.1", @@ -626,6 +626,13 @@ "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" }, + "node_modules/@mathjax/mathjax-newcm-font": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@mathjax/mathjax-newcm-font/-/mathjax-newcm-font-4.1.3.tgz", + "integrity": "sha512-gzAB3dFHilHX1l5x2xUqRL+1jDQt3Fyza1DkEMVXWC4E8SvsGdlgEza47HYi2WhVcgfkvf4zgUGzuhbq3Pjlew==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -697,13 +704,6 @@ "elementary-circuits-directed-graph": "^1.0.4" } }, - "node_modules/@plotly/mathjax-v2": { - "name": "mathjax", - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz", - "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==", - "dev": true - }, "node_modules/@plotly/mathjax-v3": { "name": "mathjax", "version": "3.2.2", @@ -711,6 +711,17 @@ "integrity": "sha512-Bt+SSVU8eBG27zChVewOicYs7Xsdt40qm4+UpHyX7k0/O9NliPc+x77k1/FEsPsjKPZGJvtRZM1vO+geW0OhGw==", "dev": true }, + "node_modules/@plotly/mathjax-v4": { + "name": "mathjax", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-4.1.3.tgz", + "integrity": "sha512-BN/8Pkgn7G1pIDYJqd9md+JHsE/jydSYbyOZnSdSA0WziuVO8mRxdYiWFumkVVly/8U+hm9DpIIoWuvySverzw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@mathjax/mathjax-newcm-font": "^4.1.3" + } + }, "node_modules/@plotly/point-cluster": { "version": "3.1.9", "resolved": "https://registry.npmjs.org/@plotly/point-cluster/-/point-cluster-3.1.9.tgz", diff --git a/package.json b/package.json index 5b3d9044e75..1d8f1c84352 100644 --- a/package.json +++ b/package.json @@ -115,8 +115,8 @@ }, "devDependencies": { "@biomejs/biome": "2.2.0", - "@plotly/mathjax-v2": "npm:mathjax@2.7.5", - "@plotly/mathjax-v3": "npm:mathjax@^3.2.2", + "@plotly/mathjax-v3": "npm:mathjax@3.2.2", + "@plotly/mathjax-v4": "npm:mathjax@^4.1.2", "@types/d3": "3.5.34", "@types/node": "^24.10.0", "amdefine": "^1.0.1", diff --git a/src/lib/svg_text_utils.js b/src/lib/svg_text_utils.js index d4bd953684b..76f1645f098 100644 --- a/src/lib/svg_text_utils.js +++ b/src/lib/svg_text_utils.js @@ -78,6 +78,10 @@ exports.convertToTspans = function(_context, gd, _callback) { _context.style('display', 'none'); var fontSize = parseInt(_context.node().style.fontSize, 10); var config = {fontSize: fontSize}; + // Capture the text-anchor value now, since the the callback function below + // will run async, and in the meantime the text-anchor may change + // which would result in a wrongly-positioned SVG + var textAnchor = _context.attr('text-anchor'); texToSVG(tex[2], config, function(_svgEl, _glyphDefs, _svgBBox) { parent.selectAll('svg.' + svgClass).remove(); @@ -90,6 +94,11 @@ exports.convertToTspans = function(_context, gd, _callback) { return; } + // Now that the MathJax render has finished, re-hide the source text. + // We hid it earlier, too, but since this callback runs async, + // another function may have made it visible again + _context.style('display', 'none'); + var mathjaxGroup = parent.append('g') .classed(svgClass + '-group', true) .attr({ @@ -151,11 +160,9 @@ exports.convertToTspans = function(_context, gd, _callback) { x = 0; y = dy; } else { - var anchor = _context.attr('text-anchor'); - x = x - w * ( - anchor === 'middle' ? 0.5 : - anchor === 'end' ? 1 : 0 + textAnchor === 'middle' ? 0.5 : + textAnchor === 'end' ? 1 : 0 ); y = y + dy - h / 2; } @@ -185,154 +192,87 @@ function cleanEscapesForTex(s) { .replace(GT_MATCH, '\\gt '); } -var inlineMath = [['$', '$'], ['\\(', '\\)']]; +// Create a dedicated MathDocument just for Plotly.js, +// to avoid interfering with any other MathJax on the page. +// mathjaxSVGDocument is initialized on the first call to texToSVG(), +// and reused for subsequent calls. +var mathjaxSVGDocument = null; function texToSVG(_texString, _config, _callback) { - var MathJaxVersion = parseInt( + const MathJaxVersion = parseInt( (MathJax.version || '').split('.')[0] ); if( - MathJaxVersion !== 2 && - MathJaxVersion !== 3 + MathJaxVersion !== 3 && + MathJaxVersion !== 4 ) { - Lib.warn('No MathJax version:', MathJax.version); + Lib.warn('Unsupported MathJax version:', MathJax.version); return; } - var originalRenderer, - originalConfig, - originalProcessSectionDelay, - tmpDiv; - - var setConfig2 = function() { - originalConfig = Lib.extendDeepAll({}, MathJax.Hub.config); - - originalProcessSectionDelay = MathJax.Hub.processSectionDelay; - if(MathJax.Hub.processSectionDelay !== undefined) { - // MathJax 2.5+ but not 3+ - MathJax.Hub.processSectionDelay = 0; - } - - return MathJax.Hub.Config({ - messageStyle: 'none', - tex2jax: { - inlineMath: inlineMath - }, - displayAlign: 'left', - }); - }; - - var setConfig3 = function() { - originalConfig = Lib.extendDeepAll({}, MathJax.config); - - if(!MathJax.config.tex) { - MathJax.config.tex = {}; - } - - MathJax.config.tex.inlineMath = inlineMath; - }; - - var setRenderer2 = function() { - originalRenderer = MathJax.Hub.config.menuSettings.renderer; - if(originalRenderer !== 'SVG') { - return MathJax.Hub.setRenderer('SVG'); - } - }; - - var setRenderer3 = function() { - originalRenderer = MathJax.config.startup.output; - if(originalRenderer !== 'svg') { - MathJax.config.startup.output = 'svg'; + var tmpDiv; + + const initiateMathJax = function() { + if(!mathjaxSVGDocument) { + const SVG = MathJax._.output.svg_ts.SVG; + // fontCache 'local' keeps each rendered svg self-contained + const svgConfig = Lib.extendFlat({}, MathJax.config.svg, {fontCache: 'local'}); + // MathJax v4 enables automatic inline linebreaking by default, which + // messes up our layout assumptions. Disabling it gives behavior consistent with v3. + if(MathJaxVersion === 4) { + svgConfig.linebreaks = Lib.extendFlat({}, svgConfig.linebreaks, {inline: false}); + } + mathjaxSVGDocument = MathJax._.mathjax.mathjax.document(document, Lib.extendFlat({}, MathJax.config.options, { + InputJax: MathJax.startup.input, + OutputJax: new SVG(svgConfig) + })); } - }; - var initiateMathJax = function() { - var randomID = 'math-output-' + Lib.randstr({}, 64); + const randomID = 'math-output-' + Lib.randstr({}, 64); tmpDiv = d3.select('body').append('div') .attr({id: randomID}) .style({ visibility: 'hidden', position: 'absolute', 'font-size': _config.fontSize + 'px' - }) - .text(cleanEscapesForTex(_texString)); - - var tmpNode = tmpDiv.node(); + }); - return MathJaxVersion === 2 ? - MathJax.Hub.Typeset(tmpNode) : - MathJax.typeset([tmpNode]); + // Strip $…$ delimiters and clean up escape charaters, + // then pass the result to MathDocument.convert() to get an SVG element back + const texMath = cleanEscapesForTex(_texString).replace(/^\$+|\$+$/g, ''); + return MathJax._.mathjax.mathjax.handleRetriesFor(function() { + return mathjaxSVGDocument.convert(texMath, {display: false}); + }).then(function(node) { + tmpDiv.node().appendChild(node); + }); }; - var finalizeMathJax = function() { - var sel = tmpDiv.select( - MathJaxVersion === 2 ? '.MathJax_SVG' : '.MathJax' - ); + const finalizeMathJax = function() { + const sel = tmpDiv.select('.MathJax'); - var node = !sel.empty() && tmpDiv.select('svg').node(); + const node = !sel.empty() && tmpDiv.select('svg').node(); if(!node) { Lib.log('There was an error in the tex syntax.', _texString); _callback(); } else { - var nodeBBox = node.getBoundingClientRect(); - var glyphDefs; - if(MathJaxVersion === 2) { - glyphDefs = d3.select('body').select('#MathJax_SVG_glyphs'); - } else { - glyphDefs = sel.select('defs'); - } + const nodeBBox = node.getBoundingClientRect(); + const glyphDefs = sel.select('defs'); _callback(sel, glyphDefs, nodeBBox); } tmpDiv.remove(); }; - var resetRenderer2 = function() { - if(originalRenderer !== 'SVG') { - return MathJax.Hub.setRenderer(originalRenderer); - } - }; - - var resetRenderer3 = function() { - if(originalRenderer !== 'svg') { - MathJax.config.startup.output = originalRenderer; - } - }; - - var resetConfig2 = function() { - if(originalProcessSectionDelay !== undefined) { - MathJax.Hub.processSectionDelay = originalProcessSectionDelay; - } - return MathJax.Hub.Config(originalConfig); - }; - - var resetConfig3 = function() { - MathJax.config = originalConfig; - }; - - if(MathJaxVersion === 2) { - MathJax.Hub.Queue( - setConfig2, - setRenderer2, - initiateMathJax, - finalizeMathJax, - resetRenderer2, - resetConfig2 - ); - } else if(MathJaxVersion === 3) { - setConfig3(); - setRenderer3(); - MathJax.startup.defaultReady(); - - MathJax.startup.promise.then(function() { - initiateMathJax(); - finalizeMathJax(); - - resetRenderer3(); - resetConfig3(); + // Initialize, render MathJax, then call _callback() + Promise.resolve() + .then(initiateMathJax) + .then(finalizeMathJax) + .catch((err) => { + Lib.log('MathJax typesetting failed.', _texString, err); + if(tmpDiv) tmpDiv.remove(); + _callback(); }); - } } var TAG_STYLES = { diff --git a/src/plot_api/plot_config.js b/src/plot_api/plot_config.js index f8f293a95e3..28fbab70b21 100644 --- a/src/plot_api/plot_config.js +++ b/src/plot_api/plot_config.js @@ -27,7 +27,7 @@ var configAttributes = { dflt: true, description: [ 'Determines whether math should be typeset or not,', - 'when MathJax (either v2 or v3) is present on the page.' + 'when MathJax (either v3 or v4) is present on the page.' ].join(' ') }, diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js index 7cb735ce338..666f3e7b6a5 100644 --- a/src/plot_api/subroutines.js +++ b/src/plot_api/subroutines.js @@ -684,7 +684,7 @@ exports.doLegend = function(gd) { }; exports.doTicksRelayout = function(gd) { - Axes.draw(gd, 'redraw'); + var drawPromise = Axes.draw(gd, 'redraw'); if(gd._fullLayout._hasOnlyLargeSploms) { Registry.subplotsRegistry.splom.updateGrid(gd); @@ -693,7 +693,9 @@ exports.doTicksRelayout = function(gd) { } exports.drawMainTitle(gd); - return Plots.previousPromises(gd); + return Promise.resolve(drawPromise).then(function() { + return Plots.previousPromises(gd); + }); }; exports.doModeBar = function(gd) { diff --git a/src/types/generated/schema.d.ts b/src/types/generated/schema.d.ts index 92fdc3e79d7..c7ed1fabf77 100644 --- a/src/types/generated/schema.d.ts +++ b/src/types/generated/schema.d.ts @@ -16375,7 +16375,7 @@ export interface ConfigBase { */ topojsonURL?: string; /** - * Determines whether math should be typeset or not, when MathJax (either v2 or v3) is present on the page. + * Determines whether math should be typeset or not, when MathJax (either v3 or v4) is present on the page. * @default true */ typesetMath?: boolean; diff --git a/test/image/baselines/legend_mathjax_title_and_items.png b/test/image/baselines/legend_mathjax_title_and_items.png index 0b3181e088d..ff1af32bde5 100644 Binary files a/test/image/baselines/legend_mathjax_title_and_items.png and b/test/image/baselines/legend_mathjax_title_and_items.png differ diff --git a/test/image/baselines/mathjax.png b/test/image/baselines/mathjax.png index dc454c412b8..22a6dc9c226 100644 Binary files a/test/image/baselines/mathjax.png and b/test/image/baselines/mathjax.png differ diff --git a/test/image/baselines/mathjax3___mathjax.png b/test/image/baselines/mathjax3___mathjax.png index d8c6aafc1ed..a4cef782d7d 100644 Binary files a/test/image/baselines/mathjax3___mathjax.png and b/test/image/baselines/mathjax3___mathjax.png differ diff --git a/test/image/baselines/mathjax3___table_latex_multitrace_scatter.png b/test/image/baselines/mathjax3___table_latex_multitrace_scatter.png index c45a197734c..e4214a24546 100644 Binary files a/test/image/baselines/mathjax3___table_latex_multitrace_scatter.png and b/test/image/baselines/mathjax3___table_latex_multitrace_scatter.png differ diff --git a/test/image/baselines/mathjax3___ternary-mathjax-title-place-subtitle.png b/test/image/baselines/mathjax3___ternary-mathjax-title-place-subtitle.png index 3d06239168e..5447c63f7e7 100644 Binary files a/test/image/baselines/mathjax3___ternary-mathjax-title-place-subtitle.png and b/test/image/baselines/mathjax3___ternary-mathjax-title-place-subtitle.png differ diff --git a/test/image/baselines/mathjax3___ternary-mathjax.png b/test/image/baselines/mathjax3___ternary-mathjax.png index a145da8021b..58f3b9302b7 100644 Binary files a/test/image/baselines/mathjax3___ternary-mathjax.png and b/test/image/baselines/mathjax3___ternary-mathjax.png differ diff --git a/test/image/baselines/parcats_grid_subplots.png b/test/image/baselines/parcats_grid_subplots.png index 0925b959212..27899d0ff86 100644 Binary files a/test/image/baselines/parcats_grid_subplots.png and b/test/image/baselines/parcats_grid_subplots.png differ diff --git a/test/image/baselines/table_latex_multitrace_scatter.png b/test/image/baselines/table_latex_multitrace_scatter.png index 973dba8886c..0628fa06092 100644 Binary files a/test/image/baselines/table_latex_multitrace_scatter.png and b/test/image/baselines/table_latex_multitrace_scatter.png differ diff --git a/test/image/baselines/table_plain_birds.png b/test/image/baselines/table_plain_birds.png index 37a4a5533a5..bfe81d92d95 100644 Binary files a/test/image/baselines/table_plain_birds.png and b/test/image/baselines/table_plain_birds.png differ diff --git a/test/image/baselines/table_wrapped_birds.png b/test/image/baselines/table_wrapped_birds.png index fc53fb898f5..b1d5edd261e 100644 Binary files a/test/image/baselines/table_wrapped_birds.png and b/test/image/baselines/table_wrapped_birds.png differ diff --git a/test/image/baselines/ternary-mathjax-title-place-subtitle.png b/test/image/baselines/ternary-mathjax-title-place-subtitle.png index 980a5beb679..c98ccb7c453 100644 Binary files a/test/image/baselines/ternary-mathjax-title-place-subtitle.png and b/test/image/baselines/ternary-mathjax-title-place-subtitle.png differ diff --git a/test/image/baselines/ternary-mathjax.png b/test/image/baselines/ternary-mathjax.png index 0eb463e26eb..2f30323640c 100644 Binary files a/test/image/baselines/ternary-mathjax.png and b/test/image/baselines/ternary-mathjax.png differ diff --git a/test/image/make_baseline.py b/test/image/make_baseline.py index 0c0934adc2c..8bce6c7e5ba 100644 --- a/test/image/make_baseline.py +++ b/test/image/make_baseline.py @@ -36,8 +36,6 @@ print("output to", dirOut) -mathjax_version = 2 -mathjax = None if "mathjax3" in sys.argv or "mathjax3=" in sys.argv: # until https://github.com/plotly/Kaleido/issues/124 is addressed # we are uanble to use local mathjax v3 installed in node_modules @@ -46,6 +44,11 @@ mathjax_version = 3 print("Kaleido using MathJax v3") +else: + mathjax_version = 4 + # Kaleido still defaults to MathJax v2, so we need to explicitly specify the path to MathJax v4 + mathjax = "https://cdn.jsdelivr.net/npm/mathjax@4.1.2/tex-svg.js" + print("Kaleido using MathJax v4") virtual_webgl_version = 0 # i.e. virtual-webgl is not used if "virtual-webgl" in sys.argv or "virtual-webgl=" in sys.argv: diff --git a/test/image/make_exports.py b/test/image/make_exports.py index de23ac74271..5d28d078d59 100644 --- a/test/image/make_exports.py +++ b/test/image/make_exports.py @@ -8,7 +8,8 @@ dirOut = os.path.join(root, "build", "test_images") pio.templates.default = "none" -pio.kaleido.scope.plotlyjs = os.path.join(root, "build", "plotly.js") +pio.defaults.plotlyjs = os.path.join(root, "build", "plotly.js") +pio.defaults.mathjax = "https://cdn.jsdelivr.net/npm/mathjax@4.1.2/tex-svg.js" allFormats = ["svg", "jpg", "jpeg", "webp", "pdf"] # 'png' is tested by image-test @@ -31,7 +32,7 @@ "zsmooth_methods", ] -failed = 0 +failed = [] for name in allNames: for fmt in allFormats: print(name + " --> " + fmt) @@ -59,8 +60,15 @@ ) except Exception as e: + import traceback print(e) - failed += 1 + traceback.print_exc() -if failed > 0: + failed.append((name, fmt)) + +if len(failed) > 0: + print("\nFailed on:") + for name, fmt in failed: + print(f" {name} ({fmt})") + print("") sys.exit(1) diff --git a/test/jasmine/bundle_tests/mathjax_config_test.js b/test/jasmine/bundle_tests/mathjax_config_test.js index 1d80b6ca933..6172a103ca4 100644 --- a/test/jasmine/bundle_tests/mathjax_config_test.js +++ b/test/jasmine/bundle_tests/mathjax_config_test.js @@ -16,46 +16,32 @@ describe('Test MathJax v' + mathjaxVersion + ' config test:', function() { beforeAll(function(done) { gd = createGraphDiv(); - if(mathjaxVersion === 3) { - window.MathJax = { - startup: { - output: 'chtml', - tex: { - inlineMath: [['|', '|']] - } - } - }; - } + window.MathJax = { + startup: { + output: 'svg' + }, + tex: { + inlineMath: [['|', '|']] + }, + svg: { + fontCache: 'none' + } + }; - var src = mathjaxVersion === 3 ? + const src = mathjaxVersion === 3 ? '/base/node_modules/@plotly/mathjax-v3/es5/tex-svg.js' : - '/base/node_modules/@plotly/mathjax-v2/MathJax.js?config=TeX-AMS_SVG'; + '/base/node_modules/@plotly/mathjax-v4/tex-svg.js'; loadScript(src, done); }); afterAll(destroyGraphDiv); - it('should maintain startup renderer & inlineMath after SVG rendering', function(done) { - if(mathjaxVersion === 2) { - window.MathJax.Hub.Config({ - tex2jax: { - inlineMath: [['|', '|']] - } - }); - - window.MathJax.Hub.setRenderer('CHTML'); - } - + it('should maintain original inlineMath & fontCache config values after SVG rendering', function(done) { // before plot - if(mathjaxVersion === 3) { - expect(window.MathJax.config.startup.output).toEqual('chtml'); - expect(window.MathJax.config.startup.tex.inlineMath).toEqual([['|', '|']]); - } - if(mathjaxVersion === 2) { - expect(window.MathJax.Hub.config.menuSettings.renderer).toEqual(''); - expect(window.MathJax.Hub.config.tex2jax.inlineMath).toEqual([['|', '|']]); - } + expect(window.MathJax.config.startup.output).toEqual('svg'); + expect(window.MathJax.config.tex.inlineMath).toEqual([['|', '|']]); + expect(window.MathJax.config.svg.fontCache).toEqual('none'); Plotly.newPlot(gd, { data: [{ @@ -69,19 +55,9 @@ describe('Test MathJax v' + mathjaxVersion + ' config test:', function() { }) .then(function() { // after plot - if(mathjaxVersion === 3) { - expect(window.MathJax.config.startup.output).toEqual('chtml'); - expect(window.MathJax.config.startup.tex.inlineMath).toEqual([['|', '|']]); - } - if(mathjaxVersion === 2) { - expect(window.MathJax.Hub.config.menuSettings.renderer).toEqual(''); - } - }) - .then(delay(1000)) // TODO: why we need this delay for mathjax v2 here? - .then(function() { - if(mathjaxVersion === 2) { - expect(window.MathJax.Hub.config.tex2jax.inlineMath).toEqual([['|', '|']]); - } + expect(window.MathJax.config.startup.output).toEqual('svg'); + expect(window.MathJax.config.tex.inlineMath).toEqual([['|', '|']]); + expect(window.MathJax.config.svg.fontCache).toEqual('none'); }) .then(done, done.fail); }); diff --git a/test/jasmine/bundle_tests/mathjax_test.js b/test/jasmine/bundle_tests/mathjax_test.js index 4b5d03a4b4b..2602ff3818c 100644 --- a/test/jasmine/bundle_tests/mathjax_test.js +++ b/test/jasmine/bundle_tests/mathjax_test.js @@ -10,10 +10,13 @@ var mathjaxVersion = __karma__.config.mathjaxVersion; describe('Test MathJax v' + mathjaxVersion + ':', function() { beforeAll(function(done) { - var src = mathjaxVersion === 3 ? + const src = mathjaxVersion === 3 ? '/base/node_modules/@plotly/mathjax-v3/es5/tex-svg.js' : - '/base/node_modules/@plotly/mathjax-v2/MathJax.js?config=TeX-AMS-MML_SVG'; + '/base/node_modules/@plotly/mathjax-v4/tex-svg.js'; + // TODO: `?config=` is not needed for MathJax v3 and onward, + // should we adjust these tests? + // N.B. we have to load MathJax "dynamically" as Karma // does not undefined the MathJax's `?config=` parameter. // diff --git a/test/jasmine/karma.conf.js b/test/jasmine/karma.conf.js index c061ff818eb..c551b0ae97e 100644 --- a/test/jasmine/karma.conf.js +++ b/test/jasmine/karma.conf.js @@ -69,7 +69,7 @@ if (argv.info) { '', 'Other options:', ' - `--info`: show this info message', - ' - `--mathjax3`: to load mathjax v3 in relevant test', + ' - `--mathjax3`: to load mathjax v3 in relevant test (otherwise mathjax v4 is loaded)', ' - `--Chrome` (alias `--chrome`): run test in (our custom) Chrome browser', ' - `--Firefox` (alias `--FF`, `--firefox`): run test in (our custom) Firefox browser', ' - `--nowatch (dflt: `false`, `true` on CI)`: run karma w/o `autoWatch` / multiple run mode', @@ -128,8 +128,8 @@ if (isFullSuite) { var pathToCustomMatchers = path.join(__dirname, 'assets', 'custom_matchers.js'); var pathToTopojsonDist = path.join(__dirname, '..', '..', 'topojson', 'dist'); -var pathToMathJax2 = path.join(__dirname, '..', '..', 'node_modules', '@plotly/mathjax-v2'); var pathToMathJax3 = path.join(__dirname, '..', '..', 'node_modules', '@plotly/mathjax-v3'); +var pathToMathJax4 = path.join(__dirname, '..', '..', 'node_modules', '@plotly/mathjax-v4'); var pathToVirtualWebgl = path.join(__dirname, '..', '..', 'node_modules', 'virtual-webgl', 'src', 'virtual-webgl.js'); var reporters = []; @@ -200,10 +200,10 @@ func.defaultConfig = { // N.B. the rest of this field is filled below files: [ pathToCustomMatchers, - // available to fetch from /base/node_modules/@plotly/mathjax-v2/ + // available to fetch from /base/node_modules/@plotly/mathjax-v3/ // more info: http://karma-runner.github.io/3.0/config/files.html - { pattern: pathToMathJax2 + '/**', included: false, watched: false, served: true }, { pattern: pathToMathJax3 + '/**', included: false, watched: false, served: true }, + { pattern: pathToMathJax4 + '/**', included: false, watched: false, served: true }, { pattern: pathToTopojsonDist + '/**', included: false, watched: false, served: true } ], @@ -308,7 +308,7 @@ func.defaultConfig = { tagPrefix: '@', skipTags: isCI ? 'noCI' : null, - mathjaxVersion: argv.mathjax3 ? 3 : 2, + mathjaxVersion: argv.mathjax3 ? 3 : 4, // See https://jasmine.github.io/api/3.4/Configuration.html jasmine: { diff --git a/test/plot-schema.json b/test/plot-schema.json index f4286815758..6a22cc6a378 100644 --- a/test/plot-schema.json +++ b/test/plot-schema.json @@ -340,7 +340,7 @@ "valType": "string" }, "typesetMath": { - "description": "Determines whether math should be typeset or not, when MathJax (either v2 or v3) is present on the page.", + "description": "Determines whether math should be typeset or not, when MathJax (either v3 or v4) is present on the page.", "dflt": true, "valType": "boolean" },