Подтвердить что ты не робот

Показать симпатичную математическую формулу в Android

Грустно видеть, что науке и математике никогда не уделяется достаточного внимания на платформе Android. Возможно, это легкая проблема, но я полный чувак в javascript, поэтому я изо всех сил пытаюсь понять, как решить эту проблему.

То, что я хочу сделать, просто: Мне просто нужно использовать математическое уравнение рендеринга. Это может быть MathJax или JqMath или что-то маленькое и быстрое. Если мне нужно сделать это в веб-просмотре, как я могу показать простой текст в абзаце и форматированном уравнении в пределах одного веб-представления?

(кто-то выходит с другими методами, которые, очевидно, работают, я также рассмотрю это как решение)

ЧТО Я СДЕЛАЛ СКАЗАТЬ:

Я начал с использования MathJax, чтобы поместить формулу в webview (я не знаю, есть ли какой-нибудь успешный случай использования jqMath? Кто-нибудь хочет поделиться своим опытом?) Я могу воспроизвести все функциональные возможности, аналогичные функциям автономного Приложение MathJax. В этом приложении пользовательские ключи в строке в поле EditText и MathJax будут отображать формулу в Latex после нажатия пользователем кнопки для подтверждения.

Мне не нужен пользователь для подтверждения. Я думал, что это должно быть проще, потому что нет взаимодействия с пользователем, но так или иначе уравнение никогда не отображается. Я знаю, что мне что-то не хватает, потому что коды в автономном MathJax предназначены для ввода пользователем. Какую часть кода я должен изменить, чтобы напрямую вывести уравнение из строки, скажем, \sqrt {b ^ 2-4ac}? Вот начальный заголовок для webview:

WebView w = (WebView) findViewById(R.id.webview);
w.getSettings().setJavaScriptEnabled(true);
w.getSettings().setBuiltInZoomControls(true);
w.loadDataWithBaseURL("http://bar", "<script type='text/x-mathjax-config'>"
                        +"MathJax.Hub.Config({ showMathMenu: false, "
                        +"jax: ['input/TeX','output/HTML-CSS'], "
                        +"extensions: ['tex2jax.js'], " 
                        +"TeX: { extensions: ['AMSmath.js','AMSsymbols.js',"
                        +"'noErrors.js','noUndefined.js'] } "
                        +"});</script>"
                        +"<script type='text/javascript' "
                        +"src='file:///android_asset/MathJax/MathJax.js'"
                        +"></script><span id='math'></span>","text/html","utf-8","");

И вот как загружается исходный веб-просмотр, когда пользователь нажимает кнопку после ввода в edittext:

WebView w = (WebView) findViewById(R.id.webview);
EditText e = (EditText) findViewById(R.id.edit);
w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                  +doubleEscapeTeX(e.getText().toString())
                  +"\\\\]';");
w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");

private static String doubleEscapeTeX(String s) {
    String t="";
    for (int i=0; i < s.length(); i++) {
        if (s.charAt(i) == '\'') t += '\\';
        if (s.charAt(i) != '\n') t += s.charAt(i);
        if (s.charAt(i) == '\\') t += "\\";
    }
    return t;
}

Я попытался заменить жестко запрограммированной строкой

w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                  +doubleEscapeTeX("sample string")
                  +"\\\\]';");

но он не работает, текст "sample string" даже не появится в веб-просмотре.

[РЕШЕНИЕ] см. "Ответ на вопрос"

Чтобы подробно описать его ответ, это пример того, как установить предложение в виде простого текста, а затем отобразить форматированное уравнение в форме отображения (все в одном веб-просмотре):

Замените последнюю строку выше на

+"></script><span id='math'></span>","text/html","utf-8","");

с

+"></script><span id='text'>This is plain text.</span> <span id='math'></span>", "text/html", "utf-8", "");

Затем вызовите

w.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
    super.onPageFinished(view, url);
        if (!url.startsWith("http://bar"))
            return;
        w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                    +doubleEscapeTeX("\\sqrt{b^2-4ac}") + "\\\\]';");
        w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
    }
});

Это установит строку. Это обычный текст в обычном шрифте, а в центре - формула foo+bar в веб-просмотре.

EDIT (проблема с Android 4.4)

Начиная с Android KitKat, вы должны заменить все строки loadUrl(...) на evaluateJavascript(...). Но это доступно только для KitKat (API 19 или выше), поэтому вам сначала нужно выполнить проверку версии SDK. Например:

if (android.os.Build.VERSION.SDK_INT < 19) {
    w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
} else {
    w.evaluateJavascript("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);",null);
}

ОБНОВЛЕНИЕ (КАК MATHJAX 2.5)

Поскольку происходят изменения папок, предыдущий код не будет работать в последней версии MathJax. Кроме того, рекомендуемый способ минимизации размера локального MathJax теперь использует Grunt. Шаблон для уменьшения размера MathJax можно найти здесь.

Предполагая, что вы успешно уменьшили размер MathJax и предположили вывод HTML-CSS, вот простая версия, которая может загружать MathJax:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    final WebView w = (WebView) findViewById(R.id.webview);
    w.getSettings().setJavaScriptEnabled(true);
    w.getSettings().setBuiltInZoomControls(true);

    String Url = "</style>"
                 + "<script type='text/x-mathjax-config'>"
                 + "  MathJax.Hub.Config({" + "    showMathMenu: false,"
                 + "             jax: ['input/TeX','output/HTML-CSS', 'output/CommonHTML'],"
                 + "      extensions: ['tex2jax.js','MathMenu.js','MathZoom.js', 'CHTML-preview.js'],"
                 + "         tex2jax: { inlineMath: [ ['$','$'] ], processEscapes: true },"
                 + "             TeX: {" + "               extensions:['AMSmath.js','AMSsymbols.js',"
                 + "                           'noUndefined.js']" + "             }"
                 + "  });"
                 + "</script>"
                 + "<script type='text/javascript' src='file:///android_asset/MathJax/MathJax.js'>"
                 + "</script>"
                 + "<p style=\"line-height:1.5; padding: 16 16\" align=\"justify\">"
                 + "<span >";

    // Demo display equation
    url += "This is a display equation: $$P=\frac{F}{A}$$";

    url += "This is also an identical display equation with different format:\\[P=\\frac{F}{A}\\]";

    // equations aligned at equal sign
    url += "You can also put aligned equations just like Latex:";
    String align = "\\begin{aligned}"
                + "F\\; &= P \\times A \\\\ "
                + "&= 4000 \\times 0.2\\\\"
                + "&= 800\\; \\text{N}\\end{aligned}"; 
    url += align;

    url += "This is an inline equation \\sqrt{b^2-4ac}.";

    // Finally, must enclose the brackets
    url += "</span></p>";

    mWebView.loadDataWithBaseURL("http://bar", url, "text/html", "utf-8", "");
    mWebView.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (!url.startsWith("http://bar")) return;
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
                view.loadUrl(JAVASCRIPT);
            } else {
                view.evaluateJavascript(JAVASCRIPT, null);
            }
        }
    });
}

В отличие от ответа Джоса, нет необходимости отделять текстовые или математические типы, MathJax просто форматирует их соответственно.

Однако, похоже, что есть ошибка, что веб-просмотр в устройствах KitKat не может отображать заглавную букву "A". Любой, кто знает способ, может предложить обходной путь для этого.

4b9b3361

Ответ 1

Если я правильно понимаю вашу проблему, кажется, проблема связана с тем, что библиотека MathJax не завершила загрузку (из вызова loadDataWithBaseURL()), когда вы вызываете дополнительный loadUrl() для отображения формулы. Самое простое решение - дождаться обратного вызова onPageFinished(), чтобы выполнить вызов.

Например, следующий код, похоже, отлично работает на моем:

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    final WebView w = (WebView) findViewById(R.id.webview);
    w.getSettings().setJavaScriptEnabled(true);
    w.getSettings().setBuiltInZoomControls(true);
    w.loadDataWithBaseURL("http://bar", "<script type='text/x-mathjax-config'>" 
            + "MathJax.Hub.Config({ "
            + "showMathMenu: false, " 
            + "jax: ['input/TeX','output/HTML-CSS'], " 
            + "extensions: ['tex2jax.js'], "
            + "TeX: { extensions: ['AMSmath.js','AMSsymbols.js'," 
            + "'noErrors.js','noUndefined.js'] } "
            + "});</script>" 
            + "<script type='text/javascript' " 
            + "src='file:///android_asset/MathJax/MathJax.js'"
            + "></script><span id='math'></span>", "text/html", "utf-8", "");
    w.setWebViewClient(new WebViewClient() {
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (!url.startsWith("http://bar")) return;
            w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                    + doubleEscapeTeX("sample string") + "\\\\]';");
            w.loadUrl("javascript:MathJax.Hub.Queue(['Typeset',MathJax.Hub]);");
        }
    });
}

Обновить. Чтобы разместить дополнительный вывод в WebView, я бы предложил добавить элементы HTML к первоначальному вызову loadDataWithBaseURL(). Итак, для примера выше, вместо этой строки в конце:

            + "></script><span id='math'></span>", "text/html", "utf-8", "");

Мы можем сделать что-то вроде следующего:

            + "></script><span id='text'>Formula:</span>"
            + "<span id='math'></span>", "text/html", "utf-8", "");

Кроме того, если вам нужно впоследствии обновить эту часть, вы можете использовать тот же механизм, который мы использовали для части "math", например:

            w.loadUrl("javascript:document.getElementById('text').innerHTML='"
                    + newText + "';");

Вы также можете использовать другие элементы HTML (вместо <span>, которые мы используем выше), если вы хотите иметь специальный стиль/форматирование.

Ответ 2

Вместо того, чтобы использовать javascript и javascript-библиотеки для визуализации клиентской стороны LaTeX, почему бы не сделать следующее?

  • Напишите серверную функцию, которая принимает некоторую строку LaTeX и создает файл изображения. Вы можете сделать это с помощью стандартного инструмента командной строки LaTeX "из коробки". (Кажется, это то, что вы способны сделать, и что проблема заключается в том, чтобы сделать рендеринг на стороне клиента.)

  • Создайте конечную точку на своем веб-сайте/службе, которая выглядит следующим образом:
    GET /latex?f={image format}&s={latex string}

  • На ваших веб-страницах используйте простой тег HTML <img/>, чтобы отобразить ваш LaTeX. Например:
    <img src="/latex?f=jpeg&s=f%40x%41%61x%942"/>
    будет отображать уравнение f(x)=x^2 как JPEG.

  • (необязательно) Создайте простой кеш-сервер для пар (f,s), чтобы вы отображали только одну строку LaTeX по первому запросу, когда-либо сделанному для этой конкретной строки (любым клиентом). В качестве первого прототипа вы можете просто иметь каталог сервера, в котором у вас есть файлы с именем {hash(s)}.{f}, где hash - это просто хеш-функция, например SHA1.

Это избавляет вас от попыток заставить все работать на стороне клиента с помощью javascript. И, я бы поспорил (хотя некоторые могут не согласиться), что это намного чище. Все, что вы отправляете клиенту:

  • тег HTML <img/>
  • фактическое содержимое изображения, когда браузер разрешает атрибут src

Очень легкий и быстрый!

Ответ 3

Проблема "Capital A" - это ошибка Konwn MathJax в Android WebView. Вы можете заменить файлы шрифтов tweaked font files. Исправление будет работать при использовании вывода HTML-CSS с TeX-шрифтами. Помимо MathJax, вы можете попробовать KaTeX, который менее красив, но быстрее.

Собственно, я упаковал их оба в пользовательское представление Android, посмотрите MathView.

Ответ 4

Поздно вечеринке, но я думаю, что у меня есть лучшее решение, чем у Джо. Первоначальный вопрос:

как я могу показать простой текст в параграфе и форматированное уравнение внутри тот же веб-просмотр?

В исходном примере мы имели:

w.loadUrl("javascript:document.getElementById('math').innerHTML='\\\\["
                  +doubleEscapeTeX("sample string")
                  +"\\\\]';");

Вы заметили \\\\[ и \\\\]? Эти четыре обратной косой черты интерпретируются LaTeX как один, а \[ и \] в LaTeX является сокращением для \begin{equation}... \end{equation}, которое производит блок отображаемой математики. Если нам нужен абзац текста с некоторыми уравнениями в абзаце, нам нужно избавиться от \\\\[ и использовать команду LaTeX \( и \). Код для примера с математикой абзаца и отображаемой математикой:

w.loadUrl("javascript:document.getElementById('math').innerHTML='"
   +doubleEscapeTeX(
           "This is a second degree equation \\( \\small ax^2+bx+c=0\\) and its "
          +"roots are \\[x=\\frac{-b\\pm \\sqrt{b^2-4ac}}{2a}. \\]"
    )+"';");

WebView становится: enter image description here Примечания:

  • Нам нужны только две обратные косые черты вместо четырех, это потому, что мы находимся внутри doubleEscapeTeX(), и эта функция дублирует обратную косую черту.

  • Также текст вне среды математики отображается с помощью HTML (внутри тега <span id='math'>).

  • Шрифт LaTeX больше, чем шрифт html, поэтому добавление \\small в каждой математической среде сделает их примерно одного размера. Здесь я добавил команду \\small только к первому уравнению, чтобы показать разницу.

Ответ 5

jqMath - это библиотека JavaScript, такая как MathJax, но намного меньше, проще и быстрее. Если вам не нужен весь LaTeX, вам может понравиться. Он должен отлично работать на Android.

Это просто предложение, я понятия не имею, какие ошибки или преимущества у вас есть, если вы используете MathJax.

MathJax намного больше и сложнее, чем jqMath, а примерно в 5 раз медленнее.

Работа JSFIDDLE: http://jsfiddle.net/sinhayash/gWWB5/1/

Для \sqrt{b^2-4ac} вы можете получить этот код: √(b^2-4ac)

Вы можете легко использовать обработку строк в javascript для преобразования строк в формат jqMath и легко отображать его

Ответ 6

Вы можете легко использовать математическую формулу в android, используя приведенный ниже код.

public void setView(String data,WebView w){
    WebSettings webSettings = w.getSettings();
    webSettings.setJavaScriptEnabled(true);
    String path="file:///android_asset/v/";
    String js="<html><head>"
       + "<link rel='stylesheet' href='file:///android_asset/v/jqmath.css'>"
       + "<script src = 'file:///android_asset/v/jquery-3.0.0.min.js'></script>"
       + "<script src = 'file:///android_asset/v/jqmath-etc-0.4.3.min.js'></script>"
       + "<script src = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'></script>"
       + "</head><body>"
       + "<script>var s ='"+data+"';M.parseMath(s);document.write(s);</script> </body>";
    w.loadDataWithBaseURL("", js, "text/html", "UTF-8", "");
}