MathJax Render Actions
A MathDocument instance contains a sequence of functions
called renderActions that are used
during the typesetting process to perform the actions needed to locate
expressions in the page, compile them into the internal format, obtain
font metrics for the surrounding text, typeset the mathematics, insert
the typeset math back into the page, add menu actions, and so on.
Loading some components will add new functions into this list. For
example, the a11y/semantic-enrich component adds a render
action that computes the semantic-enrichment for each expression.
All the typesetting and conversion functions listed above use this
collection of functions to perform their typesetting or conversion
operations.
The renderActions configuration option provides a means of linking your own functions into this processing pipeline at any point, replacing existing steps with your own custom versions, or even removing them to trim down what MathJax does.
The renderActions configuration object consists of one or more
name: value pairs (separated by commas), where the name
gives an identifier for the action, and the value is an array
consisting of a number followed by zero, one, or two functions, and
an optional boolean, as described below.
The number gives the priority of the action in relation to the other
actions that are already defined. The functions for the lowest
numbers are performed first. The number may be negative, or have
decimal places. The existing priorities are found in the
STATE variable from the ts/core/MathItem.ts file or the
MathJax._.core.MathItem object (when using MathJax
Components). These include the following:
Name |
Priority |
Identifier |
|---|---|---|
UNPROCESSED |
0 |
|
FINDMATH |
10 |
find |
COMPILED |
20 |
compile |
CONVERT |
100 |
|
METRICS |
110 |
metrics |
RERENDER |
125 |
|
TYPESET |
150 |
typeset |
INSERTED |
200 |
update |
STYLES |
201 |
styles |
LAST |
10000 |
Here, the name is the value’s key in the STATE object that
has the given priority. The identifier is the key in the
renderAction object for the action with the given priority.
Some states are for reference only and do not have associated actions;
e.g., CONVERT and RERENDER are only used to tell where a
mathDocument.convert() or
mathDocument.rerender() action should start in the list of
render actions, while UNPROCESSED and LAST mark the usual
start and end of the processing list, though values outside that range
are allowed.
Some extensions add new render actions. These include
name |
Priority |
Identifier |
Extension |
|---|---|---|---|
CONTEXT_MENU |
170 |
addMenu |
ui/menu |
205 |
getMenu |
ui/Menu |
|
1 |
checkLoading |
ui/menu |
|
LAZYALWAYS |
13 |
lazyAlways |
ui/lazy |
ENRICHED |
30 |
enrich |
a11y/semantic-enrich |
ATTACHSPEECH |
210 |
attachSpeech |
a11y/speech |
COMPLEXITY |
40 |
complexity |
a11/complexity |
EXPLORER |
230 |
explorable |
a11y/explorer |
You may use these values to determine the appropriate priorities to
use for your own actions. Actions with the same priority will be
performed in the order in which they were added to the render action
list for the document by you and the components you have loaded. The
newState() function from the ts/core/MathItem.ts file
can be used to create a new named state value like the ones above.
Otherwise, you can give priorities as numeric values, or as an
existing STATE, possibly value plus (or minus) a given number.
Following the priority in the action’s definition array should be
zero, one, or two functions. The first is called whenever the page is
typeset via a call to MathJax.typeset(),
mathDocument.render() or
mathDocument.rerender(), or their promise-based versions,
and is passed the MathDocument object in which it is running.
Usually this function will loop through the MathItem objects
stored in the mathDocument.math list and perform its action on
each of those individually.
The second function is called whenever a math expression is updated
individually via its rerender() method (e.g., when a
subexpression is collapsed, or a toggle item is toggled, or the speech
ruleset is changed), or during a mathDocument.convert()
call is made, or any of the conversion functions based on it (e.g.,
MathJax.tex2svg()), or any of the promise-based versions of
this is called. The function for this action is called with two
arguments: the MathItem on which it is to operate, and the
MathDocument that holds that item.
If either of these functions is given as an empty string, then that
action is not performed (that way, you can define a typeset action
without a rerender action, for example), and if it is a non-empty
string rather than a function, that is taken to be the name of a
method of the MathDocument (for the first function) or
MathItem (for the second function) to be called for that
action instead. If the function is missing, then the identifier used
for the action in the renderAction object is taken as the
method name to use.
Finally, the optional boolean value tells whether the second function is
to be use for both convert() and rerender() actions
(when true, the default), or only for rerender() actions
(when false).
To remove a render action, set its identifier to an empty array. For example,
MathJax = { option: { renderActions: { addMenu: [], getMenu: [], checkLoading: [], } } }
would disable all the MathJax menu actions. This would disable to the
MathJax menu, though it is easier to set enableMenu to
false to accomplish that.
To replace a render action, set its identifier to the definition
you would like to use instead. For example, you could replace the
typeset action with one that generates MathML output in the
page rather than the CHTML or SVG output from MathJax. The
MathML Support section for an example of how to do this.
A Render Action for Tooltips
Here is an example of defining your own render action that adds the original TeX notation as a tooltip on the MathJax output:
MathJax = {
addTooltip(item) {
const adaptor = MathJax.startup.adaptor;
adaptor.setAttribute(math.typesetRoot, 'title', item.math);
},
options: {
renderActions: {
addTooltip: [175,
(doc) => {
for (const item of doc.math) {
MathJax.config.addTooltip(item);
}
},
(math, doc) => MathJax.config.addTooltip(math),
]
}
},
}
This uses a function addTooltip() that is stored in the
MathJax configuration (and otherwise ignored by MathJax), and
specified a new addTooltip render action at priority 175
(after typesetting by before inserting into the page). The first
function of the action, which is called as part of a typeset action,
loops through the math items in the document and call the
addTooltip() function on each one. The second, called during
a convert or rerender action, calls the addTooltip() function
on the math item that it was passed.
A Render Action to Collapse Complex Subexpressions
This example loads the a11y/complexity component and automatically collapses any subexpressions with complexity greater than a given value (20 in this case).
MathJax = {
options: {
menuOptions: {
settings: {
collapsible: true
}
},
renderActions: {
collapse: [50,
(doc) => {
for (const math of doc.math) {
if (!math.root || math.state > 50) continue;
math.root.walkTree((node) => {
if (node.isKind('maction') && node.attributes.get('data-collapsible')) {
if (node.childNodes[1].attributes.get('data-semantic-complexity') > 20) {
node.attributes.set('selection', 1);
}
}
});
math.state(50);
}
},
'',
false
]
}
}
};
Here we define an action that occurs after the math is compiled and
its complexity values have been computed, but before the math is
typeset. The action only operates for typeset actions (not convert or
rerender calls), and it walks the MathML tree to find maction
elements inserted by the complexity component that have complexity
greater than 20. These get their selections set to 1, so they select
the collapsed version instead of the expanded ones. Then the state is
set to 50 so that if the item is processed again (either because the
typesetting had to be restarted due to an asynchronous action later in
the render actions, or by a later typesetting call), this math item
will not be checked again.