This page is meant to be a 10-minute crash-course on how to use the MathLex JavaScript library. In the process, you will learn how to produce a sample page called mathlexsample.html, which contains a simple numerical calculator. For more information, please visit the full documentation.

Quick Start

Step 1: Download the MathLex JavaScript file, mathlex.js, by clicking on the button at right and saving the linked file in a location that is accessible from the page in a web browser (/path/to/mathlex.js). In our sample page, it is located in the javascripts subfolder relative to the same folder as the mathlexsample.html page (thus we can omit the leading /), so its path is javascripts/mathlex.js.

Step 2: A MathLex sample page is shown at the right. To pop it out, click here.

This page contains a simple numerical calculator. There is an input box where a student can enter a formula which may be as complicated as desired, but must evaluate to a pure number or a function of the variable \( x \). Then there is a preview window where the student can see what they have typed. When the student clicks the Calculate button, the formula is sent to a Sage processor which returns the value, which is displayed in the output window.

The code for this page is listed below, and each part will be explained in the sections to follow. If you would like to code along with me, you can create files on your computer.

MathLex Sample

A Simple Calculator

\[ \]
\[ \]
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>MathLex Sample</title>
        <style>
            body { text-align: center; }
            #math-display, #math-output { border: 1px solid #000; margin: 5px 0;}
        </style>
    </head>
    <body>
        <h1>MathLex Sample</h1>
        <h2>A Simple Calculator</h2>
        <input type="text" id="math-input" placeholder="Type math here">
        <div id="math-display">\[ \]</div>
        <input type="button" id="send-math" value="Calculate">
        <div id="math-output">\[ \]</div>

        <script src="javascripts/mathlex.js"></script>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"></script>
        <script>
            $(document).ready(function () {
                // get MathJax output object
                var mjDisplayBox, mjOutBox;
                MathJax.Hub.Queue(function () {
                    mjDisplayBox = MathJax.Hub.getAllJax('math-display')[0];
                    mjOutBox = MathJax.Hub.getAllJax('math-output')[0];
                });

                // "live update" MathJax whenever a key is pressed
                $('#math-input').on('keyup', function (evt) {
                    var math = $(this).val();
                    $(this).css('color', 'black');
                    if (math.length > 0) {
                        try {
                            var tree = MathLex.parse(math),
                                latex = MathLex.render(tree, 'latex');
                            MathJax.Hub.Queue(['Text', mjDisplayBox, latex]);
                        } catch (err) {
                            $(this).css('color', 'red');
                        }
                    } else {
                        // clear display and output boxes if input is empty
                        MathJax.Hub.Queue(['Text', mjDisplayBox, '']);
                        MathJax.Hub.Queue(['Text', mjOutBox, '']);
                    }
                });

                // send output to sage server
                $('#send-math').on('click', function (evt) {
                    var math = $('#math-input').val();
                    if (math.length > 0) {
                        try {
                            var tree = MathLex.parse(math),
                                sageCode = MathLex.render(tree, 'sage');
                            $.post('http://aleph.sagemath.org/service?callback=?',
                                    { code: 'print latex('+sageCode+')' }, function (data) {
                                // HACK: Firefox does not convert data to JSON
                                if (typeof(data) === 'string') { data = $.parseJSON(data); }
                                // AJAX success callback
                                if (data.success) {
                                    MathJax.Hub.Queue(['Text', mjOutBox, data.stdout]);
                                } else {
                                    MathJax.Hub.Queue(['Text', mjOutBox, '\\text{Sage could not understand that input}']);
                                }
                            });
                        } catch (err) {
                            MathJax.Hub.Queue(['Text', mjOutBox, '\\text{Check your syntax and try again}']);
                        }
                    }
                });
            });
        </script>
    </body>
</html>

Step 3: The following HTML snippet creates the screen layout. Lines 12 and 13 create a header, line 14 makes the input field, line 15 produces a preview window that will be rendered by MathJax, line 16 makes the submit button, and line 17 creates the output window that will also be rendered by MathJax.

<h1>MathLex Sample</h1>
<h2>A Simple Calculator</h2>
<input type="text" id="math-input" placeholder="Type math here" />
<div id="math-display">\[ \]</div>
<input type="button" id="send-math" value="Calculate" />
<div id="math-output">\[ \]</div>

Step 4: To be able to process the math input, you need to include the MathLex JavaScript file in your HTML, which is done on line 26. I recommend putting JavaScripts just before the closing </body> tag, but you can put it in your <head> or wherever works best for you. Of course the src attribute should be replaced by the appropriate path to your MathLex JavaScript file.

<script src="javascripts/mathlex.js"></script>

Step 5: If you plan to use MathJax, jQuery, MooTools, Prototype, YUI, Dojo, or another JavaScript toolkit/library, please refer to the corresponding site for installation instructions. Lines 20 and 21 of the example code load jQuery and MathJax from their respective Content Distribution Network (CDN) URLs:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"></script>

Step 6: The math input from line 14 is processed in two ways:

  • MathLex automatically parses it and translates it into LaTeX which MathJax displays in the math-display window on line 15.
  • When the Calculate button on line 16 is clicked, MathLex parses it and translates it into Sage, which transmits to a Sage Cell server. The result returned by Sage is rendered by MathJax into the math-output window on line 17.

The first thing we need to do is define the MathJax output objects, mjDisplayBox and mjOutBox, which tell MathJax where to put the output, namely the math-display box on line 15 and the math-output box on line 17. This is done in lines 24 to 29.

// get MathJax output object
var mjDisplayBox, mjOutBox;
MathJax.Hub.Queue(function () {
    mjDisplayBox = MathJax.Hub.getAllJax('math-display')[0];
    mjOutBox = MathJax.Hub.getAllJax('math-output')[0];
});

Step 7: To automatically parse the math-input from line 14, we use jQuery's DOM event handling systems in lines 31–49. Line 32 watches for a keyup event in the math-input box. When this occurs, line 33 stores the value of the math-input as a variable math. Line 36 checks if math has a non-zero length. If it does, then in lines 37–39, MathLex tries to parse it into an abstract syntax tree structure and render that structure into latex. Then in line 40, MathJax tries to display the latex in the mjDisplayBox (previously linked to the math-display box). If this fails, then the math-input box turns red. Here this represents the math-input box that's handling the keyup event. If math is empty (i.e. has zero length), then lines 45 to 47 blank out the math-display and math-output boxes.

// "live update" MathJax whenever a key is pressed
$('#math-input').on('keyup', function (evt) {
    var math = $(this).val();
    $(this).css('color', 'black');

    if (math.length > 0) {
        try {
            var tree = MathLex.parse(math),
                latex = MathLex.render(tree, 'latex');
            MathJax.Hub.Queue(['Text', mjDisplayBox, latex]);
        } catch (err) {
            $(this).css('color', 'red');
        }
    } else {
        // clear display and output boxes if input is empty
        MathJax.Hub.Queue(['Text', mjDisplayBox, '']);
        MathJax.Hub.Queue(['Text', mjOutBox, '']);
    }
});

Step 8: The last thing to do is listen to the Calculate button to send the math-input from line 14 to a Sage processor and display the result in the math-output box. We again use jQuery's DOM event handling system in lines 52 through 71. Line 52 watches for a click event in the send-math button. When this occurs, line 53 stores the value of the math-input as a variable math. Line 54 checks if math has a non-zero length, and if it does, then, in lines 56–57, MathLex tries to parse the math into a tree structure, translate it into sage, and then store the result in a variable named sageCode. Then in lines 58–59, the sageCode is sent to a Sage server as an AJAX request. When the browser receives the AJAX response, it executes the associated function, which is receiving the associated data (more about this in Step 9). If the Sage execution was successful, then, on line 64, MathJax displays the result (data.stdout) in the mjOutBox object (previously linked to the math-output box). If the server encountered an error, then line 66 displays "Sage could not understand that input" in the mjOutBox. If anything else fails (most likely a syntax error), line 70 displays "Check your syntax and try again" in the mjOutBox.

// send output to sage server
$('#send-math').on('click', function (evt) {
    var math = $('#math-input').val();
    if (math.length > 0) {
        try {
            var tree = MathLex.parse(math),
                sageCode = MathLex.render(tree, 'sage');
            $.post('http://aleph.sagemath.org/service?callback=?',
                    {code: 'print latex('+sageCode+')'}, function (data) {
                // HACK: Firefox does not convert data to JSON
                if (typeof(data) === 'string') { data = $.parseJSON(data); }
                // AJAX success callback
                if (data.success) {
                    MathJax.Hub.Queue(['Text', mjOutBox, data.stdout]);
                } else {
                    MathJax.Hub.Queue(['Text', mjOutBox, '\\text{Sage could not understand that input}']);
                }
            });
        } catch (err) {
            MathJax.Hub.Queue(['Text', mjOutBox, '\\text{Check your syntax and try again}']);
        }
    }
});

Step 9: Finally a few words about the Sage processing on lines 58–59:

$.post('http://aleph.sagemath.org/service?callback=?',
       {code: 'print latex('+sageCode+')'}, function (data) {

The demo communicates with a Sage Cell server at http://aleph.sagemath.org operated by the Sage Math organization. The POST request sends the Sage code print latex(<sageCode>), where <sageCode> is the injected code generated by MathLex. Sage will evaluate the sent sageCode, simplify the result, convert it to LaTeX, and print it to the standard output (hence stdout). This output is passed back to the client in the form of a JSON object:

{
    success: true|false,
    stdout: 'output string'
}

This value is stored as the data parameter to the AJAX callback function; so data.success on line 60 yields true or false and data.stdout yields the output string in LaTeX form (assuming data.success is true) to be processed by MathJax on line 61.

Additional Comments

  • Both of these event callbacks have the same basic abstract structure:

    1. get MathLex code from the text field
    2. parse the MathLex code into an abstract syntax tree
    3. translate the syntax tree into another format (in the example, LaTeX or Sage code)
    4. do something with the translated code
  • The value of the math-input text field was obtained above on line 53 using a jQuery command of the form:

    var math = $('#' + inputID).val();

    where inputID stands for the input test field. In the example, this was math-input. However, there are many ways to obtain a text field's value. Here is the corresponding code for standard JavaScript and each of the JS libraries mentioned earlier:

    1. Standard JavaScript

      var math = document.getElementById(inputID).value;
    2. MooTools

      var math = document.id(inputID).value;  // OR
      var math = $(inputID).value;            // '$' is aliased to 'document.id'
    3. Prototype

      var math = $(inputID).value;
    4. YUI

      var math = Y.one('#' + inputID).get('value');
    5. Dojo

      var math = dom.byId(inputID).value

    After any of these, math is now the name given to the MathLex input value, but you can use whatever name you want (as long as it's not a reserved keyword).

  • Once you have some MathLex input, pass it to the MathLex.parse() function.

    var syntaxTree = MathLex.parse(math);

    This will give back an abstract syntax tree representing the interpreted mathematical meaning that can then be rendered/translated into other formats. To improve your web page's performance, only parse the MathLex input once. The syntax tree can be used multiple times without the overhead of reinterpreting the input's meaning.

  • Once you have a syntax tree, it can be rendered into several other formats. The general format is

    var formattedMathLex = MathLex.render(syntaxTree, targetFormat);

    Where targetFormat is a string containing the name of a renderer/translator. There are currently three renderers/translators included by default:

    • 'latex': for use in typesetting (perhaps using MathJax.)
    • 'sage' (about 80% complete): Input language for the open source Sage computer algebra system.
    • 'text-tree': outputs a plain text indented tree representation of the abstract syntax tree (intended for debugging purposes).

    These renderers/translators simply walk through the syntax tree recursively, performing a certain action at each node. For more information on the provided renderers, please visit the full documentation. We are happy to collaborate on writing additional renderers or translators.

  • Once you have your desired translation, you can do whatever you want with it. Examples of the use of the latex and sage translations are included in the example above. Here is an example using the text-tree renderer. In your HTML, include a line like:

    <pre id="text-tree-output"></pre>

    Then in the JavaScript, include the lines:

    var treeCode  = MathLex.render(syntaxTree, 'text-tree');
    document.getElementById('text-tree-output').innerHTML = treeCode;

Want to know more? Read the full documentation.