Author: Fu Yungui (netease Youdao Technology Team)

The introduction

Recently, I used MathJax to render math formulas in a desktop Web front end project, and ran into a few potholes.

What is MathJax

You can find the following introduction on the MathJax website:

A JavaScript display engine for mathematics that works in all browsers.

No more setup for readers. It just works.

What is MathJax? Contains the following text:

MathJax is an open-source JavaScript display engine for LaTeX and MathML that works in all modern browsers. …

MathJax uses web-based fonts (in those browsers that support it) to produce high-quality typesetting that scales and prints at full resolution (unlike mathematics included as images)….

MathJax is modular, so it loads components only when necessary, and can be extended to include new capabilities as needed. MathJax is highly configurable, allowing authors to customize it for the special requirements of their web sites. Finally, MathJax has a rich application programming interface (API) that can be used to make the mathematics on your web pages interactive and dynamic.

The main points are summarized as follows:

  • MathJax is an open source high quality rendering engine for mathematical formulas
  • Support for modern browsers
  • Modular, load on demand
    • High configuration
    • Interface is rich
    • The total file is very large and can only be loaded on demand

General use

As the MathJax website says “It Just works.” Using MathJax in general is very simple:

If you write your own HTML (directly or via a template/theme engine), you can include MathJax by adding this snippet to your page:

<script src="https://polyfill.io/v3/polyfill.min.js? features=es6"></script> <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>Copy the code

An example is provided:

Here’s a pre-populated example on jsbin you can re-use.

Once the MathJax seed file is introduced into HTML, MathJax will automatically render the mathematical formula in document.body when ready — a process MathJax calls Startup Typeset.

Used in the Vue

In Vue, a component completes its HTML rendering after its Mounted /updated life cycle. After the component mounted/updated life cycle, MathJax calls Typeset to render the component’s HTML for mathematical formulas.

The code is shown as follows:

@Component({})
class SomeComponent extends Vue {
    private callMathJaxTypeset(): void {
        // call window.MathJax to typeset
        const { typesetElement } = this.$refs
        MathJax.Hub.Queue(['Typeset', MathJax.Hub, typesetElement])
    }

    mounted(): void {
        this.callMathJaxTypeset()
    }

    updated(): void {
        this.callMathJaxTypeset()
    }
}

Copy the code

MathJax load

In general, MathJax seed files should not be placed in HTML — that is, not loaded at the beginning unless the entire WebApp uses MathJax.

Ideally, the MathJax seed files are loaded on demand, so implement a function loadMathJax() that loads MathJax:

Const CDN_URL = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?' + 'config = TeX - MML - AM_CHTML + '&delayStartupUntil=configured' let isLoading = false let isConfigured = false function waitUntil(callback: () => void, failCallback: () => void): void { // TODO } function isLoaded(): boolean { if (window.MathJax) { if (! isConfigured) { isConfigured = true window.MathJax.Hub.Config({ skipStartupTypeset: true, messageStyle: 'none', tex2jax: { inlineMath: [ // for recommend ['$', '$'], // the default config ['\\(', '\\)'], ], }, }) window.MathJax.Hub.Configured() } if (window.MathJax.isReady) { return true } } return false } function loadScript():  void { if (isLoaded() || isLoading) { return } isLoading = true const script = document.createElement('script') script.type = 'text/javascript' script.src = CDN_URL document.getElementsByTagName('head')[0].appendChild(script) } async function loadMathJax(): Promise<typeof MathJax> { return new Promise((resolve, reject) => { if (window.MathJax) { resolve(window.MathJax) return } waitUntil( () => { resolve(window.MathJax) }, () => { reject() }, ) loadScript() }) } export { loadMathJax }Copy the code

In the implementation of loadMathJax(), there are several points to note:

  1. Skip the Startup Typeset
  • You must add &delayStartupuntil =configured to the MathJax CDN URL
  • Call window. MathJax. Hub. Config, skipStartupTypeset set to true
  • Call window. MathJax. Hub. Configured ()
  1. Use window.mathJax. isReady to determine whether MathJax is available

Vue components are loaded with MathJax

To load and use MathJax on demand in Vue components, load MathJax in the component’s Created lifecycle:

@Component({})
class SomeComponent extends Vue {
    private mathJax: typeof MathJax | null = null

    private needTypeset: boolean = false

    private callMathJaxTypeset(): void {
        const { mathJax } = this
        if (mathJax) {
            const { typesetElement } = this.$refs
            mathJax.Hub.Queue(['Typeset', MathJax.Hub, typesetElement])
        } else {
            this.needTypeset = true
        }
    }

    created(): void {
        const mathJax = await loadMathJax()
        this.mathJax = mathJax

        if (this.needTypeset) {
            this.callMathJaxTypeset()
        }
    }

    mounted(): void {
        this.callMathJaxTypeset()
    }

    updated(): void {
        this.callMathJaxTypeset()
    }
}
Copy the code

At this point, you can use MathJax to render mathematical formulas in the Vue component to meet the application scenario of displaying mathematical formulas in a single page application.

Special demand

There is a need in the latest product

After MathJax renders the math formula (Typeset), the user prints the web page using the browser’s print function.

In this requirement, you need to determine whether MathJax Typeset is complete for all component instances.

How do I listen for MathJax Typeset completion in all component instances? Listen to the breakdown next time.

Netease technology lover team continues to recruit teammates! Netease Youdao. We choose youdao because we love you. We look forward to your joining us. Your resume can be sent to [email protected]