Introduction
If you are not used to Latex documents and started to publish scientific documents only using HTML language and MathJax javascript library, you are quickly faced to heavy and repetitive syntaxes, example :
<div class="cmath">
$$ \dfrac{dH}{dp} = \left( \dfrac{\partial H}{\partial T} \right)_p \dfrac{dT}{dp} + \left( \dfrac{\partial H}{\partial p} \right)_T $$
</div>
In the above example, we want to simplify and automate normal and partial derivatives using shortcut commands.
Another example, we want to automate and normalize units writing and to create shortcuts for physics constants used in several pages :
<div class="cmath">
$$ \begin{align} g &= 9.81 \ \mathrm{m\!\cdot\!s\small{^{-2}}} \\ R &= 8.3145 \ \mathrm{J\!\cdot\!mol\small{^{-1}}\!\cdot\!K\small{^{-1}}} \end{align} $$
</div>
To achieve it, MathJax javascript library supports Tex macros commands (\def
, \newcommand
, \let
…).
MathJax v2 and v3 loading configurations are given in the appendix. In this paper, Tex code is encapsulated in
div
, ins
and span
HTML tags having the class cmath
. Delimiters are :
- Block mode :
$$ Tex code $$
,\[ Tex code \]
- Inline mode :
## Tex code ##
,\( Tex code \)
<div class="cmath"> $$ Tex code $$ </div>
<span class="cmath"> ... \( Tex code \) ... </span>
New to MathJax and Tex ? A quick reference guide is available on this portal : SQLPAC | MathJax - Tex : Quick Reference Guide
Prerequisites
Macros are enabled by default in MathJax 2 and MathJax 3.
With MathJax 3, if a minimalist configuration has been decided, macros must be enabled in the window.MathJax
object
by adding the newcommand
and configmacros
packages. The configmacros
package is needed only
if it is planned later to define macros in the window.MathJax
object :
<script>
window.MathJax = { tex: { …, packages: ['base','newcommand','configmacros','noerrors'] }, …, loader: { load: ['input/tex-base','output/chtml','[tex]/newcommand','[tex]/configmacros','[tex]/noerrors'] }
</script> <script src="[path_to_mathjax]/startup.js" id="MathJax-script">
A basic macro
\( \def \Cg { 9.81 \ \mathrm{m\!\cdot\!s\small{^{-2}}} } % Gravitational constant \)Initiate a "hidden" tag to store macros definitions using CSS, in this paper the ins
tag having the class cmath
:
ins[class*="cmath"] {
position: fixed; top: 10px; height: 0px; width: 0px;
color: transparent; background-color: transparent;
}
Do not use the CSS property display: none
,
otherwise the MathJax v3.2 new lazy mode feature won’t work, this feature uses the IntersectionObserver
object.
A Tex shortcut Cg
is now created for the gravitational constant ##g##. In the "hidden" tag, using \def
:
<ins class="cmath">
\( \def \Cg { 9.81 \ \mathrm{m\!\cdot\!s\small{^{-2}}} } % Gravitational constant \)
</ins>
In Tex code, just call \Cg
:
<div class="cmath">
$$ \Cg{} $$
</div>
Instead of using a "hidden" tag, macros can be defined in the window.MathJax
object before calling MathJax, backslashes are escaped :
This example is very basic, values and units are hard coded. Of course macros handle arguments.
Macros with arguments
Let’s define 2 macros dvr
and dvp
respectively for regular and partial derivatives : 2 arguments in the macros.
<ins class="cmath">
\( \def \dvr #1#2 { \dfrac{d#1}{d#2} } % Regular derivative \) \( \def \dvp #1#2 { \dfrac{\partial #1}{\partial #2} } % Partial derivative \)
</ins>
The equation in the introduction is now simply written and even more readable provided you know your own macros well :
<div class="cmath">
$$ \dvr{H}{p} = \left( \dvp{H}{T} \right)_p \dvr{T}{p} + \left( \dvp{H}{p} \right)_T $$
</div>
The maximum number of arguments in the \def
command is 9 : from #1
to #9
.
By default, defining \def \dvp #1#2#3 { … }
, the syntax \dvp{ }{ }{ }
is expected in the Tex code.
In an alternate syntax, the first argument is delimited by square brackets while the others are single characters :
<ins class="cmath">
\( \def \drv[#1]#2 { \dfrac{d#1}{d#2} } % Derivative) \)
</ins>
<div class="cmath">
$$ \drv[T]{p} $$
</div>
The \def
command does not understand optional arguments. For optional arguments, use \newcommand
instead, but support is
partial, only one optional argument is allowed : this topic is addressed in the next sections.
\def
does not check whether the command already exists, definition is overwritten. Existence checks are possible :
\( \ifx \dv \undefined \def \dvr #1#2 { \dfrac{d#1}{d#2} } % Regular derivative \fi \)
Defining macros with \newcommand
Instead of the \def
command to define macros, \newcommand
may be prefered. What are the differences ?
\newcommand
fails if the command is already defined.\newcommand
provides a convenient syntax for specifying the number of arguments and an optional argument (only one).\newcommand
defines "long" commands,\def
defines short ones unless\long\def
is used.
To sum up the \newcommand
basic syntax :
\newcommand {\cmd}[number of arguments] { ...#1...#2... }
The demo equation with \newcommand
is now :
<ins class="cmath">
\( \newcommand {\dvr}[2] { \dfrac{d#1}{d#2} } % Regular derivative \) \( \newcommand {\dvp}[2] { \dfrac{\partial{#1}}{\partial{#2}} } % Partial derivative \)
</ins>
<div class="cmath">
$$ \dvr{H}{p} = \left( \dvp{H}{T} \right)_p \dvr{T}{p} + \left( \dvp{H}{p} \right)_T $$
</div>
To define the macros in the window.MathJax
object :
Optional argument
With \newcommand
, we can define one optional argument, and only one.
The syntax is then :
\newcommand {\cmd}[number of arguments][default value optional argument] { ...#1...#2... }
- The optional argument is always
#1
. - To set a value for the optional argument when calling the command :
\cmd[value]{}...
.
<ins class="cmath">
\( \newcommand {\seq}[2][n] { S_{#1} = #2_0 + #2_1 + \cdots + #2_{#1}} % Sequences \)
</ins>
\( \newcommand {\seq}[2][n] { S_{#1} = #2_0 + #2_1 + \cdots + #2_{#1}} % Sequences \)<div class="cmath">
$$ \seq{u} \\ \seq[n-1]{u} \\ \seq[j]{a} $$
</div>
Combining macros
Macros can be combined and nested. The definition order does not matter, evaluation is not performed at the definition step.
In the below example, big left and right parenthesis are automated using macros :
\( \newcommand {\bdvr}[2] { \left( \dvr{#1}{#2} \right) } % Regular derivative Big parenthesis \) \( \newcommand {\bdvp}[2] { \left( \dvp{#1}{#2} \right) } % Partial derivative Big parenthesis \) \( \newcommand {\bp}[1] { \left( #1 \right) } % Big parenthesis \)<ins class="cmath">
\( \newcommand {\dvr}[2] { \dfrac{d#1}{d#2} } % Regular derivative \) \( \newcommand {\dvp}[2] { \dfrac{\partial{#1}}{\partial{#2}} } % Partial derivative \) \( \newcommand {\bdvr}[2] { \left( \dvr{#1}{#2} \right) % Regular derivative Big parenthesis \) \( \newcommand {\bdvp}[2] { \left( \dvp{#1}{#2} \right) } % Partial derivative Big parenthesis \) \( \newcommand {\bp}[1] { \left( #1 \right) } % Big parenthesis \)
</ins>
<div class="cmath">
$$ \dvr{H}{p} = \bdvp{H}{T}_p \dvr{T}{p} + \bdvp{H}{p}_T $$
</div>
or, using bp
macro :
<div class="cmath">
$$ \dvr{H}{p} = \bp{\dvp{H}{T}}_p \dvr{T}{p} + \bp{\dvp{H}{p}}_T $$
</div>
Knowing how to combine macros, how to define an optional argument, units formatting and physics constants definitions become easier : 3 macros
\unit
: to format the whole unit (font, space).\per
: to format minusx
power, by default ##-1##.\pt
: to format the dot separator in the unit.
<ins class="cmath">
\( \newcommand {\unit}[1] {\ \mathrm{#1}} % Unit format (font, space) \) \( \newcommand {\pt}{\!\cdot\!} % Unit dot separator formatting \) \( \newcommand {\per}[1][1]{\small{^{-#1}}} % Minus x power \)
</ins>
The 2 constants ##R## and ##g## are now coded and displayed using these reusable macros :
<div class="cmath">
$$ \begin{align} R &= 8.3145 \unit{J \pt mol\per \pt K\per} \\ g &= 9.81 \unit{m \pt s\per[2]} \end{align} $$
</div>
We may now decide to define the physics constants called in several pages using macros,
moreover a uacc
macro is created for the acceleration unit (##\unit{m \pt s\per[2]}##), unit used in many pages :
<ins class="cmath">
\( \newcommand {\uacc}{ \unit{m \pt s\per[2]} } % Acceleration unit \) \( \newcommand {\CR}{ 8.3145 \unit{J \pt mol\per \pt K\per} } % Ideal gas constant \) \( \newcommand {\Cg}{ 9.81 \uacc} % Gravitational constant \)
</ins>
<div class="cmath">
$$ \begin{align} R &= \CR \\ g &= \Cg \end{align} $$
</div>
If the macros are defined in the window.MathJax
object :
Notice : in the per
macro, the third argument is the macro’s optional argument default value
and it must be a string. If default values datatypes are not string (integer
, float
, etc.), macros definitions fail with MathJax.
Building and loading macros libraries
In the previous sections, macros are defined in the HTML page or in the window.MathJax
object :
In the HTML option, commands are hard coded in each page which needs the macros. In the window.MathJax
option,
depending on how MathJax is called (call in the page or using a global function) : either macros are hard coded in the page or all macros
are loaded even those not necessary.
A more robust solution consists in splitting macros in files per features, a kind of libraries : for example, 1 file for units management macros, 1 file for derivatives/inegrals macros, etc. In the page, only the necessary libraries are loaded. How to achieve it ?
Using PHP, easy but it needs a Web server : just include the necessary files. Files will store the HTML code which encapsulates the macros definitions.
|
./lib/macros-units.inc
|
Using Javascript, a little bit more tricky :
macros definitions must be loaded just after window.MathJax
is instantiated and before MathJax runs. Use the defer
attribute to guarantee the sequence order, async mode is then no more
appropriate.
|
./lib/macros-units.js (MathJax v3)
For MathJax v2, replace m.tex by m.Tex
and m.tex.macros by m.Tex.Macros . |
MathJax v3 packages
More flexible than version 2, MathJax v3 provide new packages containing useful macros : physics
, braket
packages.
More packages to come in next v3 releases.
Regularly, consult the next versions, a new package may match to its needs : no need to reinvent the wheel.
All the macros created above for regular and partial derivatives have analogous equivalents in the physics
package included in MathJax 3.
The physics
package is not loaded by default, to load it (output is alleviated for brevity) :
window.MathJax = {
tex: { …, packages: {'[+]': ['noerrors','physics']} },
…,
loader: { load: ['[tex]/noerrors','[tex]/physics',…] }
}
The demo equation in this paper is then the following using physics
package :
(doc: CTAN - The Physics package) :
<div class="cmath">
$$ \dv{H}{p} = \left( \pdv{H}{T} \right)_p \dv{T}{p} + \left( \pdv{H}{p} \right)_T $$
</div>
Regular and partial derivatives are respectively managed with \dv
and \pdv
macros in this package.
And why not applying the bp
macro created in previous sections to manage big parenthesis :-) ?
<div class="cmath">
$$ \dv{H}{p} = \bp { \pdv{H}{T} }_p \dv{T}{p} + \bp { \pdv{H}{p} }_T $$
</div>
Another example, the mhchem
package for chemistry equations using \ce
macro :
<div class="cmath">
$$ \ce{SO4^2- + Ba^2+ -> BaSO4 v} $$
</div>