Mathematical Typesetting

As described in the documentation, Framework provides mathematical typesetting facilities using its tex macro. Technically, the macro is implemented as a particular type of Javascript function called a tagged template literal. The syntax is quite natural from the perspective of a programmer and it integrates well into Javascript programs.

This syntax is not, however, particularly natural from the LaTeX point of view and, honestly, it's a bit cumbersome compared to standard LaTeX delimiters. Particularly, if you've got a bunch of LaTeX already written, you really want to be able to type

If $f(x) = e^{-x^2}$, then $$\int_{-\infty}^{\infty} f(x) \ dx = \sqrt{\pi}.$$

like so:

If $f(x) = e^{-x^2}$, then
$$\int_{-\infty}^{\infty} f(x) \ dx = \sqrt{\pi}.$$

This page outlines a few ways to accomplish this and more.

Typesetting systems

The gold standard for mathematical typesetting is LaTeX. There are a couple of Javascript libraries that implement LaTeX's mathematical typesetting in the browser:

They both have their own advantages.

Simplest usage case

The simplest way to use either MathJax or KaTeX is to include script tags in the head of your HTML document. In the case of KaTeX, you also need to include a link tag to some CSS.

Here are a couple of examples:

Observable's tex macro is built on top of KaTeX and, furthermore, you can use KaTeX directly. KaTeX was originally written as a faster alternative to the more venerable MathJax. MathJax has always been more feature rich, though, providing

Furthermore, the speed difference since version 3 of MathJax is minimal. Let's take a look at how to use MathJax in Framework.

Placing MathJax in the head

If you simply want to use MathJax so that you can delimit LaTeX snippets with simple $dollar$ and $$double dollar$$ delimiters, then the easiest approach is to include the following line to the YAML frontmatter at the top of the document:

head: '<script>MathJax = {tex: {inlineMath: [["$", "$"], ["\\(", "\\)"]]},svg: {fontCache: "global"}};</script><script type="text/javascript" id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js"></script>'

After doing so, those script tags are placed in the resulting HTML file's head element. Thus, we can now enter the following:

While this output looks like that produced by KaTeX, it's much more interactive. If you simply click on it, you should get a zoomed version. If you control-click, you pull up a contextual menu with more options. This is largely why I prefer MathJax.

Importing MathJax

MathJax is easy to import from cloudflare. If you want dollar sign delimited snippets to be automatically rendered, you also need to configure it. You can do so by writing a component - i.e. a Javascript file that looks like so:

import './mathjax-config.js';
import "https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/tex-svg.js";

export function import_mathjax() {
  return MathJax
}

The mathjax-config file configures MathJax and should contain at least the following:

window.MathJax = {
  tex: {
    inlineMath: [['$', '$'], ['\\(', '\\)']]
  },
  loader: {
    paths: {
      mathjax: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.2.2/es5/'
    }
}

We can then import the MathJax component in a Markdown file:

import {import_mathjax} from './components/import_mathjax.js';
const MathJax = import_mathjax();

When imported this way, it is not necessary to to include the script tags in the head of the document; MathJax will automatically typeset $dollar$, delimited snippets. In addition, though, we now have access to the MathJax object for programmatic use, if desired.

Programmatic use

Since we've imported MathJax and stored the resulting object in a variable, cleverly named MathJax, we can use it programmatically.As a simple example, the drop down menu in the interactive example below specifies a LaTeX snippet; that LaTeX snippet is then typeset using MathJax.

Dynamic typesetting with MathJax

// Code block one to generate the dropdown
let math_string = view(Inputs.select([
  String.raw`x^2`,
  String.raw`\sin(x^2)`,
  String.raw`\cos(x^3)`,
  String.raw`\frac{1}{\sqrt{1-x^2}}`
], {label: "f(x):"}))

// Code block two to process the LaTeX input
display(MathJax.tex2svgPromise(`f(x) = ${math_string}`).then(p => p))

MathJax loads asynchronously and, as a result, is generally a little trickier to use than KaTeX. In the above example, we use MathJax's tex2svgPromise, which waits until all components are loaded before running.

Comments