iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0

如果我們是含有數學符號的靜態網頁,那只要依照第十天的方法,就可以輕鬆處理;然而,如果我們的運算式是由使用者輸入得到,也就是動態顯示數學符號,那程序就會麻煩多了。

如果要動態呈顯文字輸入框,一般會使用MathJax.typeset()搭配math.js幫我們解析運算式;若要從後端傳送數學方程式符號,則最好應用MathJax.typesetPromise()的非同步處理。

Math.js

載入math.js

<script type="text/javascript" src="https://unpkg.com/mathjs@9.5.1/lib/browser/math.js"></script>

首先我們需要math.js解析我們輸入的運算式並計算其值,Math.js處理運算式可拆分為parse、compile和evaluate三個步驟。

Math.js運算式的語法大致上和Javascript的運算式語法,最明顯的差異是提供了指數運算符號(^),另外則提供了複數運算和矩陣運算,以下是一些運算式的例子

// expressions
math.evaluate('12 / (2.3 + 0.7)')    // 4
math.evaluate('12.7 cm to inch')     // 5 inch
math.evaluate('cos(2*pi/3)')     // -0.4999999999999998,正確答案應是-0.5, 有誤差
math.evaluate('13 / (3 + 2i)').toString()       // 複數運算3 - 2i
math.evaluate('det([-1, 2; 3, 1])')  // 計算行列式值-7
math.evaluate('2a+3b', {a: 3, b: 5}) // 21

當運算式內含有變數時,evaluate()可以有一個選擇性的物件參數scope,用其設定變數的值。

我們除了計算運算式的值外,最重要的是parse運算式之後,可以鏈接toTex()方法,再由MathJax來呈現數學符號。

由輸入框輸入運算式

輸入框內的字串值轉換成Latex字串後,放入我們想置入的DOM後,便可由MathJax.typeset()將內容渲染為數學方程式符號。以下程式在文字輸入框輸入運算式按下Enter後,會自動呈現方程式字體。

<div class="group input-group">
  <span class="addon input-group-addon">\(f(x)\)=</span>
  <input type="text" id="expression">
</div>
<div class="group output-group">
  <span class="addon output-group-addon">\(f(x)\)=</span>
  <span class="result"></span>
</div>
const expression = document.querySelector('#expression')
const result = document.querySelector('.result')
const inputGroup = document.querySelector('.input-group')
const outputGroup = document.querySelector('.output-group')
expression.value = ''

expression.addEventListener('change', () => {
  convert()
  inputGroup.style.display = 'none'
  outputGroup.style.visibility = 'visible'
})

outputGroup.addEventListener('click', () => {
  outputGroup.style.visibility = 'hidden'
  inputGroup.style.display = null
})

function convert() {
  let latexExpr = math.parse(expression.value).toTex({
    parenthesis: 'keep',
  })
  let options = MathJax.getMetricsFor(result)
  options.display = false
  result.innerHTML = `\\(${latexExpr}\\)`
  MathJax.typeset([result], options)
}

MathJax.typset()的第二個參數是選擇性參數,用來設定渲染數學符號時的字體等相關參數,我們可以用MathJax.getMetricsFor()取得Dom的相關資訊。

非同步MathJax

非同步處理數學符號可以用MathJax.typesetPromise()或MathJax.tex2chtmlPromise();MathJax.tex2chtmlPromise()可以將Latex格式的字串,渲染成chtml數學符號字體,下面是我們的程式範例。

<div class="m-exercice" data-title="Exercise 1">
  <div id="exercise-1">試計算下列函數的導數 \(f(x) = \dfrac{x+2}{x+4} \)</div>
  <button id="show-answer">解答</button>
  <div class="answer"></div>
</div>

當按下「解答」按鈕後,網頁抓取solutions.inc檔案,並讀取檔案內容存入字串變數中,再將內容渲染成數學符號。

const showAnswer = document.querySelector('#show-answer')
const answer = document.querySelector('.answer')
showAnswer.addEventListener('click', displayAnswer)

function displayAnswer() {
   fetch(`./solutions.inc`)
   .then ( (r) => { return r.text()  } )
   .then ( (s) => {
      MathJax.tex2chtmlPromise(s)
        .then(node => {
          answer.innerHTML = ''
          answer.appendChild(node)
          MathJax.startup.document.clear()
          MathJax.startup.document.updateDocument()
        })
    })
}

檔案solutions.inc的內容為

 \begin{align*}
    \left (\dfrac{f}{g} \right)' = \dfrac{f'g -g'f}{g^2}
  
    \implies f'(x) &= \dfrac{(x+4) - (x+2)}{(x+4)^2}  \\
                   &= \dfrac{2}{(x+4)^2}
 \end{align*}

程式原始碼

今日程式原始碼

今日小結

今日介紹math.js協助我們處理輸入運算式的解析,並轉成Latex語法,再由MathJax渲染;也了解在非同步的情形下,如何呼叫Mathjax.tex2chtml()來染渲,範例中非同步處理解答的部份,解答是由檔案中預存;整個範例如果能夠整合,是否可以直接將輸入框中的微分答案找出並顯示,應該是不錯的習題;math.js有提供方法,希望大家去找找看,明天我們將利用這些技巧來完成黎曼積分的範例。


上一篇
非同步處理Promise
下一篇
黎曼積分
系列文
30天數學老師作互動式教學網頁30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言