Skip to content

My first Javascript - Mathjax

The aim of this tutorial is to integrate a javascript library easily and to understand how it works, in order to be able to replicate it for another. We illustrate it with Mathjax, a javascript library for rendering mathematical expressions, ensuring high-quality mathematical typesetting, utilizing the LaTeX syntax.

Create a new project using the File menu, then New project..., select RPGM project and name your new project "MathjaxIntegration".

Importing the Javascript library

Following the Mathjax documentation of the different ways of importing (available here),

  1. Download the Mathjax javascript library.
  2. Place the javascript file at the root of your project and name it mathjax.min.js.

    Note

    The min is a javascript convention indicating that the file is "minimized": no commentary, no white space, optimized for the javascript engine.

  3. Import it into the project.ppro file: go to the Custom JS/CSS files field, and add mathjax.min.js.

Screenshot

Now, at the start of RPGM, Mathjax will be loaded.

Creating a GUI and display a formula

We will display a simple formula in a GUI.

  1. Create main.pgui file and add it to the sequencer.
  2. In the GUI, add a label Widget as a title with Mathjax in RPGM in Font size: 32 (optional)
  3. Add another label with its label field A simple formula.

We now add a formula in the field value of this second label:

\(\frac1n\sum_{k=1}^{n}X_k \overset{p.s.}{\longrightarrow} \mathbb{E}(X)\)

In this formula:

  • we begin with \( which says where the formula starts, and finish it with \) which says when the formula ends, it replaces the $ symbol in LaTeX
  • inside the \( and \), the formula is written in LaTeX format

Info

If the formula is generated in R, you will need to replace each \ by \\ as usual. In Python, it replaces in general \ by \\ corresponding to the context, but not always: it will not in \n, you should also replace all \ by \\.

However, when we execute it, the formula is not replaced.

Screenshot

The reason is the following: Mathjax is a complete static javascript library. When it loads, it looks if there is any formula to parse, and once done, it does no refresh. In RPGM, the javascript (and custom libraries) are loaded at the beginning of the application, before the GUI. We just need to ask Mathjax to refresh, at the beginning.

In order to do that, we need to use the javascript framework of RPGM, which consists of

  • Instructing javascript that, each time we enter a step, we refresh the Mathjax.

Generating a javascript event is always done by

  1. Creating a javascript file (ex: init.js) and adding it in the Custom JS field in the project.ppro file,
  2. Inside this file, using RPGM.on(message, callback) where message corresponds to the type of event, and callback is the function triggered by the event, to define here with the message didEnterStep.

    Info

    The function RPGM.on is described in the API Javascript, with the different messages / events, but it is too early for a first tutorial to explain all of them.

It might seem complicated; however, it always follows the same pattern and becomes clearer with an example. For mathjax, the associated documentation states that it can be refresh simply using MathJax.typeset().

Then,

  1. Create a javascript file mathjax-init.js and adding it in the Custum JS in the project.ppro file, Screenshot
  2. In mathjax-init.js, add the following code
    RPGM.on('didEnterStep', (id)=>{
        MathJax.typeset();
    });
    
    Screenshot

Info

In the code above, id represents the id of the step, defined in main.pseq. You can use it, for example, by checking it and applying the code inside according to the GUI id. In a mathjax context, if a GUI step does not have any formula, you can check it and execute the MathJax.typeset() only for the GUI with formulas.

Screenshot

In general it works. However, in javascript, we can have an issue called a race condition. Since several things are executed simultaneously: even if the event associated to didEnterStep is called after the loading of the GUI, each element loads itself, and might not be already loaded. If the MathJax.typeset(); is triggered before it, the formula will not be parsed. Even if in our simple example it should work, how to prevent that in general?

The easiest way is to add a slight delay before to call it. This is done with the setTimeout function of Javascript, in which we specify the number of milliseconds to add. In general, 200 is large enough and the loading remains smooth. You can use a smaller value if it always loads without any issue.

In order to do this, replace the code in mathjax-init.js by

RPGM.on('didEnterStep', (id)=>{
    setTimeout(()=>{
        MathJax.typeset();
    }, 200);
});

This concludes our first tutorial for the javascript support. ! You can download the program as a pgm file for RPGM soon (that you can create with the top menu PGM -> Export as PGM) and as a zip file containing all the project for RCode here.