likes
comments
collection
share

❤️如何在前端渲染数学公式?❤️

作者站长头像
站长
· 阅读数 58

前言

最近遇到一个需求,需要在网页上展示如下数学公式

❤️如何在前端渲染数学公式?❤️

经过一番查阅,思路如下:

  1. 通过ocr将对应的公式图片识别成latex公式
  2. 使用MathJax去渲染对应的latex公式

思路明确,直接开干

❤️如何在前端渲染数学公式?❤️

相关概念

什么是Latex?

latex是一种标记语言,我们不需要了解太多,只需要知道,它可以排版数学公式,可以把数学公式转化为latex语法.

通过一些开源的js库,就可以将复杂数学公式渲染到前端页面上

MathJax

MathJax 是一个开源的 JavaScript 库,可以解析LaTeXMathML AsciiMath 格式的数学表达式

有了上面两大神器,我们的需求就很好做了

OCR工具

因为我的公式需求不多,所以直接手动用OCR工具去转换了

相关依赖库

  • MathJax

    这个库用npm去直接安装会有一些奇奇怪怪的问题,最终还是采用cdn引入的方式.

  • cdn地址:cdn.mathjax.org/mathjax/lat…

直接引入到index.html里面就可以

如果怕cdn不稳定,也可以直接下载下来,保存到public文件夹里面再引入

❤️如何在前端渲染数学公式?❤️

想要判断是否引入成功的话,只需要在控制台打印window.MathJax有挂载上去就是引入了

使用方式

初始化配置

在使用之前需要初始化MathJax的配置

window.MathJax.Hub.Config({
    extensions: ['tex2jax.js'],
    jax: ['input/TeX', 'output/HTML-CSS'],
    showMathMenu: false,
    tex2jax: {
      inlineMath: [
        ['$', '$'],
        ['\\(', '\\)'],
      ],
      displayMath: [
        ['$$', '$$'],
        ['\\[', '\\]'],
      ],
      processEscapes: true,
    },
    'HTML-CSS': { availableFonts: ['TeX'] },
  })
  1. extensions: 数组,指定MathJax需要加载的扩展文件。这里加载的是tex2jax.js,这是一个将TeX格式转换为MathJax能够识别的格式的扩展。
  2. jax: 数组,指定MathJax处理数学公式的输入和输出格式。input/TeX表示输入格式是TeX,output/HTML-CSS表示输出格式是HTML-CSS,即MathJax将使用CSS来渲染数学公式。
  3. showMathMenu: 布尔值,设置是否显示数学公式的上下文菜单。这里设置为false,即不显示。
  4. tex2jax: 对象,包含了tex2jax扩展的配置项:
    • inlineMath: 数组,定义了行内数学公式的界定符。这里定义了两种界定符:美元符号$...$和反斜杠加括号\(... \)
    • displayMath: 数组,定义了显示数学公式(即独占一行的数学公式)的界定符。这里定义了两种界定符:双美元符号$$...$$和反斜杠加双括号\[...\]
    • processEscapes: 布尔值,设置是否处理转义字符。如果为true,MathJax会处理如\$等特殊字符的转义。
  5. 'HTML-CSS': 对象,配置HTML-CSS输出的一些选项。availableFonts数组指定了可用的字体。这里指定为['TeX'],即使用TeX字体。

更详细的配置可以去官网上面看:配置 MathJax — MathJax 3.2 文档

或者官方的github也会有一些例子

渲染公式

在一开始加载这个mathjax的时候他就会对网页上的公式进行一次渲染.但是我们在大多数情况下是需要动态渲染的,比如我只需要某一块内容渲染,或者某一时刻渲染.

这时候就需要用到他的api

  • window.MathJax.Hub.Queue

这个方法可以排队执行一些操作,比如排版加载JS文件动态配置,我们只需要第一个排版.

全局渲染

window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub])
  • Typeset: 重新排版文档或指定的元素中的数学公式。

  • window.MathJax.Hub :传不传都可以,默认会用这个作为上下文

❤️如何在前端渲染数学公式?❤️

局部渲染

  window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, leftLatex.value])

前面的参数不变,最后第三个参数传要渲染的那个DOM的参数

❤️如何在前端渲染数学公式?❤️

完整代码

依赖引入

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/icon.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>MathJax</title>
    <style>
      #app,
      html,
      body {
        height: 100%;
        width: 100%;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <div id="app"></div>
    <script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <script>
      import('/src/main.ts')
    </script>
  </body>
</html>

实现代码

<!-- 数学公式渲染需求 -->
<template>
  <article class="latex-container">
    <t-row>
      <section ref="leftLatex" class="latex-container__show">
        {{ latexStr }}
      </section>
      <section style="margin-left: 24px" class="latex-container__show">
        {{ latexStr2 }}
      </section>
    </t-row>
    <section style="display: flex; gap: 12px">
      <t-button @click="startRenderingLeft">只渲染左边</t-button>
      <t-button @click="startRendering">全局渲染</t-button>
    </section>
  </article>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
const latexStr = ref<string>(`
对谷类、薯类、豆类、油料、草药、饲料、果蔬、茶菌、瓜果等农产品的实物量进行核算。
  $$E_{pro1}=\\Sigma_{i=1}^nEPA_i$$
  式中:
  $$E_{pro1}——$$农产品总产量(t/a);
  $$EPA_i——第i$$种产品的产量(t/a),
  谷类、薯类、豆类、油料、草药、饲料数据来自国家统计局xx调查队;果蔬、茶菌、瓜果等数据来自市统计局。`)
const latexStr2 = ref<string>('$$\\int_a^bf(x)dx=c$$')
const leftLatex = ref(null)
const startRendering = () => {
  window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub])
}
const startRenderingLeft = () => {
  window.MathJax.Hub.Queue(['Typeset', window.MathJax.Hub, leftLatex.value])
}
onMounted(() => {
  if (!window.MathJax) return console.log('MathJax不存在')
  window.MathJax.Hub.Config({
    extensions: ['tex2jax.js'],
    jax: ['input/TeX', 'output/HTML-CSS'],
    showMathMenu: false,
    tex2jax: {
      inlineMath: [
        ['$', '$'],
        ['\\(', '\\)'],
      ],
      displayMath: [
        ['$$', '$$'],
        ['\\[', '\\]'],
      ],
      processEscapes: true,
    },
    'HTML-CSS': { availableFonts: ['TeX'] },
  })
})
</script>

<style lang="scss" scoped>
.latex-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  &__show {
    width: 500px;
    height: 600px;
    box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;
    background-color: #fff;
    border-radius: 8px;
    padding: 24px;
  }
}
</style>

遇到的问题

如果出现,有些符号无法渲染,需要检查一下是不是需要转义

const latexStr2 = ref<string>('$$\\int_a^bf(x)dx=c$$')

比如这个公式,如果上面的公式变成

const latexStr2 = ref<string>('$$\int_a^bf(x)dx=c$$')

就会导致

❤️如何在前端渲染数学公式?❤️这个符号渲染不出来

转载自:https://juejin.cn/post/7396118693757927450
评论
请登录