Difference between revisions of "Javascript Calculator Simulator"
(→Introduction) |
|||
(3 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
--[[User:Thiebaut|D. Thiebaut]] 17:56, 27 January 2013 (EST) | --[[User:Thiebaut|D. Thiebaut]] 17:56, 27 January 2013 (EST) | ||
---- | ---- | ||
− | <center>[[Image:JavascriptCalculatorSimulator.png]]</center> | + | <center>[[Image:JavascriptCalculatorSimulator.png|200px]]</center> |
<br /> | <br /> | ||
− | This is the code written by Simon Southwell for the article [http://www.anita-simulators.org.uk/calc/calc_example/article2_front.htm How to Write a Calculator Simulator]. The zipped files containing all the images and the code can be found [ | + | =Introduction= |
+ | This is the code written by Simon Southwell for the article [http://www.anita-simulators.org.uk/calc/calc_example/article2_front.htm How to Write a Calculator Simulator]. The zipped files containing all the images and the code can be found [http://cs.smith.edu/dftwiki/images/javascriptCalculator_SimonSouthwell.zip here]. | ||
+ | |||
+ | =File Hierarchy= | ||
+ | The file hierarchy including images and script files is shown below | ||
+ | |||
+ | <code><pre> | ||
+ | ./calc.htm | ||
+ | ./images | ||
+ | ./images/display.jpg | ||
+ | ./images/display_left.jpg | ||
+ | ./images/display_right.jpg | ||
+ | ./images/index.html | ||
+ | ./images/keys.jpg | ||
+ | ./images/lcd0.jpg | ||
+ | ./images/lcd0dot.jpg | ||
+ | ./images/lcd1.jpg | ||
+ | ./images/lcd1dot.jpg | ||
+ | ./images/lcd2.jpg | ||
+ | ./images/lcd2dot.jpg | ||
+ | ./images/lcd3.jpg | ||
+ | ./images/lcd3dot.jpg | ||
+ | ./images/lcd4.jpg | ||
+ | ./images/lcd4dot.jpg | ||
+ | ./images/lcd5.jpg | ||
+ | ./images/lcd5dot.jpg | ||
+ | ./images/lcd6.jpg | ||
+ | ./images/lcd6dot.jpg | ||
+ | ./images/lcd7.jpg | ||
+ | ./images/lcd7dot.jpg | ||
+ | ./images/lcd8.jpg | ||
+ | ./images/lcd8dot.jpg | ||
+ | ./images/lcd9.jpg | ||
+ | ./images/lcd9dot.jpg | ||
+ | ./images/lcde.jpg | ||
+ | ./images/lcdminus.jpg | ||
+ | ./images/lcdoff.jpg | ||
+ | ./images/top.jpg | ||
+ | |||
+ | </pre></code> | ||
+ | <br /> | ||
+ | |||
+ | =Javascript Source= | ||
<br /> | <br /> | ||
<code><pre> | <code><pre> |
Latest revision as of 19:10, 27 January 2013
--D. Thiebaut 17:56, 27 January 2013 (EST)
Introduction
This is the code written by Simon Southwell for the article How to Write a Calculator Simulator. The zipped files containing all the images and the code can be found here.
File Hierarchy
The file hierarchy including images and script files is shown below
./calc.htm
./images
./images/display.jpg
./images/display_left.jpg
./images/display_right.jpg
./images/index.html
./images/keys.jpg
./images/lcd0.jpg
./images/lcd0dot.jpg
./images/lcd1.jpg
./images/lcd1dot.jpg
./images/lcd2.jpg
./images/lcd2dot.jpg
./images/lcd3.jpg
./images/lcd3dot.jpg
./images/lcd4.jpg
./images/lcd4dot.jpg
./images/lcd5.jpg
./images/lcd5dot.jpg
./images/lcd6.jpg
./images/lcd6dot.jpg
./images/lcd7.jpg
./images/lcd7dot.jpg
./images/lcd8.jpg
./images/lcd8dot.jpg
./images/lcd9.jpg
./images/lcd9dot.jpg
./images/lcde.jpg
./images/lcdminus.jpg
./images/lcdoff.jpg
./images/top.jpg
Javascript Source
<html>
<head>
<title>Calculator Example</title>
</head>
<body topmargin=0 leftmargin=0 marginheight=0 marginwidth=0 onkeypress="javascript:keyboard(event)">
<table align=center border=0 cellpadding=0 cellspacing=0>
<tr> <td colspan=10><img src="images/top.jpg"></td> </tr>
<tr>
<td><img name="dl" src="images/display_left.jpg"></td>
<td><img name="d7" src="images/lcdoff.jpg"></td>
<td><img name="d6" src="images/lcdoff.jpg"></td>
<td><img name="d5" src="images/lcdoff.jpg"></td>
<td><img name="d4" src="images/lcdoff.jpg"></td>
<td><img name="d3" src="images/lcdoff.jpg"></td>
<td><img name="d2" src="images/lcdoff.jpg"></td>
<td><img name="d1" src="images/lcdoff.jpg"></td>
<td><img name="d0" src="images/lcd0dot.jpg"></td>
<td><img name="dr" src="images/display_right.jpg"></td>
</tr>
<tr><td colspan=10><img src="images/keys.jpg" border=0 usemap="#keymap"></td></tr>
</table>
<map name="keymap">
<area shape=rect coords=" 16, 39, 46, 68" href="javascript:key_pressed('o')" title="o"></area>
<area shape=rect coords=" 55, 39, 85, 68" href="javascript:key_pressed('c')" title="c"></area>
<area shape=rect coords=" 94, 39,124, 68" href="javascript:key_pressed('r')" title="r"></area>
<area shape=rect coords="133, 39,163, 68" href="javascript:key_pressed('m')" title="m"></area>
<area shape=rect coords="169, 39,201, 68" href="javascript:key_pressed('M')" title="M"></area>
<area shape=rect coords=" 16, 74, 46,100" href="javascript:key_pressed('7')" title="7"></area>
<area shape=rect coords=" 55, 74, 85,100" href="javascript:key_pressed('8')" title="8"></area>
<area shape=rect coords=" 94, 74,124,100" href="javascript:key_pressed('9')" title="9"></area>
<area shape=rect coords="133, 74,163,100" href="javascript:key_pressed('%')" title="%"></area>
<area shape=rect coords="169, 74,201,100" href="javascript:key_pressed('s')" title="s"></area>
<area shape=rect coords=" 16,112, 46,138" href="javascript:key_pressed('4')" title="4"></area>
<area shape=rect coords=" 55,112, 85,138" href="javascript:key_pressed('5')" title="5"></area>
<area shape=rect coords=" 94,112,124,138" href="javascript:key_pressed('6')" title="6"></area>
<area shape=rect coords="133,112,163,138" href="javascript:key_pressed('*')" title="*"></area>
<area shape=rect coords="169,112,201,138" href="javascript:key_pressed('/')" title="/"></area>
<area shape=rect coords=" 16,145, 46,171" href="javascript:key_pressed('1')" title="1"></area>
<area shape=rect coords=" 55,145, 85,171" href="javascript:key_pressed('2')" title="2"></area>
<area shape=rect coords=" 94,145,124,171" href="javascript:key_pressed('3')" title="3"></area>
<area shape=rect coords="169,145,201,171" href="javascript:key_pressed('-')" title="-"></area>
<area shape=rect coords=" 16,181, 46,207" href="javascript:key_pressed('0')" title="0"></area>
<area shape=rect coords=" 55,181, 85,207" href="javascript:key_pressed('.')" title="."></area>
<area shape=rect coords=" 94,181,124,207" href="javascript:key_pressed('i')" title="i"></area>
<area shape=rect coords="133,145,163,207" href="javascript:key_pressed('+')" title="+"></area>
<area shape=rect coords="169,181,201,207" href="javascript:key_pressed('=')" title="="></area>
</map>
<script type=text/javascript>
var is_netscape = (navigator.appName=="Netscape") ? 1 : 0;
lcd0 = new Image(20, 45); lcd0.src="images/lcd0.jpg";
lcd1 = new Image(20, 45); lcd1.src="images/lcd1.jpg";
lcd2 = new Image(20, 45); lcd2.src="images/lcd2.jpg";
lcd3 = new Image(20, 45); lcd3.src="images/lcd3.jpg";
lcd4 = new Image(20, 45); lcd4.src="images/lcd4.jpg";
lcd5 = new Image(20, 45); lcd5.src="images/lcd5.jpg";
lcd6 = new Image(20, 45); lcd6.src="images/lcd6.jpg";
lcd7 = new Image(20, 45); lcd7.src="images/lcd7.jpg";
lcd8 = new Image(20, 45); lcd8.src="images/lcd8.jpg";
lcd9 = new Image(20, 45); lcd9.src="images/lcd9.jpg";
lcd0dot = new Image(20, 45); lcd0dot.src="images/lcd0dot.jpg";
lcd1dot = new Image(20, 45); lcd1dot.src="images/lcd1dot.jpg";
lcd2dot = new Image(20, 15); lcd2dot.src="images/lcd2dot.jpg";
lcd3dot = new Image(20, 45); lcd3dot.src="images/lcd3dot.jpg";
lcd4dot = new Image(20, 45); lcd4dot.src="images/lcd4dot.jpg";
lcd5dot = new Image(20, 45); lcd5dot.src="images/lcd5dot.jpg";
lcd6dot = new Image(20, 45); lcd6dot.src="images/lcd6dot.jpg";
lcd7dot = new Image(20, 45); lcd7dot.src="images/lcd7dot.jpg";
lcd8dot = new Image(20, 45); lcd8dot.src="images/lcd8dot.jpg";
lcd9dot = new Image(20, 45); lcd9dot.src="images/lcd9dot.jpg";
lcdoff = new Image(20, 45); lcdoff.src="images/lcdoff.jpg";
lcdminus = new Image(20, 45); lcdminus.src="images/lcdminus.jpg";
lcde = new Image(20, 45); lcde.src="images/lcde.jpg";
var x=0;
var y=0;
var m=0;
var disp="";
var is_new_num = true;
var is_decimal = false;
var last_op = "";
var error = false;
// ---------------------------------------------------------
function update_display(dspin) {
var disp_array = new Array();
var dot_active = false;
var dsp=dspin;
var lcds=0;
var idx=dsp.length;
if (error) {
document.d7.src = lcdoff.src;
document.d6.src = lcdoff.src;
document.d5.src = lcdoff.src;
document.d4.src = lcdoff.src;
document.d3.src = lcdoff.src;
document.d2.src = lcdminus.src;
document.d1.src = lcde.src;
document.d0.src = lcdminus.src;
return;
}
if (dspin.indexOf('.') == -1) {
dsp = dspin + '.';
idx++;
}
while (lcds < 8) {
idx--;
digit = dsp.charAt(idx);
if (digit == '.')
dot_active = true;
else if (digit == '-') {
disp_array[lcds] = lcdminus.src;
lcds++;
} else if (digit && "0123456789".indexOf(digit) != -1) {
if (dot_active)
disp_array[lcds] = "images/lcd"+digit+"dot.jpg";
else
disp_array[lcds] = "images/lcd"+digit+".jpg";
dot_active = false;
lcds++;
} else {
disp_array[lcds] = lcdoff.src;
lcds++;
}
}
document.d7.src = disp_array[7];
document.d6.src = disp_array[6];
document.d5.src = disp_array[5];
document.d4.src = disp_array[4];
document.d3.src = disp_array[3];
document.d2.src = disp_array[2];
document.d1.src = disp_array[1];
document.d0.src = disp_array[0];
}
// ---------------------------------------------------------
function rnd_to_display(val) {
var rnd_factor;
var result = (val < 0) ? -1 * val : val;
rnd_factor = 10000000;
while (result >= 10) {
result = result / 10;
rnd_factor = rnd_factor / 10;
}
if (val < 0)
rnd_factor = rnd_factor / 10;
result = (Math.round(val * rnd_factor))/rnd_factor;
return result;
}
// ---------------------------------------------------------
function reduce (op) {
if (op == '+')
x = x + y;
if (op == '-')
x = x - y;
if (op == '*')
x = x * y;
if (op == '/') {
if (y == 0) {
error = true;;
return;
}
x = x / y;
}
x = rnd_to_display(x);
if (x < -9999999 || x > 99999999)
error = true;
}
// ---------------------------------------------------------
function keyboard(e) {
var ky, code;
code = is_netscape ? e.which : e.keyCode;
ky = String.fromCharCode(code);
if (ky == 't')
test();
else
key_pressed(ky);
}
// ---------------------------------------------------------
function key_pressed(key) {
if (error && key != 'o')
return;
if ((key && ".0123456789".indexOf(key)) != -1) {
if (key == '.') {
if (is_new_num) {
disp = "0.";
is_new_num = false;
}
is_decimal = true;
} else {
if (!is_new_num && disp.length == 9)
return;
else if (is_decimal) {
disp = disp+key;
} else {
if (is_new_num)
disp = key+'.';
else
disp = disp.substring(0, disp.length-1)+key+'.';
}
y = parseFloat(disp);
is_new_num = false;
}
} else if ("*/+-".indexOf(key) != -1) {
if (last_op != "") {
reduce(last_op);
disp = x.toString();
} else
x = y;
is_new_num = true;
is_decimal = false;
last_op = key;
} else if ("=%".indexOf(key) != -1) {
if (last_op != "") {
if (key == '%')
y = y/100;
reduce(last_op);
y = x;
disp = x.toString();
}
is_new_num = true;
is_decimal = false;
last_op = "";
} else {
if (key == 's') {
if (y < 0)
error = true;
else {
y = rnd_to_display(Math.sqrt(y));
disp = y.toString();
}
is_new_num = true;
is_decimal = false;
} else if (key == 'i') {
y = -1 * y;
if (y < 0) disp = "-" + disp;
else disp = disp.substring(1, disp.length);
} else if (key == 'c') {
y = 0;
disp = "0.";
is_new_num = true;
is_decimal = false;
} else if (key == 'o') {
x = 0;
y = 0;
m = 0;
disp = "0.";
is_new_num = true;
is_decimal = false;
last_op = "";
error = false;
} else if (key == 'r') {
y = m;
disp = y.toString();
is_new_num = true;
is_decimal = false;
} else if ("mM".indexOf(key) != -1) {
m = m + y * ((key == 'm') ? 1 : -1);
is_new_num = true;
is_decimal = false;
}
}
update_display(disp);
}
// ---------------------------------------------------------
testdata = "o:0.@" + // initialise
"15.3 + 1.89 = : 17.19 @" + // Add
"15.3 - 1.89 = : 13.41 @" + // Subtract
"15.3 * 1.89 = : 28.917 @" + // Multiply
"15.3 / 1.89 = : 8.0952381 @" + // Divide
"15.3 + 1.89 i = : 13.41 @" + // change sign
"15.3 s + 1.89 = : 5.8015214 @" + // square root
"15.3 * 1.89 % : 0.28917 @" + // percent
"22.5 c 15.3 + 1.89 = : 17.19 @" + // clear entry
"1.89 m 15.3 + r = : 17.19 @" + // M+ and recall
"3.78 M 15.3 - r = : 17.19 @" + // M- and recall
"55 + 99 = : 154. @" + // Trailing decimal
"o:0."; // last line
// ---------------------------------------------------------
function test() {
var answer = false; // State indicating reading expected answer
var testnum = 0; // test number
var failures = new Array(); // List of test failures
var fidx = 0; // Failure index
var testchar = ""; // Current input character
if (!confirm("Run the self tests?\n(may take some seconds)"))
return;
// Scan through all test data ...
for (tidx = 0; tidx < testdata.length; tidx = tidx + 1) {
// get next input character
testchar = testdata.charAt(tidx);
// Non white-space input
if (testchar != ' ') {
// If answer delimiter, clear expected answer string and set state
if (testchar == ':') {
answer = true;
expected = "";
}
// If test delimiter, check answer
else if (testchar == '@') {
// Clear state
answer = false;
// Get calculator's result
result = disp;
// Check result matches expected, and log if not
if (parseFloat(expected) != parseFloat(result))
failures[fidx++] = testnum;
testnum++;
}
// Whilst in answer state, append input to expected variable
else if (answer == true)
expected = expected + testchar;
// Input key sequences
else {
// Abort if an invalid character found in the test data
if ("0123456789.+-*/=%simMroc".indexOf(testchar) == -1) {
alert("Invalid input character ("+testchar+") in test sequence\n"+
"at line "+testnum);
return;
}
key_pressed(testchar);
}
}
}
// Clear testchar and reuse for failure message
testchar = "";
// Add all failure test numbers to string
for (tidx = 0; tidx < fidx; tidx++)
testchar = testchar + " " + failures[tidx];
// Display test results
if (fidx > 0)
alert (fidx+" failures at lines:"+testchar);
else
alert ("All "+ (testnum-1) + " tests pass");
}
</script>
</body>
</html>