❤️如何在前端渲染数学公式?❤️
前言
最近遇到一个需求,需要在网页上展示如下数学公式
经过一番查阅,思路如下:
- 通过
ocr
将对应的公式图片识别成latex
公式 - 使用
MathJax
去渲染对应的latex
公式
思路明确,直接开干
相关概念
什么是Latex?
latex
是一种标记语言,我们不需要了解太多,只需要知道,它可以排版数学公式,可以把数学公式转化为latex
语法.
通过一些开源的js
库,就可以将复杂数学公式渲染到前端页面上
MathJax
MathJax
是一个开源的 JavaScript
库,可以解析LaTeX
、MathML
和 AsciiMath
格式的数学表达式
有了上面两大神器,我们的需求就很好做了
OCR工具
因为我的公式需求不多,所以直接手动用OCR工具去转换了
- 公式识别工具:公式识别 (simpletex.cn)
相关依赖库
-
MathJax
这个库用
npm
去直接安装会有一些奇奇怪怪的问题,最终还是采用cdn
引入的方式.
直接引入到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'] },
})
extensions
: 数组,指定MathJax需要加载的扩展文件。这里加载的是tex2jax.js
,这是一个将TeX格式转换为MathJax能够识别的格式的扩展。jax
: 数组,指定MathJax处理数学公式的输入和输出格式。input/TeX
表示输入格式是TeX,output/HTML-CSS
表示输出格式是HTML-CSS,即MathJax将使用CSS来渲染数学公式。showMathMenu
: 布尔值,设置是否显示数学公式的上下文菜单。这里设置为false
,即不显示。tex2jax
: 对象,包含了tex2jax
扩展的配置项:inlineMath
: 数组,定义了行内数学公式的界定符。这里定义了两种界定符:美元符号$...$
和反斜杠加括号\(... \)
。displayMath
: 数组,定义了显示数学公式(即独占一行的数学公式)的界定符。这里定义了两种界定符:双美元符号$$...$$
和反斜杠加双括号\[...\]
。processEscapes
: 布尔值,设置是否处理转义字符。如果为true
,MathJax会处理如\
和$
等特殊字符的转义。
'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