Skip to content

Instantly share code, notes, and snippets.

@think49
Last active November 11, 2016 05:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save think49/6aedea62463a741dde0a9ad2c9aa672e to your computer and use it in GitHub Desktop.
Save think49/6aedea62463a741dde0a9ad2c9aa672e to your computer and use it in GitHub Desktop.
calculator.js: 計算式を表示するシンプルな電卓
/**
* calculator.css
*/
.calc-form {
border-collapse: separate;
border-spacing: 0.2em;
font-style: monospace;
}
.calc-form caption {
font-weight: bold;
}
.calc-form td {
border: solid 1px #777;
padding: 0.2em;
text-align: center;
}
.calc-form input[type="text"] {
border: solid 1px #777;
}
.calc-result-row > td, .calc-expression-row > td {
border-style: none;
padding: 0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>calculator.js</title>
<link href="./calculator.css" rel="stylesheet" type="text/css">
<style>
pre {
border: solid 1px #999;
padding: 0.6em;
}
#history > dd {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<h1>calculator.js</h1>
<h2>概要</h2>
<p><code>calculator.js</code> はシンプルな電卓です。「マウスやタッチパネル端末のタッチでボタンをクリック」もしくは計算式のテキストボックスでキーボード入力する事で機能します。</p>
<h2>ダウンロード</h2>
<p>下記の GitHub Gist から必要なファイルをダウンロードできます。<code>calculator.js</code> は <code>eval-calculation.js</code> と組み合わせて動作する為、両方ともダウンロードして下さい。</p>
<ul>
<li><a href="https://gist.github.com/think49/6aedea62463a741dde0a9ad2c9aa672e">calculator.js: シンプルな電卓 - GitHub Gist</a></li>
<li><a href="https://gist.github.com/think49/54b074cab2145efddb48765652c74710">eval-calculation.js: 計算式の文字列を評価 - GitHub Gist</a></li>
</ul>
<h2>使い方</h2>
<p>外部CSS用のlink要素をマークアップします。</p>
<pre><code>&lt;link href=&quot;./calculator.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;</code></pre>
<p>次のHTMLを任意の場所に記述します。<br />
(※外部スクリプト用のscript要素はform要素直後に置くことを推奨しますが、head要素等、form要素より手前に置いても動作します。)</p>
<pre><code>&lt;form class=&quot;calc-form&quot;&gt;
&lt;table&gt;
&lt;caption&gt;電卓&lt;/caption&gt;
&lt;tbody&gt;
&lt;tr class=&quot;calc-expression-row&quot;&gt;
&lt;td colspan=&quot;5&quot;&gt;&lt;input name=&quot;expression&quot; type=&quot;text&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&quot;calc-result-row&quot;&gt;
&lt;td colspan=&quot;5&quot;&gt;&lt;input name=&quot;result&quot; type=&quot;text&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;calc-button&quot; rowspan=&quot;4&quot; tabindex=&quot;0&quot;&gt;C&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;7&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;8&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;9&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;4&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;5&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;6&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;1&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;2&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;3&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;0&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;.&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;=&lt;/td&gt;
&lt;td class=&quot;calc-button&quot; tabindex=&quot;0&quot;&gt;+&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/form&gt;
&lt;script src=&quot;./eval-calculation.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;./calculator.js&quot;&gt;&lt;/script&gt;</code></pre>
<h2>サンプル</h2>
<form class="calc-form">
<table>
<caption>電卓</caption>
<tbody>
<tr class="calc-expression-row">
<td colspan="5"><input name="expression" type="text" /></td>
</tr>
<tr class="calc-result-row">
<td colspan="5"><input name="result" type="text" /></td>
</tr>
<tr>
<td class="calc-button" rowspan="4" tabindex="0">C</td>
<td class="calc-button" tabindex="0">7</td>
<td class="calc-button" tabindex="0">8</td>
<td class="calc-button" tabindex="0">9</td>
<td class="calc-button" tabindex="0">/</td>
</tr>
<tr>
<td class="calc-button" tabindex="0">4</td>
<td class="calc-button" tabindex="0">5</td>
<td class="calc-button" tabindex="0">6</td>
<td class="calc-button" tabindex="0">*</td>
</tr>
<tr>
<td class="calc-button" tabindex="0">1</td>
<td class="calc-button" tabindex="0">2</td>
<td class="calc-button" tabindex="0">3</td>
<td class="calc-button" tabindex="0">-</td>
</tr>
<tr>
<td class="calc-button" tabindex="0">0</td>
<td class="calc-button" tabindex="0">.</td>
<td class="calc-button" tabindex="0">=</td>
<td class="calc-button" tabindex="0">+</td>
</tr>
</tbody>
</table>
</form>
<script src="./eval-calculation.js"></script>
<script src="./calculator.js"></script>
<h2>仕様/既知の不具合</h2>
<ul>
<li>ver.0.9.2 からAndroidアプリ『<a href="https://play.google.com/store/apps/details?id=androidx.info.speedcalc&hl=ja">Speed 電卓 Free</a>』に倣って数字入力直後に演算結果を表示にするようにしました。その結果、「<code>=</code>(イコール)」が要らない子になりました。</li>
<li>ボタンにキーボードフォーカスしますが、[Enter] キーでクリックと判定されません</li>
</ul>
<h2>更新履歴</h2>
<dl id="history">
<dt>ver.0.9.1 (2016/11/08)</dt>
<dd>
<ul>
<li>初版</li>
</ul>
</dd>
<dt>ver.0.9.2 (2016/11/08)</dt>
<dd>
<ul>
<li>数字を最後に入力した時に演算結果を表示するようにした</li>
</ul>
</dd>
<dt>ver.0.9.3 (2016/11/09)</dt>
<dd>
<ul>
<li>計算式のテキストボックスでキーボード入力できるようにした</li>
<li>適用対象を<code>&lt;form id=&quot;calc-form&quot;&gt;</code>から<code>&lt;form class=&quot;calc-form&quot;&gt;</code>に変更し、複数設置できるようにした</li>
</ul>
</dd>
<dt>ver.0.9.4 (2016/11/09)</dt>
<dd>
<ul>
<li>内部的に整数演算する事で「<code>0.6*3 === 1.8</code>」と計算できるようにした(IEEE754の丸め誤差対策)</li>
</ul>
</dd>
<dt>ver.0.9.5 (2016/11/11)</dt>
<dd>
<ul>
<li>計算式の評価関数 <code>evalCalculation()</code> を <code>eval-calculation.js</code> として分離した</li>
<li>
以下、<code>eval-calculation.js</code> 側で更新した内容。
<ul>
<li><code>.1</code> を <code>0.1</code> として評価できるようにした</li>
<li>少数同士の積算において内部処理の整数化処理で必要以上に大きな整数にされていた不具合を修正(ほとんどの計算で問題はないが、整数として扱える最大値を超えた場合にIEEE754の制約で丸められてしまう)</li>
</ul>
</li>
</ul>
</dd>
</dl>
</body>
</html>
/**
* calculator.js
* Simple Calculator.
*
* @version 0.9.5
* @author think49
* @url https://gist.github.com/think49/6aedea62463a741dde0a9ad2c9aa672e
* @license http://www.opensource.org/licenses/mit-license.php (The MIT License)
*/
(function (String, pow, max) {
'use strict';
function handleClick (event) {
var td = event.target,
elements, expression, inputChar;
if (td.tagName.toLowerCase() !== 'td' || !td.classList.contains('calc-button')) {
return;
}
inputChar = td.firstChild.data;
switch (inputChar) {
case 'C':
event.currentTarget.reset();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
elements = event.currentTarget.elements;
expression = elements['expression'];
expression.value += inputChar;
elements['result'].value = evalCalculation(expression.value);
break;
case '+':
case '-':
case '*':
case '/':
case '.':
elements = event.currentTarget.elements;
expression = elements['expression'];
expression.value += inputChar;
elements['result'].value = evalCalculation(expression.value.replace(/[*/+-]-?$/, ''));
break;
case '=':
elements = event.currentTarget.elements;
elements['result'].value = evalCalculation(elements['expression'].value);
break;
}
}
function handleInput (event) {
var input = event.target;
input.form.elements['result'].value = evalCalculation(input.value.replace(/[*/+-]-?$/, ''));
}
function handleDOMContentLoaded (event) {
var doc = event.target, forms = event.target.querySelectorAll('form.calc-form'), l = forms.length;
if (!l && !('type' in event)) {
doc.addEventListener('DOMContentLoaded', handleDOMContentLoaded, false);
return;
}
for (var i = 0, form; i < l; ++i) {
form = forms[i++];
form.addEventListener('click', handleClick, false);
form.elements['expression'].addEventListener('input', handleInput, false);
}
}
handleDOMContentLoaded({target: this.document});
}.call(this, String, Math.pow, Math.max));
@think49
Copy link
Author

think49 commented Nov 8, 2016

calculator.js は内部処理で eval-calculation() を利用している為、eval-calculation.js を合わせて設置する必要があります。


jsfiddleにもサンプルをUPしています。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment