MathJax 或类似的:在表达式中渲染任意 HTML 元素?
MathJax or similar: render arbitrary HTML element inside expression?
我对 Web 应用程序中的数学表达式呈现有特殊需求,虽然到目前为止我主要关注的是 MathJax,但我当然不拘泥于它。
我需要的是能够呈现一个数学表达式,其中一个或多个项基本上可以是任意 HTML 框元素,如下所示:
...如果布局响应 HTML 框的大小(例如,括号将自动调整大小以匹配其高度,就像任何其他 "normal" LaTeX/MathJax 元素),但如果我需要以像素为单位指定精确大小或类似的大小,那也可以。如果我不得不例如,甚至可以。在实际可视化中插入一个 "placeholder" 元素,但可以确切知道它在输出中的位置,因此我可以将 HTML 元素精确地覆盖在它上面。
换句话说,我愿意接受开箱即用甚至是骇人听闻的解决方案;只需要有用的东西。
也可能相关:我真的只会使用非常基本的 LaTeX 元素:括号、分数、普通运算符。如果这是一个复杂的因素,我什至不需要能够支持上面示例中的求和。
有几种方法可以解决这个问题。您建议的插入占位符并覆盖它是一个,可以按如下方式进行:
<script type="text/x-mathjax-config">
MathJax.Hub.Queue(function () {
var PX = function (x) {return x.toFixed(2) + 'px'};
var space = document.getElementById('space');
var sbox = space.getBoundingClientRect();
var math = MathJax.Hub.getJaxFor(space).SourceElement().previousSibling;
var mbox = math.getBoundingClientRect();
var x = sbox.left - mbox.left;
var y = sbox.top - mbox.top;
var html = MathJax.HTML.Element('div', {id:'html', style: {
position:'absolute', top:PX(y), left:PX(x),
width:PX(sbox.width), height:PX(sbox.height), 'line-height':'normal'
}}, [[
'table',{style:{height:'100%', width:'100%', background:'red', border:'5px solid green'}}, [[
'tr',{},[[
'td',{},['abc']
]]
]]
]]);
math.style.position = 'relative';
math.appendChild(html);
});
</script>
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS_CHTML" defer></script>
<div style="xfont-size: 150%">
$$x + \left(\,\cssId{space}{\Space{100px}{55px}{45px}}\,\right) + y$$
</div>
这里我们用\Space
插入一个需要宽高深的空白区域,用\cssId
标记space,方便以后检索。在 MathJax 排版数学之后,我们使用 MathJax.Hub.Queue()
将函数排队到 运行。此函数查找 space-holder 元素并找到 MathJax 用来保存数学的容器元素。它获取每个边界框的信息,并根据数学计算叠加层的位置。然后它创建了覆盖层(在本例中内容是硬编码的),具有适当的大小和药水以覆盖在 space-holder 的顶部。
这可行,但有点笨拙,对于显示的方程式,如果 window 大小发生变化,叠加层可能不会停留在正确的位置。此外,它仅设置为适用于 CommonHTML 输出。
下面是一个替代方案,它使用 <semantics>
元素将 HTML 包含到 MathJax 使用的内部 MathML 结构中。它添加了一个新的宏 \insertHTML{}
来完成它。
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
CommonHTML: {
styles: {
//
// remove CSS for '.mjx-math *'
//
'.mjx-math *': {
display: null,
'-webkit-box-sizing': null,
'-moz-box-sizing': null,
'box-sizing': null,
'tex-align': null
},
//
// add CSS for .mjx-math span instead
//
'.mjx-math span': {
display: 'inline-block',
'-webkit-box-sizing': 'context-box !important',
'-moz-box-sizing': 'context-box !important',
'box-sizing': 'context-box !important',
'tex-align': 'left'
},
//
// override display for .mjx-char spans
//
'span.mjx-char': {
display: 'block'
}
}
}
});
MathJax.Hub.Register.StartupHook("TeX Jax Ready", function () {
var MML = MathJax.ElementJax.mml;
var TEX = MathJax.InputJax.TeX;
TEX.Definitions.macros.insertHTML = 'InsertHTML';
TEX.Parse.Augment({
InsertHTML: function (name) {
var html = this.GetArgument(name).replace(/^\s*<!--\s*/,'').replace(/\s*-->\s*$/,'');
var span = MathJax.HTML.Element('mjx-reset', {style: {display:'inline-block'}});
span.innerHTML = html; // serious security risk if users can enter math
span.setAttribute("xmlns","http://www.w3.org/1999/xhtml");
var mml = MML["annotation-xml"](MML.xml(span)).With({encoding:"application/xhtml+xml",isToken:true});
this.Push(MML.semantics(mml));
}
});
});
</script>
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS_CHTML" defer></script>
<div style="xfont-size: 150%">
$$x + \left(\,\insertHTML{<!--
<table width="100" height="100"
style="display:inline-table; vertical-align:-.25em; background:red; border:5px solid green;
box-sizing:border-box !important">
<tr><td style="text-align:center">abc</td></tr>
</table>
-->}\,\right) + y$$
</div>
$$x+\left(\insertHTML{<!--
<i>this</i> is <b>html</b>
-->}\right)+y$$
因为 MathJax 不会直接处理包含 HTML 标记的数学,所以您必须将 HTML 放在注释中,您在上面的两个示例表达式中看到了这一点。此版本适用于所有输出格式(甚至是 MathML 输出),但它确实需要一些配置来覆盖一些适用于内容的 CommonHTML CSS,因为它包含在内部MathJax 布局。
在这种情况下,无论 window 发生什么情况,HTML 都会保持正确的位置,并且它的优点是允许 HTML 在表达式本身中给出.但是请注意,如果您的网站允许用户输入数学,这会带来安全风险,因为这意味着他们可以在您的页面中输入任意 HTML。在这种情况下,您需要在 InsertHTML
函数中设置 innerHTML
之前清理 HTML。
我对 Web 应用程序中的数学表达式呈现有特殊需求,虽然到目前为止我主要关注的是 MathJax,但我当然不拘泥于它。
我需要的是能够呈现一个数学表达式,其中一个或多个项基本上可以是任意 HTML 框元素,如下所示:
...如果布局响应 HTML 框的大小(例如,括号将自动调整大小以匹配其高度,就像任何其他 "normal" LaTeX/MathJax 元素),但如果我需要以像素为单位指定精确大小或类似的大小,那也可以。如果我不得不例如,甚至可以。在实际可视化中插入一个 "placeholder" 元素,但可以确切知道它在输出中的位置,因此我可以将 HTML 元素精确地覆盖在它上面。
换句话说,我愿意接受开箱即用甚至是骇人听闻的解决方案;只需要有用的东西。
也可能相关:我真的只会使用非常基本的 LaTeX 元素:括号、分数、普通运算符。如果这是一个复杂的因素,我什至不需要能够支持上面示例中的求和。
有几种方法可以解决这个问题。您建议的插入占位符并覆盖它是一个,可以按如下方式进行:
<script type="text/x-mathjax-config">
MathJax.Hub.Queue(function () {
var PX = function (x) {return x.toFixed(2) + 'px'};
var space = document.getElementById('space');
var sbox = space.getBoundingClientRect();
var math = MathJax.Hub.getJaxFor(space).SourceElement().previousSibling;
var mbox = math.getBoundingClientRect();
var x = sbox.left - mbox.left;
var y = sbox.top - mbox.top;
var html = MathJax.HTML.Element('div', {id:'html', style: {
position:'absolute', top:PX(y), left:PX(x),
width:PX(sbox.width), height:PX(sbox.height), 'line-height':'normal'
}}, [[
'table',{style:{height:'100%', width:'100%', background:'red', border:'5px solid green'}}, [[
'tr',{},[[
'td',{},['abc']
]]
]]
]]);
math.style.position = 'relative';
math.appendChild(html);
});
</script>
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS_CHTML" defer></script>
<div style="xfont-size: 150%">
$$x + \left(\,\cssId{space}{\Space{100px}{55px}{45px}}\,\right) + y$$
</div>
这里我们用\Space
插入一个需要宽高深的空白区域,用\cssId
标记space,方便以后检索。在 MathJax 排版数学之后,我们使用 MathJax.Hub.Queue()
将函数排队到 运行。此函数查找 space-holder 元素并找到 MathJax 用来保存数学的容器元素。它获取每个边界框的信息,并根据数学计算叠加层的位置。然后它创建了覆盖层(在本例中内容是硬编码的),具有适当的大小和药水以覆盖在 space-holder 的顶部。
这可行,但有点笨拙,对于显示的方程式,如果 window 大小发生变化,叠加层可能不会停留在正确的位置。此外,它仅设置为适用于 CommonHTML 输出。
下面是一个替代方案,它使用 <semantics>
元素将 HTML 包含到 MathJax 使用的内部 MathML 结构中。它添加了一个新的宏 \insertHTML{}
来完成它。
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
CommonHTML: {
styles: {
//
// remove CSS for '.mjx-math *'
//
'.mjx-math *': {
display: null,
'-webkit-box-sizing': null,
'-moz-box-sizing': null,
'box-sizing': null,
'tex-align': null
},
//
// add CSS for .mjx-math span instead
//
'.mjx-math span': {
display: 'inline-block',
'-webkit-box-sizing': 'context-box !important',
'-moz-box-sizing': 'context-box !important',
'box-sizing': 'context-box !important',
'tex-align': 'left'
},
//
// override display for .mjx-char spans
//
'span.mjx-char': {
display: 'block'
}
}
}
});
MathJax.Hub.Register.StartupHook("TeX Jax Ready", function () {
var MML = MathJax.ElementJax.mml;
var TEX = MathJax.InputJax.TeX;
TEX.Definitions.macros.insertHTML = 'InsertHTML';
TEX.Parse.Augment({
InsertHTML: function (name) {
var html = this.GetArgument(name).replace(/^\s*<!--\s*/,'').replace(/\s*-->\s*$/,'');
var span = MathJax.HTML.Element('mjx-reset', {style: {display:'inline-block'}});
span.innerHTML = html; // serious security risk if users can enter math
span.setAttribute("xmlns","http://www.w3.org/1999/xhtml");
var mml = MML["annotation-xml"](MML.xml(span)).With({encoding:"application/xhtml+xml",isToken:true});
this.Push(MML.semantics(mml));
}
});
});
</script>
<script id="MathJax-script" src="https://cdn.jsdelivr.net/npm/mathjax@2/MathJax.js?config=TeX-AMS_CHTML" defer></script>
<div style="xfont-size: 150%">
$$x + \left(\,\insertHTML{<!--
<table width="100" height="100"
style="display:inline-table; vertical-align:-.25em; background:red; border:5px solid green;
box-sizing:border-box !important">
<tr><td style="text-align:center">abc</td></tr>
</table>
-->}\,\right) + y$$
</div>
$$x+\left(\insertHTML{<!--
<i>this</i> is <b>html</b>
-->}\right)+y$$
因为 MathJax 不会直接处理包含 HTML 标记的数学,所以您必须将 HTML 放在注释中,您在上面的两个示例表达式中看到了这一点。此版本适用于所有输出格式(甚至是 MathML 输出),但它确实需要一些配置来覆盖一些适用于内容的 CommonHTML CSS,因为它包含在内部MathJax 布局。
在这种情况下,无论 window 发生什么情况,HTML 都会保持正确的位置,并且它的优点是允许 HTML 在表达式本身中给出.但是请注意,如果您的网站允许用户输入数学,这会带来安全风险,因为这意味着他们可以在您的页面中输入任意 HTML。在这种情况下,您需要在 InsertHTML
函数中设置 innerHTML
之前清理 HTML。