Latex 公式在线可视化编辑器

寻觅#

最近的一个demo需要用到Latex公式在线编辑器,从搜索引擎一般会得到类似http://latex.codecogs.com/eqneditor/editor.php的结果,这个编辑器的问题在于使用成本高,并且界面不美观。
codecogs

继续探寻,发现了wiris Editor
wiris Editor

支持mathml和latex:
wiris Editor

那么就它了!

选型#

首先,我们不会直接使用这个编辑器,只是在编辑公式的时候才使用,所以要选择合适的版本。
wiris Editor
以前用过CKEditor,所以就这它了!选用java版本
我们的数据已经是latex的,在wiris 编辑器显示需要注意latex需要用两个$$包括起来
例如:

Copy
The history of $$\sqrt(2)$$.

但是CK版本的wiris对latex的支持是非可视化支持,在编辑器里输入latex还是显示为latex:
enter description here

将焦点移动到$$内部,再点击按钮出现wiris的公式编辑器:

enter description here
这种设计适合对latex熟悉的人员,可以裸写latex,同时对不熟悉的人来说,可以使用公式编辑器。但是,这样不直观啊!你让不会latex的看到的就一堆符号!

适配#

简单试用可以发现,如果直接使用公式编辑器插入公式,是直观显示的:
enter description here

可以看到保存的时候,mathml是:

Copy
<math class="wrs_chemistry" xmlns="http://www.w3.org/1998/Math/MathML"> <msqrt> <mn>2</mn> </msqrt> </math>

那么在latex输入情况下呢:

Copy
<math xmlns="http://www.w3.org/1998/Math/MathML"> <semantics> <mrow> <msqrt><mo>(</mo></msqrt><mn>2</mn><mo>)</mo> </mrow> <annotation encoding="LaTeX">\sqrt(2)</annotation> </semantics> </math>

原来问题在这里,正是mathML的区别导致处理的区别。也就是说一开始就生成不带LaTeX的mathML,然后再放入编辑器。简单查看代码,可以知道先调用wrs_endParse,再wrs_initParse就可以了。

Copy
CKEDITOR.on("instanceReady", function(event) { CKEDITOR.instances.example.focus(); var mathxml = wrs_endParse("已知向量$$\\vec{a}=(\\sqrt{3},2)$$,$$\\vec{b}=(0,-2)$$,向量$$\\vec{c}=(k,\\sqrt{2})$$.$$\\vec{a}-1\\vec{b}$$与$$\\vec{d}$$共线,$$k=$$__."); CKEDITOR.instances.example.setData(wrs_initParse(mathxml)); // 等待完成 window.setTimeout(updateFunction,0); });

Latex

直观显示没问题了,但是mathml如何再转换成Latex呢?core.js里的wrs_parseMathmlToLatex函数是直接从mathml里将。。。里的内容提取出来:

Copy
function wrs_parseMathmlToLatex(content, characters){ .... var openTarget = characters.tagOpener + 'annotation encoding=' + characters.doubleQuote + 'LaTeX' + characters.doubleQuote + characters.tagCloser; mathml = content.substring(start, end); startAnnotation = mathml.indexOf(openTarget); // 包含 encoding=latex,保留latex if (startAnnotation != -1){ startAnnotation += openTarget.length; closeAnnotation = mathml.indexOf(closeTarget); var latex = mathml.substring(startAnnotation, closeAnnotation); if (characters == _wrs_safeXmlCharacters) { latex = wrs_mathmlDecode(latex); } output += '$$' + latex + '$$'; // Populate latex into cache. wrs_populateLatexCache(latex, mathml); }else{ output += mathml; } ...... }

但是现在的mathml不包含这个信息,如何处理?查看官方文档,发现有一个mathml2latex的服务,查看官方给的java demo里servlet并不包含这个服务,但是jar包里存在代码,于是自己封装一个servlet即可:

Copy
public class ServiceServlet extends com.wiris.plugin.dispatchers.MainServlet { @Override public void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws ServletException, IOException { PluginBuilder pb = newPluginBuilder(request); String origin = request.getHeader("origin"); HttpResponse res = new HttpResponse(response); pb.addCorsHeaders(res, origin); String pathInfo = request.getServletPath(); if (pathInfo.equals("/mathml2latex")) { response.setContentType("text/plain; charset=utf-8"); ParamsProvider provider = pb.getCustomParamsProvider(); String mml = provider.getParameter("mml", (String)null); String r = pb.newTextService().mathml2latex(mml); PrintWriter out = response.getWriter(); out.print(r); out.close(); }

js里,调用这个服务:

Copy
var _wrs_mathmlCache = {}; function wrs_getLatexFromMathML(mml) { if (_wrs_mathmlCache.hasOwnProperty(mml)) { return _wrs_mathmlCache[mml]; } var data = { 'service': 'mathml2latex', 'mml': mml }; var latex = wrs_getContent(_wrs_conf_servicePath, data); // Populate LatexCache. if (!_wrs_mathmlCache.hasOwnProperty(mml)) { _wrs_mathmlCache[mml] = latex; } return latex.split("\r").join('').split("\n").join(' '); }

wrs_getLatexFromMathML只能将一个mathml转换为latex,对于编辑器里的内容来说,需要将mathML抽取出来逐一转换:

Copy
function wrs_parseRawMathmlToLatex(content, characters){ var output = ''; var mathTagBegin = characters.tagOpener + 'math'; var mathTagEnd = characters.tagOpener + '/math' + characters.tagCloser; var start = content.indexOf(mathTagBegin); var end = 0; var mathml, startAnnotation, closeAnnotation; while (start != -1) { output += content.substring(end, start); end = content.indexOf(mathTagEnd, start); if (end == -1) { end = content.length - 1; } else { end += mathTagEnd.length; } mathml = content.substring(start, end); output += wrs_getLatexFromMathML(mathml); start = content.indexOf(mathTagBegin, end); } output += content.substring(end, content.length); return output; } function wrs_getLatex(code) { return wrs_parseRawMathmlToLatex(code, _wrs_xmlCharacters); }

末了,为了方便获取,可以将latex放到_current_latex变量里:

Copy
// 获取数据 editor.on('getData', function (e) { e.data.dataValue = wrs_endParse(e.data.dataValue || ""); _current_latex = wrs_getLatex(e.data.dataValue || ""); });

再简单修改下网页,显示latex:
enter description here

收官!

关注作者

欢迎关注作者微信公众号, 一起交流软件开发:欢迎关注作者微信公众号

posted @   JadePeng  阅读(33737)  评论(4编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示
CONTENTS