Mathjax is an open source javascript display engine for latex, MathML, and Ascimath notation. Version 3.0 of MathJax is a complete rewrite of MathJax, enabling componentization and customization for different needs. Usage and configuration are very different from the MathJAX2 version, so be aware of the version.
Recently, when refactoring a project, a requirement was added to support latex mathematical formula rendering and editing. After some research and comparison, there are two browsers with good compatibility, namely KateX and MathJax.
Performance Comparison Screenshot
MathJax3
MathJax2.7
KaTex
As you can see from the comparison, Both MathJax versions 2 and 3 use Tex-CHTML, but the performance gap is quite large. The rendering performance of Katex will be a little better than MathJax3, but the rendering performance of complex formulas will not be as good as MathJax, and the actual use of Katex will not make much difference. MathJax3 was chosen, largely due to the fact that it was already in use in a sister department with project dependencies.
Use in Vue
General contact with some new knowledge points, the author will first try to learn from the use of experience, github look at open source projects.This may not be very kind to JustForuse, but thank you for the idea. So before I start, it should be emphasized that all open source projects and authors’ efforts and achievements should be respected. The rest of the article is just a statement of what I saw and why I made the wheel.
The use of the vue – mathjaxMain code:
export default {
/ /...
watch: {
formula () {
this.renderMathJax()
}
},
mounted () {
this.renderMathJax()
},
methods: {
renderContent () {
if (this.safe) {
this.$refs.mathJaxEl.textContent = this.formula
} else {
this.$refs.mathJaxEl.innerHTML = this.formula
}
},
renderMathJax () {
this.renderContent()
if (window.MathJax) {
window.MathJax.Hub.Config({
// ...
})
window.MathJax.Hub.Queue([
'Typeset'.// ...])}}}}Copy the code
After looking at the whole project, several questions arise 🤔️
- What if I want to use it on demand?
- How much overhead does mathJax default to rendering the entire Document. body once it’s loaded? Will it lead to unnecessary errors in rendering?
- Every time the component rendering execution window. It is MathJax. Hub. The Config?
- When there are many formulas in a text, it is too cumbersome and ugly to transform each into a component.
- Performance gap between MathJAX2 and version 3.
In general, this project does not meet my needs, especially for large pages. Questions 2 and 3 will definitely bring performance problems. Personally, I guess that the starting point of question 3 is to make each component support different configurations, but the key point is that the author did not deal with the code well, burying performance problems.
Start building the wheel
According to the need to introduce
// Mathjax to be injected into the document head
export function injectMathJax() {
if (!window.MathJax) {
const script = document.createElement('script')
script.src =
'https://cdn.bootcdn.net/ajax/libs/mathjax/3.2.0/es5/tex-chtml.js'
script.async = true
document.head.appendChild(script)
}
}
Copy the code
Load and configure MathJax Refer to: MathJax
/** * Initialize MathJax *@param Callback Mathjax callback */ after loading
export function initMathJax(callback) {
injectMathJax()
window.MathJax = {
tex: {
// The inline formula flag
inlineMath: [['$'.'$']],
// Block level formula flag
displayMath: [['$$'.'$$']],
// The following two main render support some formulas, you can understand
processEnvironments: true.processRefs: true,},options: {
// Skip rendered tags
skipHtmlTags: ['noscript'.'style'.'textarea'.'pre'.'code']./ / skip mathjax processing elements in the name of the class, any element specifies a class tex2jax_ignore will be skipped, more tired = class name 'class1 | class2'
ignoreHtmlClass: 'tex2jax_ignore',},startup: {
// Callback when MathJax is loaded and initialized
pageReady: () = > {
callback && callback()
},
},
svg: {
fontCache: 'global',}}}Copy the code
Note: The pageReady function is best configured by itself for performance reasons. If it is not configured, the default automatic rendering function will be executed and the entire document.body will be rendered, resulting in unnecessary performance overhead (problem 2).
Render a Dom element or collection manually without transforming it into a component (Q4)
/** * The manual render formula returns Promise *@param El The DOM element or collection to render *@returns Promise* /
export function renderByMathjax(el) {
// Version will not be injected until mathJax is initialized
if (!window.MathJax.version) {
return
}
if (el && !Array.isArray(el)) {
el = [el]
}
return new Promise((resolve, reject) = > {
window.MathJax.typesetPromise(el)
.then(() = > {
resolve(void 0)
})
.catch((err) = > reject(err))
})
}
Copy the code
Note: these are only used to fit inside the vue, preach and can be converted into a selector, and then use the document renderByMathjax it. QuerySelectorAll, do not need to judge array, calls the concise convenient also.
Common usage
function onMathJaxReady() {
// Render according to id
const el = document.getElementById('elementId')
renderByMathjax(el)
}
initMathJax(onMathJaxReady)
// Render according to class
renderByMathjax(document.getElementByClassNAme('class1'))
Copy the code
So far, support has been introduced in various front-end projects, some of which may need to be modified, such as the introduction of HTML does not support ES6 syntax.
Vue components (no problem 3)
<template>
<span></span>
</template>
<script>
import { renderByMathjax } from '.. /utils'
export default {
name: 'MathJax'.props: {
latex: { / / latex formula
type: String.default: ' ',},block: { // Use block level formulas
type: Boolean.default: false,}},watch: {
latex() {
this.renderMathJax()
},
},
mounted() {
this.renderMathJax()
},
methods: {
renderMathJax() {
this.$el.innerText = this.block
? ` $$The ${this.latex} $$`
: ` $The ${this.latex} $`
renderByMathjax(this.$el)
},
},
}
</script>
Copy the code
Based on the example code above, THE author released the MathJAX-Vue and MathJAX-vue3 plug-ins.
The usage mathjax – vue
The installation
// npm
npm i --save mathjax-vue
// yarn
yarn add mathjax-vue
// change mathJAX-vue to mathJAX-vue3
Copy the code
Global registration
import MathJax, { initMathJax, renderByMathjax } from 'mathjax-vue'
function onMathJaxReady() {
const el = document.getElementById('elementId')
renderByMathjax(el)
}
initMathJax({}, onMathJaxReady)
// vue 2
Vue.use(MathJax)
// vue3
createApp(App).use(MathJax)
Copy the code
Private components
import { MathJax } from 'mathjax-vue'
// initMathJax must be executed first
export default{...components: {
MathJax,
},
...
}
Copy the code
Do not want to insert components
// initMathJax must be executed first
import { renderByMathjax } from 'mathjax-vue'
renderByMathjax(document.getElementById('id1'))
Copy the code
Finally, as an aside, the author is preparing to open source a mathematical formula editor recently. The main thing is that the current open source mathematical formula editor cannot meet business needs, so if you need it, you can pay attention to it. If this article has helped you, give it a thumbs up
CodeSandbox Project repository: Github