渲染数学公式,带有自定义数据

366 阅读2分钟

需求描述

公式内容包含系统数据,人工数据,数字,百分比,四则运算,自定义函数,将扁平的公式展示渲染为更容易阅读的公式展示。例如:
Fn1[Fn2[(系统数据1 - 3)* (人工数据1 + 12%)] ]/ 系统数据2

image.png

思路

使用了两个库,mathjs,katex

mathjs 获取Tex格式的字符串

  • parse() 首先使用这个函数获取公式对应的parser对象
  • toTex() 获取Tex
 const parser = math.parse(_str); // 获取实例
 let latex = parser.toTex(); //获取Tex

katex 获取公式渲染的html

katex.renderToString(latex, {
    throwOnError: false,
    displayMode: false, //行内或者块展示
})

难点实现

具体实现遇到的问题是第一步调用parse()方法时,需要校验公式是否成立,原始公式中的中文字符,自定义函数名,百分号都需要预处理,才可以通过验证。
参考文档:mathjs定制
针对以上的每种情况进行对应的处理。

  • 百分号,默认行为会转为分数,为了保留百分号显示,设置mathjs的自定义字符,替换原公式中的百分号为可通过校验的特殊字符。

// 允许指定默认不支持的字符通过校验
math.parse.isAlpha = function (c, cPrev, cNext) {
  return (
    isAlphaOriginal(c, cPrev, cNext) || c === "\u260E" 
  );
};
const _str = str.replace(/%/g, "☎")
  • 系统数据,人工数据,可能的值包含任意字符,甚至有可能包含运算符号,因此在使用parse()方法时需要先进行替换为另一个特殊字符,方法同上,并将原始值保存到数组中,后续再一一还原。
const customDataList =  [data1,data2,data3];
str.replace(customDataRegx, "★")
  • 自定义函数,因为需要保留原始公式中的函数括号[],如果只将公式名称替换为特殊字符,中括号会被去掉。所以结合使用了一个特殊操作符./,起到经过parse()后保留[]
str.replace(functionNameRegx, "✓./")

经过以上预处理,原始公式会变成✓./[✓./[(★ - 3)* (★ + 12☎)]] / ★,终于可以传入parse()了。
得到parser实例,接着调用parser.toTex()获取Tex字符串。此时我们已经拿到了可以被KateX渲染的数据格式了,接下来要做的就是一一还原被替换的内容。

customDataList.forEach((text) => {
  latex = latex.replace("★", `${text}`);
});
functionNameMatches.forEach((text) => {
    latex = latex.replace("✓.:", `${text}`); 
});

需要注意的一点,%较为特殊,需要在KateX渲染后统一替换,否则还是会改变。

let res = katex.renderToString(latex, {
      throwOnError: false,
      displayMode: false,
});
res = res.replace(/☎/g, "%");
  • 一点优化
    中文汉字在KateX渲染后会显示较大,可以设置class,在css中设置字号
 katex
      .renderToString(_str, {
        throwOnError: false,
        displayMode: false, //行内或者块展示
      })
      .replace(
        /[\u4e00-\u9fff]/g,
        (match) => `<span class="chinese-char">${match}</span>`
      );
.katex .chinese-char {
    font-size: 0.9em;
  }