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:
The value of the
math-input
text field was obtained above on line 53 using a jQuery command of the form:where
inputID
stands for the input test field. In the example, this wasmath-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:Standard JavaScript
MooTools
Prototype
YUI
Dojo
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.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
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:
Then in the JavaScript, include the lines:
Want to know more? Read the full documentation.