2014年1月21日 星期二

LimeJS : 以 MathJax 來顯示數學式子

2014年1月21日 星期二
MathJax 在網頁中可以顯示漂亮的數學式子,但是要如何能在 LimeJS 這個強項是在處理圖形的 HTML5 framework 中維持 MathJax 顯示數學符號的優勢呢?試了很多天,從原來讓 MathJax 輸出成「SVG」這條崎嶇不平的路出發,最後轉回直接讓 MathJax 輸出成「HTML-CSS」的康莊大道。整理一下重點,記錄記錄。

如果將 MathJax 的 JavaScript 掛到 LimeJS 的部份就不寫了,直接來看看處理 MathJax 輸出結果的部份。

首先,如果想讓 MathJax 以「TeX」格式輸入數學式子,並輸出成「HTML-CSS」,得在掛入 MathJax 的 JavaScript 將設定寫入名為「window.MathJax」的變數中,例如:

window.MathJax = {
 jax: ["input/TeX","output/HTML-CSS"],
 extensions: ["tex2jax.js"],
 tex2jax: {
  inlineMath: [['$','$'],['\\(','\\)']]
 },
};

有了之前處理在 LimeJS 設計的東西裡面加入 HTML  input element 的經驗後,首先當然得應 MathJax 的需求,先利用「createElement('div')」建立一個給 MathJax inpu 兼 output 的地方(假設儲存在變數「mathjaxOutput」)。

var mathjaxOutput = document.createElement("div");

我們的數學式子就設定「innerHTML」給前面建立的元件 mathjaxOutput 例如:

 mathjaxOutput.innerHTML = '$\frac{1}{5}+\frac{2}{5}=\frac{3}{5}$';


這樣子,如果將上面的「mathjaxOutput」以 appendChild 新增到 LimeJS 的某個場景中的元件以後,就可以看到 MathJax 處理完的結果了。

由於 MathJax 會依我們放數學式子的元件中的 CSS 設定而有不同的效果,因此,輸出的顯示可以透過 CSS 中的底下幾個項目來控制:

  • font-size:數學符號的大小是隨著 CSS 中字的大小而自動調整的,例如:「font-size:300%」字會變大,以此類推。由於預設的 100% 字太小,我是先將它設為 500% 放大,再利用後面的程式判斷並縮小到充滿整個顯示區。
  • visibility:是否要顯示,「hide」為隱藏輸出結果,「visible」為顯示輸出結果。
  • display:控制換行方式,此參數記得要設定為「display:inline」,不然,因為 display 預設為「block」,如果一般文字和數學符號混雜的式子會無法連成一行顯示。
  • width:搭配「附掛」的 LimeJS 元件,視它的大小調整寬度,如果有設定「display:inline」,就可以免去處理換行的問題。
  • height:同 width,搭配「附掛」的 LimeJS 元件的大小來設定高度。

CSS 其它部份就再自行玩一玩吧!

在 MathJax 的網站撈了半天,沒有看到如何讓輸出的數學符號可以完全依照顯示區大小而自動調整比例的,只好發揮 hacker 的精神,利用 Chrome 的「開發人員」工具去追 MathJax 輸出了什麼,一層層抽絲剝繭,大致找出計算最佳 CSS font-size 的方法。

MathJax 輸出的數學符號是放到一個 className 為「MathJax_Display」的 HTML div 元件中,再往下追兩層 childNodes ,找到 nodeName 為「NOBR」的,它底下的 childNode 放著我們要的資訊,將它的 clientWidth 取出來和最大的可顯示範圍計算,據此設定 CSS 的 font-size ,就不會有輸出字太大的困擾了。

Chome 中找 MathJax output 的結構


下面是土法鍊鋼的程式碼:

var child = mathjaxOutput.childNodes;
if(child.length >= 2) {
   //---------find MathJax_Display
   var found = -1;
   for(var i in child) {
      if(child[i].className == 'MathJax_Display') {
         found = i;
         break;
      }
   }
   if(found >= 0) {
      child = child[found].childNodes;
      if(child) {
         child = child[0].childNodes;
         found = -1;
         //---------found NOBR tag element
         for(var i in child) {
            if(child[i].nodeName == 'NOBR') {
               found = i;
               break;
            }
         }
         var nobrChildNodes = null;
         if(found >= 0) {
            nobrChildNodes = child[found].childNodes;
         }
         if(nobrChildNodes) {
            child = nobrChildNodes[0].childNodes;
            if(child) {
               var fontScale = 1;
               //如果超大就計算最佳的字型大小(以預設值去乘以 scale;
               if(child[0].clientWidth > cardSprite.getSize().width) {
                  fontScale = cardSprite.getSize().width/child[0].clientWidth;
               }
               fontSize = math_flashcards.mathajxFontSize * fontScale;
               mathjaxOutput.style['font-size'] = fontSize+'%';                    
            }
         }
      }
   }
}


做完的成品在下面的連結中:

  • HTML5 Math Flashcards
LimeJS : HTML5 math_flashcards



將下面的 html5_math_flashcards.zip 下載回去,解壓縮後,修改 math_flashcards_set.js 中的題庫,就可以顯示自己的數學式弓囉!


相關文章







沒有留言:

張貼留言

 
雄::gsyan © 2009. Design by Pocket