如何在我的网站上通过MathJax插入一个SVG字符?
我实现了一个使用Markdown文件来编写公式并用MathJax处理公式的维基。我想添加我自己的SVG符号来表示积分、求和等运算符,并希望能够在新符号周围放置变量。
下面是一个示例符号,我尝试在其下方放置变量:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 300" stroke="black" fill="none" style="stroke-width: 20px;">
<path d="M 5 249.5625 C 8 93.5625, 149 98.5625, 147 250.5625"/>
<path d="M 5 249.5625 C 0 42.5625, 102 22.5625, 139 63.5625"/>
</svg>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>New Maths</title>
<script defer src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-chtml.js"></script>
</head>
<body>
<!-- Acop is my new mathematical operator, it is written like a limit. -->
$$
\Acop{u\to x}\ f(u)
$$
</body>
</html>
解决方案
@herrstrietzel提到的那篇帖子给出几种将SVG图像插入到MathJax表达式中的方法。它没有讨论在图像下面放置子表达式的问题,因为一旦图像放好,你只需要使用处理这类情况的常规LaTeX宏。例如,如果你想让一个直立的 X 像求和符号一样发挥作用(显示样式下方会放置下标,文本样式下会充当上标和下标),那么你将使用 $$\mathop{\mathrm{X}}_{n=1}^{10}$$ 来得到
那些只是普通的LaTeX命令,因此与它们应用于字符还是图像无关。这也是为什么 @herrstrietzel的建议是正确的,因为图像是唯一需要你单独处理的部分;极限的位置放置是标准的LaTeX。
据此,你可以把他链接的答案和像 \mathop 之类的内容结合起来,以实现你想要的效果。我建议使用 \mmlToken 的做法,因为它很直观。请注意,它所创建的 mglyph 的边界框将等同于该SVG图像在其 viewBox 属性中给出的边界框。
不过,你贴的图像在 viewBox 这一点上有些问题。框的高度和深度过大(上方和下方有额外空白),宽度又不足(图像被裁剪),如下所示,我在这里给图片添加了红色背景以便看到它的实际范围:
按原样使用该SVG会导致极限与字形之间的距离过大,符号在左右会被裁剪。
将viewBox调整为 -10 35 173 216 将得到更好的结果:
使用那个SVG将得到间距适当的排版。下面是一个实时示例:
<script defer src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-chtml.js"></script>
<div style="font-size: 120%">
$$\mathop{\mmlToken{mglyph}[src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0xMCAzNSAxNzMgMjE2IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOiAyMHB4Ij4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyA4IDkzLjU2MjUsIDE0OSA5OC41NjI1LCAxNDcgMjUwLjU2MjUiLz4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyAwIDQyLjU2MjUsIDEwMiAyMi41NjI1LCAxMzkgNjMuNTYyNSIvPgo8L3N2Zz4=" width="17.3px" height="21.6px" valign="-4px"]{}}_{x\to u}f(x)$$
</div>
在这里我使用了一个 SVG转 Data URL的转换工具 来生成在 \mmlToken 调用中使用的 data: URL。你也可以使用该URL,或者直接链接到一个 .svg 文件。你需要根据所使用的字体大小调整 height、width 和 valign 属性。我选择了一个便于从 viewBox 计算的尺寸。
请注意,这种方法不会像LaTeX中的大型运算符那样在显示样式与文本样式之间自动改变大小(或两种脚本样式)。如果你想让它自动实现这一点,可以使用 \mathchoice 宏根据当前样式自动选择不同的大小。下面是一种做法:
<script defer src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-chtml.js"></script>
<span style="display:none">
\(\def\ACOP#1#2#3{\mmlToken{mglyph}[src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0xMCAzNSAxNzMgMjE2IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOiAyMHB4Ij4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyA4IDkzLjU2MjUsIDE0OSA5OC41NjI1LCAxNDcgMjUwLjU2MjUiLz4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyAwIDQyLjU2MjUsIDEwMiAyMi41NjI1LCAxMzkgNjMuNTYyNSIvPgo8L3N2Zz4=" width="#1px" height="#2px" valign="#3px"]{}}
\def\dAcop{\ACOP{24.3}{30.5}{-8}}
\def\tAcop{\ACOP{17.3}{21.6}{-4}}
\def\sAcop{\ACOP{12.2}{15.3}{-2.8}}
\def\ssAcop{\ACOP{8.7}{10.8}{-2}}
\def\Acop{\mathop{\mathchoice{\dAcop}{\tAcop}{\sAcop}{\ssAcop}}_}\)
</span>
<div style="font-size: 120%">
$${\displaystyle\Acop{x\to u}f(x)}+{\textstyle\Acop{x\to u}f(x)}+{\scriptstyle\Acop{x\to u}f(x)}+{\scriptscriptstyle\Acop{x\to u}f(x)}$$
</div>
在这里我定义了一个宏 \ACOP,它接受三个参数(宽度、高度和对齐基线的值),并生成带有正确属性的 mglyph。然后我定义四个宏,分别对应四种排版样式。最后,定义 \Acop 以使用 \mathchoice 来选取所需的那个,并把它们全部包裹在一个 \mathop 中,以便正确处理极限。由于你的图像表明你希望能够执行 \Acop{x\to u}f(x),我在宏定义中加入了 _,使其将下一个花括号组作为下限。所有定义都放在一个隐藏的 span 元素中,因此不会在文档中占用空间(但下面有另一种实现方式,请参阅)。
如果你不想让显示样式的大小变大,只需在 \mathchoice 调用中将 \dAcop 替换为 \tAcop 即可。
请注意,除了显示样式外,极限在所有样式中都以下标形式出现。这是运算符工作方式的标准(以避免打乱段落中的行间距)。如果你希望无论何时都将极限显示在下方,请在 _ 之前使用 \limits:
<script defer src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-chtml.js"></script>
<span style="display:none">
\(\def\ACOP#1#2#3{\mmlToken{mglyph}[src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0xMCAzNSAxNzMgMjE2IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOiAyMHB4Ij4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyA4IDkzLjU2MjUsIDE0OSA5OC41NjI1LCAxNDcgMjUwLjU2MjUiLz4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyAwIDQyLjU2MjUsIDEwMiAyMi41NjI1LCAxMzkgNjMuNTYyNSIvPgo8L3N2Zz4=" width="#1px" height="#2px" valign="#3px"]{}}
\def\dAcop{\ACOP{24.3}{30.5}{-8}}
\def\tAcop{\ACOP{17.3}{21.6}{-4}}
\def\sAcop{\ACOP{12.2}{15.3}{-2.8}}
\def\ssAcop{\ACOP{8.7}{10.8}{-2}}
\def\Acop{\mathop{\mathchoice{\dAcop}{\tAcop}{\sAcop}{\ssAcop}}\limits_}\)
</span>
<div style="font-size: 120%">
$${\displaystyle\Acop{x\to u}f(x)}+{\textstyle\Acop{x\to u}f(x)}+{\scriptstyle\Acop{x\to u}f(x)}+{\scriptscriptstyle\Acop{x\to u}f(x)}$$
</div>
请注意,当极限在符号下方时,结果的宽度取SVG的宽度和下方极限宽度中的较大者,因此在上述示例中,文本样式版本中的“f”会从紧邻着“u”的右侧开始,因此“h”的SVG与“f”之间会有空隙。如果你希望间距更小,可以使用 \! 来减少间距,如 \Acop{x\to u}\!\!f(x) 所示。
由于回退空格的大小取决于实际的下方极限和排版风格,因此这个空间不能作为宏的一部分,必须手动插入。或者,你也可以加载 mathtools 包并使用它的 \matclap{} 宏来隐藏极限的大小(不过如果使用极宽的极限,可能会有问题)。例如 \Acop{\mathclap{x\to u}}f(x) 会生成
请注意,这样会同时去掉左侧和右侧的空隙,可能并不合适。可以通过将 \mathclap 包含到 \Acap 的定义中来实现:
\def\Acop#1{\mathop{\mathchoice{\dAcop}{\tAcop}{\sAcop}{\ssAcop}}\limits_{\mathclap{#1}}
不过那会让使用宽极限变得困难。
最后,我提到还有另一种定义所需宏的方法。如果你自己管理页面,可以在MathJax的配置对象中定义这些宏:
<script defer src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-chtml.js"></script>
<script>
MathJax = {
tex: {
macros: {
ACOP: ['\\mmlToken{mglyph}[src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0xMCAzNSAxNzMgMjE2IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOiAyMHB4Ij4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyA4IDkzLjU2MjUsIDE0OSA5OC41NjI1LCAxNDcgMjUwLjU2MjUiLz4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyAwIDQyLjU2MjUsIDEwMiAyMi41NjI1LCAxMzkgNjMuNTYyNSIvPgo8L3N2Zz4=" width="#1px" height="#2px" valign="#3px"]{}', 3],
dAcop: '\\ACOP{24.3}{30.5}{-8}',
tAcop: '\\ACOP{17.3}{21.6}{-4}',
sAcop: '\\ACOP{12.2}{15.3}{-2.8}',
ssAcop: '\\ACOP{8.7}{10.8}{-2}',
Acop: '\\mathop{\\mathchoice{\\dAcop}{\\tAcop}{\\sAcop}{\\ssAcop}}\\limits_',
}
}
};
</script>
$${\displaystyle\Acop{x\to u}f(x)}+{\textstyle\Acop{x\to u}f(x)}+{\scriptstyle\Acop{x\to u}f(x)}+{\scriptscriptstyle\Acop{x\to u}f(x)}$$
如果你想在 \Acop 的定义中包含 \mathclap,那么使用
<script defer src="https://cdn.jsdelivr.net/npm/mathjax@4/tex-chtml.js"></script>
<script>
MathJax = {
loader: {load: ['[tex]/mathtools']},
tex: {
packages: {'[+]': ['mathtools']},
macros: {
ACOP: ['\\mmlToken{mglyph}[src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0xMCAzNSAxNzMgMjE2IiBzdHJva2U9ImJsYWNrIiBmaWxsPSJub25lIiBzdHlsZT0ic3Ryb2tlLXdpZHRoOiAyMHB4Ij4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyA4IDkzLjU2MjUsIDE0OSA5OC41NjI1LCAxNDcgMjUwLjU2MjUiLz4KICA8cGF0aCBkPSJNIDUgMjQ5LjU2MjUgQyAwIDQyLjU2MjUsIDEwMiAyMi41NjI1LCAxMzkgNjMuNTYyNSIvPgo8L3N2Zz4=" width="#1px" height="#2px" valign="#3px"]{}', 3],
dAcop: '\\ACOP{24.3}{30.5}{-8}',
tAcop: '\\ACOP{17.3}{21.6}{-4}',
sAcop: '\\ACOP{12.2}{15.3}{-2.8}',
ssAcop: '\\ACOP{8.7}{10.8}{-2}',
Acop: ['\\mathop{\\mathchoice{\\dAcop}{\\tAcop}{\\sAcop}{\\ssAcop}}\\limits_{\\mathclap{#1}}', 1],
}
}
};
</script>
$${\displaystyle\Acop{x\to u}f(x)}+{\textstyle\Acop{x\to u}f(x)}+{\scriptstyle\Acop{x\to u}f(x)}+{\scriptscriptstyle\Acop{x\to u}f(x)}$$
我觉得这应该就covers你所需要的一切。




