PAYATHON 2026

MathJax 3 中 MathJax 未定义或 tex2svg 不可用怎么办?

数据小陈

原因

tex-svg.js 使用 async 加载时,浏览器不会等它执行完再运行页面中的其他 JavaScript。此时调用 MathJax.tex2svg(tex),可能因 MathJax 尚未加载而报错 MathJax is not defined。如果加载的组件不包含 SVG 输出功能,或者在 MathJax 启动完成前调用,也可能出现 MathJax.tex2svg 不可用的情况。

原代码还有一个问题:base64 是字符串,不能调用 addEventListener,也不能传给 ctx.drawImage()。应先创建 Image 对象并加载 SVG,再将图像绘制到 canvas 上。

解决方法

移除 MathJax 脚本上的 async,让浏览器按页面顺序加载脚本。然后等待 MathJax 的启动 Promise 完成,再转换公式。SVG 加载到 Image 后,就可以绘制到 canvas:

<canvas id="surface">Canvas not Supported</canvas>

<script
  id="MathJax-script"
  src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-svg.js">
</script>
<script>
(async () => {
  await MathJax.startup.promise;

  const canvas = document.getElementById("surface");
  const ctx = canvas.getContext("2d");
  canvas.width = 202;

  const tex = "F=ma";
  const container = MathJax.tex2svg(tex);
  const svg = container.querySelector("svg");

  if (!svg) {
    throw new Error("MathJax 没有生成 SVG");
  }

  const svgText = new XMLSerializer().serializeToString(svg);
  const svgUrl = URL.createObjectURL(
    new Blob([svgText], { type: "image/svg+xml;charset=utf-8" })
  );

  const image = new Image();
  image.onload = () => {
    ctx.drawImage(image, 105, 15, 102.3, 23.93);
    URL.revokeObjectURL(svgUrl);
  };
  image.onerror = () => {
    URL.revokeObjectURL(svgUrl);
    console.error("SVG 图片加载失败");
  };
  image.src = svgUrl;
})().catch(console.error);
</script>

这里的 tex-svg.js 提供 tex2svg。await MathJax.startup.promise 会等 MathJax 启动完成后再调用它。代码使用 URL.createObjectURL() 创建临时的 SVG 图片地址,并在图片加载后将其绘制到 canvas。

注意事项

  • 如果必须保留 async,应等 MathJax 脚本加载并完成启动后,再执行转换逻辑。不要假设后续代码运行时全局对象已经就绪。
  • ctx.drawImage() 接收已加载的图像等绘图源,不能直接接收 Base64 字符串。也可以将 SVG 编码为 data URL 后赋给 image.src,但仍要等待 image.onload。
  • 页面里有多个公式时,记得在对应图片加载后及时释放重复生成的对象 URL。

备注:内容仅供参考。