Difference between revisions of "Javascript Calculator Simulator"

From dftwiki3
Jump to: navigation, search
(Introduction)
 
(5 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 [[media:javascriptCalculator_Southwell.zip| here]].
+
=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 18:10, 27 January 2013

--D. Thiebaut 17:56, 27 January 2013 (EST)


JavascriptCalculatorSimulator.png


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>