MathJax
MathJax copied to clipboard
Default Color
I need a way to restore the default color after changing it. One may not know the default color conveniently since it comes from CSS.
In LaTeX, we can restore the default color by doing something like:
\colorlet{colordefl}{.} %save current color
\color{red}
%color is red here
\color{colordefl}
%color is default again
However, \colorlet does not seem to be supported in MathJax. The workaround in most cases is to scope any color changes:
% color is default here
{\color{red}
%color is red here
}
% color is default here again
However, this isn't possible for certain constructs. For example, to color an underbrace and its label, but not its contents:
{\color{red}\
underbrace{\color{colordefl} ...}_{...}
}
This is somewhere between a bug report (\colorlet is missing), a feature request (add it, or equivalent mechanism, please), and a question (how do I do this / is there a workaround?).
The \colorlet macro is from the xcolor LaTeX package, but MathJax v3 implements the color package, not xcolor, which is much more complex. So \colorlet is not part of the MathJax package.
On the other hand, here is a MathJax v3 configuration that implements \colorlet enough to allow you to do what you are asking here.
MathJax = {
loader: {load: ['[tex]/color']},
tex: {packages: {'[+]': ['color', 'my-colorlet']}},
startup: {
ready() {
const {Configuration} = MathJax._.input.tex.Configuration;
const {CommandMap} = MathJax._.input.tex.SymbolMap;
new CommandMap('my-colorlet', {
colorlet: 'ColorLet'
}, {
ColorLet(parser, name) {
const type = parser.GetBrackets(name);
const cname = parser.GetArgument(name);
let model = parser.GetBrackets(name);
let def = parser.GetArgument(name);
if (def === '.') {
if (parser.stack.env.color) {
def = parser.stack.env.color;
} else {
let node = MathJax.config.tex['my-colorlet'].math.start.node.parentNode;
const style = this.window.getComputedStyle(node);
def = style.color;
}
model = 'named';
}
const colorModel = parser.configuration.packageData.get('color').model;
colorModel.defineColor(model, cname, def);
}
});
Configuration.create('my-colorlet', {
handler: {
macro: ['my-colorlet']
},
config(config, jax) {
jax.parseOptions.packageData.set('my-colorlet', {jax});
}
});
MathJax.startup.defaultReady();
MathJax.startup.document.inputJax[0].preFilters.add(({math}) => {
MathJax.config.tex['my-colorlet'] = {math};
});
}
}
};
This handled both colors inherited from the surrounding text, or explicit colors from within the LaTeX. If the color is set via css that targets a sub-element of the expression, this won't pick that up, since the DOM nodes are not built or in the DOM yet at the point that the LaTeX is being processed. To handle that, you would need a more complicated post-processing step in a renderAction that runs after the document-update action.
For the HTML
<div style="color: blue">
\[
\colorlet{c1}{.}
\color{red}\underbrace{\color{c1} x+y+z+w}_{123}
\]
\[\color{green}
\colorlet{c2}{.}
\color{red}\underbrace{\color{c2} x+y+z+w}_{123}
\]
</div>
the output is
For v4, you can do this simpler configuration that doesn't require modifying MathJax.config, as the current MathItem is stored in the parser.configutation:
MathJax = {
loader: {load: ['[tex]/color']},
tex: {packages: {'[+]': ['color', 'my-colorlet']}},
startup: {
ready() {
const {Configuration} = MathJax._.input.tex.Configuration;
const {CommandMap} = MathJax._.input.tex.TokenMap;
new CommandMap('my-colorlet', {
colorlet: 'ColorLet'
}, {
ColorLet(parser, name) {
const type = parser.GetBrackets(name);
const cname = parser.GetArgument(name);
let model = parser.GetBrackets(name);
let def = parser.GetArgument(name);
if (def === '.') {
if (parser.stack.env.color) {
def = parser.stack.env.color;
} else {
let node = parser.configuration.mathItem.start.node.parentNode;
const style = this.window.getComputedStyle(node);
def = style.color;
}
model = 'named';
}
const colorModel = parser.configuration.packageData.get('color').model;
colorModel.defineColor(model, cname, def);
}
});
Configuration.create('my-colorlet', {
handler: {
macro: ['my-colorlet']
}
});
MathJax.startup.defaultReady();
}
}
};
This seems like kindof an immense amount of code to accomplish this, though I don't doubt it works, as a workaround. I'll keep with hackish solutions to keep my page load times down; this works well enough for me until native support is added.