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需要用兩個$$包括起來
例如:

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

但是CK版本的wiris對latex的支持是非可視化支持,在編輯器里輸入latex還是顯示為latex:
enter description here

將焦點移動到$$內部,再點擊按鈕出現wiris的公式編輯器:

enter description here
這種設計適合對latex熟悉的人員,可以裸寫latex,同時對不熟悉的人來說,可以使用公式編輯器。但是,這樣不直觀啊!你讓不會latex的看到的就一堆符號!

適配

簡單試用可以發現,如果直接使用公式編輯器插入公式,是直觀顯示的:
enter description here

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

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

那么在latex輸入情況下呢:

<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就可以了。

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里將 。。。 里的內容提取出來:

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即可:

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里,調用這個服務:

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抽取出來逐一轉換:

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變量里:

	// 獲取數據
	editor.on('getData', function (e) {
		e.data.dataValue = wrs_endParse(e.data.dataValue || "");
		_current_latex = wrs_getLatex(e.data.dataValue || "");
	});

再簡單修改下網頁,顯示latex:
enter description here

收官!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM