如何在我的网站上通过MathJax插入一个SVG字符?

前端开发 2026-07-10

我实现了一个使用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}$$ 来得到

带有上下极限的 X

那些只是普通的LaTeX命令,因此与它们应用于字符还是图像无关。这也是为什么 @herrstrietzel的建议是正确的,因为图像是唯一需要你单独处理的部分;极限的位置放置是标准的LaTeX。

据此,你可以把他链接的答案和像 \mathop 之类的内容结合起来,以实现你想要的效果。我建议使用 \mmlToken 的做法,因为它很直观。请注意,它所创建的 mglyph 的边界框将等同于该SVG图像在其 viewBox 属性中给出的边界框。

不过,你贴的图像在 viewBox 这一点上有些问题。框的高度和深度过大(上方和下方有额外空白),宽度又不足(图像被裁剪),如下所示,我在这里给图片添加了红色背景以便看到它的实际范围:

带有错误边界框的 SVG(红色背景显示)

按原样使用该SVG会导致极限与字形之间的距离过大,符号在左右会被裁剪。

将viewBox调整为 -10 35 173 216 将得到更好的结果:

带有更好边界框的 SVG

使用那个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 文件。你需要根据所使用的字体大小调整 heightwidthvalign 属性。我选择了一个便于从 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) 所示。

在 f(x) 之前减少空间的 SVG

由于回退空格的大小取决于实际的下方极限和排版风格,因此这个空间不能作为宏的一部分,必须手动插入。或者,你也可以加载 mathtools 包并使用它的 \matclap{} 宏来隐藏极限的大小(不过如果使用极宽的极限,可能会有问题)。例如 \Acop{\mathclap{x\to u}}f(x) 会生成

在极限周围使用 \mathclap

请注意,这样会同时去掉左侧和右侧的空隙,可能并不合适。可以通过将 \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你所需要的一切。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章