Open AlexEdgcomb opened 1 year ago
Thanks for the report. The TeX rules for placing super- and subscripts specify that if the base is a single character, then its height and depth are to be ignored (so that super-and subscripts all align if used on different letters), which is what is causing this problem. Because TeX doesn't treat stretchy characters in the same way as MathML, MathJax has to make some exceptions to this rule (e.g., for large operators like \sum
and \int
), but it should also make exceptions for stretched characters like this.
I will make a PR to resolve the issue.
Here is a configuration you can use as a work-around for now until the fix is released.
MathJax = {
startup: {
ready() {
baseCharZero = (n) => {
const largeop = !!this.baseCore.node.attributes.get('largeop');
const sized = !!(this.baseCore.node.isKind('mo') && this.baseCore.size);
const scale = this.baseScale;
return (this.baseIsChar && !largeop && !sized && scale === 1 ? 0 : n);
};
const {ChtmlScriptbase} = MathJax._.output?.chtml?.Wrappers?.scriptbase;
if (ChtmlScriptbase) ChtmlScriptbase.prototype.baseCharZero = baseCharZero;
const {SvgScriptbase} = MathJax._.output?.svg?.Wrappers?.scriptbase;
if (SvgScriptbase) SvgScriptbase.prototype.baseCharZero = baseCharZero;
}
}
};
@dpvc , thank you for explaining!
The workaround doesn't typeset due to JS errors: https://codepen.io/alexedgcomb/pen/VwEVPme
I tried fixing, but failed: https://codepen.io/alexedgcomb/pen/bGmQgqY
MathJax = {
startup: {
ready() {
baseCharZero = (n) => {
const largeop = !!this.baseCore.node.attributes.get('largeop');
const sized = !!(this.baseCore.node.isKind('mo') && this.baseCore.size);
const scale = this.baseScale;
return (this.baseIsChar && !largeop && !sized && scale === 1 ? 0 : n);
};
const {ChtmlScriptbase} = MathJax._.output?.chtml?.Wrappers?.scriptbase ?? {};
if (ChtmlScriptbase) ChtmlScriptbase.prototype.baseCharZero = baseCharZero;
const {SvgScriptbase} = MathJax._.output?.svg?.Wrappers?.scriptbase ?? {};
if (SvgScriptbase) SvgScriptbase.prototype.baseCharZero = baseCharZero;
MathJax.startup.defaultReady();
}
}
};
Changes:
const {ChtmlScriptbase}
and const {SvgScriptbase}
lines with ?? {}
MathJax.startup.defaultReady();
Thanks for the corrections. I was working too quickly, and was doing my testing in Firefox, and without the defaultReady()
call, MathJax didn't run, and Firefox's native MathML did the rendering, and I didn't realize it and though it was fixed. Sorry about that.
In addition to the two errors you pointed out, I was working from the v4 code, which has normalized the names of the internal objects like ChtmlScriptbase
, but in v3 it should be CHTMLscriptbase
. Also, the replacement function must be a function (n) {...}
not (n) => {...}
in order to have the correct this
value.
Here is a corrected (working) version:
MathJax = {
startup: {
ready() {
baseCharZero = function (n) {
const largeop = !!this.baseCore.node.attributes.get('largeop');
const sized = !!(this.baseCore.node.isKind('mo') && this.baseCore.size);
const scale = this.baseScale;
return (this.baseIsChar && !largeop && !sized && scale === 1 ? 0 : n);
};
const CHTMLscriptbase = MathJax._.output?.chtml?.Wrappers?.scriptbase?.CHTMLscriptbase;
if (CHTMLscriptbase) CHTMLscriptbase.prototype.baseCharZero = baseCharZero;
const SVGscriptbase = MathJax._.output?.svg?.Wrappers?.scriptbase?.SVGscriptbase;
if (SVGscriptbase) SVGscriptbase.prototype.baseCharZero = baseCharZero;
MathJax.startup.defaultReady();
}
}
};
@dpvc , thank you! The v3 workaround works. I actually did happen to be interested in a v4 workaround, sorry for the confusion. I modified the v3 workaround, but I seem to be missing something: https://codepen.io/alexedgcomb/pen/gOBQQGm
OK, for v4.0.0-alpha.1, there is a little more to be done. There is a bug where a stretchy base doesn't get its bounding box updated when it is stretched, and that needs to be fixed as well. I was working in the current development branch where that is already fixed, but for the alpha release, that also needs to be patched.
Here is an updated configuration for v4.0.0-alpha.1 with SVG output.
MathJax = {
startup: {
ready() {
const SvgScriptbase = MathJax._.output.svg.Wrappers.scriptbase.SvgScriptbase.prototype;
SvgScriptbase.baseCharZero = function (n) {
const largeop = !!this.baseCore.node.attributes.get('largeop');
const sized = !!(this.baseCore.node.isKind('mo') && this.baseCore.size);
const scale = this.baseScale;
return (this.baseIsChar && !largeop && !sized && scale === 1 ? 0 : n);
};
const SvgMo = MathJax._.output.svg.Wrappers.mo.SvgMo.prototype;
Object.assign(SvgMo, {
_setDelimSize: SvgMo.setDelimSize,
setDelimSize(c, i) {
this._setDelimSize.call(this, c, i);
this.childNodes[0].invalidateBBox();
}
});
MathJax.startup.defaultReady();
}
}
};
I think that will work for you.
@dpvc , thank you! Yes, that works great for v4.0.0-alpha.1
Issue Summary
In MJ3,
<msubsup>
'ssubscript
does not align to the bottom of thebase
. Similarly,<msubsup>
'ssuperscript
does not align to the top of thebase
.https://developer.mozilla.org/en-US/docs/Web/MathML/Element/msubsup
Steps to Reproduce:
Observed: Subscript
a
and superscriptb
are in the middleExpected: Subscript
a
to be at the bottom and superscriptb
to be at the top, like in MJ2: https://codepen.io/alexedgcomb/pen/GRYYLweTechnical details:
I am NOT using a following MathJax configuration and loading MathJax via
Supporting information:
MJ4 has the same issue: https://codepen.io/alexedgcomb/pen/rNqqbmL
MathML in Firefox looks as expected: https://codepen.io/alexedgcomb/pen/ExddJKg. Chrome doesn't.