├── .gitignore ├── README.md ├── document ├── backend │ └── 1.0.md ├── command.md ├── image │ └── sample.png ├── ruby.md ├── tutorial.md └── zotica │ └── 1.0.md ├── exec ├── zotica └── zoticaf ├── sample ├── converter │ ├── main.rb │ └── utility.rb ├── document │ ├── main.zml │ └── style.css ├── macro │ └── math.rb └── template │ └── html.rb ├── source ├── zotica.rb └── zotica │ ├── builder.rb │ ├── parser.rb │ └── resource │ ├── font.otf │ ├── font │ ├── main.json │ └── math.json │ ├── math.json │ ├── script │ ├── accent.js │ ├── diagram.js │ ├── fence.js │ ├── main.js │ ├── radical.js │ ├── subsuper.js │ ├── tree.js │ ├── underover.js │ └── wide.js │ └── style │ ├── math.scss │ └── times.scss └── spec.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | sample/out 3 | source/zotica/resource/font/*.ttf 4 | mathjax.html 5 | .vscode 6 | *.gem 7 | **/debug.rb 8 | desktop.ini 9 | Thumbs.db -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Zotica

3 |
4 | 5 | ![](https://img.shields.io/gem/v/zotica?label=version) 6 | ![](https://img.shields.io/github/commit-activity/y/Ziphil/ZenithalMathWeb?label=commits) 7 | 8 | 9 | ## 概要 10 | 11 | Zotica とは、[ZenML](https://github.com/Ziphil/Zenithal) ライクな文法で数式を記述できるマークアップ言語です。 12 | 処理系を通すことで HTML 要素に変換され、専用の CSS + JavaScript を適用することで、Web ページ内に数式を表示することができます。 13 | TeX と同程度の品質の数式を組めることと、出力される HTML が難読なものにならないようにすることを目指しています。 14 | 15 | 現在このライブラリは非推奨であり、これ以上更新されることはありません。 16 | 代わりに [TypeScript 実装](https://github.com/Ziphil/ZenmlZotica)を利用してください。 17 | 18 | ブラウザ上で数式を表示するエンジンとしては、すでに [MathJax](https://www.mathjax.org/) や [KaTeX](https://katex.org/) などがあります。 19 | これらとの違いは主に以下の 3 点です。 20 | 21 | - 記号以外は本文フォントを継承して描画するので数式だけ本文から浮いてしまうことがない 22 | - 出力される HTML の構造が比較的簡潔 23 | - CSS を上書きするだけで要素間のスペーシングを比較的簡単にカスタマイズできる 24 | 25 | 以下は、Zotica による数式の出力例です (Google Chrome でのキャプチャ画像)。 26 | 27 |
28 | 29 |
30 | 31 | もしくは、描画サンプルページをご覧ください。 32 | 33 | - [描画サンプルページ](https://ziphil.github.io/ZenithalMathWebDemo/main.html) 34 | 35 | Zotica の仕様は以下の通りです。 36 | 現在は試案段階で、突然変更になる可能性がありますので、利用する際は注意してください。 37 | 38 | - [バージョン 1.0](document/zotica/1.0.md) 39 | 40 | このリポジトリは、Ruby 実装の ZenML パーサーである `ZenithalParser` クラスを拡張した `ZoticaParser` クラスを提供します。 41 | このクラスは通常の ZenML パーサーと同じように ZenML ドキュメントをパースしますが、引数の内容が Zotica で書かれたマクロを処理できるようになっています。 42 | 43 | ## インストール 44 | RubyGems からインストールしてください。 45 | ``` 46 | gem install zotica 47 | ``` 48 | 49 | ## 使い方 50 | 51 | ### とにかく試してみたい場合 52 | とりあえず試しに Zotica で数式をレンダリングしてみたいという場合は、以下のチュートリアルを参考にしてください。 53 | 環境構築から数式を含む HTML の生成までを行えます。 54 | 55 | - [チュートリアル](document/tutorial.md) 56 | 57 | ### コマンドラインを用いる場合 58 | Zotica 処理系をコマンドラインから呼び出すための API が用意されています。 59 | 上記の「インストール」の項目に沿って Ruby と Zotica をインストールすれば、自動的に使えるようになります。 60 | 61 | - [コマンドラインインタフェースの仕様](document/command.md) 62 | 63 | ### Ruby から呼び出す場合 64 | Zotica 処理系は Ruby で書かれているため、Ruby から呼び出すことができます。 65 | 詳しい方法については、以下のドキュメントを参考にしてください。 66 | 67 | - [Ruby API のチュートリアル](document/ruby.md) 68 | 69 | ## 今後のアップデート予定 70 | 以下の機能を実装予定です。 71 | 72 | - LaTeX 形式の数式記述に対応 73 | - スペーシングを調整する API の作成 74 | 75 | ## 注意点 76 | 77 | ### 数式フォントについて 78 | Zotica で用いられる数式フォントは、[STIX Two Math](https://www.stixfonts.org/) のバージョン 2.00 b137 を HTML での表示用に改変したものになっています。 79 | 改変を行ったフォントは[ここ](source/zotica/resource/font.otf)に置いてあるので、オリジナルと同じ [SIL Open Font License](http://scripts.sil.org/OFL) のもと自由に使用していただいて構いません。 80 | 施した改変の内容は以下の通りです。 81 | 82 | 追加で登録されているグリフ (`.notdef` ~ `zeroinferior.per`) に専用のコードポイントを与えるため、これらのグリフを U+F0000 ~ U+F04DB にコピーします。 83 | 以下で指定するコードポイントは、このコピーを行った後のものとします。 84 | 85 | そのままでは一部の大型演算子が若干浮いて表示されてしまうため、U+F0187 ~ U+F018A, U+F0214 ~ U+F021D のグリフを下方向に 540 移動させます。 86 | 87 | CSS による調整なしで根号を正しく表示するため、根号のグリフの位置を変更します。 88 | U+F011D, U+F011E, U+F011F のグリフをそれぞれ下方向に 667, 1183, 1704 移動させます。 89 | 90 | 位置を修正したアクセント記号を別のコードポイントに保存するため、まず U+0300 ~ U+036F と U+20D0 ~ U+20FF のグリフをそれぞれ U+F0500 ~ U+F056F と U+F0570 ~ U+F059F にコピーします。 91 | その上で、コピーした各グリフに対し、グリフの左端の X 座標を 0 にし、文字幅をグリフ幅に一致させます。 92 | 例えば U+F0500 に対しては、グリフ全体を右方向に 338 移動させ、文字幅を 162 に設定します。 93 | 94 | ### 構成要素の変更について 95 | 開発当初は、数式を記述するマークアップ言語と、数式を表示するための HTML + CSS + JavaScript セットとを分離して、後者のみを「Zotica」と呼んでいました。 96 | しかし、開発の都合により両者がかなり密結合になってしまったため、両者を合わせて 1 つのプロダクトとして「Zotica」と呼ぶことにしました。 97 | 98 | 現在は、Zotica のマークアップを HTML に変換する際の処理と CSS + JavaScript のセットが噛み合っていないと、数式が綺麗に表示できません。 99 | そのため、Zotica が出力するような HTML 要素を別のプロダクトから直接生成することは推奨しません。 100 | 例えば、別のマークアップ方式から Zotica を利用して数式を表示させたい場合など、別のプロダクトから Zotica を利用する場合は、HTML 要素ではなく Zotica のマークアップを生成してください。 101 | -------------------------------------------------------------------------------- /document/backend/1.0.md: -------------------------------------------------------------------------------- 1 | ## 注意点 2 | Zotica のカスタム要素は、要素間にスペースが入っていないものとして設計されています。 3 | 各要素の説明において最初に提示されている HTML では、見やすさのため改行やスペースを入れていますが、実際には改行やスペースを入れてはいけません。 4 | 5 | ## 用語 6 | 7 | ### 本文フォント 8 | Zotica の外側で指定されているフォントです。 9 | Zotica では、数式記号を除いた数値や変数名などには、専用のフォントを用いず外側のフォントをそのまま継承して使うので、このフォントを指して「本文フォント」と呼ぶことにします。 10 | 11 | ### 数式フォント 12 | Zotica で使われる専用の数式フォントです。 13 | 演算子などの記号を表示するのに用いられます。 14 | [ここ](../../source/zotica/resource/font.otf)に置かれています。 15 | 16 | ### 伸縮レベル 17 | 根号や括弧などの伸縮する記号の伸縮の度合いを表します。 18 | 伸縮する記号は、伸縮の度合いに合わせてフォントに複数の形状が登録されています。 19 | 伸縮していない状態をレベル 0 とし、伸びれば伸びるほどレベルは上がります。 20 | 21 | 一部の記号は、可変長に対応しています。 22 | 例えば括弧のパーレンは、端の曲がる部分と中央の直線部分が別々の文字として登録されており、直線部分の長さを調整することで、任意の大きさの括弧を作ることができるようになっています。 23 | このような状態における伸縮レベルは ∞ とします。 24 | 25 | ## 共通クラス 26 | Zotica のカスタム要素のいずれに対しても、以下のクラス名を付けることで、その要素の数式上の役割を明示して前後のスペーシングを調整することができます。 27 | 28 | **`bin`**: 29 | 二項演算子であることを明示します。 30 | 左右に 4/18 em のスペースが追加されます。 31 | **`rel`**: 32 | 二項関係子であることを明示します。 33 | 左右に 5/18 em のスペースが追加されます。 34 | **`sbin`**: 35 | 左右の空きが広めの二項演算子であることを明示します。 36 | 左右に 8/18 em のスペースが追加されます。 37 | **`srel`**: 38 | 左右の空きが広めの二項関係子であることを明示します。 39 | 左右に 8/18 em のスペースが追加されます。 40 | **`del`**: 41 | コンマやセミコロンなどの区切り記号であることを明示します。 42 | 右にのみ 5/18 em のスペースが追加されます。 43 | **`fun`**: 44 | 関数名であることを明示します。 45 | 右にのみ 3/18 em のスペースが追加されますが、開き括弧 (`par` クラスか `lpar` クラスをもつ要素) が後続した場合はこのスペースは挿入されません。 46 | **`not`**: 47 | 先行する記号に重ね打ちする記号であることを明示します。 48 | 否定を表すスラッシュ (U+0338) に使われる特殊なクラスです。 49 | **`ord`**: 50 | 通常の文字列であることを明示します。 51 | スペーシングはなされません。 52 | クラスを何も付けないのと同じです。 53 | **`par`**: 54 | 括弧で囲まれた部分であることを明示します。 55 | **`lpar`**: 56 | 括弧の左側 (開き括弧) であることを明示します。 57 | **`rpar`**: 58 | 括弧の右側 (閉じ括弧) であることを明示します。 59 | **`cpar`**: 60 | 集合の内包表記など括弧の間の区切り記号であることを明示します。 61 | 左右に 5/18 em のスペースが追加されます。 62 | 63 | なお、余計なスペースが発生するのを防ぐため、ある要素の最初の子要素となっている場合は左側のスペースは削除され、ある要素の最後の子要素となっている場合は右側のスペースは削除されます。 64 | これは、要素に以下のクラスを付けることで抑制できます。 65 | 66 | **`lpres`**: 67 | その要素の最初の子要素の左側のスペースをそのまま保持するようになります。 68 | **`rpres`**: 69 | その要素の最後の子要素の右側のスペースをそのまま保持するようになります。 70 | 71 | ## 要素 72 | 73 | ### ルート (`math-root`) 74 | ```html 75 | 76 | 77 | 78 | ``` 79 | Zotica の数式のルート要素です。 80 | 81 | ### 数値 (`math-n`) 82 | ```html 83 | 84 | ``` 85 | 数式中の数値を表します。 86 | 要素の内容はテキストノードです。 87 | 基本的には、数字か小数点か桁区切り記号の列がこの要素の内容になります。 88 | 89 | この要素は本文フォントで描画されるため、数式フォントで描画されるべき符号は、`math-n` 要素には入れずに `math-o` 要素を別途用いてください。 90 | 91 | ### 識別子 (`math-i`) 92 | ```html 93 | 94 | ``` 95 | 数式中の識別子を表します。 96 | 要素の内容はテキストノードです。 97 | 識別子には、変数名や定数名や関数名などが含まれます。 98 | 99 | 何も指定しなければ、識別子は常に本文フォントのイタリック体で描画されます。 100 | ただし、要素に `fun` クラスが付けられている場合は、例外的にローマン体で描画されます。 101 | また、以下のクラスを追加することで、フォントを変更することができます。 102 | 103 | **`rm`**: 104 | ローマン体で描画します。 105 | **`bf`**: 106 | ボールド体で描画します。 107 | デフォルトがイタリック体なので、このクラスを付けただけではボールドイタリック体で描画されることになります。 108 | ボールドローマン体で描画したい場合は、`rm` クラスと併用してください。 109 | **`alt`**: 110 | カリグラフィー体やフラクトゥール体などを表示するために、数式フォントで描画します。 111 | これらの書体の文字は Unicode 上の専用のブロック (U+1D400 ~ U+1D7FF と U+2100 ~ U+214F の一部) に収録されていますが、そこの文字への自動変換は行われません。 112 | あくまで、数式フォントで描画するようになるだけです。 113 | 114 | 描画には本文フォントが用いられるので、識別子が連続したときに、識別子間の間隔が期待より狭くなる場合 (特に `f` が連続した場合に顕著) があります。 115 | これはフォント依存の問題なので、Zotica が自動で調整することはできません。 116 | これを解消するには、`style` 属性を用いて CSS から個別にマージンなどを指定するしかありません。 117 | 118 | ### 記号 (`math-o`) 119 | ```html 120 | 121 | ``` 122 | 記号を表します。 123 | 要素の内容はテキストノードです。 124 | 記号には、演算子 (総和記号や積分記号などの大型演算子も含む), 関係子, 括弧, 区切り記号などが含まれます。 125 | 多くの場合、記号の種類を明示するために、共通クラスのいずれかが付けられます。 126 | 127 | 共通クラスの他に、以下のクラスを付けることができます。 128 | 129 | **`txt`**: 130 | 本文フォントで描画するようになります。 131 | 記号というより文字に近い記号 (いわゆる文字様記号) を表示するのに利用できます。 132 | **`int`**: 133 | 大型の積分記号 (とそれに類する記号) を表します。 134 | 高さなどが調整されます。 135 | **`sum`**: 136 | 大型の総和記号 (とそれに類する記号) を表します。 137 | 高さなどが調整されます。 138 | **`acc`**: 139 | アクセント記号を表します。 140 | このクラスが付けられた場合、中身のテキストは結合用アクセント文字 1 文字であることが期待されます。 141 | それ以外の文字が入れられた場合は、表示位置がおかしくなる可能性があります。 142 | **`wid`**: 143 | 幅の広いアクセント記号を表します。 144 | このクラスが付けられた場合、中身のテキストは U+F0000 ~ U+F04DB にある専用の文字であることが期待されます。 145 | それ以外の文字が入れられた場合は、表示位置がおかしくなる可能性があります。 146 | 147 | 記号がある要素の最初の子要素になっている場合、それは後続する要素に係る単項演算子 (符号のようなもの) だと解釈され、左側のスペースに加え右側のスペースも削除されます。 148 | ただし、その記号を含んでいる親要素に `lpres` クラスが指定されているときは、スペースの削除は行われません。 149 | 150 | Zotica はハイフン (U+002D) をマイナス記号 (U+2212) に置き換えることはしません。 151 | 負の符号や減算を表す正しい記号は U+2212 の方なので、注意してください。 152 | 153 | ### テキスト (`math-text`) 154 | ```html 155 | 156 | ``` 157 | 数式ではない通常のテキストを表します。 158 | 要素の内容はテキストノードです。 159 | 160 | ### 分数 (`math-frac`) 161 | ```html 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | ``` 174 | 分数を描画します。 175 | 176 | `math-line` 要素は分数の括線を描画するのに使われるもので、内容は常に空です。 177 | 178 | ### 根号 (`math-sqrt`) 179 | ```html 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | ``` 189 | 根号を描画します。 190 | 根号記号は U+221A, U+F011D, U+F011E, U+F011F のいずれかです。 191 | 192 | `math-sqrt` 要素に `mod` クラスを付けることで、Zotica が中身の高さに応じて自動的に根号記号を変更します。 193 | 194 | ### 下付きと上付き (`math-subsup`) 195 | ```html 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | ``` 208 | 下付きと上付きをもつ数式を描画します。 209 | 下付きと上付きのいずれかが存在しない場合は、対応する要素 (`math-sub` 要素か `math-sup` 要素) を省略してください。 210 | 211 | `math-subsup` 要素には以下のクラスがあります。 212 | 213 | **`int`**: 214 | 大型の積分記号とその添字を描画するのに使われます。 215 | このクラスが付けられた場合、`math-base` 要素の内容として、`int` クラスをもつ `math-o` 要素が 1 つ置かれることが想定されます。 216 | 下付き箇所が、積分記号の傾斜に合わせてより左に配置されるようになります。 217 | 218 | 上付きと下付きの位置は、ベースとなる数式の高さに応じて自動的に調整されます。 219 | 220 | ### アンダースクリプトとオーバースクリプト (`math-underover`) 221 | ```html 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | ``` 234 | アンダースクリプトとオーバースクリプトをもつ数式を描画します。 235 | アンダースクリプトとオーバースクリプトのいずれかが存在しない場合は、対応する要素 (`math-under` 要素か `math-over` 要素) を省略してください。 236 | 237 | `math-underover` 要素には以下のクラスがあります。 238 | 239 | **`sum`**: 240 | 大型の総和記号 (とそれに類する記号) とその添字を描画するのに使われます。 241 | このクラスが付けられた場合、`math-base` 要素の内容として、`sum` クラスをもつ `math-o` 要素が 1 つ置かれることが想定されます。 242 | 現在では、このクラスを付けても付けなくても表示は変わりませんが、将来に仕様が変更されることがあるので、付けておくのが無難です。 243 | **`acc`**: 244 | アクセント記号付きの文字を描画するのに使われます。 245 | このクラスが付けられた場合、`math-over` 要素もしくは `math-under` 要素の内容として、`acc` クラスをもつ `math-o` 要素が 1 つ置かれることが想定されます。 246 | この `math-o` 要素の中のテキストは、U+F0500 ~ U+F590 の専用コードポイントの文字にしてください。 247 | **`wid`**: 248 | 幅の広いアクセント記号付きの文字を描画するのに使われます。 249 | このクラスが付けられた場合、`math-over` 要素もしくは `math-under` 要素の内容として、`wid` クラスをもつ `math-o` 要素が 1 つ置かれるか、`math-hstretch` 要素が 1 つ置かれることが想定されます。 250 | 251 | `math-underover` 要素に `wid` クラスが付けられているとき、さらに `mod` クラスを付けることで、Zotica がベースの幅に応じて自動的にアクセント記号を変更します。 252 | このとき、アクセント記号の種類を明示するため、以下のカスタムデータ属性を設定してください。 253 | 254 | **`data-kind`**: 255 | アクセント記号の種類を表します。 256 | 指定することができる種類は後述します。 257 | 258 | カスタムデータ属性に指定できるアクセント記号の種類は以下の通りです。 259 | 260 | **`widetilde`**: 261 | 文字の上に付くチルダです。 262 | **`widehat`**: 263 | 文字の上に付くサーカムフレックス (もしくはキャレットやハット記号) です。 264 | **`widecheck`**: 265 | 文字の上に付くハーチェク (もしくはキャロン) です。 266 | **`overline`**: 267 | 文字の上に付く直線です。 268 | **`overrarr`**: 269 | 文字の上に付く右向きの矢印です。 270 | **`overlarr`**: 271 | 文字の上に付く左向きの矢印です。 272 | **`overbrace`**: 273 | 文字の上に付く波括弧です。 274 | **`widetildebelow`**: 275 | 文字の下に付くチルダです。 276 | **`underline`**: 277 | 文字の下に付く直線です。 278 | **`underrarr`**: 279 | 文字の下に付く右向きの矢印です。 280 | **`underlarr`**: 281 | 文字の下に付く左向きの矢印です。 282 | **`underbrace`**: 283 | 文字の下に付く波括弧です。 284 | 285 | JavaScript から文字のグリフの高さや深さを取得することはできないため、Zotica は文字の大きさに合わせてアクセント記号の位置を調整することはしません。 286 | そのため、エックスハイトに収まる文字にオーバーアクセントを付けたり、ディセンダーをもつ文字にアンダーアクセントを付けた場合、文字本体とアクセント記号の間隔が期待されるものとは異なる可能性があります。 287 | これを解消するには、`style` 属性によって CSS から間隔を個別に調整するしかありません。 288 | 289 | ### 括弧囲み (`math-paren`) 290 | ```html 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ``` 309 | 括弧囲みの数式を描画します。 310 | 集合の内包表記のように、中央に区切り線を隔てて左右に数式があり、それ全体を括弧が囲んでいる場合は、上のように `math-left`, `math-parencont`, `math-center`, `math-parencont`, `math-right` の順で 5 つの要素を並べます。 311 | 区切り線がなく数式を括弧で囲むだけの場合は、`math-center` 要素と一方の `math-parencont` 要素は不要になり、`math-left`, `math-parencont`, `math-right` の順で 3 つの要素を並べます。 312 | 313 | この要素は括弧囲みのためのものですが、共通クラスを明示的に指定しない限り、括弧の周囲に入るべきスペースは入れられません。 314 | 適切なスペーシングをするためには、`math-paren` 要素に `par` クラスを付け、`math-center` 要素に `cpar` クラスを付けておく必要があります。 315 | 316 | `math-left` 要素, `math-center` 要素, `math-right` 要素の内容としては、括弧記号を中身としてもつ `math-o` 要素が 1 つ置かれるか、`math-vstretch` 要素が置かれることが想定されます。 317 | 318 | `math-paren` 要素に `mod` クラスを付けることで、Zotica が中身の高さに応じて自動的に括弧記号を変更します。 319 | このとき、括弧の種類を明示するため、以下のカスタムデータ属性を設定してください。 320 | 321 | **`data-left`**: 322 | 左側の括弧の種類を指定します。 323 | **`data-right`**: 324 | 右側の括弧の種類を指定します。 325 | **`data-center`**: 326 | 中央の区切り線の種類を指定します。 327 | 区切り線がなく `math-center` 要素が存在しない場合は、このカスタムデータ属性は不要です。 328 | 329 | これらのカスタムデータ属性に指定できる括弧の種類は以下の通りです。 330 | 331 | **`paren`**: 332 | 通常の丸括弧です。 333 | **`pparen`**: 334 | 白抜きの丸括弧 (もしくは二重の丸括弧) です。 335 | **`bracket`**: 336 | 角括弧です。 337 | **`bbracket`**: 338 | 白抜きの角括弧 (もしくは二重の角括弧) です。 339 | 形式言語の意味を表す括弧 (いわゆるオックスフォードブラケット) としてよく用いられます。 340 | **`brace`**: 341 | 波括弧です。 342 | **`bbrace`**: 343 | 白抜きの波括弧 (もしくは二重の波括弧) です。 344 | **`vert`**: 345 | 縦線です。 346 | 絶対値記号として使われる他、集合の内包表記の区切り線としても使われます。 347 | **`vvert`**: 348 | 二重の縦線です。 349 | **`floor`**: 350 | 床関数を表す括弧です。 351 | **`ceil`**: 352 | 天井関数を表す括弧です。 353 | **`angle`**: 354 | 山括弧です。 355 | **`aangle`**: 356 | 二重の山括弧です。 357 | **`tort`**: 358 | 亀甲括弧です。 359 | 角括弧 (`bracket` の括弧) よりも上下隅の角張った部分の角度が緩やかになっています。 360 | **`none`**: 361 | 括弧を表示しません。 362 | 左右片方だけに括弧を付けたい場合に利用できます。 363 | 364 | なお、括弧の自動伸長を利用しないのであれば、`math-paren` 要素を使わず、単に括弧記号を `math-o` 要素として置くだけでも構いません。 365 | 366 | ### 可変長括弧 (`math-vstretch`) 367 | ```html 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | ``` 380 | 可変長の括弧を描画します。 381 | 波括弧のように中央の断片がある場合は、上のように `math-start`, `math-barwrap`, `math-middle`, `math-barwrap`, `math-end` の順で 5 つの要素を並べます。 382 | そうでない場合は、`math-start`, `math-barwrap`, `math-end` の順で 3 つの要素のみを並べます。 383 | さらに、絶対値の括弧のように上下の断片もない場合は、`math-barwrap` 要素のみを入れます。 384 | 断片を置く部分の内容は全てテキストノードです。 385 | 386 | この要素は、Zotica の JavaScript から生成されるもので、ユーザーが直接出力することはあまり想定されていません。 387 | 388 | 正しい位置と大きさで表示するには、`math-vstretch` 要素の `style` 属性で `veritcal-align` プロパティの値を適切に設定し、`math-barwrap` 要素の `style` 属性で `height` プロパティの値を適切に設定する必要があります。 389 | 390 | ### 可変長アクセント記号 (`math-hstretch`) 391 | ```html 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | ``` 404 | 可変長のアクセント記号を描画します。 405 | 波括弧のように中央の断片がある場合は、上のように `math-start`, `math-barwrap`, `math-middle`, `math-barwrap`, `math-end` の順で 5 つの要素を並べます。 406 | そうでない場合は、`math-start`, `math-barwrap`, `math-end` の順で 3 つの要素のみを並べます。 407 | さらに、直線のように左右の断片もない場合は、`math-barwrap` 要素のみを入れます。 408 | 断片を置く部分の内容は全てテキストノードです。 409 | 410 | この要素は、Zotica の JavaScript から生成されるもので、ユーザーが直接出力することはあまり想定されていません。 411 | 412 | 正しい大きさで表示するには、`math-barwrap` 要素の `style` 属性で `width` プロパティの値を適切に設定する必要があります。 413 | 414 | ### 表 (`math-table`) 415 | ```html 416 | 417 | 418 | 419 | 420 | ⋮ 421 | 422 | 423 | 424 | 425 | ``` 426 | 各セルが 1 つの数式から成る表を描画します。 427 | 行列やイコール揃えなどを実現するのに利用できます。 428 | 中身の `math-cell` 要素はセルの個数分だけ置きます。 429 | 430 | `math-cell` 要素には、`style` 属性を用いてセルの表中での位置を指定する必要があります。 431 | これは、CSS のグリッドレイアウトのプロパティ (`grid-row`, `grid-column` など) を用いることで行います。 432 | 433 | 表のセル間のスペーシングを決めるため、`math-table` に以下のクラスのいずれかを付ける必要があります。 434 | これらのクラスのいずれも付けなかった場合、レイアウトが崩れる可能性があります。 435 | 436 | **`std`**: 437 | イコール揃えなどを描画するための汎用クラスです。 438 | セル間に水平方向のスペースは挿入されません。 439 | **`stk`**: 440 | 総和記号の添字などの位置で 2 行以上の数式を描画したい場合のためのクラスです。 441 | セル間に水平方向のスペースは挿入されず、垂直方向にも最低限のスペースのみが挿入されます。 442 | **`mat`**: 443 | 行列を描画するためのクラスです。 444 | セル間には水平方向に 15/18 em のスペースが挿入されます。 445 | なお、括弧は描画されないので、適宜 `math-paren` 要素などで囲む必要があります。 446 | **`cas`**: 447 | 場合分けを描画するためのクラスです。 448 | セル間には水平方向に 24/18 em のスペースが挿入されます。 449 | なお、括弧は描画されないので、適宜 `math-paren` 要素などで囲む必要があります。 450 | 451 | セルはデフォルトで中央揃えで描画されます。 452 | 揃える位置を変えたい場合は、`style` 属性で `text-align` プロパティを変更してください。 453 | 454 | ### 可換図式 (`math-diagram`) 455 | ```html 456 | 457 | 458 | 459 | 460 | 461 | 462 | ⋮ 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | ⋮ 472 | 473 | 474 | 475 | 476 | ``` 477 | 可換図式を描画します。 478 | 中身の `math-cellwrap` 要素は図式の各ノードに描画される数式を表し、`math-arrow` 要素はノードを繋ぐ矢印とそれに付けられるラベルを表します。 479 | 480 | `math-cellwrap` 要素は、`math-table` 要素内の `math-cell` 要素のように、表形式で描画されます。 481 | そのため、`style` 属性を用いて表中での位置を指定する必要があります。 482 | これは、CSS のグリッドレイアウトのプロパティ (`grid-row`, `grid-column` など) を用いることで行います。 483 | 484 | `math-diagram` 要素に以下のクラスを付けることで、`math-cellwrap` 要素間に挿入されるスペースを変更できます。 485 | `v` から始まるクラス名は垂直方向のスペースを変更し、`h` から始まるクラス名は水平方向のスペースを変更します。 486 | 何も指定しない場合、垂直方向には 54/18 em のスペースが挿入され、水平方向には 72/18 em のスペースが挿入されます。 487 | 488 | **`vnon`, `hnon`**: 489 | スペースを挿入しません。 490 | 要素は隣接して描画されます。 491 | **`vsthn`, `hsthn`**: 492 | 通常のスペースの 1/6 倍のスペースを挿入します。 493 | **`vvthn`, `hvthn`**: 494 | 通常のスペースの 1/3 倍のスペースを挿入します。 495 | **`vthn`, `hthn`**: 496 | 通常のスペースの 2/3 倍のスペースを挿入します。 497 | **`vmed`, `hmed`**: 498 | 通常のスペースと同じスペースを挿入します。 499 | したがって、このクラスを指定しても何も変化しません。 500 | **`vthk`, `hthk`**: 501 | 通常のスペースの 4/3 倍のスペースを挿入します。 502 | **`vvthk`, `hvthk`**: 503 | 通常のスペースの 5/3 倍のスペースを挿入します。 504 | **`vsthk`, `hsthk`**: 505 | 通常のスペースの 6/3 倍のスペースを挿入します。 506 | **`vuthk`, `huthk`**: 507 | 通常のスペースの 7/3 倍のスペースを挿入します。 508 | 509 | これ以外の量のスペースを挿入したい場合は、クラスは指定せず、`style` 属性を用いて CSS から直接指定してください。 510 | 511 | `math-cellwrap` 要素にもこれと同じクラスを付けることができます。 512 | その場合、`v` から始まるクラス名であれば上方向に同量のマージンが追加され、`h` から始まるクラス名であれば左方向に同量のマージンが追加されます。 513 | `math-diagram` 要素には `vnon` と `hnon` を指定しておき、代わりに各 `math-cellwrap` 要素に上記のクラスを設定することで、行や列ごとに要素間のスペースが異なる図式が実現できます。 514 | 515 | `math-cellwrap` 要素と `math-arrow` 要素には、以下のカスタムデータ属性を指定することができます。 516 | 517 | **`data-name`**: 518 | 要素の名前を設定します。 519 | 矢印の端点を指定するのに用いられます。 520 | 521 | さらに `math-arrow` 要素に対しては、その要素が表す矢印の端点位置やスタイルなどを指定するために、カスタムデータ属性を付けることができます。 522 | 対応しているカスタムデータ属性は、以下の通りです。 523 | 524 | **`data-start`**: 525 | 矢印の始点の位置を指定します。 526 | 指定方法は後述します。 527 | **`data-end`**: 528 | 矢印の終点の位置を指定します。 529 | 指定方法は後述します。 530 | **`data-tip`**: 531 | 矢印の始点と終点に付ける鏃を指定します。 532 | 指定方法は後述します。 533 | **`data-bend`**: 534 | この属性で指定した分だけ、矢印が左に曲がるようになります。 535 | 負の数を指定すると、矢印は右に曲がります。 536 | 単位は deg (90 で直角) です。 537 | **`data-shift`**: 538 | この属性で指定した分だけ、矢印が普通に配置したときの位置から左に移動します。 539 | 負の数を指定すると、矢印は右に移動します。 540 | 単位は 1/18 em です。 541 | **`data-line`**: 542 | 矢印を何重線で描画するか指定します。 543 | `0`, `1`, `2`, `3` のいずれかのみに対応しています。 544 | `0` を指定すると、鏃も含めて矢印は描画されず、ラベルのみが描画されます。 545 | **`data-dash`**: 546 | この属性を指定すると、矢印が破線で描画されます。 547 | この属性は存在するかどうかだけが意味をもつので、値は何であっても構いません。 548 | **`data-pos`**: 549 | 矢印に付けられるラベルの位置を変更できます。 550 | `0` を指定すると矢印の始点の真横に、`100` を指定すると矢印の終点の真横に、`50` を指定すると矢印の中間点の真横に、ラベルが配置されます。 551 | 指定しなければ、`50` (矢印の中間点の横) を指定したものとしてラベルが描画されます。 552 | **`data-inv`**: 553 | この属性を指定すると、ラベルが矢印の右側に置かれるようになります。 554 | この属性が存在しない場合、ラベルは矢印の左側に置かれます。 555 | この属性は存在するかどうかだけが意味をもつので、値は何であっても構いません。 556 | 557 | 矢印の始点と終点の位置は、以下のフォーマットで指定します。 558 | 角括弧で囲まれた部分は任意です。 559 | ``` 560 | (<要素番号>|<要素名>)[:(<方角>|<方向><割合>)] 561 | ``` 562 | 563 | **`<要素番号>`**: 564 | `math-diagram` 要素内にある `math-cellwrap` 要素を先頭からの番号 (1-origin) で指定します。 565 | 例えば、`2` を指定すると、先頭から 2 番目の `math-cellwrap` 要素の枠上のどこかを端点とするという意味になります。 566 | **`<要素名>`**: 567 | ここで指定された文字列と同じ `data-name` 属性値をもつ要素を表します。 568 | **`<方角>`**: 569 | 矢印の端点を該当要素の枠上のどの位置にするかを指定します。 570 | `n`, `ne`, `e`, `se`, `s`, `sw`, `w`, `nw`, `c` のいずれかで指定します。 571 | `c` は該当要素の枠上ではなく該当要素の中央点を意味します。 572 | 例えば、`ne` を指定すると、該当要素の北東端 (右上端) が矢印の端点になります。 573 | **`<方向>`**: 574 | 矢印の端点を該当要素の枠のどの辺上に配置するかを指定します。 575 | `t`, `r`, `b`, `l` のいずれかで指定し、それぞれ上辺, 右辺, 下辺, 左辺を表します。 576 | **`<割合>`**: 577 | 矢印の端点を `<方向>` の箇所で指定された辺上のどの位置にするかを指定します。 578 | `<方向>` が `t` または `b` の場合、`0` を指定すると該当辺の左端を意味し、`100` を指定すると該当辺の右端を意味します。 579 | また、`<方向>` が `r` または `l` の場合、`0` を指定すると該当辺の上端を意味し、`100` を指定すると該当辺の左端を意味します。 580 | 581 | なお、`<方角>` もしくは `<方向><割合>` を指定しなかった場合は、端点は該当要素の枠上の良い感じの場所に自動的に決まります。 582 | 583 | 例えば、`4` と指定すると、先頭から 4 番目の `math-cellwrap` 要素の枠上の自動計算された位置が端点となります。 584 | また、`2:ne` とすると、先頭から 2 番目の `math-cellwrap` 要素の右上端が端点となります。 585 | さらに、`foo:r30` とすると、`foo` という `data-name` 属性値をもつ要素の右辺における上端から 30 % の位置が端点となります。 586 | 587 | 鏃の種類は以下のどれかから選択できます。 588 | 種類によって、始点側に付くか終点側に付くかが決まっています。 589 | 始点側と終点側の両方に鏃を付けたい場合は、コンマで区切って指定します。 590 | なお、同じ側に 2 つ以上の鏃を付けることはできないため、同じ側の鏃が 2 つ以上指定された場合は、最後に指定されたもののみが描画されます。 591 | 592 | **`tail`**: 593 | 始点側に付けられる鏃です。 594 | **`hook`**: 595 | 始点側に付けられる半円形の鈎です。 596 | 矢印の左側に曲がるようにして付けられます。 597 | 包含写像を表すのによく用いられます。 598 | **`varhook`**: 599 | 始点側に付けられる半円形の鈎です。 600 | 矢印の右側に曲がるようにして付けられます。 601 | **`head`**: 602 | 終点側に付けられる二重の鏃です。 603 | **`none`**: 604 | 終点側の鏃を描画しません。 605 | 終点側の鏃を何も指定しないと普通の山形の鏃が描画されますが、これを指定することで終点側に鏃を描画しないようにすることができます。 606 | 607 | 1 つの矢印に複数のラベルを付けることはできません。 608 | しかし、ラベルの数だけ `math-arrow` 要素を用意し、そのうちの 1 つを除いた要素に対して、`data-line` 属性を `0` に設定して矢印本体を消すことで、1 つの矢印に複数のラベルが付いているように描画することができます。 609 | 610 | ### スペース (`math-space`) 611 | ```html 612 | 613 | ``` 614 | スペースを挿入します。 615 | 要素の内容は常に空です。 616 | 617 | 挿入するスペースの量は、クラス名によって指定します。 618 | 以下のクラスがあります。 619 | 620 | **`afun`**: 621 | 関数名 (`fun` クラスをもつ要素) の右に挿入されるスペースと同じ量のスペースを挿入します。 622 | 3/18 em です。 623 | **`abin`**: 624 | 二項演算子 (`bin` クラスをもつ要素) の左右に挿入されるスペースと同じ量のスペースを挿入します。 625 | 4/18 em です。 626 | **`arel`**: 627 | 二項関係子 (`rel` クラスをもつ要素) の左右に挿入されるスペースと同じ量のスペースを挿入します。 628 | 5/18 em です。 629 | **`asbin`**: 630 | 左右の空きが広めの二項演算子 (`sbin` クラスをもつ要素) の左右に挿入されるスペースと同じ量のスペースを挿入します。 631 | 8/18 em です。 632 | **`asrel`**: 633 | 左右の空きが広めの二項関係子 (`srel` クラスをもつ要素) の左右に挿入されるスペースと同じ量のスペースを挿入します。 634 | 8/18 em です。 635 | **`amat`**: 636 | 行列 (`mat` クラスをもつ `math-table` 要素) の成分間に入る水平方向のスペースと同じ量のスペースを挿入します。 637 | 15/18 em です。 638 | **`acas`**: 639 | 場合分け (`cas` クラスをもつ `math-table` 要素) の成分間に入る水平方向のスペースと同じ量のスペースを挿入します。 640 | 24/18 em です。 641 | **`sthn`**: 642 | 1/18 em のスペースを挿入します。 643 | **`vthn`**: 644 | 2/18 em のスペースを挿入します。 645 | **`thn`**: 646 | 3/18 em のスペースを挿入します。 647 | **`med`**: 648 | 4/18 em のスペースを挿入します。 649 | **`thk`**: 650 | 5/18 em のスペースを挿入します。 651 | **`vthk`**: 652 | 6/18 em のスペースを挿入します。 653 | **`sthk`**: 654 | 7/18 em のスペースを挿入します。 655 | **`uthk`**: 656 | 8/18 em のスペースを挿入します。 657 | **`hlf`**: 658 | 9/18 em のスペースを挿入します。 659 | **`sgl`**: 660 | 18/18 em のスペースを挿入します。 661 | **`ssq`**: 662 | 27/18 em のスペースを挿入します。 663 | **`dbl`**: 664 | 36/18 em のスペースを挿入します。 665 | 666 | これ以外の量のスペースを挿入したい場合は、クラスは指定せず、`style` 属性を用いて CSS から直接指定してください。 667 | ただし、数式感のスペーシングの統一感を崩す可能性があるので、この方法はあまり推奨されません。 668 | 669 | ### 空間の確保 (`math-phantom`) 670 | ```html 671 | 672 | 673 | 674 | ``` 675 | 内容を実際に描画したのと同じだけの空間を専有しますが、内容は実際には描画されません。 676 | 表で位置揃えしたいときなどに利用できます。 677 | 678 | 以下のクラスを付けることで、確保する空間を縦方向もしくは横方向のみに限定することができます。 679 | 680 | **`hor`**: 681 | 横方向のみの空間を確保します。 682 | 縦方向の長さは 0 になります。 683 | **`ver`**: 684 | 縦方向のみの空間を確保します。 685 | 横方向の長さは 0 になります。 686 | 687 | ### グループ化 (`math-group`) 688 | ```html 689 | 690 | 691 | 692 | ``` 693 | 数式をグループ化して 1 つの要素にまとめます。 694 | 添字が付いたテンソル積の記号全体を 1 つの二項演算子として描画したい場合など、数式の一部分に 1 つの共通クラスを指定したい場合に用いられます。 695 | また、`style` 属性を指定することで、数式の一部分の色や背景色を変更したりすることにも利用できます。 -------------------------------------------------------------------------------- /document/command.md: -------------------------------------------------------------------------------- 1 | ## `zotica` コマンド 2 | 3 | ### 概要 4 | Zotica で書かれた数式を含む ZenML ドキュメントの変換や、Zotica 単体の HTML への変換など、Zotica のメイン処理を行います。 5 | 6 | 基本的に以下の形で使います。 7 | ``` 8 | zotica (入力ファイル名) 9 | ``` 10 | 入力ファイル名を省略すると、標準入力から入力を受け付けます。 11 | 12 | オプションの指定方法は以下の通りです。 13 | オプションは、ハイフンで始まるオプション名の後に、(必要ならば) スペースで区切って引数を置くことで指定します。 14 | 複数のオプションを指定したい場合は、スペースで区切ってください。 15 | 例えば、以下のようになります。 16 | ``` 17 | zotica index.zml -o index.html -f font.json 18 | zotica input.txt -s 19 | ``` 20 | 21 | このコマンドには 4 種類のモードがあり、`-z`, `-l`, `-j`, `-s` のいずれかを指定することでモードを切り替えられます。 22 | これらのいずれも指定されなかった場合は、`-z` が指定されたものと見なされます。 23 | 24 | 以下のオプションは、モードによらず共通です。 25 | 26 | **`-o`**: 27 | 引数に指定された名前のファイルに出力します。 28 | これを省略した場合、標準出力に出力します。 29 | 30 | ### `-z` オプション (もしくは指定なし) 31 | Zotica で書かれた数式を含む ZenML ドキュメントの変換を行います。 32 | 以下のオプションを受け付けます。 33 | 34 | **`-m`**: 35 | ZenML 内で Zotica の数式を書くマクロ名を、引数で指定されたものに設定します。 36 | デフォルト値は `m` です。 37 | **`-r`**: 38 | ZenML 内で Zotica の数式を書くマクロの中において、再び生の HTML を記述するのに用いるマクロ名を、引数で指定されたものに設定します。 39 | デフォルト値は `raw` です。 40 | **`-c`**: 41 | ZenML 内で Zotica 用の CSS と JavaScript を設定するタグに変換されるマクロ名を、引数で指定されたものに設定します。 42 | デフォルト値は `math-resource` です。 43 | **`-f`**: 44 | `zoticaf` コマンドによって生成された文字形データファイルのパスを指定します。 45 | 46 | ### `-l` オプション 47 | Zotica 数式を含む ZenML の変換ではなく、Zotica 数式単体の変換を行います。 48 | 49 | ### `-j` オプション 50 | Zotica の数式をブラウザ上で正しく表示するための JavaScript を出力します。 51 | 52 | ### `-s` オプション 53 | Zotica の数式をブラウザ上で正しく表示するための CSS を出力します。 54 | さらに以下のオプションを受け付けます。 55 | 56 | **`-f`**: 57 | Zotica の数式用フォント ([こちら](https://github.com/Ziphil/ZenithalMathWeb/blob/master/source/zotica/resource/font.otf)) のパスを指定します。 58 | ここで指定されたパスが、そのまま CSS 内にあるウェブフォントの設定部分の URL として書き込まれます。 59 | デフォルト値は `font.otf` です。 60 | 61 | ## `zoticaf` コマンド 62 | 63 | ### 概要 64 | フォントファイルから Zotica に必要なデータを抽出し、JSON 形式で出力します。 65 | 現在、フォントファイルは TTF 形式にのみ対応しています。 66 | 67 | 基本的に以下の形で使います。 68 | ``` 69 | zoticaf (入力ファイル名) 70 | ``` 71 | 入力ファイル名は省略できません。 72 | 73 | 以下のオプションを受け付けます。 74 | アセント値とディセント値は省略可能ですが、そのときのデフォルト値は Times New Roman フォントのものなので、多くの場合で出力が不適切な結果になります。 75 | アセント値とディセント値はあらかじめ調べておき、必ず指定してください。 76 | 77 | **`-o`**: 78 | 引数に指定された名前のファイルに出力します。 79 | これを省略した場合、標準出力に出力します。 80 | **`-a`**: 81 | フォントのアセントの値を指定します。 82 | デフォルト値は `1638` です。 83 | **`-d`**: 84 | フォントのディセントの値を指定します。 85 | デフォルト値は `410` です。 -------------------------------------------------------------------------------- /document/image/sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ziphil/ZenithalMathWeb/be28ee9cc101de9276a3a641abb9961f4614a7dd/document/image/sample.png -------------------------------------------------------------------------------- /document/ruby.md: -------------------------------------------------------------------------------- 1 | ## 基本的な使い方 2 | 3 | ### Zotica を含む ZenML のパース 4 | Zotica を含んだ ZenML をパースするには、`ZoticaParser` クラスのインスタンスを用います。 5 | ただし、パースを行う前に、Zotica 構文を記述するのに用いるマクロの名前を登録する必要があります。 6 | 7 | このパーサーは、ZenML 内の特定のマクロの中身を Zotica 構文と見なし、その部分を表示用の HTML (と等価な XML) に置き換えます。 8 | まず、`register_simple_math_macro` メソッドを用いて、このときのマクロの名前を登録する必要があります。 9 | 10 | また、Zotica が出力する HTML 要素を正しく表示するには、専用の CSS と JavaScript を適用する必要があります。 11 | `register_resource_macro` メソッドを用いてマクロ名を設定しておくと、そのマクロが書かれた位置に、表示に必要な CSS と JavaScript を含んだ `style` 要素と `script` 要素を埋め込むことができます。 12 | 13 | これらの設定後に `run` メソッドを呼ぶと、パースが実行され、その結果として `REXML::Document` インスタンスが返されます。 14 | あとは好きな方法でこれを処理してください。 15 | 16 | 以下は、ZenML ドキュメントを HTML ドキュメントに変換するコード例です。 17 | ```ruby 18 | # ライブラリの読み込み 19 | require 'rexml/document' 20 | require 'zenml' 21 | require 'zotica' 22 | include REXML 23 | include Zenithal 24 | # ファイルの読み込み 25 | source = File.read("sample.zml") 26 | # パーサーの作成 27 | parser = ZoticaParser.new(source) 28 | # Zotica 用のマクロの登録 29 | parser.register_simple_math_macro("m") 30 | parser.register_resource_macro("math-resource") 31 | # パースの実行 32 | document = parser.run 33 | # HTML として保存 34 | html_string = ZenithalConverter.simple_html(document).convert 35 | File.write("sample.html", html_string) 36 | ``` 37 | このようにすると、以下のような ZenML ドキュメントがパースされ HTML に変換できます。 38 | ``` 39 | \zml?|version="1.0"|> 40 | \xml?|version="1.0",encoding="UTF-8"|> 41 | \html< 42 | \head< 43 | ## 数式を正しく表示するための CSS と JavaScript を埋め込む 44 | ## url 属性で Zotica 用数式フォントのパスを設定する 45 | &math-resource|url="font.otf"|> 46 | > 47 | \body< 48 | \p< 49 | ## 登録したマクロ内に Zotica が書ける 50 | 2 次方程式 &m<2> + bx + c = 0> は &m<\sp<2> - 4ac = 0> のとき重解をもち・・・。 51 | > 52 | > 53 | > 54 | ``` 55 | 56 | ### Zotica 単独のパース 57 | ZenML ではなく Zotica 構文単独を HTML に変換したい場合は、`ZoticaSingleParser` クラスを用います。 58 | 59 | このクラスのインスタンスを作成して `run` メソッドを呼ぶと、パースが実行され、その結果として `REXML::Element` インスタンスが返されます。 60 | ```ruby 61 | # ライブラリの読み込み 62 | require 'rexml/document' 63 | require 'zenml' 64 | require 'zotica' 65 | include REXML 66 | include Zenithal 67 | # ファイルの読み込み 68 | source = File.read("only_zotica.zml") 69 | # パーサーの作成 70 | parser = ZoticaSingleParser.new(source) 71 | # パースの実行 72 | document = parser.run 73 | # HTML として保存 74 | html_string = ZenithalConverter.simple_html(document).convert 75 | File.write("only_zotica.html", html_string) 76 | ``` 77 | 78 | なお、このパース結果の HTML だけでは数式を正しく表示することはできず、別途 CSS と JavaScript を読み込んでおく必要があります。 79 | 必要な CSS と JavaScript は、コマンドラインインターフェースの `zotica` コマンドを用いるなどして得ることができます。 80 | 81 | ## CSS と JavaScript の直接生成 82 | Zotica が出力する HTML 要素を正しく表示するための CSS と JavaScript は、Ruby から直接生成することもできます。 83 | 以下のようにしてください。 84 | ```ruby 85 | # JavaScript の生成 86 | javascript_string = ZoticaBuilder.create_script_string 87 | # CSS の生成 88 | font_url = "font.otf" 89 | css_string = ZoticaBuilder.create_style_string(font_url) 90 | ``` -------------------------------------------------------------------------------- /document/tutorial.md: -------------------------------------------------------------------------------- 1 | ## 下準備 2 | 3 | ### Ruby のインストール 4 | [Ruby](https://www.ruby-lang.org/ja/) の最新バージョンをインストールしてください。 5 | 少なくともバージョン 2.5 以上が必要です。 6 | 7 | 以下のコマンドで、Ruby と Gem が呼び出せるか確認できます。 8 | ``` 9 | ruby -v 10 | gem -v 11 | ``` 12 | 13 | ### ZenML と Zotica の処理系のインストール 14 | RubyGems から ZenML と Zotica の処理系をそれぞれインストールします。 15 | 以下のコマンドを実行してください。 16 | ``` 17 | gem install zenml 18 | gem install zotica 19 | ``` 20 | 21 | ### Zotica Math フォントのダウンロード 22 | Zotica を正しく表示するには、専用の数式記号用フォントをダウンロードする必要があります。 23 | [こちら](https://github.com/Ziphil/ZenithalMathWeb/blob/master/source/zotica/resource/font.otf)からダウンロードし、作業フォルダに置いてください。 24 | 25 | ## 変換 26 | 27 | ### ZenML ドキュメントの作成 28 | HTML に変換したい ZenML ドキュメントを作り、作業フォルダに `index.zml` として保存してください。 29 | 例えば以下のような感じです。 30 | ``` 31 | \zml?|version="1.0"|> 32 | \html< 33 | \head< 34 | \meta|charset="UTF-8"|> 35 | ## Zotica 用の CSS と JavaScript の埋め込み 36 | ## font-url 属性には数式用フォントのパスを指定します 37 | &math-resource|font-url="font.otf"|> 38 | \title 39 | > 40 | \body< 41 | \h1 42 | \p< 43 | ## m マクロで Zotica を記述 44 | &m<\sb<0> = \frac<-b \pm> \sqrt<\sp<2> - 4 ac>><2 a>> 45 | > 46 | \p< 47 | &m<\frac<`p><2> = \sum<\infty>> \frac<(2 k)!><\sp<2><2 k> \sp<(k !)><2>> \frac<1><2 k + 1> = \prod<\infty>> \frac<4 \sp<2>><4 \sp<2> - 1>> 48 | > 49 | \p< 50 | &m<\widehat<\frak (V)> = \bigoplus \bb> (\un<\underbrace V \otimes> \cdots> \otimes> V>>>)> 51 | > 52 | > 53 | > 54 | ``` 55 | 56 | ### フォントの文字形データの抽出 57 | アクセント記号などを正しい位置に表示するため、HTML の本文に使われるフォントのデータをあらかじめ抽出しておく必要があります。 58 | この作業を行わなくてもある程度綺麗に数式を組むことはできるので、面倒であればこのセクションの作業は飛ばしても構いません。 59 | 60 | 本文フォントに使う TrueType 形式のフォントファイルを用意し、作業フォルダに `main.ttf` という名前で保存します。 61 | さらに、フォントのアセントとディセントの量をあらかじめ調べておいてください。 62 | この状態で、以下のコマンドを実行してください。 63 | ``` 64 | zoticaf main.ttf -o main.json -a (アセント) -d (ディセント) 65 | ``` 66 | 同じフォルダ内に `main.json` が生成されます。 67 | 68 | アセントとディセントは省略できますが、これを正しく指定しないと数式のレイアウトが少し崩れる可能性があります。 69 | この点はユーザーフレンドリーではないと感じているので、今後修正していく予定です。 70 | 71 | ### 変換 72 | ZenML ドキュメントの変換を行います。 73 | 前のセクションで文字形データの抽出を行っている場合は、以下のコマンドを実行してください。 74 | ``` 75 | zotica index.zml -f main.json -o index.html 76 | ``` 77 | 文字形データがない場合は、`-f` オプションを指定せず、以下のコマンドを実行してください。 78 | ``` 79 | zotica index.zml -o index.html 80 | ``` 81 | 同じフォルダ内に `index.html` が生成されます。 -------------------------------------------------------------------------------- /document/zotica/1.0.md: -------------------------------------------------------------------------------- 1 | ## コマンドの構成 2 | Zotica では、以下のような形式の「コマンド」と呼ばれる構文を組み合わせることで数式を記述します。 3 | ``` 4 | ## 基本形 5 | \コマンド名|属性="値",・・・,属性="値"|<引数>・・・<引数> 6 | ## 属性が存在しない場合 7 | \コマンド名<引数>・・・<引数> 8 | ## 引数が存在しない場合 9 | \コマンド名|属性="値",・・・,属性="値"|> 10 | ## 属性も引数も存在しない場合 11 | \コマンド名> 12 | ``` 13 | 属性の値が意味をもたない (属性の存在だけに意味がある) 場合は、値を省略することができます。 14 | 例えば、最初の属性の値を省略した場合、`\コマンド名|属性,属性="値",・・・,属性="値"|<引数>` のようになります。 15 | 16 | 常に複数の引数を渡すことができる点を除けば、Zotica のコマンドは ZenML の要素と同じ構文になっています。 17 | したがって、文字のエスケープやコメントの方法などは ZenML に準じます。 18 | 19 | コマンドによって意味のある属性や引数の個数は決まっていますが、属性や引数が余分に指定されていても、エラーにはならず単に無視されます。 20 | また、引数が足りない場合でも、エラーにならず空ノードが指定されたと見なされます。 21 | 22 | コマンドは、基本コマンドとユーティリティコマンドの 2 種類に分かれます。 23 | 基本コマンドとは、数式を記述するための最低限のコマンドの集まりです。 24 | 基本コマンドだけで (Zotica が対応している範囲の) あらゆる数式が書けますが、しばしば記述が冗長になってしまうので、より簡潔に書けるように用意されているのがユーティリティコマンドです。 25 | 26 | ## ギリシャ文字エスケープ 27 | Zotica では、ZenML のエスケープ構文が拡張されていて、`` ` `` の直後にラテン文字を置くと対応するギリシャ文字に変換されます。 28 | ラテン文字とギリシャ文字の対応は、[定義ファイル](../../source/zotica/resource/math.json)の `greek` キーを参照してください。 29 | 30 | ## アトムクラス 31 | Zotica のコマンドのいずれに対しても、以下の属性を指定することができ、そのコマンドが表す数式要素の種類を指定することができます。 32 | これらの属性は存在だけが意味をもちます。 33 | ここで指定される数式要素の種類は「アトムクラス」と呼ばれ、左右に挿入されるスペースの量が変化します。 34 | 35 | **`ord`**: 36 | 数値や変数名などの文字列であることを意味します。 37 | スペーシングはなされません。 38 | **`bin`**: 39 | 二項演算子であることを意味します。 40 | 左右に 4/18 em のスペースが追加されます。 41 | **`rel`**: 42 | 二項関係子であることを意味します。 43 | 左右に 5/18 em のスペースが追加されます。 44 | **`sbin`**: 45 | 左右の空きが広めの二項演算子であることを意味します。 46 | 左右に 8/18 em のスペースが追加されます。 47 | **`srel`**: 48 | 左右の空きが広めの二項関係子であることを意味します。 49 | 左右に 8/18 em のスペースが追加されます。 50 | **`del`**: 51 | コンマやセミコロンなどの区切り記号であることを意味します。 52 | 右にのみ 5/18 em のスペースが追加されます。 53 | **`fun`**: 54 | 関数名であることを意味します。 55 | 右にのみ 3/18 em のスペースが追加されますが、開き括弧 (`par` クラスか `lpar` クラスをもつ要素) が後続した場合はこのスペースは挿入されません。 56 | **`not`**: 57 | 先行する記号に重ね打ちする記号であることを意味します。 58 | 否定を表すスラッシュにのみ使われる特殊なクラスなので、このクラスを明示的に用いることはおそらくありません。 59 | **`par`**: 60 | 括弧で囲まれた部分であることを意味します。 61 | **`lpar`**: 62 | 括弧の左側 (開き括弧) であることを意味します。 63 | **`rpar`**: 64 | 括弧の右側 (閉じ括弧) であることを意味します。 65 | **`cpar`**: 66 | 集合の内包表記など括弧の間の区切り記号であることを明示します。 67 | 左右に 5/18 em のスペースが追加されます。 68 | 69 | ## テキストノードのパース 70 | Zotica では、マークアップを簡便にするため、テキストノードは内容がパースされてコマンド列に変換されます。 71 | 具体的には、以下のような動作をします。 72 | 73 | まず、全てのスペースは無視されます。 74 | さらに、ハイフン (U+002D) とアスタリスク (U+002A) は、それぞれマイナス記号 (U+2212) とアスタリスク演算子 (U+2217) に置き換えられます。 75 | 76 | その上で、数字 (Unicode カテゴリーが Number の文字) の連続した列は、まとめて `n` コマンドに変換されます。 77 | アルファベット (Unicode カテゴリーが Letter か Mark の文字) は、1 文字ずつがそれぞれ 1 つの `i` コマンドに変換されます。 78 | それ以外の文字は、1 文字ずつがそれぞれ 1 つの `o` コマンドに変換されます。 79 | 80 | この `o` コマンドに変換される際、Zotica が同じ記号を出力するユーティリティコマンドを提供しているのであれば、そのコマンドを用いた場合に付けられるアトムクラスが自動的に付けられます。 81 | 同じ記号を出力するコマンドが存在しない場合は、`bin` クラスが付けられます。 82 | 83 | アポストロフィー (U+0027) だけは例外で、`o` コマンドには変換されず、`\sp<><\pr>>` という記述に変換されます。 84 | 85 | `n`, `i`, `op`, `o`, `bf`, `rm`, `bfrm`, `text`, `bb`, `cal`, `scr`, `frak` の 12 種類のコマンドでは、ここでのテキストノードのパースは行われず、テキストはそのまま保持されます。 86 | このようなコマンドは、[定義ファイル](../../source/zotica/resource/math.json)の `leaf` キーで一覧できます。 87 | 88 | ## 基本コマンド 89 | 90 | ### 数値 (`n`) 91 | ``` 92 | \n<数値> 93 | ``` 94 | 数値を記述します。 95 | 96 | 引数にはテキストノードのみを指定し、コマンドは含めないでください。 97 | 98 | このコマンドを使用しなくてもテキスト内の数字列は数値だと解釈されるので、このコマンドを明示的に使うことは基本的にないでしょう。 99 | ただし、特定の数字列に何らかのアトムクラスを付けたい場合には利用できるかもしれません。 100 | 101 | ### 識別子 (`i`) 102 | ``` 103 | \i<識別子> 104 | ``` 105 | 変数名や関数名などの識別子を記述します。 106 | 107 | 引数にはテキストノードのみを指定し、コマンドは含めないでください。 108 | 109 | 識別子は常に本文フォントのイタリック体で描画されます。 110 | `t` 属性に以下の値を指定することで、描画に用いるフォントを変更することができます。 111 | 複数指定したい場合はコンマで区切ってください。 112 | 113 | **`rm`**: 114 | ローマン体で描画します。 115 | **`bf`**: 116 | ボールド体で描画します。 117 | デフォルトがイタリック体なので、このクラスを付けただけではボールドイタリック体で描画されることになります。 118 | ボールドローマン体で描画したい場合は、`rm` 属性と併用してください。 119 | **`alt`**: 120 | カリグラフィー体やフラクトゥール体などを表示するために、数式フォントで描画します。 121 | これらの書体の文字は Unicode 上の専用のブロック (U+1D400 ~ U+1D7FF と U+2100 ~ U+214F の一部) に収録されていますが、そこの文字への自動変換は行われません。 122 | あくまで、数式フォントで描画するようになるだけです。 123 | 124 | テキストノードのパースでは、1 文字がそれぞれ 1 つの識別子と解釈されてしまうので、2 文字以上の識別子を記述したい場合はこのコマンド (か類似のユーティリティコマンド) を利用する必要があります。 125 | 126 | ### 記号 (`o`) 127 | ``` 128 | \o<記号> 129 | ``` 130 | 演算子などの記号を記述します。 131 | 132 | 引数にはテキストノードのみを指定し、コマンドは含めないでください。 133 | 134 | 記号は常に数式フォントで描画されます。 135 | `t` 属性に以下の値を指定することで、描画に用いるフォントを変更することができます。 136 | 複数指定したい場合はコンマで区切ってください。 137 | 138 | **`txt`**: 139 | 本文フォントで描画します。 140 | 141 | だいたいの数学記号は、専用のユーティリティコマンドが用意されていて、そちらを利用する方が入力も簡単なため、`o` コマンドを明示的に用いることはほとんどないでしょう。 142 | あらかじめ定義されている記号以外の記号を使いたいときに、この `o` コマンドが利用できます。 143 | 144 | ### テキスト (`text`) 145 | ``` 146 | \text<テキスト> 147 | ``` 148 | 数式ではない通常のテキストを表します。 149 | 150 | 引数にはテキストノードのみを指定し、コマンドは含めないでください。 151 | 152 | ### 括弧 (`fence`) 153 | ``` 154 | \fence<内容> 155 | ``` 156 | 括弧囲みの数式を描画します。 157 | 158 | 囲むのに用いる括弧やその大きさを、以下の属性で指定することができます。 159 | 160 | **`l`**: 161 | 左側の括弧 (開き括弧) の種類を指定します。 162 | 省略した場合、`paren` が指定されたと見なされます。 163 | **`r`**: 164 | 右側の括弧 (閉じ括弧) の種類を指定します。 165 | 省略した場合、`paren` が指定されたと見なされます。 166 | **`s`**: 167 | 括弧の伸縮レベルを指定します。 168 | `0` から `12` までの整数を指定してください。 169 | 括弧の種類によっては全ての伸縮レベルに対応していないことがありますが、そのような値が指定された場合は、最も大きい括弧で描画されます。 170 | 省略した場合、中身の数式要素の大きさに応じて適切な大きさが選択されます。 171 | 172 | 括弧の種類は以下から選択できます。 173 | これらは[定義ファイル](../../source/zotica/resource/math.json)の `fence` キーで一覧できます。 174 | 175 | **`paren`**: 176 | 通常の丸括弧です。 177 | **`pparen`**: 178 | 白抜きの丸括弧 (もしくは二重の丸括弧) です。 179 | **`bracket`**: 180 | 角括弧です。 181 | **`bbracket`**: 182 | 白抜きの角括弧 (もしくは二重の角括弧) です。 183 | 形式言語の意味を表す括弧 (いわゆるオックスフォードブラケット) としてよく用いられます。 184 | **`brace`**: 185 | 波括弧です。 186 | **`bbrace`**: 187 | 白抜きの波括弧 (もしくは二重の波括弧) です。 188 | **`vert`**: 189 | 縦線です。 190 | 絶対値記号として使われる他、集合の内包表記の区切り線としても使われます。 191 | **`vvert`**: 192 | 二重の縦線です。 193 | **`floor`**: 194 | 床関数を表す括弧です。 195 | **`ceil`**: 196 | 天井関数を表す括弧です。 197 | **`angle`**: 198 | 山括弧です。 199 | **`aangle`**: 200 | 二重の山括弧です。 201 | **`tort`**: 202 | 亀甲括弧です。 203 | 角括弧 (`bracket` の括弧) よりも上下隅の角張った部分の角度が緩やかになっています。 204 | **`none`**: 205 | 括弧を表示しません。 206 | 左右片方だけに括弧を付けたい場合に利用できます。 207 | 208 | 開き括弧と閉じ括弧が同じ場合は、括弧の種類と同名のユーティリティコマンドが用意されているので、そちらを使う方が簡便です。 209 | ただし、半開区間を記述する場合など、開き括弧と閉じ括弧が異なる場合は、`fence` コマンドでしか描画できません。 210 | 211 | ### 区切り記号付き括弧 (`set`) 212 | ``` 213 | \set<左側内容><右側内容> 214 | ``` 215 | 集合の内包表記のような、中央の区切り線を境として左右に数式要素をもつ括弧囲みの数式を描画します。 216 | 217 | 囲むのに用いる括弧やその大きさを、以下の属性で指定することができます。 218 | 219 | **`l`**: 220 | 左側の括弧 (開き括弧) の種類を指定します。 221 | 省略した場合、`brace` が指定されたと見なされます。 222 | **`r`**: 223 | 右側の括弧 (閉じ括弧) の種類を指定します。 224 | 省略した場合、`brace` が指定されたと見なされます。 225 | **`c`**: 226 | 区切り線の種類を指定します。 227 | 省略した場合、`vert` が指定されたと見なされます。 228 | **`s`**: 229 | 括弧および区切り線の伸縮レベルを指定します。 230 | `0` から `12` までの整数を指定してください。 231 | 括弧の種類によっては全ての伸縮レベルに対応していないことがありますが、そのような値が指定された場合は、最も大きい括弧で描画されます。 232 | 省略した場合、中身の数式要素の大きさに応じて適切な大きさが選択されます。 233 | 234 | 指定できる括弧の種類は `fence` コマンドと同様です。 235 | 236 | ### 下付きと上付き (`multi`) 237 | ``` 238 | \multi<核要素><右下添字><右上添字><左下添字><左上添字> 239 | ``` 240 | 上付きや下付きなどの添字が付けられた数式を描画します。 241 | 各添字要素は核要素の大きさに基づいて配置されます。 242 | 243 | 核要素が 1 つのコマンドだけから成り、そのコマンドにアトムクラスが設定されていた場合、`multi` コマンドにも自動的に同じアトムクラスが設定されます。 244 | 245 | 多くの場合で添字は右側のみに付けられるため、右側の添字のみを記述できる引数の少ないユーティリティコマンド (`sb`, `sp`, `sbsp`) も用意されています。 246 | 左側の添字は `multi` コマンドを利用しないと記述できません。 247 | 248 | ### アンダースクリプトとオーバースクリプト (`unov`) 249 | ``` 250 | \unov<核要素><下添字><上添字> 251 | ``` 252 | 核要素の真下もしくは真上に添字が付けられた数式を描画します。 253 | 254 | 核要素が 1 つのコマンドだけから成り、そのコマンドにアトムクラスが設定されていた場合、`unov` コマンドにも自動的に同じアトムクラスが設定されます。 255 | 256 | 真上もしくは真下のみに添え字を付けたい場合は、引数の少ないユーティリティコマンド (`un`, `ov`) も利用できます。 257 | 258 | ### 分数 (`frac`) 259 | ``` 260 | \frac<分子><分母> 261 | ``` 262 | 分数を描画します。 263 | 264 | ### 根号 (`sqrt`) 265 | ``` 266 | \sqrt<内容><指数> 267 | ``` 268 | 根号記号とその中身を描画します。 269 | 270 | 根号記号の大きさは、以下の属性で指定することができます。 271 | 272 | **`s`**: 273 | 根号記号の伸縮レベルを指定します。 274 | `0` から `3` までの整数を指定してください。 275 | 省略した場合、中身の数式要素の大きさに応じて適切な大きさが選択されます。 276 | 277 | ### 積分様記号 (`intlike`) 278 | ``` 279 | \intlike<下添字><上添字> 280 | ``` 281 | 積分様記号とそれに付随する添字を描画します。 282 | 283 | 以下の属性が指定できます。 284 | 285 | **`k`**: 286 | 積分様記号の種類を指定します。 287 | 指定できる値は後述します。 288 | **`in`**: 289 | インライン数式用の小型の積分様記号で描画します。 290 | これを省略した場合、ディスプレイ数式用の大型の積分様記号で描画します。 291 | この属性は存在だけが意味をもちます。 292 | 293 | 積分様記号の種類のうち、主要なものを以下に示します。 294 | これ以外にも、[定義ファイル](../../source/zotica/resource/math.json)の `integral` キーで定義されているものが利用できます。 295 | 296 | **`int`**: 297 | 通常の積分記号です。 298 | **`iint`**: 299 | 二重積分記号です。 300 | **`iiint`**: 301 | 三重積分記号です。 302 | **`oint`**: 303 | 周回積分記号です。 304 | 通常の積分記号の中央に円が描かれます。 305 | 306 | 積分様記号の種類と同名のユーティリティコマンドが用意されているので、そちらを使う方が簡便です。 307 | そのため、`intlike` コマンドを利用する場面はほとんどないでしょう。 308 | 309 | ### 総和様記号 (`sumlike`) 310 | ``` 311 | \sumlike<下添字><上添字> 312 | ``` 313 | 総和様記号とそれに付随する添字を描画します。 314 | 315 | 以下の属性が指定できます。 316 | 317 | **`k`**: 318 | 総和様記号の種類を指定します。 319 | 指定できる値は後述します。 320 | **`in`**: 321 | インライン数式用の小型の総和様記号で描画し、添字を総和様記号の右上と右下に配置します。 322 | これを省略した場合、ディスプレイ数式用の大型の総和様記号で描画し、添字を総和様記号の真上と真下に配置します。 323 | この属性は存在だけが意味をもちます。 324 | 325 | 総和様記号の種類のうち、主要なものを以下に示します。 326 | これ以外にも、[定義ファイル](../../source/zotica/resource/math.json)の `sum` キーで定義されているものが利用できます。 327 | 328 | **`sum`**: 329 | 総和記号 (大きなギリシャ文字シグマ) です。 330 | **`prod`**: 331 | 総乗記号 (大きなギリシャ文字パイ) です。 332 | **`coprod`**: 333 | 直和や余積の記号です。 334 | 総乗記号を上下反転した形をしています。 335 | **`bigcap`**: 336 | 集合の共通部分を表す記号です。 337 | **`bigcup`**: 338 | 和集合を表す記号です。 339 | 340 | 総和様記号の種類と同名のユーティリティコマンドが用意されているので、そちらを使う方が簡便です。 341 | そのため、`sumlike` コマンドを利用する場面はほとんどないでしょう。 342 | 343 | ### アクセント付き文字 (`accent`) 344 | ``` 345 | \accent<文字> 346 | ``` 347 | アクセント付きの文字を描画します。 348 | 349 | 付けるアクセント記号の種類は、以下の属性で指定します。 350 | 351 | **`k`**: 352 | アクセント記号の種類を指定します。 353 | 指定できる値は後述します。 354 | 355 | アクセント記号の種類のうち、主要なものを以下に示します。 356 | これ以外にも、[定義ファイル](../../source/zotica/resource/math.json)の `accent` キーで定義されているものが利用できます。 357 | 358 | **`tilde`**: 359 | 文字の上に付くチルダです。 360 | **`hat`**: 361 | 文字の上に付くハット (もしくはサーカムフレックスやキャレット) です。 362 | **`check`**: 363 | 文字の上に付くハーチェク (もしくはキャロン) です。 364 | **`bar`**: 365 | 文字の上に付くバーです。 366 | **`vec`**: 367 | 文字の上に付く右向きの矢印です。 368 | **`dot`**: 369 | 文字の上に付くドットです。 370 | **`tildebelow`**: 371 | 文字の下に付くチルダです。 372 | 373 | 核要素として置かれる数式要素に文法的な制限はありませんが、アクセント記号のデザイン上 1 文字のみであることが想定されています。 374 | 核要素が横に長く、それに伴ってアクセント記号も伸縮させたい場合は、`wide` コマンド (か類似のユーティリティコマンド) を利用してください。 375 | 376 | アクセント記号の種類と同名のユーティリティコマンドが用意されているので、そちらを使う方が簡便です。 377 | そのため、`accent` コマンドを利用する場面はほとんどないでしょう。 378 | 379 | ### 伸縮アクセント付き文字 (`wide`) 380 | ``` 381 | \wide<核要素> 382 | ``` 383 | 伸縮するアクセント付きの数式を描画します。 384 | 385 | 以下の属性が指定できます。 386 | 387 | **`k`**: 388 | アクセント記号の種類を指定します。 389 | 指定できる値は後述します。 390 | **`s`**: 391 | アクセント記号の伸縮レベルを指定します。 392 | `0` から `5` までの整数を指定してください。 393 | アクセント記号の種類によっては全ての伸縮レベルに対応していないことがありますが、そのような値が指定された場合は、最も大きい括弧で描画されます。 394 | 省略した場合、核要素の大きさに応じて適切な大きさが選択されます。 395 | 396 | 伸縮アクセント記号の種類のうち、主要なものを以下に示します。 397 | これ以外にも、[定義ファイル](../../source/zotica/resource/math.json)の `wide` キーで定義されているものが利用できます。 398 | 399 | **`widetilde`**: 400 | 文字の上に付くチルダです。 401 | **`widehat`**: 402 | 文字の上に付くハット (もしくはサーカムフレックスやキャレット) です。 403 | **`widecheck`**: 404 | 文字の上に付くハーチェク (もしくはキャロン) です。 405 | **`overline`**: 406 | 文字の上に付く直線です。 407 | **`overrarr`**: 408 | 文字の上に付く右向きの矢印です。 409 | **`overbrace`**: 410 | 文字の上に付く波括弧です。 411 | **`widetildebelow`**: 412 | 文字の下に付くチルダです。 413 | **`underline`**: 414 | 文字の下に付く直線です。 415 | **`underbrace`**: 416 | 文字の下に付く波括弧です。 417 | 418 | 伸縮アクセント記号の種類と同名のユーティリティコマンドが用意されているので、そちらを使う方が簡便です。 419 | そのため、`wide` コマンドを利用する場面はほとんどないでしょう。 420 | 421 | ### 表 (`table`) 422 | ``` 423 | \table<セルコマンド> 424 | ``` 425 | 行列やイコール揃えなど、複数の数式要素を表形式で描画します。 426 | 427 | 描画する表の種類を `t` 属性で指定してください。 428 | `t` 属性には以下の値のいずれかを指定できます。 429 | 430 | **`std`**: 431 | 水平方向にスペースを挿入しない最もシンプルな表として描画します。 432 | イコール揃えの数式などに利用できます。 433 | **`mat`**: 434 | 行列として描画します。 435 | 各成分が独立するよう、水平方向に一定量のスペースが挿入されます。 436 | 括弧は描画されないので、別途 `fence` コマンドなどで囲む必要があります。 437 | **`cas`**: 438 | 場合分けとして描画します。 439 | 1 列目と 2 列目の間に、適切な量のスペースが挿入されます。 440 | 場合分けであることを表す左側の中括弧は描画されないので、別途 `fence` コマンドなどで囲む必要があります。 441 | **`stk`**: 442 | 総和記号などの大型演算子の添字に 2 行以上の数式を描画したいときに利用できます。 443 | 添字として置いたときに自然に見えるよう、鉛直方向のスペースが小さめになっています。 444 | 445 | 子要素には、次で説明する `c` コマンドもしくは `br` コマンドのみを置くことができます。 446 | 447 | 各属性に対応したユーティリティコマンドがそれぞれ用意されているので、そちらも利用できます。 448 | 449 | ### 表のセル (`c`, `br`) 450 | ``` 451 | \c<内容> 452 | \br> 453 | ``` 454 | 表を構成する各セルを描画します。 455 | `c` コマンドはセルの内容となる数式要素を表し、`br` コマンドはセルの描画位置を表内の次の行にすることを表します。 456 | これらのコマンドは `table` コマンドの直下に置いてください。 457 | 458 | ### 図式 (`diag`) 459 | ``` 460 | \diag<セルコマンド> 461 | ``` 462 | 図式を描画します。 463 | 464 | セル間の間隔を以下の属性で指定することができます。 465 | 466 | **`hor`**: 467 | 水平方向の間隔です。 468 | 指定できる値は後述します。 469 | 省略した場合は `med` が指定されたものと見なされます。 470 | **`ver`**: 471 | 鉛直方向の間隔です。 472 | 指定できる値は後述します。 473 | 省略した場合は `med` が指定されたものと見なされます。 474 | 475 | 間隔には以下の値が指定できます。 476 | 1 つの値を指定すると、全ての列もしくは行の間に指定されたスペースが空けられます。 477 | 複数の値をコンマで区切って指定すると、左もしくは上から順に指定されたスペースが空けられます。 478 | 479 | **`non`**: 480 | スペースは空きません。 481 | **`sthn`**: 482 | 水平方向には 12/18 em, 鉛直方向には 9/18 em のスペースを空けます。 483 | **`vthn`**: 484 | 水平方向には 24/18 em, 鉛直方向には 18/18 em のスペースを空けます。 485 | **`thn`**: 486 | 水平方向には 48/18 em, 鉛直方向には 36/18 em のスペースを空けます。 487 | **`med`**: 488 | 水平方向には 72/18 em, 鉛直方向には 54/18 em のスペースを空けます。 489 | **`thk`**: 490 | 水平方向には 96/18 em, 鉛直方向には 72/18 em のスペースを空けます。 491 | **`vthk`**: 492 | 水平方向には 120/18 em, 鉛直方向には 90/18 em のスペースを空けます。 493 | **`sthk`**: 494 | 水平方向には 144/18 em, 鉛直方向には 108/18 em のスペースを空けます。 495 | **`uthk`**: 496 | 水平方向には 168/18 em, 鉛直方向には 126/18 em のスペースを空けます。 497 | **数値**: 498 | 上記の識別子の他、数値を直接指定することができます。 499 | 単位は 1/18 em です。 500 | 501 | 子要素には、次で説明する `v` コマンド, `br` コマンド, `ar` コマンドのみを置くことができます。 502 | 503 | ### 図式のセル (`v`, `br`) 504 | ``` 505 | \v<内容> 506 | \br> 507 | ``` 508 | 図式中のセルを描画します。 509 | `v` コマンドはセルの内容となる数式要素を表し、`br` コマンドはセルの描画位置を表内の次の行にすることを表します。 510 | これらのコマンドは `diag` コマンドの直下に置いてください。 511 | 512 | `v` コマンドには以下の属性を指定できます。 513 | 514 | **`name`**: 515 | セルに名前を付けます。 516 | この名前は、図式の矢印の端点を指定するときに利用できます。 517 | 省略した場合、名前は付けられません。 518 | 519 | ### 図式の矢印とラベル (`ar`) 520 | ``` 521 | \ar<ラベル> 522 | ``` 523 | 図式の矢印とそれに付随するラベルを描画します。 524 | このコマンドは `diag` コマンドの直下に置いてください。 525 | 526 | 矢印の端点位置やスタイルなどを、以下の属性で指定できます。 527 | `s` と `e` は必須です。 528 | 529 | **`s`**: 530 | 矢印の始点の位置を指定します。 531 | 指定方法は後述します。 532 | **`e`**: 533 | 矢印の終点の位置を指定します。 534 | 指定方法は後述します。 535 | **`tip`**: 536 | 矢印の始点と終点に付ける鏃を指定します。 537 | 指定方法は後述します。 538 | 省略した場合、終点側にのみ通常の鏃が描画されます。 539 | **`bend`**: 540 | この属性で指定した分だけ、矢印が左に曲がるようになります。 541 | 負の数を指定すると、矢印は右に曲がります。 542 | 単位は deg (90 で直角) です。 543 | 省略した場合、`0` が指定されたと見なされます。 544 | **`shift`**: 545 | この属性で指定した分だけ、矢印が普通に配置したときの位置から左に移動します。 546 | 負の数を指定すると、矢印は右に移動します。 547 | 単位は 1/18 em です。 548 | 省略した場合、`0` が指定されたと見なされます。 549 | **`line`**: 550 | 矢印を何重線で描画するか指定します。 551 | `0`, `1`, `2`, `3` のいずれかのみに対応しています。 552 | `0` を指定すると、鏃も含めて矢印は描画されず、ラベルのみが描画されます。 553 | 省略した場合、`1` が指定されたと見なされます。 554 | **`dash`**: 555 | この属性を指定すると、矢印が破線で描画されます。 556 | この属性は存在するかどうかだけが意味をもちます。 557 | 省略した場合、矢印は実線で描画されます。 558 | **`pos`**: 559 | 矢印に付けられるラベルの位置を変更できます。 560 | `0` を指定すると矢印の始点の真横に、`100` を指定すると矢印の終点の真横に、`50` を指定すると矢印の中間点の真横に、ラベルが配置されます。 561 | 省略した場合、`50` (矢印の中間点の横) を指定したものとしてラベルが描画されます。 562 | **`inv`**: 563 | この属性を指定すると、ラベルが矢印の右側に置かれるようになります。 564 | この属性が存在しない場合、ラベルは矢印の左側に置かれます。 565 | この属性は存在するかどうかだけが意味をもちます。 566 | **`name`**: 567 | ラベルに名前を付け、別の矢印の端点を指定するときに利用できるようにします。 568 | 省略した場合、名前は付けられません。 569 | 570 | 矢印の始点と終点の位置は、以下のフォーマットで指定します。 571 | 角括弧で囲まれた部分は任意であることを意味します。 572 | ``` 573 | (<要素番号>|<要素名>)[:(<方角>|<方向><割合>)] 574 | ``` 575 | 576 | **`<要素番号>`**: 577 | `diag` コマンドの直下にある `v` コマンドを先頭からの番号 (1-origin) で指定します。 578 | 例えば、`2` を指定すると、先頭から 2 番目の `v` コマンドによって描画される数式要素を意味します。 579 | **`<要素名>`**: 580 | ここで指定された文字列と同じ `name` 属性値をもつコマンドを表します。 581 | **`<方角>`**: 582 | 矢印の端点を該当要素の枠上のどの位置にするかを指定します。 583 | `n`, `ne`, `e`, `se`, `s`, `sw`, `w`, `nw`, `c` のいずれかで指定します。 584 | `c` は該当要素の枠上ではなく該当要素の中央点を意味します。 585 | 例えば、`ne` を指定すると、該当要素の北東端 (右上端) が矢印の端点になります。 586 | **`<方向>`**: 587 | 矢印の端点を該当要素の枠のどの辺上に配置するかを指定します。 588 | `t`, `r`, `b`, `l` のいずれかで指定し、それぞれ上辺, 右辺, 下辺, 左辺を表します。 589 | **`<割合>`**: 590 | 矢印の端点を `<方向>` の箇所で指定された辺上のどの位置にするかを指定します。 591 | `<方向>` が `t` または `b` の場合、`0` を指定すると該当辺の左端を意味し、`100` を指定すると該当辺の右端を意味します。 592 | また、`<方向>` が `r` または `l` の場合、`0` を指定すると該当辺の上端を意味し、`100` を指定すると該当辺の左端を意味します。 593 | 594 | なお、`<方角>` もしくは `<方向><割合>` を指定しなかった場合は、端点は該当要素の枠上の良い感じの場所に自動的に決まります。 595 | 596 | 例えば、`4` と指定すると、先頭から 4 番目の `v` コマンドによる数式要素の枠上の自動計算された位置が端点となります。 597 | また、`2:ne` とすると、先頭から 2 番目の `v` コマンドの右上端が端点となります。 598 | さらに、`foo:r30` とすると、`foo` という `name` 属性値をもつコマンドの右辺における上端から 30 % の位置が端点となります。 599 | 600 | 鏃の種類は以下のどれかから選択できます。 601 | 種類によって、始点側に付くか終点側に付くかが決まっています。 602 | 始点側と終点側の両方に鏃を付けたい場合は、コンマで区切って指定します。 603 | なお、同じ側に 2 つ以上の鏃を付けることはできないため、同じ側の鏃が 2 つ以上指定された場合は、最後に指定されたもののみが描画されます。 604 | 605 | **`tail`**: 606 | 始点側に付けられる鏃です。 607 | **`hook`**: 608 | 始点側に付けられる半円形の鈎です。 609 | 矢印の左側に曲がるようにして付けられます。 610 | 包含写像を表すのによく用いられます。 611 | **`varhook`**: 612 | 始点側に付けられる半円形の鈎です。 613 | 矢印の右側に曲がるようにして付けられます。 614 | **`head`**: 615 | 終点側に付けられる二重の鏃です。 616 | **`none`**: 617 | 終点側の鏃を描画しません。 618 | 終点側の鏃を何も指定しないと普通の山形の鏃が描画されますが、これを指定することで終点側に鏃を描画しないようにすることができます。 619 | 620 | 1 つの矢印に複数のラベルを付けることはできません。 621 | しかし、ラベルの数だけ `ar` コマンドを用意し、そのうちの 1 つを除いた要素に対して、`line` 属性を `0` に設定して矢印本体を消すことで、1 つの矢印に複数のラベルが付いているように描画することができます。 622 | 623 | ### グループ化 (`g`) 624 | ``` 625 | \g<内容> 626 | ``` 627 | 複数のコマンドを 1 つの数式にまとめます。 628 | 629 | 複数のコマンドから成る箇所にアトムクラスを与えたり、`class` 属性を指定して CSS からスタイルを変更したりするのに利用できます。 630 | 631 | ### 空間の確保 (`ph`) 632 | ``` 633 | \ph<内容> 634 | ``` 635 | 指定された数式要素を実際に描画したときに領有する空間のみを描画し、数式そのものは描画しません。 636 | 637 | `t` 属性に以下のいずれかの値を指定することで、確保する空間の方向を変更できます。 638 | 省略した場合は `bth` が指定されたものと見なされます。 639 | 640 | **`bth`**: 641 | 縦方向にも横方向にも空間を確保します。 642 | **`ver`**: 643 | 縦方向の空間のみを確保し、横方向には空間を挿入しません。 644 | **`hor`**: 645 | 横方向の空間のみを確保し、縦方向には空間を挿入しません。 646 | 647 | ### スペース (`s`) 648 | ``` 649 | \s> 650 | ``` 651 | 横方向に一定のスペースを挿入します。 652 | 引数はありません。 653 | 654 | 挿入するスペースの量は、`t` 属性に以下のいずれかの値を指定することで設定します。 655 | 656 | **`afun`**: 657 | 関数名 (`fun` クラスをもつ要素) の右に挿入されるスペースと同じ量のスペースを挿入します。 658 | 3/18 em です。 659 | **`abin`**: 660 | 二項演算子 (`bin` クラスをもつ要素) の左右に挿入されるスペースと同じ量のスペースを挿入します。 661 | 4/18 em です。 662 | **`arel`**: 663 | 二項関係子 (`rel` クラスをもつ要素) の左右に挿入されるスペースと同じ量のスペースを挿入します。 664 | 5/18 em です。 665 | **`asbin`**: 666 | 左右の空きが広めの二項演算子 (`sbin` クラスをもつ要素) の左右に挿入されるスペースと同じ量のスペースを挿入します。 667 | 8/18 em です。 668 | **`asrel`**: 669 | 左右の空きが広めの二項関係子 (`srel` クラスをもつ要素) の左右に挿入されるスペースと同じ量のスペースを挿入します。 670 | 8/18 em です。 671 | **`amat`**: 672 | 行列 (`mat` を指定した `table` 要素) の成分間に入る水平方向のスペースと同じ量のスペースを挿入します。 673 | 15/18 em です。 674 | **`acas`**: 675 | 場合分け (`cas` を指定した `table` 要素) の成分間に入る水平方向のスペースと同じ量のスペースを挿入します。 676 | 24/18 em です。 677 | **`sthn`**: 678 | 1/18 em のスペースを挿入します。 679 | **`vthn`**: 680 | 2/18 em のスペースを挿入します。 681 | **`thn`**: 682 | 3/18 em のスペースを挿入します。 683 | **`med`**: 684 | 4/18 em のスペースを挿入します。 685 | **`thk`**: 686 | 5/18 em のスペースを挿入します。 687 | **`vthk`**: 688 | 6/18 em のスペースを挿入します。 689 | **`sthk`**: 690 | 7/18 em のスペースを挿入します。 691 | **`uthk`**: 692 | 8/18 em のスペースを挿入します。 693 | **`hlf`**: 694 | 9/18 em のスペースを挿入します。 695 | **`sgl`**: 696 | 18/18 em のスペースを挿入します。 697 | **`ssq`**: 698 | 27/18 em のスペースを挿入します。 699 | **`dbl`**: 700 | 36/18 em のスペースを挿入します。 701 | **数値**: 702 | 上記の識別子の他、数値を直接指定することができます。 703 | 単位は 1/18 em です。 704 | 705 | 上記の値の前に `-` を付けることで、同じ量の負のスペースを挿入することができます。 706 | 例えば、`-thk` を指定すると -5/18 em のスペースが挿入されます。 707 | 708 | いくつかのスペース量については、同じ量のスペースを挿入するユーティリティコマンドも用意されています。 709 | 710 | ## ユーティリティコマンド 711 | 712 | ### フォント指定した識別子 (`bf`, `rm`, `bfrm`) 713 | ``` 714 | \bf<識別子> ≅ \i|t="bf"|<識別子> 715 | \rm<識別子> ≅ \i|t="rm"|<識別子> 716 | \bfrm<識別子> ≅ \i|t="bf,rm"|<識別子> 717 | ``` 718 | フォントを指定した識別子を簡潔に書くためのユーティリティコマンドです。 719 | 720 | いずれのコマンドでも、引数にはテキストノードのみを指定し、コマンドは含めないでください。 721 | 722 | ### 特殊フォントの識別子 (`bb`, `cal`, `scr`, `frak`) 723 | ``` 724 | \bb<文字> ≅ \i|t="alt"|<変換後の文字> 725 | \cal<文字> ≅ \i|t="alt"|<変換後の文字> 726 | \scr<文字> ≅ \i|t="alt"|<変換後の文字> 727 | \frak<文字> ≅ \i|t="alt"|<変換後の文字> 728 | ``` 729 | 黒板太字体やカリグラフィー体などの特殊フォントの文字を記述します。 730 | 通常のラテン文字や数字を、対応する Unicode 上の専用のブロックの文字に変換します。 731 | `bb`, `cal`, `scr`, `frak` はそれぞれ黒板太字体, カリグラフィー体, スクリプト体, フラクトゥール体を意味します。 732 | 733 | いずれのコマンドでも、引数にはテキストノードのみを指定し、コマンドは含めないでください。 734 | また、そのテキストノードは、ラテンアルファベットもしくは通常の数字のみであるようにしてください。 735 | 736 | ### ユーザー定義関数 (`op`) 737 | ``` 738 | \op<関数名> ≅ \i|fun,t="rm"|<関数名> 739 | ``` 740 | lcm や supp などのユーザー定義の関数名を簡潔に書くためのユーティリティコマンドです。 741 | 742 | 引数にはテキストノードのみを指定し、コマンドは含めないでください。 743 | 744 | ### 定義済み識別子 (`varbeta`, `varepsilon`, ・・・) 745 | ``` 746 | \varbeta> ≅ \i<ϐ> 747 | ⋮ 748 | ``` 749 | ギリシャ文字の異体字など、入力しづらい識別子をコマンドとして記述するためのユーティリティコマンドです。 750 | 引数は不要です。 751 | 752 | 定義されている識別子は、[定義ファイル](../../source/zotica/resource/math.json)の `identifier` キーを参照してください。 753 | 754 | ### 定義済み関数 (`sin`, `cos`, ・・・) 755 | ``` 756 | \sin> ≅ \i|fun,t="rm"| 757 | ⋮ 758 | ``` 759 | 汎用の関数名はそれぞれ 1 つのコマンドとしてあらかじめ定義してあります。 760 | 引数は不要です。 761 | 762 | 定義されている関数は、[定義ファイル](../../source/zotica/resource/math.json)の `function` キーを参照してください。 763 | 764 | ### 定義済み記号 (`pm`, `times`, ・・・) 765 | ``` 766 | \pm> ≅ \o|bin|<±> 767 | ⋮ 768 | ``` 769 | だいたいの数学記号は、それを出力するためのユーティリティコマンドが用意されています。 770 | 全て引数は不要です。 771 | 772 | このユーティリティコマンドを仕様すると、自動的にあらかじめ定義されているアトムクラスが付けられます。 773 | コマンドにアトムクラスを明示的に指定することで、あらかじめ定義されたアトムクラスを上書きすることができます。 774 | 775 | 定義されている記号とそのアトムクラスは、[定義ファイル](../../source/zotica/resource/math.json)の `operator` キーを参照してください。 776 | 777 | ### 括弧 (`paren`, `pparen`, ・・・) 778 | ``` 779 | \paren<内容> ≅ \fence|l="paren",r="paren"|<内容> 780 | ⋮ 781 | ``` 782 | 左右の括弧が同じ括弧囲みの数式を描画するユーティリティコマンドです。 783 | 784 | 以下の属性を指定することができます。 785 | 786 | **`s`**: 787 | 括弧の伸縮レベルを指定します。 788 | `fence` コマンドの `s` 属性と同様です。 789 | 790 | 定義されているコマンドは、[定義ファイル](../../source/zotica/resource/math.json)の `fence` キーで一覧できます。 791 | 792 | ### 下付きと上付き (`sb`, `sp`, `sbsp`) 793 | ``` 794 | \sb<核要素><右下添字> ≅ \multi<核要素><右下添字><><><> 795 | \sp<核要素><右上添字> ≅ \multi<核要素><><右上添字><><> 796 | \sbsp<核要素><右下添字><右上添字> ≅ \multi<核要素><右下添字><右上添字><><> 797 | ``` 798 | 右側に付く添字を描画するのに特化したユーティリティコマンドです。 799 | 800 | ### アンダースクリプトとオーバースクリプト (`un`, `ov`) 801 | ``` 802 | \un<核要素><下添字> ≅ \unov<核要素><下添字><> 803 | \ov<核要素><上添字> ≅ \unov<核要素><><上添字> 804 | ``` 805 | 上下一方にのみ添字を描画するのに特化したユーティリティコマンドです。 806 | 807 | ### 積分様記号 (`int`, `iint`, ・・・) 808 | ``` 809 | \int<下添字><上添字> ≅ \intlike|k="int"|<下添字><上添字> 810 | ⋮ 811 | ``` 812 | 特定の積分様記号とそれに付随する添字を描画するユーティリティコマンドです。 813 | 814 | 以下の属性が指定できます。 815 | 816 | **`in`**: 817 | インライン数式用の小型の積分様記号で描画します。 818 | `intlike` コマンドの `in` 属性と同様です。 819 | 820 | 定義されているコマンドは、[定義ファイル](../../source/zotica/resource/math.json)の `integral` キーで一覧できます。 821 | 822 | ### 総和様記号 (`sum`, `prod`, ・・・) 823 | ``` 824 | \sum<下添字><上添字> ≅ \sumlike|k="sum"|<下添字><上添字> 825 | ⋮ 826 | ``` 827 | 特定の総和様記号とそれに付随する添字を描画するユーティリティコマンドです。 828 | 829 | 以下の属性が指定できます。 830 | 831 | **`in`**: 832 | インライン数式用の小型の総和様記号で描画し、添字を総和様記号の右上と右下に配置します。 833 | `sumlike` コマンドの `in` 属性と同様です。 834 | 835 | 定義されているコマンドは、[定義ファイル](../../source/zotica/resource/math.json)の `sum` キーで一覧できます。 836 | 837 | ### アクセント付き文字 (`tilde`, `hat`, ・・・) 838 | ``` 839 | \tilde<文字> ≅ \accent|k="tilde"|<文字> 840 | ⋮ 841 | ``` 842 | 特定のアクセント付きの文字を描画するユーティリティコマンドです。 843 | 844 | 定義されているコマンドは、[定義ファイル](../../source/zotica/resource/math.json)の `accent` キーで一覧できます。 845 | 846 | ### 伸縮アクセント付き文字 (`widetilde`, `widehat`, ・・・) 847 | ``` 848 | \widetilde<核要素> ≅ \wide|k="widetilde"|<各要素> 849 | ⋮ 850 | ``` 851 | 特定の伸縮するアクセント付きの数式を描画するユーティリティコマンドです。 852 | 853 | 以下の属性が指定できます。 854 | 855 | **`s`**: 856 | アクセント記号の伸縮レベルを指定します。 857 | `wide` コマンドの `s` 属性と同様です。 858 | 859 | 定義されているコマンドは、[定義ファイル](../../source/zotica/resource/math.json)の `wide` キーで一覧できます。 860 | 861 | ### 各種表 (`array`, `matrix`, `stack`) 862 | ``` 863 | \array<セルコマンド> ≅ \table|t="std"|<セルコマンド> 864 | \matrix<セルコマンド> ≅ \table|t="mat"|<セルコマンド> 865 | \stack<セルコマンド> ≅ \table|t="stk"|<セルコマンド> 866 | ``` 867 | 特定のスタイルの表を描画するユーティリティコマンドです。 868 | 869 | ### 場合分け (`case`) 870 | ``` 871 | \case<セルコマンド> ≅ \fence|l="brace",r="none"|<\table|t="cas"|<セルコマンド>> 872 | ``` 873 | 場合分けを描画するユーティリティコマンドです。 874 | 875 | `table` コマンドと違い、`case` コマンドは場合分けの左側の波括弧も描画します。 876 | 877 | ### 表の 1 行分のセル (`cc`) 878 | ``` 879 | \cc<内容>・・・<内容> ≅ \c<内容> ・・・ \c<内容> \br> 880 | ``` 881 | 表を構成する各セルの 1 行分をまとめて描画するユーティリティコマンドです。 882 | 引数は何個でも構いません。 883 | 884 | ### 図式の 1 行分のセル (`vv`) 885 | ``` 886 | \vv<内容>・・・<内容> ≅ \v<内容> ・・・ \v<内容> \br> 887 | ``` 888 | 図式中のセルの 1 行分をまとめて描画するユーティリティコマンドです。 889 | 引数は何個でも構いません。 890 | 891 | ### 一方向の空間の確保 (`vph`, `hph`) 892 | ``` 893 | \vph<内容> ≅ \ph|t="ver"|<内容> 894 | \hph<内容> ≅ \ph|t="hor"|<内容> 895 | ``` 896 | 指定された数式要素を実際に描画したときに領有する空間のうち一方向のみを描画するユーティリティコマンドです。 897 | 898 | ### スペース (`sfun`, `sbin`, ・・・) 899 | ``` 900 | \sfun> ≅ \s|t="afun"|> 901 | ⋮ 902 | ``` 903 | 特定の量のスペースを挿入するユーティリティコマンドです。 904 | 905 | 定義されているコマンドは、[ソースファイル](../../source/zotica/builder.rb)の `SPACE_ALTERNATIVES` 定数で一覧できます。 -------------------------------------------------------------------------------- /exec/zotica: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # coding: utf-8 3 | 4 | 5 | require 'optparse' 6 | require 'zotica' 7 | include Zenithal 8 | 9 | 10 | class Executor 11 | 12 | def initialize(args) 13 | @mode, @options, @paths = nil, {}, [] 14 | parser = OptionParser.new 15 | parser.on("-o PATH") do |value| 16 | @options[:output_path] = value 17 | end 18 | parser.on("-m NAME") do |value| 19 | @options[:math_macro_name] = value 20 | end 21 | parser.on("-r NAME") do |value| 22 | @options[:raw_macro_name] = value 23 | end 24 | parser.on("-c NAME") do |value| 25 | @options[:resource_macro_name] = value 26 | end 27 | parser.on("-f PATH") do |value| 28 | @options[:font_path] = value 29 | end 30 | parser.on("-z") do 31 | @mode = nil 32 | end 33 | parser.on("-l") do 34 | @mode = :light 35 | end 36 | parser.on("-j") do 37 | @mode = :script 38 | end 39 | parser.on("-s") do 40 | @mode = :style 41 | end 42 | @paths = parser.parse(args) 43 | end 44 | 45 | def execute 46 | case @mode 47 | when :light 48 | convert(true) 49 | when :script, :style 50 | output_resource 51 | else 52 | convert(false) 53 | end 54 | end 55 | 56 | def convert(only_math = false) 57 | unless @paths.empty? 58 | source = File.read(@paths.first) 59 | else 60 | source = STDIN.read 61 | end 62 | if only_math 63 | parser = ZoticaSingleParser.new(source) 64 | else 65 | parser = ZoticaParser.new(source) 66 | parser.register_simple_math_macro(@options[:math_macro_name] || "m") 67 | parser.register_raw_macro(@options[:raw_macro_name] || "raw") 68 | parser.register_resource_macro(@options[:resource_macro_name] || "math-resource") 69 | end 70 | parser.load_font(@options[:font_path]) 71 | document = parser.run 72 | converter = ZenithalConverter.simple_html(document) 73 | output = converter.convert 74 | if @options[:output_path] 75 | File.write(@options[:output_path], output) 76 | else 77 | STDOUT.print(output) 78 | end 79 | end 80 | 81 | def output_resource 82 | case @mode 83 | when :script 84 | output = ZoticaBuilder.create_script_string 85 | when :style 86 | font_url = @options[:font_path] || "font.otf" 87 | output = ZoticaBuilder.create_style_string(font_url) 88 | end 89 | if @options[:output_path] 90 | File.write(@options[:output_path], output) 91 | else 92 | STDOUT.print(output) 93 | end 94 | end 95 | end 96 | 97 | 98 | executor = Executor.new(ARGV) 99 | executor.execute -------------------------------------------------------------------------------- /exec/zoticaf: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # coding: utf-8 3 | 4 | 5 | require 'optparse' 6 | require 'zotica' 7 | include Zenithal 8 | 9 | 10 | class Executor 11 | 12 | def initialize(args) 13 | @mode, @options, @paths = nil, {}, [] 14 | parser = OptionParser.new 15 | parser.on("-o PATH") do |value| 16 | @options[:output_path] = value 17 | end 18 | parser.on("-a ASCENT", Numeric) do |value| 19 | @options[:ascent] = value.to_f 20 | end 21 | parser.on("-d DESCENT", Numeric) do |value| 22 | @options[:descent] = value.to_f 23 | end 24 | @paths = parser.parse(args) 25 | end 26 | 27 | def execute 28 | case @mode 29 | when :other 30 | else 31 | create_font 32 | end 33 | end 34 | 35 | def create_font 36 | metrics = {} 37 | metrics[:ascent] = @options[:ascent] || 1638 38 | metrics[:descent] = @options[:descent] || 410 39 | metrics[:em] = metrics[:ascent] + metrics[:descent] 40 | output = ZoticaBuilder.create_font_string(:main, @paths.first, metrics) 41 | if @options[:output_path] 42 | File.write(@options[:output_path], output) 43 | else 44 | STDOUT.print(output) 45 | end 46 | end 47 | 48 | end 49 | 50 | 51 | executor = Executor.new(ARGV) 52 | executor.execute -------------------------------------------------------------------------------- /sample/converter/main.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | require 'fileutils' 5 | require 'open3' 6 | require 'pp' 7 | require 'rexml/document' 8 | require 'zenml' 9 | require_relative '../../source/zotica' 10 | 11 | include REXML 12 | include Zenithal 13 | 14 | BASE_PATH = File.expand_path("..", File.dirname($0)).encode("utf-8") 15 | 16 | Kernel.load(File.join(BASE_PATH, "converter/utility.rb")) 17 | Encoding.default_external = "UTF-8" 18 | $stdout.sync = true 19 | 20 | 21 | class SampleConverter < ZenithalConverter 22 | 23 | def initialize(document) 24 | super(document, :text) 25 | end 26 | 27 | def pass_element(element, scope, close = true) 28 | tag = Tag.new(element.name, nil, close) 29 | element.attributes.each_attribute do |attribute| 30 | tag[attribute.name] = attribute.to_s 31 | end 32 | tag << apply(element, scope) 33 | return tag 34 | end 35 | 36 | def pass_text(text, scope) 37 | string = text.to_s 38 | return string 39 | end 40 | 41 | end 42 | 43 | 44 | class WholeSampleConverter 45 | 46 | DOCUMENT_DIR = "sample/document" 47 | MACRO_DIR = "sample/macro" 48 | TEMPLATE_DIR = "sample/template" 49 | OUTPUT_DIR = "sample/out" 50 | 51 | def initialize(args) 52 | end 53 | 54 | def execute 55 | convert_normal 56 | end 57 | 58 | def convert_normal 59 | parser = create_parser 60 | converter = create_converter.tap{|s| s.update(parser.run)} 61 | ZoticaBuilder.save_font_strings 62 | File.write(OUTPUT_DIR + "/main.html", converter.convert) 63 | FileUtils.copy(DOCUMENT_DIR + "/style.css", OUTPUT_DIR + "/style.css") 64 | end 65 | 66 | def create_parser 67 | source = File.read(DOCUMENT_DIR + "/main.zml") 68 | parser = ZoticaParser.new(source) 69 | parser.register_resource_macro("math-resource") 70 | parser.register_raw_macro("raw") 71 | parser.brace_name = "x" 72 | parser.bracket_name = "xn" 73 | parser.slash_name = "i" 74 | Dir.each_child(MACRO_DIR) do |entry| 75 | if entry.end_with?(".rb") 76 | binding = TOPLEVEL_BINDING 77 | binding.local_variable_set(:parser, parser) 78 | Kernel.eval(File.read(MACRO_DIR + "/" + entry), binding, entry) 79 | end 80 | end 81 | return parser 82 | end 83 | 84 | def create_converter 85 | converter = SampleConverter.new(nil) 86 | Dir.each_child(TEMPLATE_DIR) do |entry| 87 | if entry.end_with?(".rb") 88 | binding = TOPLEVEL_BINDING 89 | binding.local_variable_set(:converter, converter) 90 | Kernel.eval(File.read(TEMPLATE_DIR + "/" + entry), binding, entry) 91 | end 92 | end 93 | return converter 94 | end 95 | 96 | end 97 | 98 | 99 | whole_converter = WholeSampleConverter.new(ARGV) 100 | whole_converter.execute -------------------------------------------------------------------------------- /sample/converter/utility.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | class Tag 5 | 6 | attr_accessor :name 7 | attr_accessor :content 8 | 9 | def initialize(name = nil, clazz = nil, close = true) 10 | @name = name 11 | @attributes = (clazz) ? {"class" => clazz} : {} 12 | @content = "" 13 | @close = close 14 | end 15 | 16 | def [](key) 17 | return @attributes[key] 18 | end 19 | 20 | def []=(key, value) 21 | @attributes[key] = value 22 | end 23 | 24 | def class 25 | return @attributes["class"] 26 | end 27 | 28 | def class=(clazz) 29 | @attributes["class"] = clazz 30 | end 31 | 32 | def <<(content) 33 | @content << content 34 | end 35 | 36 | def to_s 37 | result = "" 38 | if @name 39 | result << "<" 40 | result << @name 41 | @attributes.each do |key, value| 42 | result << " #{key}=\"#{value}\"" 43 | end 44 | result << ">" 45 | result << @content 46 | if @close 47 | result << "" 50 | end 51 | else 52 | result << @content 53 | end 54 | return result 55 | end 56 | 57 | def to_str 58 | return self.to_s 59 | end 60 | 61 | def self.build(name = nil, clazz = nil, close = true, &block) 62 | tag = Tag.new(name, clazz, close) 63 | block.call(tag) 64 | return tag 65 | end 66 | 67 | end -------------------------------------------------------------------------------- /sample/document/main.zml: -------------------------------------------------------------------------------- 1 | \zml?|version="1.1"|; 2 | \xml?|version="1.0",encoding="UTF-8"|; 3 | 4 | \html|lang="ja"|< 5 | \head< 6 | \meta|charset="UTF-8"|; 7 | &math-resource|font-url="font.otf"|; 8 | \link|rel="stylesheet",type="text/css",href="style.css"|; 9 | \title 10 | > 11 | \body< 12 | 13 | \div|class="title"|< 14 | Zotica 15 | > 16 | 17 | \article< 18 | \h1 19 | \p< 20 | The spacing is optimised for Times New Roman. 21 | If you would like to render formulae using a different font, you may need to modify margin or padding values in the stylesheet. 22 | > 23 | \p< 24 | Google Chrome, Mozilla Firefox, Opera and Sleipnir can properly render formulae and diagrams. 25 | Microsoft Edge has some rendering issues, mainly on the placement of arrows in a diagram. 26 | Internet Explorer is not supported, so do not use it. 27 | > 28 | \h1 29 | \p< 30 | &m<\frac>, &m<\frac - \frac

> 31 | or more complicated 32 | &m<\bb<4> \pitchfork; \frac<φ \bowtie; \frac<2>><3 - \frac<\frac<1> \smash; \frac<7 Ψ>><Δ>>>. 33 | > 34 | \h1 35 | \p< 36 | &m<\sqrt>, &m<\sqrt>, &m<\sqrt> 37 | or 38 | &m<\sqrt<\frac<1> + \frac<1>>> 39 | or 40 | &m<\frac<\sqrt<5 W>> = \sqrt<\frac<5>>>. 41 | > 42 | \p< 43 | Sizes: 44 | &m<\sqrt<&raw<\span|class="box",style="height:1em"|;>>> 45 | &m<\sqrt<&raw<\span|class="box",style="height:1.1em"|;>>> 46 | &m<\sqrt<&raw<\span|class="box",style="height:1.2em"|;>>> 47 | &m<\sqrt<&raw<\span|class="box",style="height:1.3em"|;>>> 48 | &m<\sqrt<&raw<\span|class="box",style="height:1.4em"|;>>> 49 | &m<\sqrt<&raw<\span|class="box",style="height:1.5em"|;>>> 50 | &m<\sqrt<&raw<\span|class="box",style="height:1.6em"|;>>> 51 | &m<\sqrt<&raw<\span|class="box",style="height:1.7em"|;>>> 52 | &m<\sqrt<&raw<\span|class="box",style="height:1.8em"|;>>> 53 | &m<\sqrt<&raw<\span|class="box",style="height:1.9em"|;>>> 54 | &m<\sqrt<&raw<\span|class="box",style="height:2em"|;>>> 55 | &m<\sqrt<&raw<\span|class="box",style="height:2.1em"|;>>> 56 | &m<\sqrt<&raw<\span|class="box",style="height:2.2em"|;>>> 57 | &m<\sqrt<&raw<\span|class="box",style="height:2.3em"|;>>> 58 | &m<\sqrt<&raw<\span|class="box",style="height:2.4em"|;>>>. 59 | > 60 | \p< 61 | With index: 62 | &m<\sqrt> 63 | or 64 | &m<\sqrt<\frac + \frac><3>>. 65 | > 66 | \p< 67 | Very large: not implemented. 68 | > 69 | \h1 70 | \p< 71 | &m<(A)>, &m<\vert>, &m<\brace<\frac<1><2>>>, &m<\angle<\frac<1><2>>>, &m<\tort<\frac<1><2>>>, &m<\ceil<\sp<2><\sp<3><4>>>>, &m<\pparen<\sp<2><\sp<3><4>>>>, &m<\vvert<\frac<1 + \frac<1><2>><2>>>, 72 | or more 73 | &m<\sp<\bracket<1 + \frac<1 + \frac<\sp<`a><2>><2>><4>>><2>>>. 74 | > 75 | \p< 76 | Sizes: 77 | &m<\paren<&raw<\span|class="box",style="height:1em"|;>>> 78 | &m<\paren<&raw<\span|class="box",style="height:1.2em"|;>>> 79 | &m<\paren<&raw<\span|class="box",style="height:1.4em"|;>>> 80 | &m<\paren<&raw<\span|class="box",style="height:1.6em"|;>>> 81 | &m<\paren<&raw<\span|class="box",style="height:1.8em"|;>>> 82 | &m<\paren<&raw<\span|class="box",style="height:2em"|;>>> 83 | &m<\paren<&raw<\span|class="box",style="height:2.2em"|;>>> 84 | &m<\paren<&raw<\span|class="box",style="height:2.4em"|;>>> 85 | &m<\paren<&raw<\span|class="box",style="height:2.6em"|;>>> 86 | &m<\paren<&raw<\span|class="box",style="height:2.8em"|;>>> 87 | &m<\paren<&raw<\span|class="box",style="height:3em"|;>>> 88 | &m<\paren<&raw<\span|class="box",style="height:3.2em"|;>>> 89 | &m<\paren<&raw<\span|class="box",style="height:3.4em"|;>>> 90 | &m<\paren<&raw<\span|class="box",style="height:3.6em"|;>>> 91 | &m<\paren<&raw<\span|class="box",style="height:3.8em"|;>>> 92 | &m<\paren<&raw<\span|class="box",style="height:4em"|;>>>. 93 | > 94 | \p< 95 | Very large: 96 | &m<\paren<\frac<1 + \frac<1 + \frac<1><2>><2 + \frac<1><2>>><2 + \frac<1 + \frac<1><\frac<1><2>>><2>>>>, 97 | &m<\sbsp<\tort<\frac<1 + \frac<3><2 + \frac<1><2>>><2 + \frac<1 + \frac<1><1 + \frac<1><2>>><2 + \frac<1><2>>>>>>, 98 | &m<\sbsp<\brace<\frac<1 + \frac<1 + \frac<1 + \frac<1><2>><2>><2>><2 + \frac<1 + \frac<1><2>><2>>>>>. 99 | > 100 | \p< 101 | With a middle bar: 102 | &m<\set> 103 | or 104 | &m<\set<\frac \in; \bb>>. 105 | or 106 | &m<\set<\frac<\frac<\frac>> \in; \bb><\frac> \ggt; 0>>. 107 | > 108 | \p< 109 | Asymmetric: 110 | &m<\fence|l="paren",r="bracket"|<0, \frac<1><2>>>. 111 | > 112 | \h1 113 | \p< 114 | &m<\sp \sb> 115 | or 116 | &m<\sp<\sp<2> + \sqrt<2> q - 2> * \sb<\sp<2> + \sqrt<2> d - 2>> 117 | or 118 | &m<\sp<\paren<1 + \frac<1><1 + \frac<`j><2>>>><1 + \frac<1><\sp<`j><2>>> * \sb<\paren<1 + \frac<1 + \frac<`h><2>><2>>><`h + \frac<1><2>>>. 119 | > 120 | \p< 121 | Both: 122 | &m<\sbsp> 123 | or 124 | &m<\sbsp<\paren<1 + \frac<1><2>>><`G><`D>>, 125 | compare 126 | &m<\sp<\sb>> 127 | with 128 | &m<\sbsp>. 129 | > 130 | \p< 131 | Nested: 132 | &m<\sp<1><\sp<2><\sp<3><\sp<4><\sp<5><6>>>>>>. 133 | > 134 | \p< 135 | Primes are kinds of superscripts: 136 | &m<\pr;> * \sp<\ppr;>>. 137 | > 138 | \p< 139 | Left scripts: 140 | &m<\multi>, &m<\multi<\rm><4><2-><16><35>>, &m<\multi<\rm

><><>>, 141 | &m<\multi<>>, 142 | &m<\multi<\paren<\matrix<\cc \cc>>><><><><\rm>>. 143 | > 144 | \h1 145 | \p< 146 | &m<\int C>, &m<\intlike|k="intanticlock"| C> 147 | or 148 | &m<\intlike|k="fint"|<\sp<3> + 3a + 1><\sp<4> - 2> g (x) dx>. 149 | > 150 | \p< 151 | Small: 152 | &m<\int|in| C>, &m<\int|in|<> C>, &m<\int|in|<> C>. 153 | > 154 | \h1 155 | \p< 156 | &m<\ov \un>. 157 | > 158 | \p< 159 | Both: 160 | &m<\unov> 161 | or 162 | &m

<\sp<2> + 2 n + 1><\sp<2> - 2 n> Q> 163 | or 164 | &m<\sb<\aleph;><0>><2>> V>. 165 | > 166 | \h1 167 | \p< 168 | &m<\sum C>, &m<\sumlike|k="bigsqcup"| C> 169 | or more practically 170 | &m<\varphi; (x) = \sum<\infty;> \frac<\sp<\varphi;><(n)> (0)> \sp> 171 | or 172 | &m<\bigotimes><> \bigoplus><> \op (L, M)>. 173 | > 174 | \p< 175 | Inline forms: 176 | &m<\sum|in| C> 177 | or 178 | &m<\bigotimes|in|><> \sp<\otimes; n>>. 179 | > 180 | \h1 181 | \p< 182 | &m<\dot>, &m<\hat>, &m<\tilde>, &m<\accent|k="ring"|>, &m<\accent|k="vec"|>, &m<\barbelow>, &m<\tildebelow>, &m<\tildebelow>. 183 | > 184 | \p< 185 | Wide: 186 | &m<\widetilde>, &m<\widetilde>, &m<\widehat>, &m<\widehat>, &m<\wide|k="widecheck"|>, &m<\widetildebelow>, &m<\widetildebelow>, &m<\widetildebelow>. 187 | > 188 | \p< 189 | Sizes: 190 | &m<\widetilde<&raw<\span|class="box",style="width:0.5em"|;>>> 191 | &m<\widetilde<&raw<\span|class="box",style="width:0.6em"|;>>> 192 | &m<\widetilde<&raw<\span|class="box",style="width:0.7em"|;>>> 193 | &m<\widetilde<&raw<\span|class="box",style="width:0.8em"|;>>> 194 | &m<\widetilde<&raw<\span|class="box",style="width:0.9em"|;>>> 195 | &m<\widetilde<&raw<\span|class="box",style="width:1em"|;>>> 196 | &m<\widetilde<&raw<\span|class="box",style="width:1.1em"|;>>> 197 | &m<\widetilde<&raw<\span|class="box",style="width:1.2em"|;>>> 198 | &m<\widetilde<&raw<\span|class="box",style="width:1.3em"|;>>> 199 | &m<\widetilde<&raw<\span|class="box",style="width:1.4em"|;>>> 200 | &m<\widetilde<&raw<\span|class="box",style="width:1.5em"|;>>> 201 | &m<\widetilde<&raw<\span|class="box",style="width:1.6em"|;>>> 202 | &m<\widetilde<&raw<\span|class="box",style="width:1.7em"|;>>> 203 | &m<\widetilde<&raw<\span|class="box",style="width:1.8em"|;>>> 204 | &m<\widetilde<&raw<\span|class="box",style="width:1.9em"|;>>> 205 | &m<\widetilde<&raw<\span|class="box",style="width:2em"|;>>> 206 | or 207 | &m<\widetildebelow<&raw<\span|class="box",style="width:1.5em"|;>>>. 208 | > 209 | \p< 210 | Wide braces: 211 | &m<\overbrace<&raw<\span|class="box",style="width:1em"|;>>> 212 | &m<\overbrace<&raw<\span|class="box",style="width:1.1em"|;>>> 213 | &m<\overbrace<&raw<\span|class="box",style="width:1.2em"|;>>> 214 | &m<\overbrace<&raw<\span|class="box",style="width:1.3em"|;>>> 215 | &m<\overbrace<&raw<\span|class="box",style="width:1.4em"|;>>> 216 | &m<\overbrace<&raw<\span|class="box",style="width:1.5em"|;>>> 217 | &m<\overbrace<&raw<\span|class="box",style="width:1.6em"|;>>> 218 | &m<\overbrace<&raw<\span|class="box",style="width:1.7em"|;>>> 219 | &m<\overbrace<&raw<\span|class="box",style="width:1.8em"|;>>> 220 | &m<\overbrace<&raw<\span|class="box",style="width:1.9em"|;>>> 221 | &m<\overbrace<&raw<\span|class="box",style="width:2em"|;>>> 222 | &m<\overbrace<&raw<\span|class="box",style="width:2.1em"|;>>> 223 | &m<\overbrace<&raw<\span|class="box",style="width:2.2em"|;>>> 224 | &m<\overbrace<&raw<\span|class="box",style="width:2.3em"|;>>> 225 | &m<\overbrace<&raw<\span|class="box",style="width:2.4em"|;>>> 226 | &m<\overbrace<&raw<\span|class="box",style="width:2.5em"|;>>> 227 | &m<\overbrace<&raw<\span|class="box",style="width:2.6em"|;>>> 228 | &m<\overbrace<&raw<\span|class="box",style="width:2.7em"|;>>> 229 | &m<\overbrace<&raw<\span|class="box",style="width:2.8em"|;>>> 230 | &m<\overbrace<&raw<\span|class="box",style="width:2.9em"|;>>> 231 | &m<\overbrace<&raw<\span|class="box",style="width:3em"|;>>>. 232 | > 233 | \p< 234 | Other examples: 235 | &m<\widetilde>, &m<\widehat>, &m<\overrarr>, &m<\underlarr>, 236 | &m<\ov<\overbrace>>>, &m<\un<\underbrace>>>, 237 | &m<\overline>, &m<\wide|k="underline"|>. 238 | > 239 | \p< 240 | Accent position: 241 | &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, 242 | &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, 243 | &m<\tilde>, &m<\tilde

>, &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, 244 | &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, &m<\tilde>, 245 | &m<\tilde<α>>, &m<\tilde<β>>, &m<\tilde<γ>>, &m<\tilde<δ>>, &m<\tilde<ε>>, &m<\tilde<ζ>>, &m<\tilde<η>>, 246 | &m<\tilde<θ>>, &m<\tilde<ι>>, &m<\tilde<κ>>, &m<\tilde<λ>>, &m<\tilde<μ>>, &m<\tilde<ν>>, &m<\tilde<ξ>>, 247 | &m<\tilde<ο>>, &m<\tilde<π>>, &m<\tilde<ρ>>, &m<\tilde<σ>>, &m<\tilde<τ>>, &m<\tilde<υ>>, &m<\tilde<φ>>, 248 | &m<\tilde<χ>>, &m<\tilde<ψ>>, &m<\tilde<ω>>, 249 | &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, 250 | &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, 251 | &m<\tildebelow>, &m<\tildebelow

>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, 252 | &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, &m<\tildebelow>, 253 | &m<\tildebelow<α>>, &m<\tildebelow<β>>, &m<\tildebelow<γ>>, &m<\tildebelow<δ>>, &m<\tildebelow<ε>>, &m<\tildebelow<ζ>>, &m<\tildebelow<η>>, 254 | &m<\tildebelow<θ>>, &m<\tildebelow<ι>>, &m<\tildebelow<κ>>, &m<\tildebelow<λ>>, &m<\tildebelow<μ>>, &m<\tildebelow<ν>>, &m<\tildebelow<ξ>>, 255 | &m<\tildebelow<ο>>, &m<\tildebelow<π>>, &m<\tildebelow<ρ>>, &m<\tildebelow<σ>>, &m<\tildebelow<τ>>, &m<\tildebelow<υ>>, &m<\tildebelow<φ>>, 256 | &m<\tildebelow<χ>>, &m<\tildebelow<ψ>>, &m<\tildebelow<ω>>. 257 | > 258 | \p< 259 | Accented symbols: 260 | &m<\ring<0>>, &m<\tilde<\bf>>, &m<2 \dot<-> 3>, &m B>, &m<`a: D \ddot<\to;> E>. 261 | > 262 | \p< 263 | Double: 264 | &m<\hat<\hat>>, &m<\bar<\tilde

>>, &m<\tildebelow<\barbelow>>, &m<\ring<\tildebelow>>. 265 | > 266 | \h1 267 | \p< 268 | &m< 269 | \paren<\matrix< 270 | \c<1> \c<2> \br; 271 | \c<3> \c<4> 272 | >> 273 | >, 274 | &m< 275 | \vert<\matrix< 276 | \c<\sb<11>> \c<\sb<12>> \c<\sb<13>> \c<\sb<14>> \c<\sb<15>> \br; 277 | \c<\sb<21>> \c<\sb<22>> \c<\sb<23>> \c<\sb<24>> \c<\sb<25>> \br; 278 | \c<\sb<31>> \c<\sb<32>> \c<\sb<33>> \c<\sb<34>> \c<\sb<35>> \br; 279 | \c<\sb<41>> \c<\sb<42>> \c<\sb<43>> \c<\sb<44>> \c<\sb<45>> 280 | >> 281 | > 282 | or 283 | &m< 284 | \sb \coloneqq; \det; 285 | \paren<\matrix< 286 | \c<1> \c<\sb<1>> \c<\sp<\sb<1>><2>> \c<\cdots;> \c<\sp<\sb<1>>> \br; 287 | \c<1> \c<\sb<2>> \c<\sp<\sb<2>><2>> \c<\cdots;> \c<\sp<\sb<2>>> \br; 288 | \c<\vdots;> \c<\vdots;> \c<\vdots;> \c<\ddots;> \c<\vdots;> \br; 289 | \c<1> \c<\sb> \c<\sp<\sb><2>> \c<\cdots;> \c<\sp<\sb>> 290 | >> 291 | = \prod<\stack<\cc<1 \leq; i \leq; n> \cc<1 \leq; j \leq; n> \cc>><> (\sb - \sb) 292 | >. 293 | > 294 | \h1 295 | \p< 296 | &m< 297 | \array< 298 | \c<`F :> \c \c<\longto;> \c<\bb> \br; 299 | \c; \c \c<\longmapsto;> \c 300 | > 301 | > 302 | or 303 | &m< 304 | \array|align="rcl"|< 305 | \cc<\nabla; \cdot; \bf><=><0> 306 | \cc<\nabla; \times; \bf + \frac<\partial; \bf><\partial; t>><=><\bfrm<0>> 307 | \cc<\nabla; \cdot; \bf><=><`r> 308 | \cc<\nabla; \times; \bf - \frac<\partial; \bf><\partial; t>><=><\bf> 309 | > 310 | >. 311 | > 312 | \p< 313 | Cases: 314 | &m< 315 | \vert = 316 | \case< 317 | \cc<(x \geq; 0)> 318 | \cc<- x><(x `< 0)> 319 | > 320 | >. 321 | > 322 | \h1 323 | \p< 324 | &m<\sin; A> 325 | or 326 | &m<\exp; (a - b) = \frac<\exp; a><\exp; b>> 327 | or 328 | &m<\max; `{ \dim; V \mid; V \in; \op (\scr) `}>. 329 | > 330 | \h1 331 | \p< 332 | &m<\bb * \varbb * \cal * \scr

* \frak> 333 | or 334 | &m<`s \nin; \frak (\sb<\frak>)> 335 | or 336 | &m<`t \in; \sp<\scr><\scr>: T \raarr; S> 337 | or 338 | &m<\frak = \frak \oplus; \bigoplus<`a \in; `D> \sb<\frak><`a>>. 339 | > 340 | \h1 341 | \p< 342 | Greek variants: 343 | &m<(\varbeta;, `b)>, &m<(\varepsilon;, `e)>, &m<(\vartheta;, `u)>, &m<(\varkappa;, `k)>, &m<(\varpi;, `p)>, &m<(\varrho;, `r)>, &m<(\varphi;, `f)>, &m<(\varcapupsilon;, `Y)> 344 | and 345 | &m<(\capdigamma;, \digamma;)>, &m<(\capkoppa;, \koppa;)>, &m<(\capsampi;, \sampi;)>. 346 | > 347 | \p< 348 | Various symbols: 349 | &m<\hbar;>, &m<\sharp; \flat;>, &m<\crotchet; \quaver;>, &m<\bspade; \wheart;>, &m<\dagger;>, &m<\amp; \invamp;> 350 | and 351 | &m<\op (`b \ltriangle; `J, F \circ; \hyphen;)> 352 | and 353 | &m<\natural;> \scand; g (m) \nin; G> 354 | > 355 | \p< 356 | Added symbols: 357 | &m b \scand; a \sb<\frown;> b \scand; a \sb<\closure;> b \scand; a \sb<\asymp;> b> 358 | > 359 | \p< 360 | Combining negation symbol: 361 | &m, &m. 362 | > 363 | \p< 364 | Grouping: 365 | &m<\bb> N> 366 | or 367 | &m<\un<\lim;> \frac<\log; n> = 0> 368 | or 369 | &m. 370 | > 371 | \p< 372 | Changing identifier styles: 373 | &m>> 374 | or 375 | &m<\rm = `r \sfun; \sin; `f \sfun; d `r d `u d`f> 376 | or 377 | &m<\tt \sfun; B \sfun; \tt \sfun; M \sfun; \tt \sfun; N>. 378 | > 379 | \p< 380 | Changing spacing: 381 | &m 382 | and 383 | &m. 384 | > 385 | \p< 386 | Inserting spaces: 387 | &m<&raw<\span|class="box"|;> \s|t="thn"|; &raw<\span|class="box",style="color:hsl(0,100%,40%)"|;>>, 388 | &m<&raw<\span|class="box"|;> \s|t="40"|; &raw<\span|class="box",style="color:hsl(0,100%,40%)"|;>>, 389 | &m<&raw<\span|class="box"|;> \s|t="-med"|; &raw<\span|class="box",style="color:hsl(0,100%,40%)"|;>>, 390 | &m<&raw<\span|class="box"|;> \s|t="-12"|; &raw<\span|class="box",style="color:hsl(0,100%,40%)"|;>>. 391 | > 392 | \p< 393 | Phantoms: 394 | &m< 395 | \array|align="rr"|< 396 | \cc 397 | \cc + B b \ph<+ C c> + D d> 398 | > 399 | > 400 | or 401 | &m< 402 | \paren<2>>> \paren<2>> 403 | >. 404 | > 405 | \p< 406 | Texts as subformulae: 407 | &m<`{ x \in; X \mid; x \text< is very good> `}> 408 | or 409 | &m<`{ x \in; X \mid; &raw<&m is very good> `}>. 410 | > 411 | \p< 412 | Specifying classes: 413 | &m<\g|class="red"| \sp<2> + \g|class="yellow"| \sp + \g|class="green"|> 414 | or 415 | &m<\g|class="frame"|<\int<-1><1> \sqrt<1 - \sp<\g|class="red"|><2>> d \g|class="red"| > = \g|class="fill"|<\frac<`p><2>>>. 416 | > 417 | \h1 418 | \p< 419 | Standard: 420 | &m< 421 | \diag< 422 | \v \v<1> \v \br; 423 | \v \v \v 424 | \ar|s="1",e="2"| \ar|s="1",e="4",inv| \ar|s="1",e="5",inv| \ar|s="1",e="6"| 425 | \ar|s="2",e="3"|<\sb<`v>> \ar|s="3",e="6"|<`r> \ar|s="4",e="5",inv|<\sb<`r><2>> \ar|s="5",e="3"|; 426 | > 427 | >. 428 | > 429 | \p< 430 | Bent arrows: 431 | &m< 432 | \diag< 433 | \v \v; \v; \br; 434 | \v; \v<\sp<*> M> \v \br; 435 | \v; \v \v 436 | \ar|s="8",e="9",inv| \ar|s="5",e="6"|; 437 | \ar|s="6",e="9",tip="tail"| \ar|s="5",e="8",tip="tail",inv|<\sp<*> m> 438 | \ar|s="1",e="6",bend="30"|

\sb<\bracket<> \sb<`[ P, \sb `]>>>> 625 | \v<\bigoplus<> \sb<`[ P, \sb `]>> \br; 626 | \v

\sb<\bracket<> \sb>>>>> 627 | \v<\sb<\bracket<> \sb>>> 628 | \ar|s="1",e="2",line="2",tip="none"|; \ar|s="3",e="4",line="2",tip="none"|; 629 | \ar|s="1",e="3",inv|<\rm \otimes; `[ \rm, `l `]> \ar|s="2",e="4"|<`l> 630 | > 631 | > 632 | > 633 | \p< 634 | 4: 635 | &mb< 636 | \diag< 637 | \v<\sb<0>> \v<\sb<1>> \v<\sb<2>> \v<\cdots;> \v<\sb> \v<\sb> \v<\cdots;> \v<\sb<\infty;>> 638 | \ar|s="1",e="2",shift="3",pos="70"|<\sbsp<`F><1><0>> \ar|s="2",e="1",shift="3",pos="30"|<\sbsp<`F><0><1>> 639 | \ar|s="2",e="3",shift="3",pos="70"|<\sbsp<`F><2><1>> \ar|s="3",e="2",shift="3",pos="30"|<\sbsp<`F><1><2>> 640 | \ar|s="3",e="4",shift="3"|; \ar|s="4",e="3",shift="3"|; \ar|s="4",e="5",shift="3"|; \ar|s="5",e="4",shift="3"|; 641 | \ar|s="5",e="6",shift="3",pos="70"|<\sbsp<`F>> \ar|s="6",e="5",shift="3",pos="30"|<\sbsp<`F>> 642 | \ar|s="6",e="7",shift="3"|; \ar|s="7",e="6",shift="3"|; 643 | \ar|s="1",e="8",bend="40",pos="15"|<\sbsp<`F><\infty;><0>> 644 | \ar|s="2",e="8",tip="none",bend="40",pos="15"|<\sbsp<`F><\infty;><1>> 645 | \ar|s="3",e="8",tip="none",bend="40",pos="15"|<\sbsp<`F><\infty;><2>> 646 | \ar|s="5",e="8",tip="none",bend="40",pos="15"|<\sbsp<`F><\infty;>> 647 | \ar|s="6",e="8",tip="none",bend="40",pos="15"|<\sbsp<`F><\infty;>> 648 | \ar|s="8",e="1",bend="40",pos="85"|<\sbsp<`F><0><\infty;>> 649 | \ar|s="8",e="2",bend="40",pos="85"|<\sbsp<`F><1><\infty;>> 650 | \ar|s="8",e="3",bend="40",pos="85"|<\sbsp<`F><2><\infty;>> 651 | \ar|s="8",e="5",bend="40",pos="85"|<\sbsp<`F><\infty;>> 652 | \ar|s="8",e="6",bend="40",pos="85"|<\sbsp<`F><\infty;>> 653 | > 654 | > 655 | > 656 | \p< 657 | 5: 658 | &mb< 659 | \tree< 660 | \axm<`[p`] \sb<><2>> \axm<`[\neg; p`] \sb<><3>> 661 | \infr|n="2"|<\bot;><><\neg; \rm> \axm<`[\neg; q`] \sb<><1>> 662 | \infr|n="2"|<\neg; \neg; q><1><\neg; \rm> 663 | \infr|n="1"|<><\neg; \neg;> 664 | \infr|n="1"|

<2><\to|ord|; \rm> \axm<`[(p \to|bin|; q) \to|bin|; p`] \sb<><4>> 665 | \infr|n="2"|

<><\to|ord|; \rm> \axm<`[\neg; p`] \sb<><3>> 666 | \infr|n="2"|<\bot;><><\neg; \rm> 667 | \infr|n="2"|<\neg; \neg; p><3><\neg; \rm> 668 | \infr|n="1"|

<><\neg; \neg;> 669 | \infr|n="1"|<((p \to|bin|; q) \to|bin|; p) \to|bin|; p><4><\to|ord|; \rm> 670 | > 671 | > 672 | > 673 | \h1 674 | \p|class="normal"|< 675 | The quadratic equation &m<2> + bx + c = 0> has two real roots when &m<2> - 4 ac `> 0> holds, and those roots are explicitly written as 676 | &mb< 677 | x = \frac<-b \pm; \sqrt<\sp<2> - 4 ac>><2 a>. 678 | > 679 | The proof is quite easy. 680 | The left-hand side of the equation is transformed as: 681 | &mb< 682 | \array|align="rcl"|< 683 | \cc<2> + bx + c><=><2> + \frac x> + c> 684 | \cc<><=><2 a>>><2> - \sp<\paren<\frac<2 a>>><2>> + c> 685 | \cc<><=><2 a>>><2> - \frac<\sp<2>><4 a> + c> 686 | \cc<><=><2 a>>><2> - \frac<\sp<2> - 4 ac><4 a>.> 687 | > 688 | > 689 | Thus the equation is equivalent to 690 | &mb< 691 | a \sp<\paren<2 a>>><2> - \frac<\sp<2> - 4 ac><4 a> = 0, 692 | > 693 | and also equivalent to 694 | &mb< 695 | \sp<\paren<2 a>>><2> = \frac<\sp<2> - 4 ac><4 \sp<2>>. 696 | > 697 | Taking the square roots of both sides yields 698 | &mb< 699 | x + \frac<2 a> = [\pm; \frac<\sqrt<\sp<2> - 4 ac>><2 a>]. 700 | > 701 | Transposing &m to the left finally gives the desired formula. 702 | > 703 | \p|class="normal"|< 704 | 主イデアル整域 &m 上の多項式 &m

を考え、 705 | &mb< 706 | P \eqqcolon; \sp + \sb<1> \sp + \cdots; + \sb 707 | > 708 | と係数表示する。 709 | &m のある素元 &m<π> が存在し、各 &m に対して &m<π> は &m<\sb> をわり切り、さらに &m<\sp<π><2>> は &m<\sb> をわり切らないとする。 710 | このとき、&m (A)> とおくと、&m

は &m 上既約である。 711 | > 712 | \p|class="normal"|< 713 | 2 階連続的微分可能な &m<\bb> 値 2 変数関数 &m の極大値や極小値が知りたいとする。 714 | 点 &m<(\sb<0>, \sb<0>)> が極大値もしくは極小値であるための必要条件として、その点が停留点であること、すなわち 715 | &mb< 716 | \frac<\partial; f><\partial; x> (\sb<0>, \sb<0>) = \frac<\partial; f><\partial; y> (\sb<0>, \sb<0>) = 0 717 | > 718 | が成り立つことが挙げられる。 719 | この条件のもと、Taylor 展開を行うことで、&m の点 &m<(\sb<0>, \sb<0>)> の周りでの振る舞いは、 720 | &mb< 721 | f (\sb<0> + h, \sb<0> + k) = f (\sb<0>, \sb<0>) + \frac<1><2> \paren<\sp<2> \frac<\sp<\partial;><2> f><\partial; \sp<2>> (\sb<0>, \sb<0>) + 2 hk \frac<\sp<\partial;><2> f><\partial; x \partial; y> (\sb<0>, \sb<0>) + \sp<2> \frac<\sp<\partial;><2> f><\partial; \sp<2>> (\sb<0>, \sb<0>)> + o (\sp<`r><2>) 722 | > 723 | と記述できる。 724 | ここで、&m<`r \coloneqq; \sqrt<\sp<2> + \sp<2>>> とした。 725 | > 726 | \p|class="normal"|< 727 | Cauchy の積分公式により、正則関数 &m の値は、ある単純閉曲線 &m の内側の点 &m に対し、 728 | &mb< 729 | F (z) = \frac<1><2 `p i> \oint<> \frac<`z - z> d `z 730 | > 731 | で与えられる。 732 | これにより、&m の &m 階導関数は、 733 | &mb< 734 | \sp<(n)> (z) = \frac<2 `p i> \oint<> \frac<\sp<(`z - z)>> d `z 735 | > 736 | と書けることが分かる。 737 | > 738 | \p|class="normal"|< 739 | &m<\sp<\bb><2 \times; 2>> の部分集合 740 | &mb< 741 | \array|align="rcl"|< 742 | \c<\sb<\frak><2> (\bb)> \c<\coloneqq;> \c<\set<\paren<\matrix<\cc\cc<-c>>> \in; \sp<\bb><2 \times; 2>>>> \br; 743 | \c; \c<=> \c<\bb \paren<\matrix<\cc<0><1>\cc<0><0>>> \oplus; \bb \paren<\matrix<\cc<0><0>\cc<1><0>>> \oplus; \bb \paren<\matrix<\cc<1><0>\cc<0><-1>>>> 744 | > 745 | > 746 | は、通常の和と交換積によって Lie 代数になる。 747 | これは、2 次の特殊線型 Lie 代数と呼ばれる。 748 | > 749 | > 750 | 751 | > 752 | > -------------------------------------------------------------------------------- /sample/document/style.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | 4 | body { 5 | margin: 0px; 6 | padding: 0px; 7 | font-family: "Times New Roman", "IPA P明朝", "YuMincho", "Yu Mincho", serif; 8 | font-size: 16px; 9 | text-size-adjust: 100%; 10 | -webkit-text-size-adjust: 100%; 11 | } 12 | 13 | div.title { 14 | width: 700px; 15 | margin: 40px auto 60px auto; 16 | padding: 0px; 17 | font-size: 36px; 18 | text-align: center; 19 | } 20 | 21 | article { 22 | width: 700px; 23 | margin: 40px auto; 24 | padding: 0px; 25 | } 26 | 27 | article h1 { 28 | margin: 40px 0px 15px 0px; 29 | padding: 0px; 30 | font-size: 22px; 31 | font-weight: normal; 32 | } 33 | 34 | article p { 35 | margin: 5px 0px; 36 | padding: 0px; 37 | line-height: 1.6; 38 | text-align: justify; 39 | } 40 | 41 | article a { 42 | color: hsl(200, 80%, 50%); 43 | text-decoration: underline; 44 | } 45 | 46 | article span.display-math { 47 | margin: 8px 0px; 48 | text-align: center; 49 | line-height: 1; 50 | display: block; 51 | } 52 | 53 | article p math-root { 54 | color: hsl(240, 80%, 50%); 55 | } 56 | 57 | article p.normal math-root { 58 | color: black; 59 | } 60 | 61 | article p math-root span.box { 62 | width: 1em; 63 | height: 1em; 64 | color: hsl(240, 80%, 50%); 65 | display: inline-block; 66 | vertical-align: middle; 67 | background: linear-gradient(-45deg, currentcolor 25%, transparent 25%, transparent 50%, currentcolor 50%, currentcolor 75%, transparent 75%, transparent); 68 | background-size: 4px 4px; 69 | } 70 | 71 | article p math-root span.box::before { 72 | line-height: 1; 73 | content: ""; 74 | } 75 | 76 | .red { 77 | color: hsl(0, 100%, 40%); 78 | } 79 | 80 | .yellow { 81 | color: hsl(60, 100%, 40%); 82 | } 83 | 84 | .green { 85 | color: hsl(120, 100%, 40%); 86 | } 87 | 88 | .frame { 89 | padding: 0.2em; 90 | border: 3px double; 91 | } 92 | 93 | .fill { 94 | padding: 0.2em; 95 | color: white; 96 | background: linear-gradient(-45deg, hsl(60, 80%, 30%) 25%, black 25%, black 50%, hsl(60, 80%, 30%) 50%, hsl(60, 80%, 30%) 75%, black 75%, black); 97 | background-size: 6px 6px; 98 | } -------------------------------------------------------------------------------- /sample/macro/math.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | parser.register_math_macro("m") do |attributes, children_list| 5 | this = Nodes[] 6 | this << children_list.first 7 | next this 8 | end 9 | 10 | parser.register_math_macro("mb") do |attributes, children_list| 11 | this = Nodes[] 12 | this << Element.build("span") do |this| 13 | this["class"] = "display-math" 14 | this << children_list.first 15 | end 16 | next this 17 | end -------------------------------------------------------------------------------- /sample/template/html.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | OPEN_TAG_NAMES = ["br", "img", "hr", "meta", "input", "embed", "area", "base", "link"] 5 | 6 | converter.add(["html"], [""]) do |element| 7 | this = "" 8 | this << "\n\n" 9 | this << pass_element(element, "html") 10 | next this 11 | end 12 | 13 | converter.add([//], ["html"]) do |element| 14 | close = !OPEN_TAG_NAMES.include?(element.name) 15 | this = pass_element(element, "html", close) 16 | next this 17 | end 18 | 19 | converter.add_default(nil) do |text| 20 | string = text.to_s.clone 21 | string.gsub!("、", "、 ") 22 | string.gsub!("。", "。 ") 23 | string.gsub!("「", " 「") 24 | string.gsub!("」", "」 ") 25 | string.gsub!("『", " 『") 26 | string.gsub!("』", "』 ") 27 | string.gsub!("〈", " 〈") 28 | string.gsub!("〉", "〉 ") 29 | string.gsub!(/(、|。)\s+(」|』)/){$1 + $2} 30 | string.gsub!(/(」|』|〉)\s+(、|。|,|\.)/){$1 + $2} 31 | string.gsub!(/(\(|「|『)\s+(「|『)/){$1 + $2} 32 | string.gsub!(/(^|>)\s+(「|『)/){$1 + $2} 33 | next string 34 | end -------------------------------------------------------------------------------- /source/zotica.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | module Zenithal 5 | 6 | ZOTICA_VERSION = "1.7.0" 7 | ZOTICA_VERSION_ARRAY = ZOTICA_VERSION.split(/\./).map(&:to_i) 8 | 9 | end 10 | 11 | 12 | require 'json' 13 | require 'rexml/document' 14 | require 'sassc' 15 | require 'ttfunk' 16 | require 'zenml' 17 | 18 | require_relative 'zotica/builder' 19 | require_relative 'zotica/parser' -------------------------------------------------------------------------------- /source/zotica/parser.rb: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | module Zenithal::ZoticaSingleParserMethod 5 | 6 | SPACE_ALTERNATIVES = {"sfun" => "afun", "sbin" => "abin", "srel" => "arel", "ssbin" => "asbin", "ssrel" => "asrel", "scas" => "acas", "quad" => "sgl", "qquad" => "dbl"} 7 | PHANTOM_TYPES = {"ph" => "bth", "vph" => "ver", "hph" => "hor"} 8 | 9 | private 10 | 11 | def parse 12 | if @block 13 | inner_element = parse_math_root 14 | raw_nodes = @block.call(@attributes, [inner_element]) 15 | nodes = raw_nodes.inject(REXML::Nodes[], :<<) 16 | else 17 | nodes = parse_math_root 18 | end 19 | return nodes 20 | end 21 | 22 | def create_math_element(name, attributes, children_list, options = {}) 23 | this = REXML::Nodes[] 24 | options[:role] = determine_role(attributes) 25 | options[:class] = attributes["class"] 26 | options[:style] = attributes["style"] 27 | options[:fonts] = @fonts 28 | case name 29 | when "n" 30 | text = children_list[0].first.to_s 31 | this << ZoticaBuilder.build_number(text, options) 32 | when "i" 33 | types = attributes["t"]&.split(/\s*,\s*/) || [] 34 | text = children_list[0].first.to_s 35 | this << ZoticaBuilder.build_identifier(text, types, options) 36 | when "bf" 37 | text = children_list[0].first.to_s 38 | this << ZoticaBuilder.build_identifier(text, ["bf"], options) 39 | when "rm" 40 | text = children_list[0].first.to_s 41 | this << ZoticaBuilder.build_identifier(text, ["rm"], options) 42 | when "bfrm" 43 | text = children_list[0].first.to_s 44 | this << ZoticaBuilder.build_identifier(text, ["bf", "rm"], options) 45 | when "tt" 46 | text = children_list[0].first.to_s 47 | this << ZoticaBuilder.build_identifier(text, ["tt"], options) 48 | when "bb", "varbb", "cal", "scr", "frak", "varfrak" 49 | raw_text = children_list[0].first.value 50 | text = ZoticaBuilder.fetch_alternative_identifier_text(name, raw_text) 51 | this << ZoticaBuilder.build_identifier(text, ["alt"], options) 52 | when "op" 53 | text = children_list[0].first.to_s 54 | this << ZoticaBuilder.build_identifier(text, ["fun", "rm"], options) 55 | when DATA["identifier"].method(:key?) 56 | char = ZoticaBuilder.fetch_identifier_char(name) 57 | this << ZoticaBuilder.build_identifier(char, [], options) 58 | when DATA["function"].method(:include?) 59 | this << ZoticaBuilder.build_identifier(name, ["fun", "rm"], options) 60 | when "o" 61 | types = attributes["t"]&.split(/\s*,\s*/) || ["ord"] 62 | symbol = children_list[0].first.to_s 63 | this << ZoticaBuilder.build_operator(symbol, types, options) 64 | when DATA["operator"].method(:key?) 65 | symbol, types = ZoticaBuilder.fetch_operator_symbol(name) 66 | this << ZoticaBuilder.build_operator(symbol, types, options) 67 | when "text" 68 | text = children_list[0].first.value 69 | this << ZoticaBuilder.build_text(text, options) 70 | when "fence" 71 | stretch_level = attributes["s"] 72 | left_kind = attributes["l"] || "paren" 73 | right_kind = attributes["r"] || "paren" 74 | left_symbol = ZoticaBuilder.fetch_fence_symbol(left_kind, 0, stretch_level) 75 | right_symbol = ZoticaBuilder.fetch_fence_symbol(right_kind, 1, stretch_level) 76 | modify = !stretch_level 77 | this << ZoticaBuilder.build_fence(left_kind, right_kind, left_symbol, right_symbol, modify, options) do |content_this| 78 | content_this << children_list.fetch(0, REXML::Nodes[]) 79 | end 80 | when "set" 81 | stretch_level = attributes["s"] 82 | left_kind = attributes["l"] || "brace" 83 | right_kind = attributes["r"] || "brace" 84 | center_kind = attributes["c"] || "vert" 85 | left_symbol = ZoticaBuilder.fetch_fence_symbol(left_kind, 0, stretch_level) 86 | right_symbol = ZoticaBuilder.fetch_fence_symbol(right_kind, 1, stretch_level) 87 | center_symbol = ZoticaBuilder.fetch_fence_symbol(center_kind, 0, stretch_level) 88 | modify = !stretch_level 89 | this << ZoticaBuilder.build_set(left_kind, right_kind, center_kind, left_symbol, right_symbol, center_symbol, modify, options) do |left_this, right_this| 90 | left_this << children_list.fetch(0, REXML::Nodes[]) 91 | right_this << children_list.fetch(1, REXML::Nodes[]) 92 | end 93 | when DATA["fence"].method(:key?) 94 | stretch_level = attributes["s"] 95 | left_symbol = ZoticaBuilder.fetch_fence_symbol(name, 0, stretch_level) 96 | right_symbol = ZoticaBuilder.fetch_fence_symbol(name, 1, stretch_level) 97 | modify = !stretch_level 98 | this << ZoticaBuilder.build_fence(name, name, left_symbol, right_symbol, modify, options) do |content_this| 99 | content_this << children_list.fetch(0, REXML::Nodes[]) 100 | end 101 | when "intlike" 102 | kind = attributes["k"] || "int" 103 | size = (attributes["in"]) ? "inl" : "lrg" 104 | symbol = ZoticaBuilder.fetch_integral_symbol(kind, size) 105 | this << ZoticaBuilder.build_integral(symbol, size, options) do |sub_this, super_this| 106 | sub_this << children_list.fetch(0, REXML::Nodes[]) 107 | super_this << children_list.fetch(1, REXML::Nodes[]) 108 | end 109 | when DATA["integral"].method(:key?) 110 | size = (attributes["in"]) ? "inl" : "lrg" 111 | symbol = ZoticaBuilder.fetch_integral_symbol(name, size) 112 | this << ZoticaBuilder.build_integral(symbol, size, options) do |sub_this, super_this| 113 | sub_this << children_list.fetch(0, REXML::Nodes[]) 114 | super_this << children_list.fetch(1, REXML::Nodes[]) 115 | end 116 | when "sumlike" 117 | kind = attributes["k"] || "sum" 118 | size = (attributes["in"]) ? "inl" : "lrg" 119 | symbol = ZoticaBuilder.fetch_sum_symbol(kind, size) 120 | this << ZoticaBuilder.build_sum(symbol, size, options) do |under_this, over_this| 121 | under_this << children_list.fetch(0, REXML::Nodes[]) 122 | over_this << children_list.fetch(1, REXML::Nodes[]) 123 | end 124 | when DATA["sum"].method(:key?) 125 | size = (attributes["in"]) ? "inl" : "lrg" 126 | symbol = ZoticaBuilder.fetch_sum_symbol(name, size) 127 | this << ZoticaBuilder.build_sum(symbol, size, options) do |under_this, over_this| 128 | under_this << children_list.fetch(0, REXML::Nodes[]) 129 | over_this << children_list.fetch(1, REXML::Nodes[]) 130 | end 131 | when "accent" 132 | kind = attributes["k"] 133 | under_symbol = ZoticaBuilder.fetch_accent_symbol(kind, 0) 134 | over_symbol = ZoticaBuilder.fetch_accent_symbol(kind, 1) 135 | this << ZoticaBuilder.build_accent(under_symbol, over_symbol, options) do |base_this| 136 | base_this << children_list.fetch(0, REXML::Nodes[]) 137 | end 138 | when DATA["accent"].method(:key?) 139 | under_symbol = ZoticaBuilder.fetch_accent_symbol(name, 0) 140 | over_symbol = ZoticaBuilder.fetch_accent_symbol(name, 1) 141 | this << ZoticaBuilder.build_accent(under_symbol, over_symbol, options) do |base_this| 142 | base_this << children_list.fetch(0, REXML::Nodes[]) 143 | end 144 | when "wide" 145 | kind = attributes["k"] 146 | stretch_level = attributes["s"] 147 | under_symbol = ZoticaBuilder.fetch_wide_symbol(kind, 0, stretch_level) 148 | over_symbol = ZoticaBuilder.fetch_wide_symbol(kind, 1, stretch_level) 149 | modify = !stretch_level 150 | this << ZoticaBuilder.build_wide(kind, under_symbol, over_symbol, modify, options) do |base_this| 151 | base_this << children_list.fetch(0, REXML::Nodes[]) 152 | end 153 | when DATA["wide"].method(:key?) 154 | stretch_level = attributes["s"] 155 | under_symbol = ZoticaBuilder.fetch_wide_symbol(name, 0, stretch_level) 156 | over_symbol = ZoticaBuilder.fetch_wide_symbol(name, 1, stretch_level) 157 | modify = !stretch_level 158 | this << ZoticaBuilder.build_wide(name, under_symbol, over_symbol, modify, options) do |base_this| 159 | base_this << children_list.fetch(0, REXML::Nodes[]) 160 | end 161 | when "multi" 162 | this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this, left_sub_this, left_super_this| 163 | base_this << children_list.fetch(0, REXML::Nodes[]) 164 | sub_this << children_list.fetch(1, REXML::Nodes[]) 165 | super_this << children_list.fetch(2, REXML::Nodes[]) 166 | left_sub_this << children_list.fetch(3, REXML::Nodes[]) 167 | left_super_this << children_list.fetch(4, REXML::Nodes[]) 168 | end 169 | when "sb" 170 | this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this, left_sub_element, left_super_element| 171 | base_this << children_list.fetch(0, REXML::Nodes[]) 172 | sub_this << children_list.fetch(1, REXML::Nodes[]) 173 | end 174 | when "sp" 175 | this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this, left_sub_element, left_super_element| 176 | base_this << children_list.fetch(0, REXML::Nodes[]) 177 | super_this << children_list.fetch(1, REXML::Nodes[]) 178 | end 179 | when "sbsp" 180 | this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this, left_sub_element, left_super_element| 181 | base_this << children_list.fetch(0, REXML::Nodes[]) 182 | sub_this << children_list.fetch(1, REXML::Nodes[]) 183 | super_this << children_list.fetch(2, REXML::Nodes[]) 184 | end 185 | when "unov" 186 | this << ZoticaBuilder.build_underover(options) do |base_this, under_this, over_this| 187 | base_this << children_list.fetch(0, REXML::Nodes[]) 188 | under_this << children_list.fetch(1, REXML::Nodes[]) 189 | over_this << children_list.fetch(2, REXML::Nodes[]) 190 | end 191 | when "un" 192 | this << ZoticaBuilder.build_underover(options) do |base_this, under_this, over_this| 193 | base_this << children_list.fetch(0, REXML::Nodes[]) 194 | under_this << children_list.fetch(1, REXML::Nodes[]) 195 | end 196 | when "ov" 197 | this << ZoticaBuilder.build_underover(options) do |base_this, under_this, over_this| 198 | base_this << children_list.fetch(0, REXML::Nodes[]) 199 | over_this << children_list.fetch(1, REXML::Nodes[]) 200 | end 201 | when "frac" 202 | this << ZoticaBuilder.build_fraction(options) do |numerator_this, denominator_this| 203 | numerator_this << children_list.fetch(0, REXML::Nodes[]) 204 | denominator_this << children_list.fetch(1, REXML::Nodes[]) 205 | end 206 | when "sqrt" 207 | stretch_level = attributes["s"] 208 | symbol = ZoticaBuilder.fetch_radical_symbol(stretch_level) 209 | modify = !stretch_level 210 | this << ZoticaBuilder.build_radical(symbol, modify, options) do |content_this, index_this| 211 | content_this << children_list.fetch(0, REXML::Nodes[]) 212 | index_this << children_list.fetch(1, REXML::Nodes[]) 213 | end 214 | when "table" 215 | type = attributes["t"] 216 | align_config = attributes["align"] 217 | raw = !!attributes["raw"] 218 | this << ZoticaBuilder.build_table(type, align_config, raw, options) do |table_this| 219 | table_this << children_list.fetch(0, REXML::Nodes[]) 220 | end 221 | when "array" 222 | align_config = attributes["align"] 223 | this << ZoticaBuilder.build_table("std", align_config, true, options) do |table_this| 224 | table_this << children_list.fetch(0, REXML::Nodes[]) 225 | end 226 | when "stack" 227 | this << ZoticaBuilder.build_table("stk", nil, true, options) do |table_this| 228 | table_this << children_list.fetch(0, REXML::Nodes[]) 229 | end 230 | when "matrix" 231 | this << ZoticaBuilder.build_table("mat", nil, false, options) do |table_this| 232 | table_this << children_list.fetch(0, REXML::Nodes[]) 233 | end 234 | when "case" 235 | left_symbol = ZoticaBuilder.fetch_fence_symbol("brace", 0, nil) 236 | right_symbol = ZoticaBuilder.fetch_fence_symbol("none", 1, nil) 237 | this << ZoticaBuilder.build_fence("brace", "none", left_symbol, right_symbol, true, options) do |this| 238 | this << ZoticaBuilder.build_table("cas", "ll", false) do |table_this| 239 | table_this << children_list.fetch(0, REXML::Nodes[]) 240 | end 241 | end 242 | when "diag" 243 | vertical_gaps_string = attributes["ver"] 244 | horizontal_gaps_string = attributes["hor"] 245 | align_baseline = attributes["bl"] 246 | this << ZoticaBuilder.build_diagram(vertical_gaps_string, horizontal_gaps_string, align_baseline, options) do |table_this| 247 | table_this << children_list.fetch(0, REXML::Nodes[]) 248 | end 249 | when "c" 250 | this << ZoticaBuilder.build_table_cell(options) do |cell_this| 251 | cell_this << children_list.fetch(0, REXML::Nodes[]) 252 | end 253 | when "cc" 254 | children_list.each do |children| 255 | this << ZoticaBuilder.build_table_cell(options) do |cell_this| 256 | cell_this << children 257 | end 258 | end 259 | this << REXML::Element.new("math-sys-br") 260 | when "v" 261 | vertex_name = attributes["name"] 262 | this << ZoticaBuilder.build_diagram_vertex(vertex_name, options) do |vertex_this| 263 | vertex_this << children_list.fetch(0, REXML::Nodes[]) 264 | end 265 | when "vv" 266 | children_list.each do |children| 267 | this << ZoticaBuilder.build_diagram_vertex(options) do |vertex_this| 268 | vertex_this << children 269 | end 270 | end 271 | this << REXML::Element.new("math-sys-br") 272 | when "ar" 273 | configs = {} 274 | configs[:start_config] = attributes["s"] 275 | configs[:end_config] = attributes["e"] 276 | configs[:tip_kinds] = attributes["tip"] 277 | configs[:bend_angle] = attributes["bend"] 278 | configs[:shift] = attributes["shift"] 279 | configs[:line_count] = attributes["line"] 280 | configs[:dashed] = attributes["dash"] 281 | configs[:label_position] = attributes["pos"] 282 | configs[:inverted] = attributes["inv"] 283 | configs[:mark] = attributes["mark"] 284 | arrow_name = attributes["name"] 285 | this << ZoticaBuilder.build_arrow(arrow_name, configs, options) do |label_this| 286 | label_this << children_list.fetch(0, REXML::Nodes[]) 287 | end 288 | when "tree" 289 | this << ZoticaBuilder.build_tree(options) do |content_this| 290 | content_this << children_list.fetch(0, REXML::Nodes[]) 291 | end 292 | when "axm" 293 | this << ZoticaBuilder.build_tree_axiom(options) do |content_this| 294 | content_this << children_list.fetch(0, REXML::Nodes[]) 295 | end 296 | when "infr" 297 | number = attributes["n"].to_i 298 | this << ZoticaBuilder.build_tree_inference(number, options) do |content_this, right_label_this, left_label_this| 299 | content_this << children_list.fetch(0, REXML::Nodes[]) 300 | right_label_this << children_list.fetch(1, REXML::Nodes[]) 301 | left_label_this << children_list.fetch(2, REXML::Nodes[]) 302 | end 303 | when "br" 304 | this << REXML::Element.new("math-sys-br") 305 | when "g" 306 | transform_configs = {} 307 | transform_configs[:rotate] = attributes["rotate"] 308 | this << ZoticaBuilder.build_group(transform_configs, options) do |content_this| 309 | content_this << children_list.fetch(0, REXML::Nodes[]) 310 | end 311 | when "ph", "vph", "hph" 312 | type = PHANTOM_TYPES[name] || attributes["t"] || "bth" 313 | this << ZoticaBuilder.build_phantom(type, options) do |content_this| 314 | content_this << children_list.fetch(0, REXML::Nodes[]) 315 | end 316 | when "s" 317 | type = attributes["t"] || "med" 318 | this << ZoticaBuilder.build_space(type, options) 319 | when SPACE_ALTERNATIVES.method(:key?) 320 | type = SPACE_ALTERNATIVES[name] 321 | this << ZoticaBuilder.build_space(type, options) 322 | else 323 | this << REXML::Element.build(name) do |this| 324 | attributes.each do |key, value| 325 | this[key] = value 326 | end 327 | this << children_list.fetch(0, REXML::Nodes[]) 328 | end 329 | end 330 | return this 331 | end 332 | 333 | def create_math_text(text, options = {}) 334 | this = REXML::Nodes[] 335 | options[:fonts] = @fonts 336 | text.each_char do |char| 337 | if char =~ /\p{Number}/ 338 | this << ZoticaBuilder.build_number(char, options) 339 | elsif char =~ /\p{Letter}|\p{Mark}/ 340 | this << ZoticaBuilder.build_identifier(char, [], options) 341 | elsif char == "'" 342 | symbol, types = ZoticaBuilder.fetch_operator_symbol("pr") 343 | this << ZoticaBuilder.build_subsuper(options) do |base_this, sub_this, super_this| 344 | super_this << ZoticaBuilder.build_operator(symbol, types, options) 345 | end 346 | elsif char !~ /\s/ 347 | char = DATA["replacement"][char] || char 348 | name = DATA["operator"].find{|s, (t, u)| char == t}&.first || char 349 | symbol, kinds = DATA["operator"][name] || [name, ["bin"]] 350 | this << ZoticaBuilder.build_operator(symbol, kinds, options) 351 | end 352 | end 353 | return this 354 | end 355 | 356 | def create_math_escape(char, options = {}) 357 | next_char = char 358 | if DATA["greek"].key?(char) 359 | next_char = DATA["greek"][char] 360 | end 361 | return next_char 362 | end 363 | 364 | def parse_math_root 365 | element = REXML::Element.new("math-root") 366 | children = parse_nodes({}) 367 | if @exact 368 | parse_eof 369 | end 370 | children.each do |child| 371 | element.add(child) 372 | end 373 | return element 374 | end 375 | 376 | def determine_options(name, marks, attributes, macro, options) 377 | if DATA["leaf"].include?(name) 378 | options = options.clone 379 | options[:math_leaf] = true 380 | return options 381 | else 382 | return super 383 | end 384 | end 385 | 386 | def determine_role(attributes) 387 | role = nil 388 | roles = ZoticaBuilder::ROLES 389 | roles.each do |each_role| 390 | if attributes[each_role] 391 | role = each_role 392 | end 393 | end 394 | return role 395 | end 396 | 397 | def create_element(name, marks, attributes, children_list, options) 398 | element = create_math_element(name, attributes, children_list) 399 | return element 400 | end 401 | 402 | def create_special_element(kind, children, options) 403 | element = create_math_element("g", {}, [children]) 404 | return element 405 | end 406 | 407 | def create_text(raw_text, options) 408 | if !options[:math_leaf] 409 | text = create_math_text(raw_text) 410 | else 411 | text = super 412 | end 413 | return text 414 | end 415 | 416 | def create_escape(place, char, options) 417 | if place == :text 418 | escape = create_math_escape(char) 419 | else 420 | escape = super 421 | end 422 | return escape 423 | end 424 | 425 | ZoticaBuilder = Zenithal::ZoticaBuilder 426 | 427 | DATA = ZoticaBuilder::DATA 428 | DEFAULT_FONTS = ZoticaBuilder::DEFAULT_FONTS 429 | 430 | end 431 | 432 | 433 | class Zenithal::ZoticaSingleParser < Zenithal::ZenithalParser 434 | 435 | include Zenithal::ZoticaSingleParserMethod 436 | 437 | attr_accessor :exact 438 | attr_accessor :fonts 439 | 440 | def initialize(source) 441 | super(source) 442 | @exact = false 443 | @fonts = {} 444 | @attributes = nil 445 | @block = nil 446 | end 447 | 448 | def setup(attributes, block) 449 | @attributes = attributes 450 | @block = block 451 | end 452 | 453 | def load_font(path) 454 | if path 455 | @fonts[:main] = JSON.parse(File.read(path)) 456 | end 457 | end 458 | 459 | end 460 | 461 | 462 | class Zenithal::ZoticaParser < Zenithal::ZenithalParser 463 | 464 | def initialize(source) 465 | super(source) 466 | @inner_parser = Zenithal::ZoticaSingleParser.new(source) 467 | end 468 | 469 | def load_font(path) 470 | @inner_parser.load_font(path) 471 | end 472 | 473 | def register_math_macro(name, &block) 474 | outer_self = self 475 | register_plugin(name) do |attributes| 476 | parser = @inner_parser.clone 477 | parser.version = outer_self.instance_variable_get("@version") 478 | parser.update(@source) 479 | parser.setup(attributes, block) 480 | next parser 481 | end 482 | @inner_parser.register_plugin(name) do |attributes| 483 | parser = @inner_parser.clone 484 | parser.version = outer_self.instance_variable_get("@version") 485 | parser.update(@source) 486 | parser.setup(attributes, block) 487 | next parser 488 | end 489 | end 490 | 491 | def register_simple_math_macro(name) 492 | register_math_macro(name) do |attributes, children_list| 493 | next [children_list.first] 494 | end 495 | end 496 | 497 | def simple_math_macro_name=(name) 498 | warn("This method is now obsolete. Use 'register_simple_math_macro' instead.", uplevel: 1) 499 | register_simple_math_macro(name) 500 | end 501 | 502 | def register_raw_macro(name) 503 | outer_self = self 504 | @inner_parser.register_plugin(name) do |_| 505 | raw_parser = outer_self.clone 506 | raw_parser.exact = false 507 | raw_parser.whole = false 508 | next raw_parser 509 | end 510 | end 511 | 512 | def raw_macro_name=(name) 513 | warn("This method is now obsolete. Use 'register_raw_macro' instead.", uplevel: 1) 514 | register_raw_macro(name) 515 | end 516 | 517 | def register_resource_macro(name) 518 | register_macro(name) do |attributes, children_list| 519 | style_string = Zenithal::ZoticaBuilder.create_style_string(attributes["font-url"]) 520 | script_string = Zenithal::ZoticaBuilder.create_script_string 521 | nodes = REXML::Nodes[] 522 | nodes << REXML::Element.build("style") do |element| 523 | element << REXML::Text.new(style_string, true, nil, true) 524 | end 525 | nodes << REXML::Element.build("script") do |element| 526 | element << REXML::CData.new(script_string) 527 | end 528 | next nodes 529 | end 530 | end 531 | 532 | def resource_macro_name=(name) 533 | warn("This method is now obsolete. Use 'register_resource_macro' instead.", uplevel: 1) 534 | register_resource_macro(name) 535 | end 536 | 537 | end -------------------------------------------------------------------------------- /source/zotica/resource/font.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ziphil/ZenithalMathWeb/be28ee9cc101de9276a3a641abb9961f4614a7dd/source/zotica/resource/font.otf -------------------------------------------------------------------------------- /source/zotica/resource/math.json: -------------------------------------------------------------------------------- 1 | { 2 | "leaf": [ 3 | "n", "i", "op", "o", "bf", "rm", "bfrm", "tt", 4 | "text", 5 | "bb", "varbb", "cal", "scr", "frak", "varfrak" 6 | ], 7 | "replacement": { 8 | "-": "−", 9 | "*": "∗" 10 | }, 11 | "fence": { 12 | "paren": [ 13 | { 14 | "0": "(", 15 | "1": "\uDB80\uDC39", "2": "\uDB80\uDC3A", "3": "\uDB80\uDC3B", "4": "\uDB80\uDC3C", "5": "\uDB80\uDC3D", "6": "\uDB80\uDC3E", 16 | "7": "\uDB80\uDC3F", "8": "\uDB80\uDC40", "9": "\uDB80\uDC41", "10": "\uDB80\uDC42", "11": "\uDB80\uDC43", "12": "\uDB80\uDC44", 17 | "start": "⎛", "bar": "⎜", "end": "⎝" 18 | }, 19 | { 20 | "0": ")", 21 | "1": "\uDB80\uDC45", "2": "\uDB80\uDC46", "3": "\uDB80\uDC47", "4": "\uDB80\uDC48", "5": "\uDB80\uDC49", "6": "\uDB80\uDC4A", 22 | "7": "\uDB80\uDC4B", "8": "\uDB80\uDC4C", "9": "\uDB80\uDC4D", "10": "\uDB80\uDC4E", "11": "\uDB80\uDC4F", "12": "\uDB80\uDC50", 23 | "start": "⎞", "bar":"⎟", "end": "⎠" 24 | } 25 | ], 26 | "pparen": [ 27 | { 28 | "0": "⦅", 29 | "1": "\uDB80\uDE0A", "2": "\uDB80\uDE0B", "3": "\uDB80\uDE0C", "4": "\uDB80\uDE0D" 30 | }, 31 | { 32 | "0": "⦆", 33 | "1": "\uDB80\uDE0E", "2": "\uDB80\uDE0F", "3": "\uDB80\uDE10", "4": "\uDB80\uDE11" 34 | } 35 | ], 36 | "bracket": [ 37 | { 38 | "0": "[", 39 | "1": "\uDB80\uDC51", "2": "\uDB80\uDC52", "3": "\uDB80\uDC53", "4": "\uDB80\uDC54", "5": "\uDB80\uDC55", "6": "\uDB80\uDC56", 40 | "7": "\uDB80\uDC57", "8": "\uDB80\uDC58", "9": "\uDB80\uDC59", "10": "\uDB80\uDC5A", "11": "\uDB80\uDC5B", "12": "\uDB80\uDC5C", 41 | "start": "⎡", "bar": "⎢", "end": "⎣" 42 | }, 43 | { 44 | "0": "]", 45 | "1": "\uDB80\uDC5D", "2": "\uDB80\uDC5E", "3": "\uDB80\uDC5F", "4": "\uDB80\uDC60", "5": "\uDB80\uDC61", "6": "\uDB80\uDC62", 46 | "7": "\uDB80\uDC63", "8": "\uDB80\uDC64", "9": "\uDB80\uDC65", "10": "\uDB80\uDC66", "11": "\uDB80\uDC67", "12": "\uDB80\uDC68", 47 | "start": "⎤", "bar": "⎥", "end": "⎦" 48 | } 49 | ], 50 | "bbracket": [ 51 | { 52 | "0": "⟦", 53 | "1": "\uDB80\uDDE8", "2": "\uDB80\uDDE9", "3": "\uDB80\uDDEA", "4": "\uDB80\uDDEB" 54 | }, 55 | { 56 | "0": "⟧", 57 | "1": "\uDB80\uDDEC", "2": "\uDB80\uDDED", "3": "\uDB80\uDDEE", "4": "\uDB80\uDDEF" 58 | } 59 | ], 60 | "brace": [ 61 | { 62 | "0": "{", 63 | "1": "\uDB80\uDC69", "2": "\uDB80\uDC6A", "3": "\uDB80\uDC6B", "4": "\uDB80\uDC6C", "5": "\uDB80\uDC6D", "6": "\uDB80\uDC6E", 64 | "7": "\uDB80\uDC6F", "8": "\uDB80\uDC70", "9": "\uDB80\uDC71", "10": "\uDB80\uDC72", "11": "\uDB80\uDC73", "12": "\uDB80\uDC74", 65 | "start": "⎧", "bar": "⎪", "middle": "⎨", "end": "⎩" 66 | }, 67 | { 68 | "0": "}", 69 | "1": "\uDB80\uDC75", "2": "\uDB80\uDC76", "3": "\uDB80\uDC77", "4": "\uDB80\uDC78", "5": "\uDB80\uDC79", "6": "\uDB80\uDC7A", 70 | "7": "\uDB80\uDC7B", "8": "\uDB80\uDC7C", "9": "\uDB80\uDC7D", "10": "\uDB80\uDC7E", "11": "\uDB80\uDC7F", "12": "\uDB80\uDC80", 71 | "start": "⎫", "bar": "⎪", "middle": "⎬", "end": "⎭" 72 | } 73 | ], 74 | "bbrace": [ 75 | { 76 | "0": "⦃", 77 | "1": "\uDB80\uDE02", "2": "\uDB80\uDE03", "3": "\uDB80\uDE04", "4": "\uDB80\uDE05" 78 | }, 79 | { 80 | "0": "⦄", 81 | "1": "\uDB80\uDE06", "2": "\uDB80\uDE07", "3": "\uDB80\uDE08", "4": "\uDB80\uDE09" 82 | } 83 | ], 84 | "vert": [ 85 | { 86 | "0": "|", 87 | "bar": "|" 88 | }, 89 | { 90 | "0": "|", 91 | "bar": "|" 92 | } 93 | ], 94 | "vvert": [ 95 | { 96 | "0": "‖", 97 | "bar": "‖" 98 | }, 99 | { 100 | "0": "‖", 101 | "bar": "‖" 102 | } 103 | ], 104 | "floor": [ 105 | { 106 | "0": "⌊", 107 | "1": "\uDB80\uDD99", "2": "\uDB80\uDD9A", "3": "\uDB80\uDD9B", "4": "\uDB80\uDD9C" 108 | }, 109 | { 110 | "0": "⌋", 111 | "1": "\uDB80\uDD9D", "2": "\uDB80\uDD9E", "3": "\uDB80\uDD9F", "4": "\uDB80\uDDA0" 112 | } 113 | ], 114 | "ceil": [ 115 | { 116 | "0": "⌈", 117 | "1": "\uDB80\uDD91", "2": "\uDB80\uDD92", "3": "\uDB80\uDD93", "4": "\uDB80\uDD94" 118 | }, 119 | { 120 | "0": "⌉", 121 | "1": "\uDB80\uDD95", "2": "\uDB80\uDD96", "3": "\uDB80\uDD97", "4": "\uDB80\uDD98" 122 | } 123 | ], 124 | "angle": [ 125 | { 126 | "0": "⟨", 127 | "1": "\uDB80\uDDF0", "2": "\uDB80\uDDF1", "3": "\uDB80\uDDF2", "4": "\uDB80\uDDF3" 128 | }, 129 | { 130 | "0": "⟩", 131 | "1": "\uDB80\uDDF4", "2": "\uDB80\uDDF5", "3": "\uDB80\uDDF6", "4": "\uDB80\uDDF7" 132 | } 133 | ], 134 | "aangle": [ 135 | { 136 | "0": "⟪", 137 | "1": "\uDB80\uDDF8", "2": "\uDB80\uDDF9", "3": "\uDB80\uDDFA", "4": "\uDB80\uDDFB" 138 | }, 139 | { 140 | "0": "⟫", 141 | "1": "\uDB80\uDDFC", "2": "\uDB80\uDDFD", "3": "\uDB80\uDDFE", "4": "\uDB80\uDDFF" 142 | } 143 | ], 144 | "tort": [ 145 | { 146 | "0": "❲", 147 | "1": "\uDB80\uDDE0", "2": "\uDB80\uDDE1", "3": "\uDB80\uDDE2", "4": "\uDB80\uDDE3", 148 | "start": "\uDB81\uDDA4", "bar": "\uDB81\uDDA5", "end": "\uDB81\uDDA6" 149 | }, 150 | { 151 | "0": "❳", 152 | "1": "\uDB80\uDDE4", "2": "\uDB80\uDDE5", "3": "\uDB80\uDDE6", "4": "\uDB80\uDDE7", 153 | "start": "\uDB81\uDDA7", "bar": "\uDB81\uDDA8", "end": "\uDB81\uDDA9" 154 | } 155 | ] 156 | }, 157 | "integral": { 158 | "int": ["∫", "\uDB80\uDD35"], 159 | "iint": ["∬", "\uDB80\uDD3A"], 160 | "iiint": ["∭", "\uDB80\uDD3F"], 161 | "iiiint": ["⨌", "\uDB80\uDE24"], 162 | "oint": ["∮", "\uDB80\uDD44"], 163 | "oiint": ["∯", "\uDB80\uDD49"], 164 | "oiiint": ["∰", "\uDB80\uDD4E"], 165 | "intclock": ["∱", "\uDB80\uDD53"], 166 | "intanticlock": ["⨑", "\uDB80\uDE3D"], 167 | "ointclock": ["∲", "\uDB80\uDD58"], 168 | "ointanticlock": ["∳", "\uDB80\uDD5D"], 169 | "fint": ["⨍", "\uDB80\uDE29"] 170 | }, 171 | "sum": { 172 | "sum": ["∑", "\uDB80\uDD1A"], 173 | "prod": ["∏", "\uDB80\uDD16"], 174 | "coprod": ["∐", "\uDB80\uDD18"], 175 | "bigoplus": ["⨁", "\uDB80\uDE15"], 176 | "bigotimes": ["⨂", "\uDB80\uDE16"], 177 | "bigodot": ["⨀", "\uDB80\uDE14"], 178 | "bigcap": ["⋂", "\uDB80\uDD89"], 179 | "bigcup": ["⋃", "\uDB80\uDD8A"], 180 | "bigsqcap": ["⨅", "\uDB80\uDE19"], 181 | "bigsqcup": ["⨆", "\uDB80\uDE1A"], 182 | "bigwedge": ["⋀", "\uDB80\uDD87"], 183 | "bigvee": ["⋁", "\uDB80\uDD88"] 184 | }, 185 | "radical": { 186 | "0": "√", "1": "\uDB80\uDD1D", "2": "\uDB80\uDD1E", "3": "\uDB80\uDD1F", 187 | "height": [1486, 2102, 2623, 3100] 188 | }, 189 | "accent": { 190 | "bar": [null, "\uDB81\uDD04"], 191 | "tilde": [null, "\uDB81\uDD03"], 192 | "hat": [null, "\uDB81\uDD02"], 193 | "check": [null, "\uDB81\uDD0C"], 194 | "acute": [null, "\uDB81\uDD01"], 195 | "grave": [null, "\uDB81\uDD00"], 196 | "breve": [null, "\uDB81\uDD06"], 197 | "invbreve": [null, "\uDB81\uDD11"], 198 | "ring": [null, "\uDB81\uDD0A"], 199 | "vec": [null, "\uDB81\uDD77"], 200 | "invvec": [null, "\uDB81\uDD76"], 201 | "dot": [null, "\uDB81\uDD07"], 202 | "ddot": [null, "\uDB81\uDD08"], 203 | "dddot": [null, "\uDB81\uDD7B"], 204 | "ddddot": [null, "\uDB81\uDD7C"], 205 | "barbelow": ["\uDB81\uDD31", null], 206 | "tildebelow": ["\uDB81\uDD30", null] 207 | }, 208 | "wide": { 209 | "widetilde": [ 210 | null, 211 | { 212 | "0": "\uDB80\uDCA1", "1": "\uDB80\uDCA2", "2": "\uDB80\uDCA3", "3": "\uDB80\uDCA4", "4": "\uDB80\uDCA5", 213 | "width": [1002, 1495, 1931, 2384, 10000] 214 | } 215 | ], 216 | "widehat": [ 217 | null, 218 | { 219 | "0": "\uDB80\uDC97", "1": "\uDB80\uDC98", "2": "\uDB80\uDC99", "3": "\uDB80\uDC9A", "4": "\uDB80\uDC9B", 220 | "width": [1002, 1495, 1931, 2384, 10000] 221 | } 222 | ], 223 | "widecheck": [ 224 | null, 225 | { 226 | "0": "\uDB80\uDC9C", "1": "\uDB80\uDC9D", "2": "\uDB80\uDC9E", "3": "\uDB80\uDC9F", "4": "\uDB80\uDCA0", 227 | "width": [1002, 1495, 1931, 2384, 10000] 228 | } 229 | ], 230 | "overline": [ 231 | null, 232 | { 233 | "0": "", 234 | "bar": "\uDB80\uDCB5" 235 | } 236 | ], 237 | "overrarr": [ 238 | null, 239 | { 240 | "0": "", 241 | "bar": "\uDB80\uDCE9", "end": "\uDB80\uDCEA" 242 | } 243 | ], 244 | "overlarr": [ 245 | null, 246 | { 247 | "0": "", 248 | "end": "\uDB80\uDCE4", "bar": "\uDB80\uDCE9" 249 | } 250 | ], 251 | "overbrace": [ 252 | null, 253 | { 254 | "0": "⏞", "1": "\uDB80\uDDC7", "2": "\uDB80\uDDC8", "3": "\uDB80\uDDC9", "4": "\uDB80\uDDCA", "5": "\uDB80\uDDCB", 255 | "start": "\uDB80\uDDC4", "bar": "\uDB80\uDDAA", "middle": "\uDB80\uDDC5", "end": "\uDB80\uDDC6", 256 | "width": [1000, 1500, 1770, 2180, 2600, 2850] 257 | } 258 | ], 259 | "overgroup": [ 260 | null, 261 | { 262 | "0": "", 263 | "start": "\uDB80\uDDC4", "bar": "\uDB80\uDDAA", "end": "\uDB80\uDDC6" 264 | } 265 | ], 266 | "widetildebelow": [ 267 | { 268 | "0": "\uDB80\uDCA6", "1": "\uDB80\uDCA7", "2": "\uDB80\uDCA8", "3": "\uDB80\uDCA9", "4": "\uDB80\uDCAA", 269 | "width": [1002, 1495, 1931, 2384, 10000] 270 | }, 271 | null 272 | ], 273 | "underline": [ 274 | { 275 | "0": "", 276 | "bar": "\uDB80\uDC92" 277 | }, 278 | null 279 | ], 280 | "underrarr": [ 281 | { 282 | "0": "", 283 | "bar": "\uDB80\uDCFE", "end": "\uDB80\uDCFF" 284 | }, 285 | null 286 | ], 287 | "underlarr": [ 288 | { 289 | "0": "", 290 | "start": "\uDB80\uDCF9", "bar": "\uDB80\uDCFE" 291 | }, 292 | null 293 | ], 294 | "underbrace": [ 295 | { 296 | "0": "⏟", "1": "\uDB80\uDDCF", "2": "\uDB80\uDDD0", "3": "\uDB80\uDDD1", "4": "\uDB80\uDDD2", "5": "\uDB80\uDDD3", 297 | "start": "\uDB80\uDDCC", "bar": "\uDB80\uDDB2", "middle": "\uDB80\uDDCD", "end": "\uDB80\uDDCE", 298 | "width": [1000, 1500, 1770, 2180, 2600, 2850] 299 | }, 300 | null 301 | ], 302 | "undergroup": [ 303 | { 304 | "0": "", 305 | "start": "\uDB80\uDDCC", "bar": "\uDB80\uDDB2", "end": "\uDB80\uDDCE" 306 | }, 307 | null 308 | ] 309 | }, 310 | "function": [ 311 | "sin", "cos", "tan", "cot", "sec", "csc", "sinh", "cosh", "tanh", 312 | "log", "ln", "lg", "exp", 313 | "inf", "sup", "min", "max", 314 | "ker", "im", 315 | "lim", "colim", 316 | "deg", "dim", "det", "sgn", "arg" 317 | ], 318 | "identifier": { 319 | "varbeta": "ϐ", 320 | "varepsilon": "ϵ", 321 | "vartheta": "ϑ", 322 | "varkappa": "ϰ", 323 | "varpi": "ϖ", 324 | "varrho": "ϱ", 325 | "varphi": "ϕ", 326 | "varcapupsilon": "ϒ", 327 | "digamma": "ϝ", "capdigamma": "Ϝ", 328 | "koppa": "ϙ", "capkoppa": "Ϙ", 329 | "varkoppa": "ϟ", "varcapkoppa": "Ϟ", 330 | "sampi": "ϡ", "capsampi": "Ϡ", 331 | "varsampi": "ͳ", "varcapsampi": "Ͳ" 332 | }, 333 | "operator": { 334 | "plus": ["+", ["bin"]], 335 | "minus": ["−", ["bin"]], 336 | "setminus": ["∖", ["bin"]], 337 | "pm": ["±", ["bin"]], 338 | "mp": ["∓", ["bin"]], 339 | "times": ["×", ["bin"]], 340 | "ltimes": ["⋉", ["bin"]], 341 | "rtimes": ["⋊", ["bin"]], 342 | "btimes": ["⨲", ["bin"]], 343 | "bowtie": ["⋈", ["bin"]], 344 | "lthree": ["⋋", ["bin"]], 345 | "rthree": ["⋌", ["bin"]], 346 | "smash": ["⨳", ["bin"]], 347 | "div": ["÷", ["bin"]], 348 | "cdot": ["·", ["bin"]], 349 | "ast": ["∗", ["bin"]], "tast": ["∗", ["ord"]], 350 | "star": ["⋆", ["bin"]], "tstar": ["⋆", ["ord"]], 351 | "wr": ["≀", ["bin"]], 352 | "circ": ["∘", ["bin"]], 353 | "diamond": ["⋄", ["bin"]], 354 | "rcomp": ["\uDB81\uDDA1", ["bin"]], 355 | "lcomp": ["\uDB81\uDDA3", ["bin"]], 356 | "oplus": ["⊕", ["bin"]], 357 | "loplus": ["⨭", ["bin"]], "roplus": ["⨮", ["bin"]], 358 | "ominus": ["⊖", ["bin"]], 359 | "otimes": ["⊗", ["bin"]], 360 | "lotimes": ["⨴", ["bin"]], "rotimes": ["⨵", ["bin"]], 361 | "odiv": ["⨸", ["bin"]], 362 | "oslash": ["⊘", ["bin"]], 363 | "obackslash": ["⦸", ["bin"]], 364 | "odot": ["⊙", ["bin"]], 365 | "ocirc": ["⊚", ["bin"]], 366 | "cast": ["⊛", ["bin"]], 367 | "oeq": ["⊜", ["bin"]], 368 | "box": ["◻", ["bin"]], 369 | "boxplus": ["⊞", ["bin"]], 370 | "boxminus": ["⊟", ["bin"]], 371 | "boxtimes": ["⊠", ["bin"]], 372 | "boxslash": ["⧄", ["bin"]], 373 | "boxbackslash": ["⧅", ["bin"]], 374 | "boxdot": ["⊡", ["bin"]], 375 | "boxcirc": ["⧇", ["bin"]], 376 | "boxast": ["⧆", ["bin"]], 377 | "rhombus": ["⬦", ["bin"]], "trhombus": ["⬦", ["ord"]], 378 | "pentagon": ["⬠", ["bin"]], "tpentagon": ["⬠", ["ord"]], 379 | "hexagon": ["⬡", ["bin"]], "thexagon": ["⬡", ["ord"]], 380 | "utriangle": ["▵", ["bin"]], "tutriangle": ["▵", ["ord"]], 381 | "dtriangle": ["▿", ["bin"]], "tdtriangle": ["▿", ["ord"]], 382 | "rtriangle": ["▹", ["bin"]], "trtriangle": ["▹", ["ord"]], 383 | "ltriangle": ["◃", ["bin"]], "tltriangle": ["◃", ["ord"]], 384 | "cap": ["∩", ["bin"]], 385 | "cup": ["∪", ["bin"]], 386 | "ccap": ["⋒", ["bin"]], 387 | "ccup": ["⋓", ["bin"]], 388 | "sqcap": ["⊓", ["bin"]], 389 | "sqcup": ["⊔", ["bin"]], 390 | "ssqcap": ["⩎", ["bin"]], 391 | "ssqcup": ["⩏", ["bin"]], 392 | "wedge": ["∧", ["bin"]], 393 | "vee": ["∨", ["bin"]], 394 | "barwedge": ["⊼", ["bin"]], 395 | "barvee": ["⊽", ["bin"]], 396 | "veebar": ["⊻", ["bin"]], 397 | "wwedge": ["⩕", ["bin"]], 398 | "vvee": ["⩖", ["bin"]], 399 | "varwwedge": ["⩓", ["bin"]], 400 | "varvvee": ["⩔", ["bin"]], 401 | "pitchfork": ["⋔", ["bin"]], 402 | "percent": ["%", ["bin", "txt"]], 403 | "atsym": ["@", ["bin", "txt"]], 404 | "eq": ["=", ["rel"]], "neq": ["≠", ["rel"]], 405 | "asiansim": ["≒", ["rel"]], 406 | "varasiansim": ["≓", ["rel"]], 407 | "coloneqq": [":=", ["rel"]], 408 | "eqqcolon": ["=:", ["rel"]], 409 | "ccoloneqq": ["::=", ["rel"]], 410 | "eqqccolon": ["=::", ["rel"]], 411 | "equiv": ["≡", ["rel"]], "nequiv": ["≢", ["rel"]], 412 | "colonequiv": [":≡", ["rel"]], 413 | "eequiv": ["≣", ["rel"]], 414 | "coloneqquiv": [":≣", ["rel"]], 415 | "sim": ["∼", ["rel"]], "nsim": ["≁", ["rel"]], 416 | "colonsim": [":∼", ["rel"]], 417 | "simeq": ["≃", ["rel"]], "nsimeq": ["≄", ["rel"]], 418 | "colonsimeq": [":≃", ["rel"]], 419 | "eqsim": ["≂", ["rel"]], 420 | "coloneqsim": [":≂", ["rel"]], 421 | "cong": ["≅", ["rel"]], "ncong": ["≇", ["rel"]], 422 | "coloncong": [":≅", ["rel"]], 423 | "approx": ["≈", ["rel"]], "napprox": ["≉", ["rel"]], 424 | "colonapprox": [":≈", ["rel"]], 425 | "approxeq": ["≊", ["rel"]], 426 | "colonapproxeq": [":≊", ["rel"]], 427 | "aapprox": ["≋", ["rel"]], 428 | "colonaapprox": [":≋", ["rel"]], 429 | "smile": ["\uDB81\uDDAA", ["rel"]], 430 | "largesmile": ["⌣", ["rel"]], 431 | "frown": ["\uDB81\uDDAB", ["rel"]], 432 | "largefrown": ["⌢", ["rel"]], 433 | "closure": ["\uDB81\uDDAC", ["rel"]], 434 | "asymp": ["≍", ["rel"]], "nasymp": ["≭", ["rel"]], 435 | "bumpeq": ["≏", ["rel"]], 436 | "bumpbump": ["≎", ["rel"]], 437 | "eqcirc": ["≖", ["rel"]], 438 | "gt": [">", ["rel"]], "ngt": ["≯", ["rel"]], 439 | "ls": ["<", ["rel"]], "nls": ["≮", ["rel"]], 440 | "geq": ["≥", ["rel"]], "ngeq": ["≱", ["rel"]], "gneq": ["⪈", ["rel"]], 441 | "leq": ["≤", ["rel"]], "nleq": ["≰", ["rel"]], "lneq": ["⪇", ["rel"]], 442 | "geqq": ["≧", ["rel"]], "gneqq": ["≩", ["rel"]], 443 | "leqq": ["≦", ["rel"]], "lneqq": ["≨", ["rel"]], 444 | "gsim": ["≳", ["rel"]], "ngsim": ["≵", ["rel"]], "gnsim": ["⋧", ["rel"]], 445 | "lsim": ["≲", ["rel"]], "nlsim": ["≴", ["rel"]], "lnsim": ["⋦", ["rel"]], 446 | "gapprox": ["⪆", ["rel"]], "gnapprox": ["⪊", ["rel"]], 447 | "lapprox": ["⪅", ["rel"]], "lnapprox": ["⪉", ["rel"]], 448 | "eqg": ["⋝", ["rel"]], 449 | "eql": ["⋜", ["rel"]], 450 | "eqqg": ["⪚", ["rel"]], 451 | "eqql": ["⪙", ["rel"]], 452 | "simg": ["⪞", ["rel"]], 453 | "siml": ["⪝", ["rel"]], 454 | "gl": ["≷", ["rel"]], "ngl": ["≹", ["rel"]], 455 | "lg": ["≶", ["rel"]], "nlg": ["≸", ["rel"]], 456 | "geql": ["⋛", ["rel"]], 457 | "leqg": ["⋚", ["rel"]], 458 | "geqql": ["⪌", ["rel"]], 459 | "leqqg": ["⪋", ["rel"]], 460 | "ggt": ["≫", ["rel"]], 461 | "lls": ["≪", ["rel"]], 462 | "llseq": ["⪣", ["rel"]], 463 | "varggt": ["⪢", ["rel"]], 464 | "varlls": ["⪡", ["rel"]], 465 | "gggt": ["⋙", ["rel"]], 466 | "llls": ["⋘", ["rel"]], 467 | "vargggt": ["⫸", ["rel"]], 468 | "varllls": ["⫷", ["rel"]], 469 | "succ": ["≻", ["rel"]], "nsucc": ["⊁", ["rel"]], 470 | "prec": ["≺", ["rel"]], "nprec": ["⊀", ["rel"]], 471 | "succeq": ["⪰", ["rel"]], "succneq": ["⪲", ["rel"]], 472 | "preceq": ["⪯", ["rel"]], "precneq": ["⪱", ["rel"]], 473 | "succeqq": ["⪴", ["rel"]], "succneqq": ["⪶", ["rel"]], 474 | "preceqq": ["⪳", ["rel"]], "precneqq": ["⪵", ["rel"]], 475 | "succsim": ["≿", ["rel"]], "succnsim": ["⋩", ["rel"]], 476 | "precsim": ["≾", ["rel"]], "precnsim": ["⋨", ["rel"]], 477 | "succapprox": ["⪸", ["rel"]], "succnapprox": ["⪺", ["rel"]], 478 | "precapprox": ["⪷", ["rel"]], "precnapprox": ["⪹", ["rel"]], 479 | "ssucc": ["⪼", ["rel"]], 480 | "pprec": ["⪻", ["rel"]], 481 | "succrel": ["⊱", ["rel"]], 482 | "precrel": ["⊰", ["rel"]], 483 | "in": ["∈", ["rel"]], "nin": ["∉", ["rel"]], 484 | "ni": ["∋", ["rel"]], "nni": ["∌", ["rel"]], 485 | "ineq": ["⋸", ["rel"]], 486 | "disin": ["⋲", ["rel"]], 487 | "smt": ["⪪", ["rel"]], 488 | "lat": ["⪫", ["rel"]], 489 | "smteq": ["⪬", ["rel"]], 490 | "lateq": ["⪭", ["rel"]], 491 | "supset": ["⊃", ["rel"]], "nsupset": ["⊃⃒", ["rel"]], 492 | "subset": ["⊂", ["rel"]], "nsubset": ["⊂⃒", ["rel"]], 493 | "supseteq": ["⊇", ["rel"]], "nsupseteq": ["⊉", ["rel"]], "supsetneq": ["⊋", ["rel"]], 494 | "subseteq": ["⊆", ["rel"]], "nsubseteq": ["⊈", ["rel"]], "subsetneq": ["⊊", ["rel"]], 495 | "supseteqq": ["⫆", ["rel"]], "supsetneqq": ["⫌", ["rel"]], 496 | "subseteqq": ["⫅", ["rel"]], "subsetneqq": ["⫋", ["rel"]], 497 | "supsetsim": ["⫈", ["rel"]], 498 | "subsetsim": ["⫇", ["rel"]], 499 | "supsetapprox": ["⫊", ["rel"]], 500 | "subsetapprox": ["⫉", ["rel"]], 501 | "ssupset": ["⋑", ["rel"]], 502 | "ssubset": ["⋐", ["rel"]], 503 | "sqsupset": ["⊐", ["rel"]], "nsqsupset": ["⊐̸", ["rel"]], 504 | "sqsubset": ["⊏", ["rel"]], "nsqsubset": ["⊏̸", ["rel"]], 505 | "sqsupseteq": ["⊒", ["rel"]], "nsqsupseteq": ["⋣", ["rel"]], "sqsupsetneq": ["⋥", ["rel"]], 506 | "sqsubseteq": ["⊑", ["rel"]], "nsqsubseteq": ["⋢", ["rel"]], "sqsubsetneq": ["⋤", ["rel"]], 507 | "rhd": ["⊳", ["rel"]], "nrhd": ["⋫", ["rel"]], 508 | "lhd": ["⊲", ["rel"]], "nlhd": ["⋪", ["rel"]], 509 | "rhdeq": ["⊵", ["rel"]], "nrhdeq": ["⋭", ["rel"]], 510 | "lhdeq": ["⊴", ["rel"]], "nlhdeq": ["⋬", ["rel"]], 511 | "curverhd": ["⪧", ["rel"]], 512 | "curvelhd": ["⪦", ["rel"]], 513 | "barrhd": ["⩥", ["rel"]], 514 | "barlhd": ["⩤", ["rel"]], 515 | "vdash": ["⊢", ["rel"]], "nvdash": ["⊬", ["rel"]], 516 | "vddash": ["⊨", ["rel"]], "nvddash": ["⊭", ["rel"]], 517 | "vvdash": ["⊩", ["rel"]], "nvvdash": ["⊮", ["rel"]], 518 | "dashv": ["⊣", ["rel"]], 519 | "dashvv": ["⫣", ["rel"]], 520 | "ddashv": ["⫤", ["rel"]], 521 | "mid": ["∣", ["rel"]], "nmid": ["∤", ["rel"]], 522 | "parallel": ["∥", ["rel"]], "nparallel": ["∦", ["rel"]], 523 | "between": ["≬", ["rel"]], 524 | "perp": ["⟂", ["rel"]], 525 | "propto": ["∝", ["rel"]], 526 | "similarto": ["∽", ["rel"]], 527 | "rarr": ["→", ["rel"]], "to": ["→", ["rel"]], "brarr": ["→", ["bin"]], "bto": ["→", ["bin"]], 528 | "larr": ["←", ["rel"]], "from": ["←", ["rel"]], "blarr": ["←", ["bin"]], "bfrom": ["←", ["bin"]], 529 | "lrarr": ["↔", ["rel"]], "blrarr": ["↔", ["bin"]], 530 | "longrarr": ["⟶", ["rel"]], "longto": ["⟶", ["rel"]], 531 | "longlarr": ["⟵", ["rel"]], "longfrom": ["⟵", ["rel"]], 532 | "longlrarr": ["⟷", ["rel"]], 533 | "rmap": ["↦", ["rel"]], "mapsto": ["↦", ["rel"]], "brmap": ["↦", ["bin"]], "bmapsto": ["↦", ["bin"]], 534 | "lmap": ["↤", ["rel"]], "mappedfrom": ["↤", ["rel"]], "blmap": ["↤", ["bin"]], "bmappedfrom": ["↤", ["bin"]], 535 | "longrmap": ["⟼", ["rel"]], "longmapsto": ["⟼", ["rel"]], 536 | "longlmap": ["⟻", ["rel"]], "longmappedfrom": ["⟻", ["rel"]], 537 | "rmulti": ["⊸", ["rel"]], "brmulti": ["⊸", ["bin"]], 538 | "lmulti": ["⟜", ["rel"]], "blmulti": ["⟜", ["bin"]], 539 | "lrmulti": ["⧟", ["rel"]], "blrmulti": ["⧟", ["bin"]], 540 | "openrarr": ["⇾", ["rel"]], "bopenrarr": ["⇾", ["bin"]], 541 | "openlarr": ["⇽", ["rel"]], "bopenlarr": ["⇽", ["bin"]], 542 | "lopenrarr": ["⇿", ["rel"]], "blopenrarr": ["⇿", ["bin"]], 543 | "hookrarr": ["↪", ["rel"]], "bhookrarr": ["↪", ["bin"]], 544 | "hooklarr": ["↩", ["rel"]], "bhooklarr": ["↩", ["bin"]], 545 | "tailrarr": ["↣", ["rel"]], "btailrarr": ["↣", ["bin"]], 546 | "taillarr": ["↢", ["rel"]], "btaillarr": ["↢", ["bin"]], 547 | "headrarr": ["↠", ["rel"]], "bheadrarr": ["↠", ["bin"]], 548 | "headlarr": ["↞", ["rel"]], "bheadlarr": ["↞", ["bin"]], 549 | "tailheadrarr": ["⤖", ["rel"]], "btailheadrarr": ["⤖", ["bin"]], 550 | "uharprarr": ["⇀", ["rel"]], "buharprarr": ["⇀", ["bin"]], 551 | "uharplarr": ["↼", ["rel"]], "buharplarr": ["↼", ["bin"]], 552 | "dharprarr": ["⇁", ["rel"]], "bdharprarr": ["⇁", ["bin"]], 553 | "dharplarr": ["↽", ["rel"]], "bdharplarr": ["↽", ["bin"]], 554 | "waverarr": ["↝", ["rel"]], "bwaverarr": ["↝", ["bin"]], 555 | "wavelarr": ["↜", ["rel"]], "bwavelarr": ["↜", ["bin"]], 556 | "wavelrarr": ["↭", ["rel"]], "bwavelrarr": ["↭", ["bin"]], 557 | "squigrarr": ["⇝", ["rel"]], "bsquigrarr": ["⇝", ["bin"]], 558 | "squiglarr": ["⇜", ["rel"]], "bsquiglarr": ["⇜", ["bin"]], 559 | "curverarr": ["↷", ["rel"]], "bcurverarr": ["↷", ["bin"]], 560 | "curvelarr": ["↶", ["rel"]], "bcurvelarr": ["↶", ["bin"]], 561 | "vertrarr": ["⇸", ["rel"]], "bvertrarr": ["⇸", ["bin"]], 562 | "vertlarr": ["⇷", ["rel"]], "bvertlarr": ["⇷", ["bin"]], 563 | "vertlrarr": ["⇹", ["rel"]], "bvertlrarr": ["⇹", ["bin"]], 564 | "vvertrarr": ["⇻", ["rel"]], "bvvertrarr": ["⇻", ["bin"]], 565 | "vvertlarr": ["⇺", ["rel"]], "bvvertlarr": ["⇺", ["bin"]], 566 | "vvertlrarr": ["⇼", ["rel"]], "bvvertlrarr": ["⇼", ["bin"]], 567 | "circlerarr": ["↻", ["rel"]], 568 | "circlelarr": ["↺", ["rel"]], 569 | "raarr": ["⇒", ["rel"]], "braarr": ["⇒", ["bin"]], 570 | "laarr": ["⇐", ["rel"]], "blaarr": ["⇐", ["bin"]], 571 | "lraarr": ["⇔", ["rel"]], "blraarr": ["⇔", ["bin"]], 572 | "rmmap": ["⤇", ["rel"]], "brmmap": ["⤇", ["bin"]], 573 | "lmmap": ["⤆", ["rel"]], "blmmap": ["⤆", ["bin"]], 574 | "vertraarr": ["⤃", ["rel"]], "bvertraarr": ["⤃", ["bin"]], 575 | "vertlaarr": ["⤂", ["rel"]], "bvertlaarr": ["⤂", ["bin"]], 576 | "vertlraarr": ["⤄", ["rel"]], "bvertlraarr": ["⤄", ["bin"]], 577 | "longraarr": ["⟹", ["rel"]], 578 | "longlaarr": ["⟸", ["rel"]], 579 | "longlraarr": ["⟺", ["rel"]], 580 | "raaarr": ["⇛", ["rel"]], "braaarr": ["⇛", ["bin"]], 581 | "laaarr": ["⇚", ["rel"]], "blaaarr": ["⇚", ["bin"]], 582 | "uarr": ["↑", ["rel"]], "buarr": ["↑", ["bin"]], 583 | "darr": ["↓", ["rel"]], "bdarr": ["↓", ["bin"]], 584 | "udarr": ["↕", ["rel"]], "budarr": ["↕", ["bin"]], 585 | "uaarr": ["⇑", ["rel"]], "buaarr": ["⇑", ["bin"]], 586 | "daarr": ["⇓", ["rel"]], "bdaarr": ["⇓", ["bin"]], 587 | "udaarr": ["⇕", ["rel"]], "budaarr": ["⇕", ["bin"]], 588 | "scand": ["AND", ["sbin", "sml"]], 589 | "scor": ["OR", ["sbin", "sml"]], 590 | "scimplies": ["IMPLIES", ["sbin", "sml"]], 591 | "implies": ["⟹", ["srel"]], 592 | "implied": ["⟸", ["srel"]], 593 | "iff": ["⟺", ["srel"]], 594 | "coloniff": [":⟺", ["srel"]], 595 | "comma": [",", ["del", "txt"]], 596 | "colon": [":", ["del", "txt"]], 597 | "semicolon": [";", ["del", "txt"]], 598 | "period": [".", ["ord", "txt"]], 599 | "excl": ["!", ["ord", "txt"]], 600 | "ques": ["?", ["ord", "txt"]], 601 | "hyphen": ["-", ["ord", "txt"]], 602 | "pr": ["\uDB80\uDF98", ["ord"]], 603 | "ppr": ["\uDB80\uDF99", ["ord"]], 604 | "pppr": ["\uDB80\uDF9A", ["ord"]], 605 | "ppppr": ["\uDB80\uDF9B", ["ord"]], 606 | "bpr": ["\uDB80\uDF9C", ["ord"]], 607 | "bppr": ["\uDB80\uDF9D", ["ord"]], 608 | "bpppr": ["\uDB80\uDF9E", ["ord"]], 609 | "not": ["\u0338", ["not"]], 610 | "partial": ["∂", ["ord", "txt"]], 611 | "nabla": ["∇", ["ord"]], 612 | "infty": ["∞", ["ord", "txt"]], 613 | "empty": ["∅", ["ord"]], 614 | "amp": ["&", ["ord"]], 615 | "invamp": ["⅋", ["ord"]], 616 | "num": ["#", ["ord", "txt"]], 617 | "dollar": ["$", ["ord", "txt"]], 618 | "section": ["§", ["ord", "txt"]], 619 | "wp": ["℘", ["ord"]], 620 | "hbar": ["ℏ", ["ord", "txt"]], 621 | "sharp": ["♯", ["ord"]], 622 | "flat": ["♭", ["ord"]], 623 | "natural": ["♮", ["ord"]], 624 | "crotchet": ["♩", ["ord"]], 625 | "quaver": ["♪", ["ord"]], 626 | "linkquaver": ["♫", ["ord"]], 627 | "dagger": ["†", ["ord", "txt"]], 628 | "ddagger": ["‡", ["ord", "txt"]], 629 | "bspade": ["♠", ["ord"]], 630 | "bheart": ["♥", ["ord"]], 631 | "bdiamond": ["♦", ["ord"]], 632 | "bclub": ["♣", ["ord"]], 633 | "wspade": ["♤", ["ord"]], 634 | "wheart": ["♡", ["ord"]], 635 | "wdiamond": ["♢", ["ord"]], 636 | "wclub": ["♧", ["ord"]], 637 | "slash": ["/", ["ord"]], 638 | "backslash": ["\\", ["ord"]], 639 | "top": ["⊤", ["ord"]], 640 | "bot": ["⊥", ["ord"]], 641 | "ttop": ["⫪", ["ord"]], 642 | "bbot": ["⫫", ["ord"]], 643 | "neg": ["¬", ["ord"]], 644 | "forall": ["∀", ["ord"]], 645 | "exists": ["∃", ["ord"]], "nexists": ["∄", ["ord"]], 646 | "aleph": ["ℵ", ["ord"]], 647 | "beth": ["ℶ", ["ord"]], 648 | "ldots": ["…", ["ord"]], 649 | "cdots": ["⋯", ["ord"]], 650 | "vdots": ["⋮", ["ord"]], 651 | "ddots": ["⋱", ["ord"]], 652 | "udots": ["⋰", ["ord"]], 653 | "lparen": ["(", ["lpar"]], "rparen": [")", ["rpar"]], 654 | "lpparen": ["⦅", ["lpar"]], "rpparen": ["⦆", ["rpar"]], 655 | "lbracket": ["[", ["lpar"]], "rbracket": ["]", ["rpar"]], 656 | "lbbracket": ["⟦", ["lpar"]], "rbbracket": ["⟧", ["rpar"]], 657 | "lbrace": ["{", ["lpar"]], "rbrace": ["}", ["rpar"]], 658 | "lbbrace": ["⦃", ["lpar"]], "rbbrace": ["⦄", ["rpar"]], 659 | "lvert": ["|", ["lpar"]], "rvert": ["|", ["rpar"]], 660 | "lvvert": ["‖", ["lpar"]], "rvvert": ["‖", ["rpar"]], 661 | "lfloor": ["⌊", ["lpar"]], "rfloor": ["⌋", ["rpar"]], 662 | "lceil": ["⌈", ["lpar"]], "rceil": ["⌉", ["rpar"]], 663 | "langle": ["⟨", ["lpar"]], "rangle": ["⟩", ["rpar"]], 664 | "laangle": ["⟪", ["lpar"]], "raangle": ["⟫", ["rpar"]], 665 | "ltort": ["❲", ["lpar"]], "rtort": ["❳", ["rpar"]] 666 | }, 667 | "arrow": { 668 | "normal": { 669 | "edge": "end", 670 | "x": 0.3, "y": 0.18, "width": 0.3, "height": 0.36, "extrusion": 0, 671 | "command": "M 0 0 L 0.3 0.18 L 0 0.36" 672 | }, 673 | "dnormal": { 674 | "edge": "end", 675 | "x": 0.21, "y": 0.27, "width": 0.3, "height": 0.54, "extrusion": 0.09, 676 | "command": "M 0 0 L 0.3 0.27 L 0 0.54" 677 | }, 678 | "tnormal": { 679 | "edge": "end", 680 | "x": 0.15, "y": 0.36, "width": 0.3, "height": 0.72, "extrusion": 0.15, 681 | "command": "M 0 0 L 0.3 0.36 L 0 0.72 M 0.15 0.36 L 0.3 0.36" 682 | }, 683 | "head": { 684 | "edge": "end", 685 | "x": 0.54, "y": 0.18, "width": 0.54, "height": 0.36, "extrusion": 0, 686 | "command": "M 0 0 L 0.3 0.18 L 0 0.36 M 0.24 0 L 0.54 0.18 L 0.24 0.36" 687 | }, 688 | "tail": { 689 | "edge": "start", 690 | "x": 0.3, "y": 0.18, "width": 0.3, "height": 0.36, "extrusion": 0.3, 691 | "command": "M 0 0 L 0.3 0.18 L 0 0.36" 692 | }, 693 | "hook": { 694 | "edge": "start", 695 | "x": 0.12, "y": 0.3, "width": 0.24, "height": 0.3, "extrusion": 0.18, 696 | "command": "M 0.18 0 L 0.12 0 A 0.15 0.15 0 0 0 0.12 0.3" 697 | }, 698 | "varhook": { 699 | "edge": "start", 700 | "x": 0.12, "y": 0, "width": 0.24, "height": 0.3, "extrusion": 0.18, 701 | "command": "M 0.12 0 A 0.15 0.15 0 0 0 0.12 0.3 L 0.18 0.3" 702 | } 703 | }, 704 | "alternative": { 705 | "varbb": { 706 | "a": "𝕒", "b": "𝕓", "c": "𝕔", "d": "𝕕", "e": "𝕖", "f": "𝕗", "g": "𝕘", "h": "𝕙", "i": "𝕚", "j": "𝕛", "k": "𝕜", "l": "𝕝", "m": "𝕞", 707 | "n": "𝕟", "o": "𝕠", "p": "𝕡", "q": "𝕢", "r": "𝕣", "s": "𝕤", "t": "𝕥", "u": "𝕦", "v": "𝕧", "w": "𝕨", "x": "𝕩", "y": "𝕪", "z": "𝕫", 708 | "A": "𝔸", "B": "𝔹", "C": "ℂ", "D": "𝔻", "E": "𝔼", "F": "𝔽", "G": "𝔾", "H": "ℍ", "I": "𝕀", "J": "𝕁", "K": "𝕂", "L": "𝕃", "M": "𝕄", 709 | "N": "ℕ", "O": "𝕆", "P": "ℙ", "Q": "ℚ", "R": "ℝ", "S": "𝕊", "T": "𝕋", "U": "𝕌", "V": "𝕍", "W": "𝕎", "X": "𝕏", "Y": "𝕐", "Z": "ℤ", 710 | "0": "𝟘", "1": "𝟙", "2": "𝟚", "3": "𝟛", "4": "𝟜", "5": "𝟝", "6": "𝟞", "7": "𝟟", "8": "𝟠", "9": "𝟡" 711 | }, 712 | "bb": { 713 | "a": "\uDB84\uDC1A", "b": "\uDB84\uDC1B", "c": "\uDB84\uDC1C", "d": "\uDB84\uDC1D", "e": "\uDB84\uDC1E", "f": "\uDB84\uDC1F", "g": "\uDB84\uDC20", 714 | "h": "\uDB84\uDC21", "i": "\uDB84\uDC22", "j": "\uDB84\uDC23", "k": "\uDB84\uDC24", "l": "\uDB84\uDC25", "m": "\uDB84\uDC26", "n": "\uDB84\uDC27", 715 | "o": "\uDB84\uDC28", "p": "\uDB84\uDC29", "q": "\uDB84\uDC2A", "r": "\uDB84\uDC2B", "s": "\uDB84\uDC2C", "t": "\uDB84\uDC2D", "u": "\uDB84\uDC2E", 716 | "v": "\uDB84\uDC2F", "w": "\uDB84\uDC30", "x": "\uDB84\uDC31", "y": "\uDB84\uDC32", "z": "\uDB84\uDC33", 717 | "A": "\uDB84\uDC00", "B": "\uDB84\uDC01", "C": "\uDB84\uDC02", "D": "\uDB84\uDC03", "E": "\uDB84\uDC04", "F": "\uDB84\uDC05", "G": "\uDB84\uDC06", 718 | "H": "\uDB84\uDC07", "I": "\uDB84\uDC08", "J": "\uDB84\uDC09", "K": "\uDB84\uDC0A", "L": "\uDB84\uDC0B", "M": "\uDB84\uDC0C", "N": "\uDB84\uDC0D", 719 | "O": "\uDB84\uDC0E", "P": "\uDB84\uDC0F", "Q": "\uDB84\uDC10", "R": "\uDB84\uDC11", "S": "\uDB84\uDC12", "T": "\uDB84\uDC13", "U": "\uDB84\uDC14", 720 | "V": "\uDB84\uDC15", "W": "\uDB84\uDC16", "X": "\uDB84\uDC17", "Y": "\uDB84\uDC18", "Z": "\uDB84\uDC19", 721 | "0": "\uDB84\uDC34", "1": "\uDB84\uDC35", "2": "\uDB84\uDC36", "3": "\uDB84\uDC37", "4": "\uDB84\uDC38", 722 | "5": "\uDB84\uDC39", "6": "\uDB84\uDC3A", "7": "\uDB84\uDC3B", "8": "\uDB84\uDC3C", "9": "\uDB84\uDC3D" 723 | }, 724 | "cal": { 725 | "a": "𝒶", "b": "𝒷", "c": "𝒸", "d": "𝒹", "e": "ℯ", "f": "𝒻", "g": "ℊ", "h": "𝒽", "i": "𝒾", "j": "𝒿", "k": "𝓀", "l": "𝓁", "m": "𝓂", 726 | "n": "𝓃", "o": "ℴ", "p": "𝓅", "q": "𝓆", "r": "𝓇", "s": "𝓈", "t": "𝓉", "u": "𝓊", "v": "𝓋", "w": "𝓌", "x": "𝓍", "y": "𝓎", "z": "𝓏", 727 | "A": "𝒜", "B": "ℬ", "C": "𝒞", "D": "𝒟", "E": "ℰ", "F": "ℱ", "G": "𝒢", "H": "ℋ", "I": "ℐ", "J": "𝒥", "K": "𝒦", "L": "ℒ", "M": "ℳ", 728 | "N": "𝒩", "O": "𝒪", "P": "𝒫", "Q": "𝒬", "R": "ℛ", "S": "𝒮", "T": "𝒯", "U": "𝒰", "V": "𝒱", "W": "𝒲", "X": "𝒳", "Y": "𝒴", "Z": "𝒵" 729 | }, 730 | "scr": { 731 | "a": "𝒶", "b": "𝒷", "c": "𝒸", "d": "𝒹", "e": "ℯ", "f": "𝒻", "g": "ℊ", "h": "𝒽", "i": "𝒾", "j": "𝒿", "k": "𝓀", "l": "𝓁", "m": "𝓂", 732 | "n": "𝓃", "o": "ℴ", "p": "𝓅", "q": "𝓆", "r": "𝓇", "s": "𝓈", "t": "𝓉", "u": "𝓊", "v": "𝓋", "w": "𝓌", "x": "𝓍", "y": "𝓎", "z": "𝓏", 733 | "A": "\uDB81\uDC98", "B": "\uDB81\uDC99", "C": "\uDB81\uDC9A", "D": "\uDB81\uDC9B", "E": "\uDB81\uDC9C", "F": "\uDB81\uDC9D", "G": "\uDB81\uDC9E", 734 | "H": "\uDB81\uDC9F", "I": "\uDB81\uDCA0", "J": "\uDB81\uDCA1", "K": "\uDB81\uDCA2", "L": "\uDB81\uDCA3", "M": "\uDB81\uDCA4", "N": "\uDB81\uDCA5", 735 | "O": "\uDB81\uDCA6", "P": "\uDB81\uDCA7", "Q": "\uDB81\uDCA8", "R": "\uDB81\uDCA9", "S": "\uDB81\uDCAA", "T": "\uDB81\uDCAB", "U": "\uDB81\uDCAC", 736 | "V": "\uDB81\uDCAD", "W": "\uDB81\uDCAE", "X": "\uDB81\uDCAF", "Y": "\uDB81\uDCB0", "Z": "\uDB81\uDCB1" 737 | }, 738 | "varfrak": { 739 | "a": "𝔞", "b": "𝔟", "c": "𝔠", "d": "𝔡", "e": "𝔢", "f": "𝔣", "g": "𝔤", "h": "𝔥", "i": "𝔦", "j": "𝔧", "k": "𝔨", "l": "𝔩", "m": "𝔪", 740 | "n": "𝔫", "o": "𝔬", "p": "𝔭", "q": "𝔮", "r": "𝔯", "s": "𝔰", "t": "𝔱", "u": "𝔲", "v": "𝔳", "w": "𝔴", "x": "𝔵", "y": "𝔶", "z": "𝔷", 741 | "A": "𝔄", "B": "𝔅", "C": "ℭ", "D": "𝔇", "E": "𝔈", "F": "𝔉", "G": "𝔊", "H": "ℌ", "I": "ℑ", "J": "𝔍", "K": "𝔎", "L": "𝔏", "M": "𝔐", 742 | "N": "𝔑", "O": "𝔒", "P": "𝔓", "Q": "𝔔", "R": "ℜ", "S": "𝔖", "T": "𝔗", "U": "𝔘", "V": "𝔙", "W": "𝔚", "X": "𝔛", "Y": "𝔜", "Z": "ℨ" 743 | }, 744 | "frak": { 745 | "a": "\uDB84\uDC58", "b": "\uDB84\uDC59", "c": "\uDB84\uDC5A", "d": "\uDB84\uDC5B", "e": "\uDB84\uDC5C", "f": "\uDB84\uDC5D", "g": "\uDB84\uDC5E", 746 | "h": "\uDB84\uDC5F", "i": "\uDB84\uDC60", "j": "\uDB84\uDC61", "k": "\uDB84\uDC62", "l": "\uDB84\uDC63", "m": "\uDB84\uDC64", "n": "\uDB84\uDC65", 747 | "o": "\uDB84\uDC66", "p": "\uDB84\uDC67", "q": "\uDB84\uDC68", "r": "\uDB84\uDC69", "s": "\uDB84\uDC6A", "t": "\uDB84\uDC6B", "u": "\uDB84\uDC6C", 748 | "v": "\uDB84\uDC6D", "w": "\uDB84\uDC6E", "x": "\uDB84\uDC6F", "y": "\uDB84\uDC70", "z": "\uDB84\uDC71", 749 | "A": "\uDB84\uDC3E", "B": "\uDB84\uDC3F", "C": "\uDB84\uDC40", "D": "\uDB84\uDC41", "E": "\uDB84\uDC42", "F": "\uDB84\uDC43", "G": "\uDB84\uDC44", 750 | "H": "\uDB84\uDC45", "I": "\uDB84\uDC46", "J": "\uDB84\uDC47", "K": "\uDB84\uDC48", "L": "\uDB84\uDC49", "M": "\uDB84\uDC4A", "N": "\uDB84\uDC4B", 751 | "O": "\uDB84\uDC4C", "P": "\uDB84\uDC4D", "Q": "\uDB84\uDC4E", "R": "\uDB84\uDC4F", "S": "\uDB84\uDC50", "T": "\uDB84\uDC51", "U": "\uDB84\uDC52", 752 | "V": "\uDB84\uDC53", "W": "\uDB84\uDC54", "X": "\uDB84\uDC55", "Y": "\uDB84\uDC56", "Z": "\uDB84\uDC57" 753 | } 754 | }, 755 | "greek": { 756 | "a": "α", "b": "β", "c": "ψ", "d": "δ", "e": "ε", "f": "φ", "g": "γ", "h": "η", "i": "ι", "j": "ξ", "k": "κ", "l": "λ", "m": "μ", 757 | "n": "ν", "o": "ο", "p": "π", "q": "ϕ", "r": "ρ", "s": "σ", "t": "τ", "u": "θ", "v": "ω", "w": "ς", "x": "χ", "y": "υ", "z": "ζ", 758 | "A": "Α", "B": "Β", "C": "Ψ", "D": "Δ", "E": "Ε", "F": "Φ", "G": "Γ", "H": "Η", "I": "Ι", "J": "Ξ", "K": "Κ", "L": "Λ", "M": "Μ", 759 | "N": "Ν", "O": "Ο", "P": "Π", "Q": "Φ", "R": "Ρ", "S": "Σ", "T": "Τ", "U": "Θ", "V": "Ω", "W": "Σ", "X": "Χ", "Y": "Υ", "Z": "Ζ" 760 | } 761 | } -------------------------------------------------------------------------------- /source/zotica/resource/script/accent.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | class AccentModifier extends Modifier { 5 | 6 | modify(element) { 7 | let baseWrapperElement = this.findChild(element, "math-basewrap"); 8 | let overElement = this.findChild(element, "math-over"); 9 | let contentElement = baseWrapperElement.children[0]; 10 | let parentElements = [baseWrapperElement.children[1], overElement]; 11 | for (let position of [0, 1]) { 12 | let parentElement = parentElements[position]; 13 | if (parentElement) { 14 | this.modifyPosition(contentElement, parentElement, position); 15 | } 16 | } 17 | } 18 | 19 | modifyPosition(contentElement, parentElement, position) { 20 | let charElement = contentElement.children[0]; 21 | let string = charElement && charElement.textContent; 22 | if (string && string.length == 1 && contentElement.children.length == 1) { 23 | let char = string.substring(0, 1); 24 | let shift = DATA["shift"][position][char]; 25 | if (shift) { 26 | let marginString; 27 | if (position == 0) { 28 | marginString = window.getComputedStyle(parentElement).marginTop; 29 | } else { 30 | marginString = window.getComputedStyle(parentElement).marginBottom; 31 | } 32 | let margin = parseFloat(marginString) / this.getFontSize(parentElement); 33 | if (position == 0) { 34 | parentElement.style.marginTop = "" + (margin + shift) + "em"; 35 | } else { 36 | parentElement.style.marginBottom = "" + (margin - shift) + "em"; 37 | } 38 | } 39 | } 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /source/zotica/resource/script/diagram.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | const ANGLE_EPSILON = Math.PI / 90; 5 | 6 | const UNIT = 1 / 18; 7 | const ARROW_MARGIN = 8 * UNIT; 8 | const LABEL_DISTANCE = 5 * UNIT; 9 | 10 | 11 | class DiagramModifier extends Modifier { 12 | 13 | modify(element) { 14 | let arrowElements = this.findChildren(element, "math-arrow"); 15 | let cellElements = this.findChildren(element, "math-cellwrap").map((child) => child.children[0]); 16 | let backgroundColor = this.getBackgroundColor(element); 17 | let graphic = this.createGraphic(element); 18 | element.appendChild(graphic); 19 | for (let arrowElement of arrowElements) { 20 | let arrowSpec = this.determineArrowSpec(graphic, arrowElement, cellElements, arrowElements); 21 | let arrows = this.createArrows(arrowSpec, backgroundColor); 22 | graphic.append(...arrows); 23 | let labelPoint = this.determineLabelPoint(graphic, arrowElement, arrowSpec); 24 | let fontRatio = this.getFontSize(graphic) / this.getFontSize(arrowElement); 25 | arrowElement.style.left = "" + (labelPoint[0] * fontRatio) + "em"; 26 | arrowElement.style.top = "" + (labelPoint[1] * fontRatio) + "em"; 27 | } 28 | let pathElements = Array.from(graphic.children).filter((child) => child.localName == "path"); 29 | let extrusion = this.calcExtrusion(graphic, arrowElements.concat(pathElements)); 30 | element.style.marginTop = "" + extrusion.top + "em"; 31 | element.style.marginBottom = "" + extrusion.bottom + "em"; 32 | element.style.marginLeft = "" + extrusion.left + "em"; 33 | element.style.marginRight = "" + extrusion.right + "em"; 34 | } 35 | 36 | determineArrowSpec(graphic, arrowElement, cellElements, arrowElements) { 37 | let spec = {}; 38 | let startConfigString = arrowElement.getAttribute("data-start"); 39 | let endConfigString = arrowElement.getAttribute("data-end"); 40 | let startConfig = this.parseEdgeConfig(startConfigString, graphic, cellElements, arrowElements); 41 | let endConfig = this.parseEdgeConfig(endConfigString, graphic, cellElements, arrowElements); 42 | if (startConfig && endConfig) { 43 | let bendAngleString = arrowElement.getAttribute("data-bend"); 44 | if (bendAngleString) { 45 | spec.bendAngle = parseFloat(bendAngleString) * Math.PI / 180; 46 | } 47 | let shiftString = arrowElement.getAttribute("data-shift"); 48 | if (shiftString) { 49 | spec.shift = parseFloat(shiftString) * UNIT; 50 | } 51 | let startElement = startConfig.element; 52 | let endElement = endConfig.element; 53 | let startDimension = startConfig.dimension; 54 | let endDimension = endConfig.dimension; 55 | if (startConfig.point) { 56 | spec.startPoint = startConfig.point; 57 | } else { 58 | spec.startPoint = this.calcEdgePoint(startDimension, endDimension, spec.bendAngle, spec.shift); 59 | } 60 | if (endConfig.point) { 61 | spec.endPoint = endConfig.point; 62 | } else { 63 | spec.endPoint = this.calcEdgePoint(endDimension, startDimension, -spec.bendAngle, -spec.shift); 64 | } 65 | } else { 66 | spec.startPoint = [0, 0]; 67 | spec.endPoint = [0, 0]; 68 | } 69 | let labelPositionString = arrowElement.getAttribute("data-pos"); 70 | if (labelPositionString) { 71 | spec.labelPosition = parseFloat(labelPositionString) / 100; 72 | } 73 | let lineCountString = arrowElement.getAttribute("data-line"); 74 | if (lineCountString) { 75 | spec.lineCount = parseInt(lineCountString); 76 | } 77 | let dashed = !!arrowElement.getAttribute("data-dash"); 78 | if (dashed) { 79 | spec.dashed = true; 80 | } 81 | let inverted = !!arrowElement.getAttribute("data-inv"); 82 | if (inverted) { 83 | spec.inverted = true; 84 | } 85 | let mark = !!arrowElement.getAttribute("data-mark"); 86 | if (mark) { 87 | spec.mark = true; 88 | } 89 | let tipKindsString = arrowElement.getAttribute("data-tip"); 90 | spec.tipKinds = this.parseTipKinds(tipKindsString, spec.lineCount); 91 | spec.intrudedStartPoint = this.calcIntrudedPoint(spec.startPoint, spec.endPoint, spec.bendAngle, spec.tipKinds.start); 92 | spec.intrudedEndPoint = this.calcIntrudedPoint(spec.endPoint, spec.startPoint, -spec.bendAngle, spec.tipKinds.end); 93 | return spec; 94 | } 95 | 96 | determineLabelPoint(graphic, labelElement, arrowSpec) { 97 | let labelDimension = this.calcDimension(graphic, labelElement); 98 | let startPoint = arrowSpec.startPoint; 99 | let endPoint = arrowSpec.endPoint; 100 | let bendAngle = arrowSpec.bendAngle; 101 | let position = (arrowSpec.labelPosition == undefined) ? 0.5 : arrowSpec.labelPosition; 102 | let basePoint = [0, 0]; 103 | let angle = 0; 104 | if (bendAngle != undefined) { 105 | let controlPoint = this.calcControlPoint(startPoint, endPoint, bendAngle); 106 | let basePointX = (1 - position) * (1 - position) * startPoint[0] + 2 * (1 - position) * position * controlPoint[0] + position * position * endPoint[0]; 107 | let basePointY = (1 - position) * (1 - position) * startPoint[1] + 2 * (1 - position) * position * controlPoint[1] + position * position * endPoint[1]; 108 | let speedX = -2 * (1 - position) * startPoint[0] + 2 * (1 - 2 * position) * controlPoint[0] + 2 * position * endPoint[0]; 109 | let speedY = -2 * (1 - position) * startPoint[1] + 2 * (1 - 2 * position) * controlPoint[1] + 2 * position * endPoint[1]; 110 | basePoint = [basePointX, basePointY]; 111 | angle = this.calcAngle([0, 0], [speedX, speedY]) + Math.PI / 2; 112 | } else { 113 | let basePointX = (1 - position) * startPoint[0] + position * endPoint[0]; 114 | let basePointY = (1 - position) * startPoint[1] + position * endPoint[1]; 115 | basePoint = [basePointX, basePointY]; 116 | angle = this.calcAngle(startPoint, endPoint) + Math.PI / 2; 117 | } 118 | if (arrowSpec.inverted) { 119 | angle += Math.PI; 120 | } 121 | angle = this.normalizeAngle(angle); 122 | let point; 123 | if (arrowSpec.mark) { 124 | let pointX = basePoint[0] + labelDimension.northWest[0] - labelDimension.center[0]; 125 | let pointY = basePoint[1] + labelDimension.northWest[0] - labelDimension.center[1]; 126 | point = [pointX, pointY]; 127 | } else { 128 | point = this.calcLabelPoint(basePoint, labelDimension, angle, arrowSpec.lineCount); 129 | } 130 | return point; 131 | } 132 | 133 | calcEdgePoint(baseDimension, destinationDimension, bendAngle, shift) { 134 | let margin = ARROW_MARGIN; 135 | let angle = this.calcAngle(baseDimension.center, destinationDimension.center) + (bendAngle || 0); 136 | let shiftAngle = angle + Math.PI / 2; 137 | let southWestAngle = this.calcAngle(baseDimension.center, baseDimension.southWestMargined); 138 | let southEastAngle = this.calcAngle(baseDimension.center, baseDimension.southEastMargined); 139 | let northEastAngle = this.calcAngle(baseDimension.center, baseDimension.northEastMargined); 140 | let northWestAngle = this.calcAngle(baseDimension.center, baseDimension.northWestMargined); 141 | let x = 0; 142 | let y = 0; 143 | angle = this.normalizeAngle(angle); 144 | shiftAngle = this.normalizeAngle(shiftAngle); 145 | if (angle >= southWestAngle && angle <= southEastAngle) { 146 | x = baseDimension.center[0] + (baseDimension.center[1] - baseDimension.southMargined[1]) / Math.tan(angle); 147 | y = baseDimension.southMargined[1]; 148 | } else if (angle >= southEastAngle && angle <= northEastAngle) { 149 | x = baseDimension.eastMargined[0]; 150 | y = baseDimension.center[1] + (baseDimension.center[0] - baseDimension.eastMargined[0]) * Math.tan(angle); 151 | } else if (angle >= northEastAngle && angle <= northWestAngle) { 152 | x = baseDimension.center[0] + (baseDimension.center[1] - baseDimension.northMargined[1]) / Math.tan(angle); 153 | y = baseDimension.northMargined[1]; 154 | } else if (angle >= northWestAngle || angle <= southWestAngle) { 155 | x = baseDimension.westMargined[0]; 156 | y = baseDimension.center[1] + (baseDimension.center[0] - baseDimension.westMargined[0]) * Math.tan(angle); 157 | } 158 | if (shift) { 159 | x += Math.cos(shiftAngle) * shift; 160 | y -= Math.sin(shiftAngle) * shift; 161 | } 162 | return [x, y]; 163 | } 164 | 165 | calcIntrudedPoint(basePoint, destinationPoint, bendAngle, tipKind) { 166 | if (tipKind != "none") { 167 | let angle = this.calcAngle(basePoint, destinationPoint) + (bendAngle || 0); 168 | let distance = DATA["arrow"][tipKind]["extrusion"]; 169 | angle = this.normalizeAngle(angle); 170 | let intrudedPointX = basePoint[0] + distance * Math.cos(angle); 171 | let intrudedPointY = basePoint[1] - distance * Math.sin(angle); 172 | let intrudedPoint = [intrudedPointX, intrudedPointY]; 173 | return intrudedPoint; 174 | } else { 175 | return basePoint; 176 | } 177 | } 178 | 179 | calcLabelPoint(basePoint, labelDimension, angle, lineCount) { 180 | let distance = LABEL_DISTANCE + ((lineCount || 1) - 1) * 0.09; 181 | let direction = "east"; 182 | if (angle <= -Math.PI + ANGLE_EPSILON) { 183 | direction = "east"; 184 | } else if (angle <= -Math.PI / 2 - ANGLE_EPSILON) { 185 | direction = "northEast"; 186 | } else if (angle <= -Math.PI / 2 + ANGLE_EPSILON) { 187 | direction = "north"; 188 | } else if (angle <= -ANGLE_EPSILON) { 189 | direction = "northWest"; 190 | } else if (angle <= ANGLE_EPSILON) { 191 | direction = "west"; 192 | } else if (angle <= Math.PI / 2 - ANGLE_EPSILON) { 193 | direction = "southWest"; 194 | } else if (angle <= Math.PI / 2 + ANGLE_EPSILON) { 195 | direction = "south"; 196 | } else if (angle <= Math.PI - ANGLE_EPSILON) { 197 | direction = "southEast"; 198 | } else { 199 | direction = "east"; 200 | } 201 | let x = basePoint[0] + Math.cos(angle) * distance + labelDimension.northWest[0] - labelDimension[direction][0]; 202 | let y = basePoint[1] - Math.sin(angle) * distance + labelDimension.northWest[1] - labelDimension[direction][1]; 203 | return [x, y]; 204 | } 205 | 206 | parseEdgeConfig(string, graphic, cellElements, arrowElements) { 207 | let config = null; 208 | let match = string.match(/(?:(\d+)|([A-Za-z]\w*))(?:\:(\w+))?/); 209 | if (match) { 210 | let element = null; 211 | if (match[1]) { 212 | let number = parseInt(match[1]) - 1; 213 | element = cellElements[number]; 214 | } else if (match[2]) { 215 | let candidates = cellElements.map((candidate) => candidate.parentNode).concat(arrowElements); 216 | let name = match[2]; 217 | element = candidates.find((candidate) => candidate.getAttribute("data-name") == name); 218 | } 219 | if (element) { 220 | let dimension = this.calcDimension(graphic, element); 221 | let point = null; 222 | if (match[3]) { 223 | point = this.parsePoint(match[3], dimension); 224 | } 225 | config = {element, dimension, point}; 226 | } 227 | } 228 | return config; 229 | } 230 | 231 | parsePoint(string, dimension) { 232 | let point = null; 233 | let match; 234 | if (match = string.match(/^n(|w|e)|s(|w|e)|w|e|c$/)) { 235 | if (string == "nw") { 236 | point = dimension.northWestMargined; 237 | } else if (string == "n") { 238 | point = dimension.northMargined; 239 | } else if (string == "ne") { 240 | point = dimension.northEastMargined; 241 | } else if (string == "e") { 242 | point = dimension.eastMargined; 243 | } else if (string == "se") { 244 | point = dimension.southEastMargined; 245 | } else if (string == "s") { 246 | point = dimension.southMargined; 247 | } else if (string == "sw") { 248 | point = dimension.southWestMargined; 249 | } else if (string == "w") { 250 | point = dimension.westMargined; 251 | } else if (string == "c") { 252 | point = dimension.center; 253 | } 254 | } else if (match = string.match(/^(t|r|b|l)([\d.]+)$/)) { 255 | let direction = match[1]; 256 | let position = parseFloat(match[2]) / 100; 257 | let pointX = null; 258 | let pointY = null; 259 | if (direction == "t") { 260 | pointX = (1 - position) * dimension.northWestMargined[0] + position * dimension.northEastMargined[0]; 261 | pointY = dimension.northMargined[1]; 262 | } else if (direction == "r") { 263 | pointX = dimension.eastMargined[0]; 264 | pointY = (1 - position) * dimension.northEastMargined[1] + position * dimension.southEastMargined[1]; 265 | } else if (direction == "b") { 266 | pointX = (1 - position) * dimension.southWestMargined[0] + position * dimension.southEastMargined[0]; 267 | pointY = dimension.southMargined[1]; 268 | } else if (direction == "l") { 269 | pointX = dimension.westMargined[0]; 270 | pointY = (1 - position) * dimension.northWestMargined[1] + position * dimension.southWestMargined[1]; 271 | } 272 | if (pointX != null && pointY != null) { 273 | point = [pointX, pointY]; 274 | } 275 | } 276 | return point; 277 | } 278 | 279 | parseTipKinds(string, lineCount) { 280 | let tipKinds = {start: "none", end: "normal"}; 281 | if (string != null) { 282 | let specifiedTipKinds = string.split(/\s*,\s*/); 283 | for (let specifiedTipKind of specifiedTipKinds) { 284 | let spec = DATA["arrow"][specifiedTipKind]; 285 | if (spec) { 286 | tipKinds[spec.edge] = specifiedTipKind; 287 | } 288 | if (specifiedTipKind == "none") { 289 | tipKinds.end = "none"; 290 | } 291 | } 292 | } 293 | if (lineCount == 2) { 294 | if (tipKinds.start != "none") { 295 | tipKinds.start = "d" + tipKinds.start; 296 | } 297 | if (tipKinds.end != "none") { 298 | tipKinds.end = "d" + tipKinds.end; 299 | } 300 | } else if (lineCount == 3) { 301 | if (tipKinds.start != "none") { 302 | tipKinds.start = "t" + tipKinds.start; 303 | } 304 | if (tipKinds.end != "none") { 305 | tipKinds.end = "t" + tipKinds.end; 306 | } 307 | } 308 | return tipKinds; 309 | } 310 | 311 | calcAngle(basePoint, destinationPoint) { 312 | let x = destinationPoint[0] - basePoint[0]; 313 | let y = destinationPoint[1] - basePoint[1]; 314 | let angle = -Math.atan2(y, x); 315 | return angle; 316 | } 317 | 318 | normalizeAngle(angle) { 319 | let normalizedAngle = (angle + Math.PI) % (Math.PI * 2) - Math.PI; 320 | return normalizedAngle; 321 | } 322 | 323 | createArrows(arrowSpec, backgroundColor) { 324 | let startPoint = arrowSpec.intrudedStartPoint; 325 | let endPoint = arrowSpec.intrudedEndPoint; 326 | let bendAngle = arrowSpec.bendAngle; 327 | let lineCount = (arrowSpec.lineCount == undefined) ? 1 : arrowSpec.lineCount; 328 | let command = "M " + startPoint[0] + " " + startPoint[1]; 329 | if (bendAngle != undefined) { 330 | let controlPoint = this.calcControlPoint(startPoint, endPoint, bendAngle) 331 | command += " Q " + controlPoint[0] + " " + controlPoint[1] + ", " + endPoint[0] + " " + endPoint[1]; 332 | } else { 333 | command += " L " + endPoint[0] + " " + endPoint[1]; 334 | } 335 | let arrows = []; 336 | for (let i = 0 ; i < lineCount ; i ++) { 337 | let arrow = this.createSvgElement("path"); 338 | arrow.setAttribute("d", command); 339 | if (arrowSpec.tipKinds.start != "none" && i == lineCount - 1) { 340 | arrow.setAttribute("marker-start", "url(#tip-" + arrowSpec.tipKinds.start +")"); 341 | } 342 | if (arrowSpec.tipKinds.end != "none" && i == lineCount - 1) { 343 | arrow.setAttribute("marker-end", "url(#tip-" + arrowSpec.tipKinds.end + ")"); 344 | } 345 | if (arrowSpec.dashed && i % 2 == 0) { 346 | arrow.classList.add("dashed"); 347 | } 348 | if (i == 0) { 349 | arrow.classList.add("base"); 350 | } else if (i == 1) { 351 | arrow.classList.add("cover"); 352 | arrow.style.stroke = backgroundColor; 353 | } else if (i == 2) { 354 | arrow.classList.add("front"); 355 | } 356 | if (lineCount == 2) { 357 | arrow.classList.add("double"); 358 | } else if (lineCount == 3) { 359 | arrow.classList.add("triple"); 360 | } 361 | arrows.push(arrow); 362 | } 363 | return arrows; 364 | } 365 | 366 | calcControlPoint(startPoint, endPoint, bendAngle) { 367 | let x = (endPoint[0] + startPoint[0] + (endPoint[1] - startPoint[1]) * Math.tan(bendAngle)) / 2; 368 | let y = (endPoint[1] + startPoint[1] - (endPoint[0] - startPoint[0]) * Math.tan(bendAngle)) / 2; 369 | return [x, y]; 370 | } 371 | 372 | calcExtrusion(graphic, elements) { 373 | let fontSize = this.getFontSize(graphic); 374 | let xOffset = window.pageXOffset; 375 | let yOffset = window.pageYOffset; 376 | let graphicRect = graphic.getBoundingClientRect(); 377 | let graphicTop = graphicRect.top + yOffset 378 | let graphicBottom = graphicRect.bottom + yOffset; 379 | let graphicLeft = graphicRect.left + xOffset; 380 | let graphicRight = graphicRect.right + xOffset; 381 | let extrusion = {top: 0, bottom: 0, left: 0, right: 0}; 382 | for (let element of elements) { 383 | let rect = element.getBoundingClientRect(); 384 | let topExtrusion = -(rect.top + yOffset - graphicTop) / fontSize; 385 | let bottomExtrusion = (rect.bottom + yOffset - graphicBottom) / fontSize; 386 | let leftExtrusion = -(rect.left + xOffset - graphicLeft) / fontSize; 387 | let rightExtrusion = (rect.right + xOffset - graphicRight) / fontSize; 388 | if (topExtrusion > extrusion.top) { 389 | extrusion.top = topExtrusion; 390 | } 391 | if (bottomExtrusion > extrusion.bottom) { 392 | extrusion.bottom = bottomExtrusion; 393 | } 394 | if (leftExtrusion > extrusion.left) { 395 | extrusion.left = leftExtrusion; 396 | } 397 | if (rightExtrusion > extrusion.right) { 398 | extrusion.right = rightExtrusion; 399 | } 400 | } 401 | return extrusion; 402 | } 403 | 404 | createGraphic(element) { 405 | let width = this.getWidth(element); 406 | let height = this.getHeight(element); 407 | let graphic = this.createSvgElement("svg"); 408 | graphic.setAttribute("viewBox", "0 0 " + width + " " + height); 409 | let definitionElement = this.createSvgElement("defs"); 410 | let tipSpecKeys = Object.keys(DATA["arrow"]); 411 | for (let tipSpecKey of tipSpecKeys) { 412 | let tipSpec = DATA["arrow"][tipSpecKey]; 413 | let markerElement = this.createSvgElement("marker"); 414 | let markerPathElement = this.createSvgElement("path"); 415 | markerElement.setAttribute("id", "tip-" + tipSpecKey); 416 | markerElement.setAttribute("refX", tipSpec["x"]); 417 | markerElement.setAttribute("refY", tipSpec["y"]); 418 | markerElement.setAttribute("markerWidth", tipSpec["width"]); 419 | markerElement.setAttribute("markerHeight", tipSpec["height"]); 420 | markerElement.setAttribute("markerUnits", "userSpaceOnUse"); 421 | markerElement.setAttribute("orient", "auto"); 422 | markerPathElement.setAttribute("d", tipSpec["command"]); 423 | markerElement.appendChild(markerPathElement); 424 | definitionElement.appendChild(markerElement); 425 | } 426 | graphic.appendChild(definitionElement); 427 | return graphic; 428 | } 429 | 430 | createSvgElement(name) { 431 | let element = document.createElementNS("http://www.w3.org/2000/svg", name); 432 | return element; 433 | } 434 | 435 | calcDimension(graphic, element) { 436 | let dimension = {}; 437 | let margin = ARROW_MARGIN; 438 | let fontSize = this.getFontSize(graphic) 439 | let graphicTop = graphic.getBoundingClientRect().top + window.pageYOffset; 440 | let graphicLeft = graphic.getBoundingClientRect().left + window.pageXOffset; 441 | let top = (element.getBoundingClientRect().top + window.pageYOffset - graphicTop) / fontSize; 442 | let left = (element.getBoundingClientRect().left + window.pageXOffset - graphicLeft) / fontSize; 443 | let width = this.getWidth(element, graphic); 444 | let height = this.getHeight(element, graphic); 445 | let lowerHeight = this.getLowerHeight(element, graphic); 446 | dimension.northWest = [left, top]; 447 | dimension.north = [left + width / 2, top]; 448 | dimension.northEast = [left + width, top]; 449 | dimension.west = [left, top + height - lowerHeight]; 450 | dimension.center = [left + width / 2, top + height - lowerHeight]; 451 | dimension.east = [left + width, top + height - lowerHeight]; 452 | dimension.southWest = [left, top + height]; 453 | dimension.south = [left + width / 2, top + height]; 454 | dimension.southEast = [left + width, top + height]; 455 | dimension.northWestMargined = [left - margin, top - margin]; 456 | dimension.northMargined = [left + width / 2, top - margin]; 457 | dimension.northEastMargined = [left + width + margin, top - margin]; 458 | dimension.westMargined = [left - margin, top + height - lowerHeight]; 459 | dimension.centerMargined = [left + width / 2, top + height - lowerHeight]; 460 | dimension.eastMargined = [left + width + margin, top + height - lowerHeight]; 461 | dimension.southWestMargined = [left - margin, top + height + margin]; 462 | dimension.southMargined = [left + width / 2, top + height + margin]; 463 | dimension.southEastMargined = [left + width + margin, top + height + margin]; 464 | return dimension; 465 | } 466 | 467 | getBackgroundColor(element) { 468 | let currentElement = element; 469 | let color = "white"; 470 | while (currentElement && currentElement instanceof Element) { 471 | let currentColor = window.getComputedStyle(currentElement).backgroundColor; 472 | if (currentColor != "rgba(0, 0, 0, 0)" && currentColor != "transparent") { 473 | color = currentColor; 474 | break; 475 | } 476 | currentElement = currentElement.parentNode; 477 | } 478 | return color; 479 | } 480 | 481 | } -------------------------------------------------------------------------------- /source/zotica/resource/script/fence.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | class FenceModifier extends Modifier { 5 | 6 | modify(element) { 7 | let contentElements = this.findChildren(element, "math-cont"); 8 | let leftElement = this.findChild(element, "math-left"); 9 | let rightElement = this.findChild(element, "math-right"); 10 | let centerElement = this.findChild(element, "math-center"); 11 | let parentElements = [leftElement, rightElement, centerElement]; 12 | let kinds = this.calcKinds(element); 13 | for (let position of [0, 1, 2]) { 14 | let parentElement = parentElements[position]; 15 | let kind = kinds[position]; 16 | if (position == 2) { 17 | position = 0; 18 | } 19 | if (parentElement && kind != "none") { 20 | let stretchLevel = this.calcStretchLevel(contentElements, kind, position); 21 | if (stretchLevel != null) { 22 | this.modifyStretch(contentElements, parentElement, kind, stretchLevel, position); 23 | } else { 24 | this.appendStretch(contentElements, parentElement, kind, position); 25 | } 26 | } 27 | } 28 | } 29 | 30 | modifyStretch(contentElements, parentElement, kind, stretchLevel, position) { 31 | let symbolElement = parentElement.children[0]; 32 | let shift = this.calcShift(contentElements, stretchLevel); 33 | symbolElement.textContent = DATA["fence"][kind][position][stretchLevel]; 34 | parentElement.style.verticalAlign = "" + shift + "em"; 35 | } 36 | 37 | appendStretch(contentElements, parentElement, kind, position) { 38 | let stretchElement = document.createElement("math-vstretch"); 39 | let hasStart = !!DATA["fence"][kind][position]["start"]; 40 | let hasEnd = !!DATA["fence"][kind][position]["end"]; 41 | let hasMiddle = !!DATA["fence"][kind][position]["middle"]; 42 | let startElement = null; 43 | let endElement = null; 44 | let middleElement = null; 45 | if (hasStart) { 46 | startElement = document.createElement("math-start"); 47 | startElement.textContent = DATA["fence"][kind][position]["start"]; 48 | stretchElement.append(startElement); 49 | } 50 | if (hasMiddle) { 51 | middleElement = document.createElement("math-middle"); 52 | middleElement.textContent = DATA["fence"][kind][position]["middle"]; 53 | stretchElement.append(middleElement); 54 | } 55 | if (hasEnd) { 56 | endElement = document.createElement("math-end"); 57 | endElement.textContent = DATA["fence"][kind][position]["end"]; 58 | stretchElement.append(endElement); 59 | } 60 | parentElement.removeChild(parentElement.children[0]); 61 | parentElement.appendChild(stretchElement); 62 | let barSize = (hasMiddle) ? 2 : 1; 63 | let barHeight = this.calcBarHeight(contentElements, startElement, endElement, middleElement); 64 | let stretchShift = this.calcStretchShift(contentElements); 65 | for (let i = 0 ; i < barSize ; i ++) { 66 | let barWrapperElement = document.createElement("math-barwrap"); 67 | let barElement = document.createElement("math-bar"); 68 | barElement.textContent = DATA["fence"][kind][position]["bar"]; 69 | barWrapperElement.style.height = "" + barHeight + "em"; 70 | barWrapperElement.append(barElement); 71 | if (i == 0) { 72 | stretchElement.insertBefore(barWrapperElement, stretchElement.children[(hasStart) ? 1 : 0]); 73 | } else { 74 | stretchElement.insertBefore(barWrapperElement, stretchElement.children[(hasStart) ? 3 : 2]); 75 | } 76 | } 77 | stretchElement.style.verticalAlign = "" + stretchShift + "em"; 78 | } 79 | 80 | calcKinds(element) { 81 | let leftKind = "paren"; 82 | let rightKind = "paren"; 83 | let centerKind = "vert"; 84 | if (element.getAttribute("data-left")) { 85 | leftKind = element.getAttribute("data-left"); 86 | } 87 | if (element.getAttribute("data-right")) { 88 | rightKind = element.getAttribute("data-right"); 89 | } 90 | if (element.getAttribute("data-center")) { 91 | centerKind = element.getAttribute("data-center"); 92 | } 93 | return [leftKind, rightKind, centerKind]; 94 | } 95 | 96 | calcMaxStretchLevel(kind, position) { 97 | let keys = Object.keys(DATA["fence"][kind][position]); 98 | let maxStretchLevel = 0; 99 | for (let key of keys) { 100 | if (key.match(/^\d+$/) && parseInt(key) > maxStretchLevel) { 101 | maxStretchLevel = parseInt(key); 102 | } 103 | } 104 | return maxStretchLevel; 105 | } 106 | 107 | calcWholeHeight(elements) { 108 | let upperHeights = []; 109 | let lowerHeights = []; 110 | for (let element of elements) { 111 | upperHeights.push(this.getUpperHeight(element)); 112 | lowerHeights.push(this.getLowerHeight(element)); 113 | } 114 | let maxUpperHeight = Math.max(...upperHeights); 115 | let maxLowerHeight = Math.max(...lowerHeights); 116 | return maxUpperHeight + maxLowerHeight; 117 | } 118 | 119 | calcStretchLevel(elements, kind, position) { 120 | let heightAbs = this.calcWholeHeight(elements) * 1000; 121 | let maxStretchLevel = this.calcMaxStretchLevel(kind, position); 122 | let stretchLevel = null; 123 | for (let i = 0 ; i <= maxStretchLevel ; i ++) { 124 | if (heightAbs <= 1059 + 242 * i) { 125 | stretchLevel = i; 126 | break; 127 | } 128 | } 129 | if (stretchLevel == null && !DATA["fence"][kind][position]["bar"]) { 130 | stretchLevel = maxStretchLevel; 131 | } 132 | return stretchLevel; 133 | } 134 | 135 | calcShift(elements, stretchLevel) { 136 | let shift = this.calcWholeHeight(elements) / 2 - Math.max(...elements.map((element) => this.getLowerHeight(element))); 137 | if (stretchLevel == 0) { 138 | shift = 0; 139 | } 140 | return shift; 141 | } 142 | 143 | calcBarHeight(elements, startElement, endElement, middleElement) { 144 | let wholeHeight = this.calcWholeHeight(elements); 145 | let startHeight = (startElement) ? this.getHeight(startElement) : 0; 146 | let endHeight = (endElement) ? this.getHeight(endElement) : 0; 147 | let middleHeight = (middleElement) ? this.getHeight(middleElement) : 0; 148 | let height = wholeHeight - startHeight - endHeight - middleHeight; 149 | if (middleElement) { 150 | height = height / 2; 151 | } 152 | if (height < 0) { 153 | height = 0; 154 | } 155 | return height; 156 | } 157 | 158 | calcStretchShift(elements) { 159 | let shift = Math.max(...elements.map((element) => this.getUpperHeight(element))) - 0.95; 160 | return shift; 161 | } 162 | 163 | } -------------------------------------------------------------------------------- /source/zotica/resource/script/main.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | class Modifier { 5 | 6 | modify() { 7 | console.info("[Zotica] Start"); 8 | let startDate = new Date(); 9 | let elements = []; 10 | elements.push(...document.querySelectorAll("math-subsup")); 11 | elements.push(...document.querySelectorAll("math-underover")); 12 | elements.push(...document.querySelectorAll("math-rad.mod")); 13 | elements.push(...document.querySelectorAll("math-fence.mod")); 14 | elements.push(...document.querySelectorAll("math-diagram")); 15 | elements.push(...document.querySelectorAll("math-step")); 16 | elements = elements.sort((first, second) => { 17 | return this.getDepth(second) - this.getDepth(first); 18 | }); 19 | elements.forEach((element) => { 20 | let name = element.localName; 21 | if (name == "math-subsup") { 22 | SubsuperModifier.execute(element); 23 | } else if (name == "math-underover") { 24 | UnderoverModifier.execute(element); 25 | if (element.classList.contains("wid") && element.classList.contains("mod")) { 26 | WideModifier.execute(element); 27 | } 28 | } else if (name == "math-rad") { 29 | RadicalModifier.execute(element); 30 | } else if (name == "math-fence") { 31 | FenceModifier.execute(element); 32 | } else if (name == "math-diagram") { 33 | DiagramModifier.execute(element); 34 | } else if (name == "math-step") { 35 | TreeModifier.execute(element); 36 | } 37 | }); 38 | let finishDate = new Date(); 39 | let elapsedTime = ((finishDate - startDate) / 1000).toFixed(4); 40 | console.info("[Zotica] Finish (" + elements.length + " elements, " + elapsedTime + " seconds)"); 41 | } 42 | 43 | modifyDebug() { 44 | document.querySelectorAll("debug").forEach((element) => { 45 | let modifier = new Modifier(); 46 | modifier.renderDebug(element); 47 | }); 48 | } 49 | 50 | getFontSize(element) { 51 | let fontSizeString = window.getComputedStyle(element).fontSize; 52 | let fontSize = parseFloat(fontSizeString); 53 | return fontSize; 54 | } 55 | 56 | getWidthPx(element) { 57 | let width = element.getBoundingClientRect().width; 58 | return width; 59 | } 60 | 61 | getWidth(element, fontElement) { 62 | let width = this.getWidthPx(element) / this.getFontSize(fontElement || element); 63 | return width; 64 | } 65 | 66 | getHeightPx(element) { 67 | let height = element.getBoundingClientRect().height; 68 | return height; 69 | } 70 | 71 | getHeight(element, fontElement) { 72 | let height = this.getHeightPx(element) / this.getFontSize(fontElement || element); 73 | return height; 74 | } 75 | 76 | getLowerHeightPx(element) { 77 | let bottom = element.getBoundingClientRect().bottom + window.pageYOffset; 78 | let locator = document.createElement("math-sys-locator"); 79 | element.appendChild(locator); 80 | locator.style.verticalAlign = "baseline"; 81 | let baselineBottom = locator.getBoundingClientRect().bottom + window.pageYOffset; 82 | let height = bottom - baselineBottom + this.getFontSize(element) * 0.3; 83 | element.removeChild(locator); 84 | return height; 85 | } 86 | 87 | getLowerHeight(element, fontElement) { 88 | let height = this.getLowerHeightPx(element) / this.getFontSize(fontElement || element); 89 | return height; 90 | } 91 | 92 | getUpperHeightPx(element) { 93 | let height = this.getHeightPx(element) - this.getLowerHeightPx(element); 94 | return height; 95 | } 96 | 97 | getUpperHeight(element, fontElement) { 98 | let height = this.getHeight(element, fontElement) - this.getLowerHeight(element, fontElement); 99 | return height; 100 | } 101 | 102 | getOffsetLeft(element, fontElement) { 103 | let offset = element.offsetLeft / this.getFontSize(fontElement || element); 104 | return offset; 105 | } 106 | 107 | getOffsetRight(element, fontElement) { 108 | let offset = (element.offsetParent.offsetWidth - element.offsetLeft - element.offsetWidth) / this.getFontSize(fontElement || element); 109 | return offset; 110 | } 111 | 112 | getDepth(element) { 113 | let depth = 0; 114 | if (element.zoticaDepth != undefined) { 115 | depth = element.zoticaDepth; 116 | } else { 117 | let parent = element.parentNode; 118 | if (parent) { 119 | depth = this.getDepth(parent) + 1; 120 | } else { 121 | depth = 0; 122 | } 123 | } 124 | element.zoticaDepth = depth; 125 | return depth; 126 | } 127 | 128 | findChild(element, name) { 129 | return Array.from(element.children).find((child) => child.localName == name); 130 | } 131 | 132 | findChildren(element, name) { 133 | return Array.from(element.children).filter((child) => child.localName == name); 134 | } 135 | 136 | renderDebug(element) { 137 | let clientRect = element.getBoundingClientRect(); 138 | let scrollOffset = window.pageYOffset; 139 | let lowerHeight = this.getLowerHeightPx(element); 140 | let upperHeight = this.getUpperHeightPx(element); 141 | let line = document.createElement("div"); 142 | let upperBox = document.createElement("div"); 143 | let lowerBox = document.createElement("div"); 144 | line.style.position = "absolute"; 145 | line.style.borderTop = "1px #FF000088 solid"; 146 | line.style.width = "" + clientRect.width + "px"; 147 | line.style.height = "1px"; 148 | line.style.top = "" + (clientRect.bottom - lowerHeight + scrollOffset) + "px"; 149 | line.style.left = "" + clientRect.left + "px"; 150 | lowerBox.style.position = "absolute"; 151 | lowerBox.style.backgroundColor = "#FFFF0033"; 152 | lowerBox.style.width = "" + clientRect.width + "px"; 153 | lowerBox.style.height = "" + lowerHeight + "px"; 154 | lowerBox.style.top = "" + (clientRect.top + upperHeight + scrollOffset) + "px"; 155 | lowerBox.style.left = "" + clientRect.left + "px"; 156 | upperBox.style.position = "absolute"; 157 | upperBox.style.backgroundColor = "#FF000033"; 158 | upperBox.style.width = "" + clientRect.width + "px"; 159 | upperBox.style.height = "" + upperHeight + "px"; 160 | upperBox.style.top = "" + (clientRect.top + scrollOffset) + "px"; 161 | upperBox.style.left = "" + clientRect.left + "px"; 162 | document.body.appendChild(line); 163 | document.body.appendChild(lowerBox); 164 | document.body.appendChild(upperBox); 165 | } 166 | 167 | static execute(element) { 168 | let modifier = new this(); 169 | modifier.modify(element); 170 | } 171 | 172 | } -------------------------------------------------------------------------------- /source/zotica/resource/script/radical.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | class RadicalModifier extends Modifier { 5 | 6 | modify(element) { 7 | let squareElement = this.findChild(element, "math-sqrt"); 8 | let indexElement = this.findChild(element, "math-index"); 9 | let surdElement = this.findChild(squareElement, "math-surd"); 10 | let contentElement = this.findChild(squareElement, "math-cont"); 11 | let surdSymbolElement = surdElement.children[0]; 12 | let stretchLevel = this.calcStretchLevel(contentElement); 13 | surdSymbolElement.textContent = DATA["radical"][stretchLevel]; 14 | if (indexElement) { 15 | this.modifyIndex(element, indexElement); 16 | } 17 | } 18 | 19 | modifyIndex(element, indexElement) { 20 | let width = this.getWidth(indexElement); 21 | let fontRatio = this.getFontSize(element) / this.getFontSize(indexElement); 22 | if (width / fontRatio < 0.5) { 23 | let margin = 0.5 * fontRatio - width; 24 | indexElement.style.marginLeft = "" + margin + "em"; 25 | } 26 | } 27 | 28 | calcStretchLevel(element) { 29 | let heightAbs = this.getHeight(element) * 1000; 30 | let stretchLevel = null; 31 | for (let i = 0 ; i <= 3 ; i ++) { 32 | if (heightAbs <= DATA["radical"]["height"][i]) { 33 | stretchLevel = i; 34 | break; 35 | } 36 | } 37 | if (stretchLevel == null) { 38 | stretchLevel = 3; 39 | } 40 | return stretchLevel; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /source/zotica/resource/script/subsuper.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | class SubsuperModifier extends Modifier { 5 | 6 | modify(element) { 7 | let baseElement = this.findChild(element, "math-base"); 8 | let subElement = this.findChild(element, "math-sub"); 9 | let superElement = this.findChild(element, "math-sup"); 10 | let leftSubElement = this.findChild(element, "math-lsub"); 11 | let leftSuperElement = this.findChild(element, "math-lsup"); 12 | this.modifySide(element, baseElement, subElement, superElement, "right"); 13 | this.modifySide(element, baseElement, leftSubElement, leftSuperElement, "left"); 14 | } 15 | 16 | modifySide(element, baseElement, subElement, superElement, side) { 17 | let bothShifts = this.calcBothShifts(baseElement, subElement, superElement); 18 | let subShift = bothShifts.sub; 19 | let superShift = bothShifts.super; 20 | let subMargin = 0; 21 | let superMargin = (subElement) ? -this.getWidth(subElement) : 0; 22 | let subWidth = (subElement) ? this.getWidth(subElement) : 0; 23 | let superWidth = (superElement) ? this.getWidth(superElement) : 0; 24 | if (side == "right" && element.classList.contains("int")) { 25 | let slope = (element.classList.contains("inl")) ? 0.3 : 0.6 26 | subWidth -= slope; 27 | subMargin -= slope; 28 | if (subElement) { 29 | superMargin += slope; 30 | } 31 | } 32 | if (subElement) { 33 | subElement.style.verticalAlign = "" + subShift + "em"; 34 | subElement.style.marginLeft = "" + subMargin + "em"; 35 | } 36 | if (superElement) { 37 | superElement.style.verticalAlign = "" + superShift + "em"; 38 | superElement.style.marginLeft = "" + superMargin + "em"; 39 | } 40 | if (side == "right" && superElement && subWidth > superWidth) { 41 | superElement.style.width = "" + subWidth + "em"; 42 | } 43 | if (side == "left" && subElement && superWidth > subWidth) { 44 | subElement.style.width = "" + superWidth + "em"; 45 | } 46 | } 47 | 48 | calcBothShifts(baseElement, subElement, superElement) { 49 | let subShift = (subElement) ? this.calcSubShift(baseElement, subElement) : 0; 50 | let superShift = (superElement) ? this.calcSuperShift(baseElement, superElement) : 0; 51 | if (subElement && superElement) { 52 | let subHeight = this.getHeight(subElement); 53 | let gap = -subShift + superShift - subHeight; 54 | if (gap < 0.2) { 55 | subShift -= (0.2 - gap) / 2; 56 | superShift += (0.2 - gap) / 2; 57 | } 58 | } 59 | return {sub: subShift, super: superShift}; 60 | } 61 | 62 | calcSubShift(baseElement, subElement) { 63 | let fontRatio = this.getFontSize(baseElement) / this.getFontSize(subElement); 64 | let height = this.getLowerHeight(baseElement); 65 | if (height < 0.4875) { 66 | height = 0.4875; 67 | } 68 | let shiftConst = -0.25; 69 | if (baseElement.parentNode.classList.contains("int") && !baseElement.parentNode.classList.contains("inl")) { 70 | shiftConst = -0.15; 71 | } 72 | let shift = (height + shiftConst) * fontRatio; 73 | return -shift; 74 | } 75 | 76 | calcSuperShift(baseElement, superElement) { 77 | let fontRatio = this.getFontSize(baseElement) / this.getFontSize(superElement); 78 | let height = this.getUpperHeight(baseElement); 79 | if (height < 0.5125) { 80 | height = 0.5125; 81 | } 82 | let shiftConst = -0.2; 83 | if (baseElement.parentNode.classList.contains("int") && !baseElement.parentNode.classList.contains("inl")) { 84 | shiftConst = -0.1; 85 | } 86 | let shift = (height + shiftConst) * fontRatio; 87 | return shift; 88 | } 89 | 90 | } -------------------------------------------------------------------------------- /source/zotica/resource/script/tree.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | class TreeModifier extends Modifier { 5 | 6 | modify(element) { 7 | let antecendentContainerElement = this.findChild(element, "math-ant"); 8 | let firstAntecedentElement = antecendentContainerElement.children[0]; 9 | let lastAntecedentElement = antecendentContainerElement.children[antecendentContainerElement.children.length - 1]; 10 | let firstContentElement = this.calcContentElement(firstAntecedentElement); 11 | let lastContentElement = this.calcContentElement(lastAntecedentElement); 12 | let leftLabelElement = element.previousElementSibling; 13 | let rightLabelElement = element.nextElementSibling; 14 | let consequentWrapperElement = this.findChild(element, "math-conwrap"); 15 | let lineElement = this.findChild(consequentWrapperElement, "math-line"); 16 | let consequentElement = this.findChild(consequentWrapperElement, "math-con"); 17 | let contentElement = this.findChild(consequentElement, "math-cont"); 18 | let fontRatio = this.getFontSize(element) / this.getFontSize(leftLabelElement); 19 | let leftLabelWidth = this.getWidth(leftLabelElement, element); 20 | let rightLabelWidth = this.getWidth(rightLabelElement, element); 21 | let contentWidth = this.getWidth(contentElement); 22 | let wholeWidth = this.getWidth(element); 23 | let leftExtrusion = 0; 24 | let rightExtrusion = 0; 25 | if (firstContentElement && firstContentElement.localName != "math-axiom") { 26 | leftExtrusion = this.getOffsetLeft(firstContentElement); 27 | } 28 | if (lastContentElement && lastContentElement.localName != "math-axiom") { 29 | rightExtrusion = this.getOffsetRight(lastContentElement); 30 | } 31 | let lineWidth = wholeWidth - leftExtrusion - rightExtrusion; 32 | let leftMargin = (lineWidth - contentWidth) / 2 + leftExtrusion; 33 | consequentElement.style.setProperty("margin-left", "" + leftMargin + "em"); 34 | if (leftExtrusion > this.getOffsetLeft(contentElement) - leftLabelWidth) { 35 | leftExtrusion = this.getOffsetLeft(contentElement) - leftLabelWidth; 36 | } 37 | if (rightExtrusion > this.getOffsetRight(contentElement) - rightLabelWidth) { 38 | rightExtrusion = this.getOffsetRight(contentElement) - rightLabelWidth; 39 | } 40 | lineWidth = wholeWidth - leftExtrusion - rightExtrusion; 41 | lineElement.style.setProperty("width", "" + lineWidth + "em", "important"); 42 | lineElement.style.setProperty("margin-left", "" + leftExtrusion + "em", "important"); 43 | element.style.setProperty("margin-right", "" + (-rightExtrusion) + "em", "important"); 44 | if (rightLabelWidth < rightExtrusion) { 45 | rightLabelElement.style.setProperty("margin-right", "" + ((rightExtrusion - rightLabelWidth) * fontRatio) + "em", "important"); 46 | } 47 | element.style.setProperty("margin-left", "" + (-leftExtrusion) + "em", "important"); 48 | if (leftLabelWidth < leftExtrusion) { 49 | leftLabelElement.style.setProperty("margin-left", "" + ((leftExtrusion - leftLabelWidth) * fontRatio) + "em", "important"); 50 | } 51 | } 52 | 53 | calcContentElement(antecedentElement) { 54 | let contentElement = null; 55 | if (antecedentElement) { 56 | if (antecedentElement.localName == "math-axiom") { 57 | contentElement = antecedentElement; 58 | } else { 59 | let stepElement = this.findChild(antecedentElement, "math-step"); 60 | let consequenceWrapperElement = this.findChild(stepElement, "math-conwrap"); 61 | let consequentElement = this.findChild(consequenceWrapperElement, "math-con"); 62 | contentElement = this.findChild(consequentElement, "math-cont"); 63 | } 64 | } 65 | return contentElement; 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /source/zotica/resource/script/underover.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | class UnderoverModifier extends Modifier { 5 | 6 | modify(element) { 7 | } 8 | 9 | } -------------------------------------------------------------------------------- /source/zotica/resource/script/wide.js: -------------------------------------------------------------------------------- 1 | // 2 | 3 | 4 | class WideModifier extends Modifier { 5 | 6 | modify(element) { 7 | let baseWrapperElement = this.findChild(element, "math-basewrap"); 8 | let overElement = this.findChild(element, "math-over"); 9 | let contentElement = baseWrapperElement.children[0]; 10 | let parentElements = [baseWrapperElement.children[1], overElement]; 11 | let kind = this.calcKind(element); 12 | for (let position of [0, 1]) { 13 | let parentElement = parentElements[position]; 14 | if (parentElement) { 15 | let stretchLevel = this.calcStretchLevel(contentElement, kind, position); 16 | if (stretchLevel != null) { 17 | this.modifyStretch(contentElement, parentElement, kind, stretchLevel, position); 18 | } else { 19 | this.appendStretch(contentElement, parentElement, kind, position); 20 | } 21 | } 22 | } 23 | } 24 | 25 | modifyStretch(contentElement, parentElement, kind, stretchLevel, position) { 26 | let symbolElement = parentElement.children[0]; 27 | symbolElement.textContent = DATA["wide"][kind][position][stretchLevel]; 28 | } 29 | 30 | appendStretch(contentElement, parentElement, kind, position) { 31 | let stretchElement = document.createElement("math-hstretch"); 32 | let hasStart = !!DATA["wide"][kind][position]["start"]; 33 | let hasEnd = !!DATA["wide"][kind][position]["end"]; 34 | let hasMiddle = !!DATA["wide"][kind][position]["middle"]; 35 | let startElement = null; 36 | let endElement = null; 37 | let middleElement = null; 38 | if (hasStart) { 39 | startElement = document.createElement("math-start"); 40 | startElement.textContent = DATA["wide"][kind][position]["start"]; 41 | stretchElement.append(startElement); 42 | } 43 | if (hasMiddle) { 44 | middleElement = document.createElement("math-middle"); 45 | middleElement.textContent = DATA["wide"][kind][position]["middle"]; 46 | stretchElement.append(middleElement); 47 | } 48 | if (hasEnd) { 49 | endElement = document.createElement("math-end"); 50 | endElement.textContent = DATA["wide"][kind][position]["end"]; 51 | stretchElement.append(endElement); 52 | } 53 | parentElement.removeChild(parentElement.children[0]); 54 | parentElement.appendChild(stretchElement); 55 | let barSize = (hasMiddle) ? 2 : 1; 56 | let barWidth = this.calcBarWidth(contentElement, startElement, endElement, middleElement); 57 | for (let i = 0 ; i < barSize ; i ++) { 58 | let barWrapperElement = document.createElement("math-barwrap"); 59 | let barElement = document.createElement("math-bar"); 60 | barElement.textContent = DATA["wide"][kind][position]["bar"]; 61 | barWrapperElement.style.width = "" + barWidth + "em"; 62 | barWrapperElement.append(barElement); 63 | if (i == 0) { 64 | stretchElement.insertBefore(barWrapperElement, stretchElement.children[(hasStart) ? 1 : 0]); 65 | } else { 66 | stretchElement.insertBefore(barWrapperElement, stretchElement.children[(hasStart) ? 3 : 2]); 67 | } 68 | } 69 | } 70 | 71 | calcKind(element) { 72 | let kind = "widetilde"; 73 | if (element.getAttribute("data-kind")) { 74 | kind = element.getAttribute("data-kind"); 75 | } 76 | return kind; 77 | } 78 | 79 | calcMaxStretchLevel(kind, position) { 80 | let keys = Object.keys(DATA["wide"][kind][position]); 81 | let maxStretchLevel = -1; 82 | for (let key of keys) { 83 | if (key.match(/^\d+$/) && DATA["wide"][kind][position][key] && parseInt(key) > maxStretchLevel) { 84 | maxStretchLevel = parseInt(key); 85 | } 86 | } 87 | return maxStretchLevel; 88 | } 89 | 90 | calcStretchLevel(element, kind, position) { 91 | let widthAbs = this.getWidth(element) * 1000; 92 | let maxStretchLevel = this.calcMaxStretchLevel(kind, position); 93 | let stretchLevel = null; 94 | for (let i = 0 ; i <= maxStretchLevel ; i ++) { 95 | if (widthAbs <= DATA["wide"][kind][position]["width"][i]) { 96 | stretchLevel = i; 97 | break; 98 | } 99 | } 100 | if (stretchLevel == null && !DATA["wide"][kind][position]["bar"]) { 101 | stretchLevel = maxStretchLevel; 102 | } 103 | return stretchLevel; 104 | } 105 | 106 | calcBarWidth(element, startElement, endElement, middleElement) { 107 | let wholeWidth = this.getWidth(element); 108 | let startWidth = (startElement) ? this.getWidth(startElement) : 0; 109 | let endWidth = (endElement) ? this.getWidth(endElement) : 0; 110 | let middleWidth = (middleElement) ? this.getWidth(middleElement) : 0; 111 | let width = wholeWidth - startWidth - endWidth - middleWidth; 112 | if (middleElement) { 113 | width = width / 2; 114 | } 115 | if (width < 0) { 116 | width = 0; 117 | } 118 | return width; 119 | } 120 | 121 | } -------------------------------------------------------------------------------- /source/zotica/resource/style/math.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | 4 | @function spacing($value) { 5 | $spacing-const: 1em / 18; 6 | @return $value * $spacing-const; 7 | } 8 | 9 | 10 | @mixin math-font { 11 | margin-top: 0.12em; 12 | margin-bottom: 0em; 13 | line-height: 0.9; 14 | font-family: "Math"; 15 | } 16 | 17 | @mixin normal-font { 18 | margin-top: 0em; 19 | margin-bottom: 0em; 20 | font-family: inherit; 21 | } 22 | 23 | 24 | math-n { 25 | margin: 0em spacing(0); 26 | line-height: 1; 27 | } 28 | 29 | 30 | math-i { 31 | padding-right: spacing(1); 32 | line-height: 1; 33 | font-style: italic; 34 | 35 | &.rm { 36 | padding-right: spacing(0); 37 | font-style: normal; 38 | } 39 | 40 | &.bf { 41 | font-weight: bold; 42 | } 43 | 44 | &.tt { 45 | font-family: "Consolas"; 46 | font-style: normal; 47 | } 48 | 49 | &.alt { 50 | @include math-font; 51 | padding-right: spacing(0); 52 | font-style: normal; 53 | } 54 | 55 | } 56 | 57 | 58 | math-o { 59 | @include math-font; 60 | 61 | &.txt { 62 | @include normal-font; 63 | } 64 | 65 | &.sml { 66 | @include normal-font; 67 | font-variant: all-small-caps; 68 | } 69 | 70 | &.int { 71 | margin-top: 0.65em; 72 | margin-bottom: 0.7em; 73 | } 74 | 75 | &.int.inl { 76 | margin-top: 0em; 77 | margin-bottom: 0.05em; 78 | } 79 | 80 | &.sum { 81 | margin-top: 0.24em; 82 | margin-bottom: 0.24em; 83 | } 84 | 85 | &.sum.inl { 86 | margin-top: 0.1em; 87 | margin-bottom: 0.05em; 88 | } 89 | 90 | &.acc { 91 | margin-top: 0em; 92 | margin-bottom: 0em; 93 | } 94 | 95 | math-over >&.acc { 96 | margin-top: -0.05em; 97 | } 98 | 99 | math-over >&.acc.it { 100 | margin-right: -0.15em !important; 101 | } 102 | 103 | math-under >&.acc { 104 | margin-bottom: -0.05em; 105 | } 106 | 107 | math-under >&.acc.it { 108 | margin-left: -0.1em !important; 109 | } 110 | 111 | math-over >&.wid { 112 | margin-top: 0.1em; 113 | margin-bottom: 0em; 114 | } 115 | 116 | math-under >&.wid { 117 | margin-top: 0em; 118 | margin-bottom: 0.1em; 119 | } 120 | 121 | *:not(.lpres) >&:first-child, 122 | *:not(.lpres) >math-strut +& { 123 | margin-left: spacing(0); 124 | margin-right: spacing(0); 125 | } 126 | 127 | } 128 | 129 | 130 | math-frac { 131 | margin: 0em spacing(2) !important; 132 | vertical-align: -0.01em; 133 | 134 | >math-num { 135 | margin-bottom: -0.1em; 136 | text-align: center; 137 | display: block; 138 | } 139 | 140 | >math-denwrap { 141 | margin: 0.2em 0em 0em 0em; 142 | width: 100%; 143 | display: inline-table; 144 | text-align: center; 145 | } 146 | 147 | >math-denwrap >math-line { 148 | margin: 0em spacing(-2) 0.18em spacing(-2) !important; 149 | padding: 0em spacing(2) !important; 150 | width: 100%; 151 | height: 0.06em; 152 | border-top: 0.06em solid; 153 | box-sizing: content-box; 154 | } 155 | 156 | >math-denwrap >math-den { 157 | margin: 0em 0em; 158 | text-align: center; 159 | display: block; 160 | } 161 | 162 | } 163 | 164 | 165 | math-step { 166 | margin: 0em !important; 167 | vertical-align: -0.01em; 168 | 169 | >math-ant { 170 | margin-bottom: -0.1em; 171 | text-align: center; 172 | display: block; 173 | } 174 | 175 | >math-ant >* { 176 | margin-left: spacing(24); 177 | } 178 | 179 | >math-ant >*:first-child { 180 | margin-left: spacing(0); 181 | } 182 | 183 | >math-conwrap { 184 | margin: 0.2em 0em 0em 0em; 185 | width: 100%; 186 | display: inline-table; 187 | text-align: left; 188 | } 189 | 190 | >math-conwrap >math-line { 191 | margin: 0em 0em 0.18em 0em !important; 192 | padding: 0em 0em !important; 193 | width: 0em; 194 | height: 0.06em; 195 | border-top: 0.06em solid; 196 | box-sizing: content-box; 197 | } 198 | 199 | >math-conwrap >math-con { 200 | margin: 0em 0em; 201 | text-align: left; 202 | display: block; 203 | } 204 | 205 | } 206 | 207 | 208 | math-rad { 209 | 210 | >math-sqrt { 211 | margin-top: 0em; 212 | } 213 | 214 | >math-sqrt >math-surd { 215 | margin-top: 0.21em; 216 | vertical-align: top; 217 | } 218 | 219 | >math-sqrt >math-surd >math-o { 220 | margin-top: 0em; 221 | margin-bottom: 0em; 222 | } 223 | 224 | >math-sqrt >math-cont { 225 | margin: 0em spacing(1) 0em spacing(0); 226 | padding-top: 0.25em; 227 | border-top: 0.06em solid; 228 | } 229 | 230 | >math-index { 231 | vertical-align: 0.9em; 232 | font-size: 64%; 233 | } 234 | 235 | >math-index +math-sqrt { 236 | margin-left: -0.5em; 237 | } 238 | 239 | } 240 | 241 | 242 | math-subsup { 243 | 244 | >math-base { 245 | margin: 0em spacing(0); 246 | } 247 | 248 | >math-sub, 249 | >math-lsub { 250 | margin-bottom: -0em; 251 | vertical-align: -0.2969em; 252 | font-size: 80%; 253 | text-align: left; 254 | } 255 | 256 | >math-lsub { 257 | text-align: right; 258 | } 259 | 260 | >math-sup, 261 | >math-lsup { 262 | margin-top: -0em; 263 | vertical-align: 0.3906em; 264 | font-size: 80%; 265 | text-align: left; 266 | } 267 | 268 | >math-lsup { 269 | text-align: right; 270 | } 271 | 272 | &.int { 273 | margin: 0em spacing(0); 274 | } 275 | 276 | } 277 | 278 | 279 | math-underover { 280 | 281 | >math-over { 282 | margin-bottom: spacing(4); 283 | margin-top: -0em; 284 | font-size: 80%; 285 | text-align: center; 286 | display: block; 287 | } 288 | 289 | &.acc >math-over { 290 | margin-bottom: -0.55em; 291 | font-size: 100%; 292 | } 293 | 294 | &.wid >math-over { 295 | margin-bottom: -0.6em; 296 | font-size: 100%; 297 | } 298 | 299 | &.wid[data-kind="overbrace"] >math-over { 300 | margin-bottom: -0.6em; 301 | margin-top: 0.05em; 302 | } 303 | 304 | &.wid[data-kind="overline"] >math-over { 305 | margin-top: -0.1em; 306 | } 307 | 308 | &.wid[data-kind="overrarr"] >math-over, 309 | &.wid[data-kind="overlarr"] >math-over { 310 | margin-top: -0.05em; 311 | } 312 | 313 | >math-basewrap { 314 | margin: 0em 0em; 315 | width: 100%; 316 | display: inline-table; 317 | } 318 | 319 | >math-basewrap >math-base { 320 | margin: 0em 0em; 321 | text-align: center; 322 | display: block; 323 | } 324 | 325 | >math-basewrap >math-under { 326 | margin-top: spacing(4); 327 | margin-bottom: -0em; 328 | font-size: 80%; 329 | text-align: center; 330 | display: block; 331 | } 332 | 333 | &.acc >math-basewrap >math-under { 334 | margin-top: -0.6em; 335 | font-size: 100%; 336 | } 337 | 338 | &.wid >math-basewrap >math-under { 339 | margin-top: -0.7em; 340 | font-size: 100%; 341 | } 342 | 343 | &.wid[data-kind="underbrace"] >math-basewrap >math-under { 344 | margin-top: -0.6em; 345 | margin-bottom: 0.05em; 346 | } 347 | 348 | &.wid[data-kind="underline"] >math-basewrap >math-under { 349 | margin-bottom: -0.15em; 350 | } 351 | 352 | &.wid[data-kind="underrarr"] >math-basewrap >math-under, 353 | &.wid[data-kind="underlarr"] >math-basewrap >math-under { 354 | margin-bottom: -0.1em; 355 | } 356 | 357 | } 358 | 359 | 360 | math-vstretch { 361 | display: inline-flex !important; 362 | flex-direction: column; 363 | 364 | >math-start, 365 | >math-barwrap >math-bar, 366 | >math-middle, 367 | >math-end { 368 | height: 1.25em; 369 | line-height: 2em; 370 | font-family: "Math"; 371 | display: block; 372 | } 373 | 374 | >math-middle { 375 | height: 1.9em; 376 | line-height: 3.4em; 377 | } 378 | 379 | >math-barwrap { 380 | overflow: hidden; 381 | } 382 | 383 | >math-barwrap >math-bar { 384 | transform: scale(1, 100); 385 | } 386 | 387 | } 388 | 389 | 390 | math-hstretch { 391 | 392 | >math-start, 393 | >math-barwrap >math-bar, 394 | >math-middle, 395 | >math-end { 396 | font-family: "Math"; 397 | line-height: 0.8em; 398 | } 399 | 400 | math-over >& >math-start, 401 | math-over >& >math-barwrap, 402 | math-over >& >math-middle, 403 | math-over >& >math-end { 404 | padding-top: 0.2em; 405 | vertical-align: top; 406 | } 407 | 408 | math-under >& >math-start, 409 | math-under >& >math-barwrap, 410 | math-under >& >math-middle, 411 | math-under >& >math-end { 412 | padding-bottom: 0.2em; 413 | vertical-align: bottom; 414 | } 415 | 416 | >math-barwrap { 417 | overflow: hidden; 418 | } 419 | 420 | >math-barwrap >math-bar { 421 | transform: scale(100, 1); 422 | } 423 | 424 | } 425 | 426 | 427 | math-table { 428 | vertical-align: middle; 429 | display: inline-grid !important; 430 | align-items: baseline; 431 | 432 | &.std { 433 | gap: spacing(10) spacing(0); 434 | } 435 | 436 | &.stk { 437 | gap: spacing(3) spacing(0); 438 | } 439 | 440 | &.mat { 441 | gap: spacing(6) spacing(15); 442 | } 443 | 444 | &.cas { 445 | gap: spacing(6) spacing(24); 446 | } 447 | 448 | >math-cell { 449 | text-align: center; 450 | } 451 | 452 | } 453 | 454 | 455 | math-diagram { 456 | row-gap: spacing(54); 457 | column-gap: spacing(72); 458 | vertical-align: middle; 459 | display: inline-grid !important; 460 | align-items: baseline; 461 | position: relative; 462 | 463 | $row-gaps: (non: 0, sthn: 9, vthn: 18, thn: 36, med: 54, thk: 72, vthk: 90, sthk: 108, uthk: 126); 464 | $column-gaps: (non: 0, sthn: 12, vthn: 24, thn: 48, med: 72, thk: 96, vthk: 120, sthk: 144, uthk: 168); 465 | 466 | @each $name, $gap in $row-gaps { 467 | &.v#{$name} { 468 | row-gap: spacing($gap); 469 | } 470 | } 471 | 472 | @each $name, $gap in $column-gaps { 473 | &.h#{$name} { 474 | column-gap: spacing($gap); 475 | } 476 | } 477 | 478 | &.baseline { 479 | vertical-align: baseline; 480 | } 481 | 482 | >math-cellwrap { 483 | text-align: center; 484 | } 485 | 486 | @each $name, $gap in $row-gaps { 487 | >math-cellwrap.v#{$name} { 488 | margin-top: spacing($gap); 489 | } 490 | } 491 | 492 | @each $name, $gap in $column-gaps { 493 | >math-cellwrap.h#{$name} { 494 | margin-left: spacing($gap); 495 | } 496 | } 497 | 498 | >math-arrow { 499 | font-size: 80%; 500 | position: absolute; 501 | } 502 | 503 | >svg { 504 | width: 100%; 505 | height: 100%; 506 | position: absolute; 507 | top: 0px; 508 | left: 0px; 509 | overflow: visible; 510 | pointer-events: none; 511 | } 512 | 513 | >svg path { 514 | stroke-width: 0.06; 515 | stroke: currentcolor; 516 | fill: none; 517 | } 518 | 519 | >svg path.double.base { 520 | stroke-width: 0.24; 521 | } 522 | 523 | >svg path.double.cover { 524 | stroke-width: 0.12; 525 | } 526 | 527 | >svg path.triple.base { 528 | stroke-width: 0.42; 529 | } 530 | 531 | >svg path.triple.cover { 532 | stroke-width: 0.3; 533 | } 534 | 535 | >svg path.triple.front { 536 | stroke-width: 0.06; 537 | } 538 | 539 | >svg path.dashed { 540 | stroke-dasharray: 0.2 0.2; 541 | } 542 | 543 | >svg marker { 544 | overflow: visible; 545 | } 546 | 547 | } 548 | 549 | 550 | math-tree { 551 | vertical-align: middle; 552 | 553 | math-infer { 554 | vertical-align: bottom; 555 | position: relative; 556 | } 557 | 558 | math-infer >math-label { 559 | font-size: 80%; 560 | } 561 | 562 | math-infer >math-label:first-child { 563 | padding-right: spacing(3); 564 | } 565 | 566 | math-infer >math-label:last-child { 567 | padding-left: spacing(3); 568 | } 569 | 570 | math-infer >math-label.non { 571 | padding-left: spacing(0); 572 | padding-right: spacing(0); 573 | } 574 | 575 | math-axiom, 576 | math-con >math-cont { 577 | padding: 0em spacing(5); 578 | } 579 | 580 | } 581 | 582 | 583 | math-space { 584 | 585 | $margins: ( 586 | afun: 3, abin: 4, arel: 5, asbin: 8, asrel: 8, amat: 15, acas: 24, 587 | sthn: 1, vthn: 2, thn: 3, med: 4, thk: 5, vthk: 6, sthk: 7, uthk: 8, hlf: 9, sgl: 18, ssq: 27, dbl: 36 588 | ); 589 | 590 | @each $name, $margin in $margins { 591 | &.#{$name} { 592 | margin-left: spacing($margin) !important; 593 | } 594 | } 595 | 596 | @each $name, $margin in $margins { 597 | &.m#{$name} { 598 | margin-left: spacing(-$margin) !important; 599 | } 600 | } 601 | 602 | } 603 | 604 | 605 | math-phantom { 606 | visibility: hidden; 607 | 608 | &.hor { 609 | height: 0em !important; 610 | } 611 | 612 | &.ver { 613 | width: 0em !important; 614 | } 615 | 616 | } 617 | 618 | 619 | math-strut { 620 | width: 0em !important; 621 | visibility: hidden; 622 | } 623 | 624 | 625 | math-text { 626 | line-height: 0.8; 627 | white-space: pre; 628 | } 629 | 630 | 631 | math-root { 632 | line-height: 0; 633 | display: inline-block; 634 | box-sizing: border-box; 635 | white-space: nowrap; 636 | 637 | * { 638 | display: inline-block; 639 | box-sizing: border-box; 640 | } 641 | 642 | $margins: (bin: 4 4, rel: 5 5, sbin: 8 8, srel: 8 8, del: 0 5, fun: 0 3, ord: 0 0, par: 0 0, lpar: 0 0, rpar: 0 0, cpar: 5 5); 643 | 644 | @each $name, $margin in $margins { 645 | *.#{$name} { 646 | margin-left: spacing(nth($margin, 1)); 647 | margin-right: spacing(nth($margin, 2)); 648 | } 649 | } 650 | 651 | $small-elements: math-sub, math-sup, math-lsub, math-lsup, math-under, math-over, math-index, math-arrow, math-label; 652 | $shrink-names: bin, rel, sbin, srel, del, cpar; 653 | 654 | @each $small-element in $small-elements { 655 | @each $shrink-name in $shrink-names { 656 | #{$small-element} *.#{$shrink-name} { 657 | margin-left: spacing(0) !important; 658 | margin-right: spacing(0) !important; 659 | } 660 | } 661 | } 662 | 663 | *.fun +*.par, 664 | *.fun +*.lpar { 665 | margin-left: spacing(- nth(map-get($margins, fun), 2)) !important; 666 | } 667 | 668 | *.not { 669 | padding-left: spacing(5); 670 | padding-right: spacing(5); 671 | margin-left: spacing(-10); 672 | margin-right: spacing(0); 673 | } 674 | 675 | *:not(.lpres) >*:first-child, 676 | *:not(.lpres) >math-strut +* { 677 | margin-left: spacing(0); 678 | } 679 | 680 | *:not(.rpres) >*:last-child { 681 | margin-right: spacing(0); 682 | } 683 | 684 | } 685 | 686 | 687 | @font-face { 688 | font-family: "Math"; 689 | src: url("__mathfonturl__"); 690 | } -------------------------------------------------------------------------------- /source/zotica/resource/style/times.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | 4 | math-i { 5 | 6 | &:not(.fun):not(.rm)[data-cont="f"] { 7 | padding-left: 0.15em; 8 | padding-right: 0.1em; 9 | } 10 | 11 | } -------------------------------------------------------------------------------- /spec.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | 4 | lib = File.expand_path("../lib", __FILE__) 5 | unless $LOAD_PATH.include?(lib) 6 | $LOAD_PATH.unshift(lib) 7 | end 8 | 9 | Gem::Specification.new do |spec| 10 | spec.name = "zotica" 11 | spec.version = "1.7.0" 12 | spec.authors = ["Ziphil"] 13 | spec.email = ["ziphil.shaleiras@gmail.com"] 14 | spec.licenses = ["MIT"] 15 | spec.homepage = "https://github.com/Ziphil/ZenithalMathWeb" 16 | spec.summary = "Web rendering engine for mathematical formulae" 17 | spec.description = <<~end_string 18 | To be written. 19 | end_string 20 | spec.required_ruby_version = ">= 2.5" 21 | 22 | spec.add_runtime_dependency("zenml", ">= 1.6.0", "~> 1") 23 | spec.add_runtime_dependency("sassc", "~> 2") 24 | spec.add_runtime_dependency("ttfunk", "~> 1") 25 | 26 | spec.files = Dir.glob("source/**/*") 27 | spec.require_paths = ["source"] 28 | spec.bindir = "exec" 29 | spec.executables = ["zotica", "zoticaf"] 30 | end --------------------------------------------------------------------------------

\ar|s="1",e="8",bend="-30",inv| 439 | \ar|s="1",e="5"| 440 | > 441 | > 442 | and 443 | &m< 444 | \diag< 445 | \v<\bfrm \vph<\sb<\bfrm> (\sp<\bfrm><\sp<\scr><\circ;>>)>> 446 | \v<\sp<\bfrm><\sp<\scr><\circ;>> \vph<\sb<\bfrm> (\sp<\bfrm><\sp<\scr><\circ;>>)>> 447 | \v<\sb<\bfrm> (\sp<\bfrm><\sp<\scr><\circ;>>)> 448 | \ar|s="1:r40",e="2:l40",bend="40"|<`D> \ar|s="2:l60",e="1:r60",bend="40"|<`G> 449 | \ar|s="2:r40",e="3:l40",bend="40"|<\bf> \ar|s="3:l60",e="2:r60",bend="40"|<\bf> 450 | > 451 | >. 452 | > 453 | \p< 454 | Shifted arrows: 455 | &m< 456 | \diag< 457 | \v<\op (A, B)> \v \v \br; 458 | \v \v; \v; 459 | \ar|s="1",e="2"| \ar|s="4",e="2",inv| \ar|s="4",e="1"|; 460 | \ar|s="2",e="3",shift="3"| \ar|s="2",e="3",shift="-3",inv| 461 | > 462 | >. 463 | > 464 | \p< 465 | Changing label positions: 466 | &m< 467 | \diag< 468 | \v<1> \v<2> \v<3> \v<4> \br; 469 | \ar|s="1",e="2",pos="10"| 470 | \ar|s="2",e="3",pos="30"| 471 | \ar|s="3",e="4",pos="90"| 472 | \ar|s="1",e="3",bend="-30",pos="20",inv| 473 | \ar|s="2",e="4",bend="-30",pos="80",inv| 474 | > 475 | >. 476 | > 477 | \p< 478 | Changing arrow tips: 479 | &m< 480 | \diag< 481 | \v<1> \v<2> \br; 482 | \v<3> \v<4> 483 | \ar|s="1",e="2",tip="hook",shift="3"|; 484 | \ar|s="1",e="2",shift="-3"|; 485 | \ar|s="3",e="4",tip="varhook,head",shift="-3"|; 486 | \ar|s="3",e="4",shift="3"|; 487 | \ar|s="2",e="4",tip="tail,none",shift="-3"|; 488 | \ar|s="2",e="4",shift="3"|; 489 | \ar|s="1",e="3",tip="bar",dash|; 490 | \ar|s="1",e="4",line="0",mark|<\circlelarr;> 491 | > 492 | >, 493 | compare with &m<\to;>, &m<\headrarr;>, &m<\hookrarr;>. 494 | > 495 | \p< 496 | Double and triple arrows: 497 | &m< 498 | \diag< 499 | \v; \v<2> \v; \br; 500 | \v<4> \v<5> \v<6> \v<7> 501 | \ar|s="2",e="5",line="2",dash|; \ar|s="5",e="6",line="2",inv| \ar|s="2",e="4",bend="-30",line="2"|; 502 | \ar|s="4",e="5",line="3",inv| \ar|s="2",e="6",bend="30",line="3",dash|; 503 | \ar|s="6",e="7"| \ar|s="6",e="7",line="0",inv| \ar|s="6",e="7",line="0",pos="10"| \ar|s="6",e="7",line="0",pos="90"| 504 | > 505 | >, 506 | compare with &m<\to;>, &m<\raarr;>, &m<\raaarr;>. 507 | > 508 | \p< 509 | Changing margin: 510 | &m< 511 | \diag|hor="med,sthk",ver="vthn"|< 512 | \v \v; \v; \br; 513 | \v; \v \v \br; 514 | \v \v; \v; 515 | \ar|s="1",e="7",inv| \ar|s="1",e="5"| \ar|s="7",e="5",inv|<`c> 516 | \ar|s="5",e="6",inv|<\sb<\text> + \sb<\text>> 517 | > 518 | > 519 | or 520 | &m< 521 | \diag|hor="thn,med,thk,36"|< 522 | \v<1> \v<2> \v<3> \v<4> \v<5> \br; 523 | \v<6> \v<7> \v<8> \v<9> \v<10> \br; 524 | \v<11> \v<12> \v<13> \v<14> \v<15> \br; 525 | \ar|s="1",e="2"|; \ar|s="2",e="3"|; \ar|s="3",e="4"|; \ar|s="4",e="5"|; 526 | \ar|s="6",e="7"|; \ar|s="7",e="8"|; \ar|s="8",e="9"|; \ar|s="9",e="10"|; 527 | \ar|s="11",e="12"|; \ar|s="12",e="13"|; \ar|s="13",e="14"|; \ar|s="14",e="15"|; 528 | \ar|s="1",e="6"|; \ar|s="6",e="11"|; 529 | \ar|s="2",e="7"|; \ar|s="7",e="12"|; 530 | \ar|s="3",e="8"|; \ar|s="8",e="13"|; 531 | \ar|s="4",e="9"|; \ar|s="9",e="14"|; 532 | \ar|s="5",e="10"|; \ar|s="10",e="15"|; 533 | > 534 | >. 535 | > 536 | \p< 537 | Specifying a node by its name: 538 | &m< 539 | \diag< 540 | \v|name="a"| \v|name="c"| \br; 541 | \v|name="b"| \v; \br; 542 | \ar|s="a",e="b",inv|<\sb> \ar|s="a",e="c"|<\sb> \ar|s="c",e="b"|<\sb> 543 | > 544 | > 545 | or 546 | &m< 547 | \diag|hor="vthk"|< 548 | \v<\scr> \v<\scr> 549 | \ar|s="1",e="2",bend="40"| \ar|s="1",e="2",bend="-40",inv| 550 | \ar|s="1",e="2",bend="40",pos="30",line="0",name="fl",inv|; \ar|s="1",e="2",bend="-40",pos="30",line="0",name="gl"|; 551 | \ar|s="1",e="2",bend="40",pos="70",line="0",name="fr",inv|; \ar|s="1",e="2",bend="-40",pos="70",line="0",name="gr"|; 552 | \ar|s="fl:c",e="gl:c",line="2",inv|<`a> \ar|s="fr:c",e="gr:c",line="2"|<`b> 553 | \ar|s="fl:c",e="gl:c",line="0",name="a"|; \ar|s="fr:c",e="gr:c",line="0",name="b",inv|; 554 | \ar|s="a:c",e="b:c",line="3"|<`J> 555 | > 556 | >. 557 | > 558 | \p< 559 | Alignments: 560 | &m< 561 | P = \op [] \tort<\diag|bl|< 562 | \v<\bfrm (P)> \v<\scr> \v<\sp<\bfrm><\sp<\scr><\circ;>>> 563 | \ar|s="1",e="2"|; \ar|s="2",e="3"|<\bf> 564 | >> 565 | > 566 | or 567 | &m< 568 | \array|align="rcl"|< 569 | \c<\op (MX, A)> \c<\diag|bl,style="color:red;"|<\v; \v; \ar|s="1",e="2"|>> \c<\op (RLMX, RLA)> \br; 570 | \c; \c<\diag|bl|<\v; \v; \ar|s="1",e="2"|<\hyphen; \circ; R \sb<`f>>>> \c<\op (RKMX, RLA)> \br; 571 | \c; \c<\diag|bl|<\v; \v; \ar|s="1",e="2"|<\hyphen; \circ; \sb<`h>>>> \c<\op (MX, RLA)> 572 | > 573 | > 574 | > 575 | \h1 576 | \p< 577 | &m< 578 | \tree< 579 | \infr|n="0"| \axm 580 | \infr|n="2"|<\wedge|ord|; \rm> \axm<`F> 581 | \infr|n="2"|<\to|ord|; \rm> 582 | > 583 | > 584 | or 585 | &m< 586 | \tree< 587 | \axm<`[Aaa`]> \axm<`[Bbb`]> 588 | \infr|n="2"|<`[Cc`]> \axm<`[W`]> 589 | \infr|n="2"|<`[Ddddd`]> 590 | \axm<`[Ppp`]> \axm<`[Qqq`]> 591 | \infr|n="1"|<`[R`]> 592 | \infr|n="2"|<`[Ee`]> 593 | \infr|n="1"|<`[Fffff`]> \axm<`[X`]> 594 | \infr|n="2"|<`[Gg`]> \axm<`[Yyy`]> 595 | \infr|n="2"|<`[Hhhh`]> 596 | \infr|n="2"|<`[Ii`]> 597 | \infr|n="1"|<`[J`]> 598 | > 599 | >. 600 | > 601 | \h1 602 | \p< 603 | 1: 604 | &mb< 605 | \frac<`p><2> 606 | = \sum<\infty;> \frac<(2 k)!><\sp<2><2 k> \sfun; \sp<(k!)><2>> \sfun; \frac<1><2 k + 1> 607 | = \prod<\infty;> \frac<4 \sp<2>><4 \sp<2> - 1> 608 | = \sp<\paren<\int<0><\infty;> \frac<\sin; x><\sqrt> dx>><2> 609 | > 610 | > 611 | \p< 612 | 2: 613 | &mb< 614 | \array|align="rrcl"|< 615 | \c<`C:> \c<\set<\paren<\matrix<\cc<- b> \cc>> \in; \sb<\op><2> (\bb)><\sp<2> + \sp<2> = 1>> \c<\longto;> \c<\sp<\bb><1>> \br; 616 | \c; \c<\paren<\matrix<\cc<- b> \cc>>> \c<\longmapsto;> \c> 617 | > 618 | > 619 | > 620 | \p< 621 | 3: 622 | &mb< 623 | \diag< 624 | \v