4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

4
Last updated at Posted at 2021-11-20

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

はじめに

僕のブログは静的サイトジェネレータの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を公開すればいいんだけどね...

4
4
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
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?