MathJax icon indicating copy to clipboard operation
MathJax copied to clipboard

Error rendering the formula

Open saraOrkide opened this issue 1 year ago • 5 comments

Hello good time To render, I use the formulas from the code below

window.MathJax.typeset()

This code sometimes gives this error

TypeError: Cannot read properties of null (reading 'replaceChild')

Can you help me what is this error?

using mathjax-4.0.0-beta.4/mathjax/mml-chtml.js mathjax config:

(window.MathJax = {
            options: {
                enableMenu: !1,
            },
            loader: {
                paths: {
                    "mathjax-fira": "https://cdn.chista.me/chista-mathjax-4.0.0-beta.4/mathjax-fira-font",
                }
            },
            chtml: {
                displayAlign: 'right',
                scale: 1,
                merrorInheritFont: !0,
                matchFontHeight: false,
                mtextFont: 'fontRegular, Noto Sans, sans-serif',
                mtextInheritFont: false,
                unknownFamily: 'fontRegular, Noto Sans, sans-serif',
                font: 'mathjax-fira',
            },
            mml: {
                allowHtmlInTokenNodes: true
              },

            startup: {
                ready() {
                    const { ChtmlMn: e } = MathJax._.output.chtml.Wrappers.mn;
                    e.prototype.remapChars = function (t) {
                        const a = [];
                        for (const e of t) {
                            const t = this.font.getRemappedChar("mn", e);
                            a.push(...(t ? this.unicodeChars(t, this.variant) : [e]));
                        }
                        return a;
                    };
                    const { FontData: n } = MathJax._.output.common.FontData,
                        o = n.defaultMnMap;
                    for (var s = 0; s < 10; s++) o[48 + s] = String.fromCodePoint(1776 + s);
                    const { CHTML } = MathJax._.output.chtml_ts;
                    Object.assign(CHTML.prototype, {
                        _unknownText: CHTML.prototype.unknownText,
                        unknownText(text, variant, width = null, rscale = 1) {
                            const node = this._unknownText(text, variant, width, rscale);
                            if (width !== null) {
                                this.adaptor.setStyle(node, 'width', this.fixed(width * this.math.metrics.scale) + 'em');
                            }
                            return node;
                        },
                        measureTextNode(textNode) {
                            const adaptor = this.adaptor;
                            const text = adaptor.clone(textNode);
                            adaptor.setStyle(text, 'font-family', adaptor.getStyle(text, 'font-family').replace(/MJXZERO, /g, ''));
                            const em = this.math.metrics.em;
                            const style = {
                                position: 'absolute', top: 0, left: 0,
                                'white-space': 'nowrap',
                                'font-size': this.fixed(em, 3) + 'px'
                            };
                            const node = this.html('mjx-measure-text', { style }, [text]);
                            adaptor.append(adaptor.parent(this.math.start.node), this.container);
                            adaptor.append(this.container, node);
                            let w = adaptor.nodeSize(text, em)[0];
                            adaptor.remove(this.container);
                            adaptor.remove(node);

                            return { w: w, h: .6, d: .2 };
                        }
                    });
                    const { MmlMath } = MathJax._.core.MmlTree.MmlNodes.math;
                    const { MmlMstyle } = MathJax._.core.MmlTree.MmlNodes.mstyle;
                    MmlMath.defaults.scriptsizemultiplier = MmlMstyle.defaults.scriptsizemultiplier = 1;
                    MathJax.startup.defaultReady();
                    const params = MathJax.startup.document.outputJax.font.params;
                    params.rule_thickness = .130;
                    params.rule_factor = .75;
                    params.sub1 = .6;
                },
            },
        });

saraOrkide avatar Jun 26 '24 11:06 saraOrkide

Do you have an expression where this always happens? If so, can you provide that? Also, can you provide the full stack trace from the error message?

Without an example that exhibits the problem, and without the stack trace, there is very little to go on, here.

dpvc avatar Jun 26 '24 12:06 dpvc

Sometimes this command window.MathJax.typeset(); I run it, I get this error and the formulas are not rendered Screenshot from 2024-07-31 10-53-24

saraOrkide avatar Jul 31 '24 07:07 saraOrkide

Still not enough information to diagnose the problem. The error message suggests that some piece of math that is trying to be inserted into the document came from a part of the page that is no longer in the document. That is, the document has been altered to remove the content containing the math before the math has been fully processed.

If your system is modifying the page to remove old content and add new content, you should be sure to use MathJax.startup.document.clearMathItemsWithin(container) where container is the DOM element being removed from the page, before you remove the content.

If you are using MathJax.typesetPromise(), you should be sure to wait for the promise to be resolved before modifying the content on the page, otherwise it could lead to this message.

dpvc avatar Jul 31 '24 18:07 dpvc

@dpvc Hello I have similar issue but for mathjax/3.2.2/tex-chtml-full-speech.js Could you please provide example how i can make sure MathJax.typesetPromise() is resolved before modifying the content on the page?

Lumeniz avatar Dec 20 '24 14:12 Lumeniz

@Lumeniz, it is hard to do that without knowing how your code works and is organized. But the basic idea is that you either use

MathJax.typesetPromise().then(() => {
  // your code that runs after MathJax is complete
});

or

await MathJax.typesetPromise();
// your code that runs after MathJax is complete

to synchronize your code with MathJax. Note, however, that the functions that perform these actions will complete before MathJax has finished its typesetting, so the functions that call these functions can't assume that MathJax is finished. That means your whole workflow may need to be aware of the asynchronous nature of these calls, and may need to be broken into pieces in a way that handles that properly. That might not be the way it is currently organized.

For example, if your code responds to use interaction to modify the page, you may have to prevent additional interactions from occurring until after MathJax has finished typesetting. One way would be to disable buttons or other means of triggering updates until the MathJax promise is resolved, at which point you re-enable them.

If you are responding to updates in an input area and updating a typeset preview, for example, you might need to suspend the changes until MathJax has completed, and then make a single change that includes all the cached changes and typeset again. That takes a little more code than just updating immediately when the input changes, but is certainly doable.

These are the kinds of things you need to be aware of when you work with promises.

dpvc avatar Dec 23 '24 13:12 dpvc