LoginSignup
3
3

More than 1 year has passed since last update.

超高速な数式表示(KaTeX より高速!)

Posted at

この数式表示を実際に利用した 僕のブログ を確認してもらえると嬉しいです。

この記事は静的サイトジェネレータ向けの内容です。もちろん動的なサイトでも使えますが,おすすめしません。

はじめに

僕のブログは静的サイトジェネレータの HUGO で作成しています。ここでは HUGO 用の説明をしますが,他の静的サイトジェネレータ(Hexo,Jekyll など)でも使える内容だと思います。

静的サイトジェネレータはその名の通り,静的なサイトを生成します。WordPress のようにユーザがサイトにアクセスするたびに,ページを作成する動的なものと比べ,読み込み速度などのパフォーマンスが高いメリットがあります。

科学技術に関する内容の記事を書く場合,サイト上に数式を表示したくなります。数式表示には MathJax や KaTeX がよく利用されています1。これらはユーザがサイトにアクセスすると,LaTeX 記述の数式を JavaScript を用いてブラウザ上で表示させます。この処理のせいで,サイトにアクセスした直後少しの間,数式がちゃんと表示されません。

当たり前ですが,数式の見た目は何度読み込んでも同じです。せっかく HUGO を使っているのに,これでは何となく嫌な感じです。最初から HUGO で HTML を生成するときに数式を埋め込んでしまえば,ユーザがアクセスするたびに,MathJax や KaTeX の処理をしなくていいです。

こんなこといいな できたらいいな...

できます!

目標

このコードのように LaTeX 数式コードを SVG へ変換し挿入する Shortcode を作成することを目標にします。作り方なんて興味ないから使い方教えろって人は使い方を見てください。

{{< tex2svg >}}E=mc^2{{< /tex2svg >}}
<svg> ... </svg>

いざ作成

アイデアは文献 4 の tex2svg (GitHub) と同じです。個人的に使いやすくするようにカスタマイズします。

LaTeX から SVG に変換

LaTeX を SVG に変換するツールは色々あります。しかし,HUGO から外部コマンドは実行できないので,簡単ではなさそうです。

HUGO は getJSON でインターネット上の JSON を取得することができます。LaTeX を SVG の情報を含む JSON を返す API を探したところ,tex2svgCODECOGS が見つかりました。

  • tex2svg:MathJax によって数式を生成します。Heroku で API が公開されていてのレスポンスは少し遅いです。
  • CODECOGS:昔からある有名な奴です。SVG 以外に PNG や GMP とかも生成できます。ベースラインが無く,インラインで表示すると微妙になる。

インライン表示が綺麗に見えないと嫌なので,tex2svg を利用します。

tex2svg は https://tex2svg.herokuapp.com/?+q=E=m^2+&inline=true のように叩きます。q= に表示したい数式の LaTeX コードを書きます。&inline=true を書くとインライン表示になります。また,ディスプレイ表示のとき class=tex,インライン表示のとき class=i-tex にしてくれます。

API は次のような JSON を返します。svgvertical-align などのパラメータもすでに含まれているので,svg だけを利用します。

{
  "speakText": "equation",
  "svg": "<svg ...",
  "width":"...ex",
  "height":"....ex",
  "style": "vertical-align: ...ex;"
}

Shortcodes

getJSON は URLが str1str2str3 のとき "str1" "str2" "str3" のように分割して指定できます。(querify "q" .Inner){{< tex2svg >}}{{< /tex2svg >}} の間のテキストを q=%5Cfrac%7B1%7D%7Bx%7D みたいにします。インライン表示するときは &inline=true を加えます。svg には \n などのコードを含むので,それを safeHTML でいい感じにして表示させます。

{{- $json := getJSON "https://tex2svg.herokuapp.com/" "?" (querify "q" .Inner) "&inline=true" -}}
{{- $json.svg | safeHTML -}}

Shortcode の引数を指定して表示方法の選択ができたほうが便利です。{{- if eq (.Get 0) "display" -}} で引数に display の有無に応じて,<span><div> を分岐し,&inline=true を適宜付けます。具体例は次節の使い方で紹介します。

使い方

この節では使い方だけを説明します。コピペで簡単に利用できるので,「中身とか知らねーけど使わせろ」って人はここだけ見てください。

shortcodes に次のコードを tex2svg.html2 として保存してください。

{{- if eq (.Get 0) "display" -}}
<div class="displaystyle">
  {{- $json := getJSON "https://tex2svg.herokuapp.com/" "?" (querify "q" (replace .Inner "\\bm" "\\boldsymbol")) -}}
  {{- $json.svg | safeHTML -}}
</div>
{{- else -}}
<span class="inline">
  {{- $json := getJSON "https://tex2svg.herokuapp.com/" "?" (querify "q" (replace .Inner "\\bm" "\\boldsymbol")) "&inline=true" -}}
  {{- $json.svg | safeHTML -}}
</span>
{{- end -}}

次のように Markdown で記事を書いて見てください。

ディスプレイ表示の数式は
{{< tex2svg display >}}
  (f \ast g)(t)=\int_{-\infty}^{\infty} f(\tau) g(t - \tau) \, \mathrm{d}\tau
{{< /tex2svg >}}
となる。

インライン表示の数式は
{{< tex2svg >}}
  (f \ast g)(t)=\int_{-\infty}^{\infty} f(\tau) g(t - \tau) \, \mathrm{d}\tau
{{< /tex2svg >}}
となる。

次のような表示(出力)が確認できます。


ディスプレイ表示の数式は

(f \ast g)(t)=\int_{-\infty}^{\infty} f(\tau) g(t - \tau) \, \mathrm{d}\tau

となる。

インライン表示の数式は $(f \ast g)(t)=\int_{-\infty}^{\infty} f(\tau) g(t - \tau) \, \mathrm{d}\tau$ となる。


もちろん align 環境も使えます。

\begin{align}
  f(x) &= x+1\\
  g(x) &= x^2\\
  h(x) &= \frac{1}{\sqrt{x}}
\end{align}

インライン表示のときは <span class="inline"> ... </span> で囲み,ディスプレイ表示のときは <div class="display"> ... </div> で囲みます。CSS で設定することで,表示方法を簡単に設定できます。

おまけ

カスタマイズ

ディスプレイ表示を中央へ

ディスプレイ表示の時は TeX みたいに中央に置きたい場合は CSS で左右にマージンを与えます。

.tex {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

フォントサイズを変更したい

ちょっと本文より大きくて嫌だな~と思ったので,フォントサイズを $0.9$ 倍させました。

.tex {font-size: 0.9em;}
.i-tex {font-size: 0.9em;}

\bm を使いたい

MathJax はデフォルトでは \bm を使えないので,代わりに \boldsymbol で太字にします。\bm\boldsymbol に置換すればもっと便利です。

replace .Inner "\\bm" "\\boldsymbol"

テキスト選択したい

単なる画像としての SVG なので,数式をコピペできません。SVG 内に見えないテキストを用意してコピペできるようにしたいと思います。replace を使って </svg><text> ... </text></svg> に置換して,無理やりテキスト情報を入れます。CSS テキストのスタイルを指定します。色を無色 rgba(0,0,0,0) にします。SVG 内のフォントサイズがはちょっとアレですごく小さいみたいなので,適当に超大きくなるように設定します。

{{- (replace $json.svg "</svg>" (printf "<text x=\"0\" y=\"0\" class=\"eq-text\">%s</text></svg>" $.Inner)) | safeHTML -}}
.eq-text {
  fill: rgba(0, 0, 0, 0);
  font-size: 100ex;
}

tex2svg

MathJax にはパッケージを追加したり,フォントを変更する機能があります。tex2svg ではデフォルト状態になっています。MathJax の設定をやりたい場合は自分で API を用意してください。ソースコードは tex2svg (GitHub) を参考にすれば良いと思います。ローカルで HUGO を使う場合は localhost:3000 に API をたてたとしたら,https://tex2svg.herokuapp.com/http://localhost:3030/ に置きかえらば良いです。僕は GitHub Actions で HUGO しているので,tex2svg を直接利用しています3

文献

  1. 超高速な数式表示(KaTeX より高速!)
  2. MathJax
  3. KaTeX
  4. tex2svg (API)
  5. tex2svg (GitHub)
  6. CODECOGS

  1. KaTeX は MathJax より早いです。僕のブログでは KaTeX を利用していました。 

  2. 好きな名前で構いません。僕は短いほうが楽なので eq.html にしています。 

  3. まあ,自分で Heroku とか Repl.it とかで API を公開すればいいんだけどね... 

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3