Click here to Skip to main content
Click here to Skip to main content

Scientific Calculator ZENO-5000

, 7 Dec 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
Scientific Calculator ZENO-5000: HTML 5, CSS 3 and client-side jQuery/JavaScript

Introduction

Scientific Calculator ZENO-5000 is a lightweight web application (<40kb), utilizing the latest HTML5/CSS3 features and client-side jQuery/Java scripting. The application does not include any graphic files. It is portable, capable of running in online/offline modes on PC/mobile devices.

WORKING DEMO

Background

Calculators software are extremely powerful tools, complementing/replacing their hardware counterparts. Calculators implemented as the web “thin client” type of application require the “live” Internet connection. There are certain pros and cons in such approach: “thin client” web applications are “zero-installable” and platform/OS independent, which make them portable, capable of running within any major web browser (it’s relevant to mention, that web browsers are rapidly becoming de facto a “virtual OS”, kind of substitute for real OS in regards to the web applications and services).

The need for open Internet connection is certainly a disadvantage in many cases, thus it would be highly desirable to have the calculator application, capable of running in off-line mode as well. A possible solution is to implement the application utilizing just client-scripting, primarily JavaScript code, which is compatible with practically any major existing web browser. Such web application could either run in online mode as usual, or it could be downloaded and cached on the client’s platform.

A possible solution is to implement the application utilizing just client-scripting, primarily JavaScript code, which is compatible with practically any major existing web browser. Such web application could either run in online mode as usual, or it could be downloaded and cached on the client’s platform, available in offline mode as well. There are several core requirements to such “universal” solutions:

  • It must be platform/OS independent, capable of running within 4 major browsers (Mozilla Firefox, Internet Explorer from Microsoft, Google Chrome and Apple Safari)
  • Installation process must be simple and straightforward, just as “copy-paste” 
  • It should have an extremely small “digital footprint” considering the potential memory space limitations on the portable devices

Adherence to the above mentioned design principle would ensure the high portability of OSC and its compliance with the majority of available mobile/stationary computational platforms.

Scientific Calculator ZENO-5000, Sample Screenshots

Calculator_Screen1.jpg

Fig.1. Scientific Calculator ZENO-5000 running in Mozilla FireFox (3.6x), sample screen shot showing the extended key pad

Calculator_Screen2.jpg

Fig.2. Scientific Calculator ZENO-5000: sample screen shot showing stack register pop-up

Calculator_Screen2.jpg

Fig.3. Scientific Calculator ZENO-5000: sample screen shot showing the key pad in collapsed mode

Core Functionality

  • Data Entry operations: In simple words, that means clicking on any numeric key, or just entering the constant values, like number pi, e, square root of 2, etc.
  • Unary operations: These are to be performed directly on the content of the input box, like inverse function 1/x, or trigonometric sin(x).
  • Binary operations to be performed on the pair of numeric values: one of them stored in the internal memory register called “stack” and the second number shown in the input box. This type includes all four arithmetic operations, exponent calculation (y^x, which stands for “y power x”) and percent calculation.

Memory operations are implemented in practically every modern calculator. This convenient feature allows the intermediate results to be stored in internal memory register for later use. In brief, memory operations include the following:

  • Move/Copy the content of the input box to the memory (use down arrow key)
  • Move/Copy the content of the memory to the input box (use up arrow key)
  • Clear Memory: Click on the memory box (just below the input box) to clear the content
  • Add to Memory (use the key labeled as M+)
  • Subtract from Memory (use the key labeled as M-)

Application Architecture

Online Scientific Calculator ZENO-5000 (hereinafter – ZENO) is implemented as Rich Internet Application [1...3], utilizing the latest features presented in emerging Internet standards (HTML5/CSS3) and client-side scripting (jQuery/JavaScript). It could run in major web browsers in either online, or offline modes: to utilize the latter, application files must be downloaded and stored on the client’s computer. These files include:

  1. Main file: zeno.htm (file contains dynamic link to jQuery library online)
  2. Style sheet (CSS) file: oscZeno.css
  3. Computational engine written in Javascript: oscZeno.js
  4. Reference file: oscZenoRef.js

Binary operations involve the “stack” memory register (variable stackValue), storing the first operand. Another variable opCode stores the operation code:

0-no operation 
1-Addition 
2-Subtraction 
3-Multiplication 
4-Division 
5-power (y^x) 
6-percent 

The operations are performed on the content of the stack and numeric value entered into the input box. Auxiliary register (var boolClear) provides “clear input box before next data entry” functionality: it stores the Boolean value, forcing the code to clear the input register before another numeric value could be entered.

Points of Interest

Scientific Calculator ZENO-5000 is fully compatible with Mozilla/Webkit based Web Browsers, presumably with Internet Explorer 9. It has been tested on various desktop and mobile platforms (iPod Touch (Safari) and Windows Phone 7).

Project ZENO-5000 does not utilize any image files, thus having an extremely small digital footprint. All aesthetic enhancements achieved through the novel features are introduced in HTML 5/ CSS 3, namely: rounded corners, gradients, drop-shadows, etc. The most innovative HTML 5/CSS 3 coding techniques are demonstrated below:

Listing 1: CSS 3 code snippet is used to add the shadows to the screen objects (note: no graphic images required).

-moz-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
-webkit-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
box-shadow: 5px 5px 10px rgba(0,0,0,0.3);

Listing 2: CSS 3 code snippet used to implement the rounded corners (note: no graphic images required).

-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;	 

Listing 3: CSS 3 code snippet used to create the color gradient (does not work in IE<9).

/* WebKit */
background: -webkit-gradient(linear, left top, right top from(#ffffcc), to(#ffffff));
/* Mozilla/Gecko  */
background: -moz-linear-gradient(left top, #ffffcc, #ffffff); 	 

Listing 4: jQuery code snippet performs a short animation on document load event, demonstrating the toggle features. Initially, the sliding panel is shown in collapsed mode (Fig.3).

$(document).ready(function () {
    // ON LOAD ********************************************
    $("div.oscExtControl").fadeTo(1000, 0.25,
    function () { $("div.oscExtControl").fadeTo(1000, 1.00); });
    //
    $("div.oscExtPanel").slideToggle("fast");
    $("div.oscStackRegister").slideToggle("normal");

Listing 5: jQuery code snippet enables the panel slide (toggle) on control button click (see the Fig.1,2, showing the extended panel)

    // TOGGLE EXT PANEL ON CLICK
    $("div.oscExtControl").click(function () {
        var ctl = $(this);
        $("div.oscExtPanel").slideToggle("fast", function () {
            oscExtState = !oscExtState;
            if (oscExtState) ctl.html(strLess); else ctl.html(strMore);
        });
    });

Listing 6: Available Unary operations apply directly to the content of the input box.

 // UNARY OPERATIONS *******************************************************
    $("button.keyPad_btnUnaryOp").click(function () {
        var inputBox = $(keyPad_UserInput);
        var x = parseFloat(inputBox.val());
        var retVal = oscError;

        switch (this.id) {
            // +/-                                 
            case 'keyPad_btnInverseSign': retVal = -x; break;
            // 1/X                                 
            case 'keyPad_btnInverse': retVal = 1 / x; break;
            // X^2                                 
            case 'keyPad_btnSquare': retVal = x * x; break;
            // SQRT(X)                                 
            case 'keyPad_btnSquareRoot': retVal = Math.sqrt(x); break;
            // X^3                                 
            case 'keyPad_btnCube': retVal = x * x * x; break;
            // POW (X, 1/3)                                 
            case 'keyPad_btnCubeRoot': retVal = Math.pow(x, 1 / 3); break;
            // NATURAL LOG                                 
            case 'keyPad_btnLn': retVal = Math.log(x); break;
            // LOG BASE 10                                 
            case 'keyPad_btnLg': retVal = Math.log(x) / Math.LN10; break;
            // E^(X)                                 
            case 'keyPad_btnExp': retVal = Math.exp(x); break;
            // SIN                                 
            case 'keyPad_btnSin': retVal = Math.sin(x); break;
            // COS                                 
            case 'keyPad_btnCosin': retVal = Math.cos(x); break;
            // TAN                                 
            case 'keyPad_btnTg': retVal = Math.tan(x); break;
            // CTG                                 
            case 'keyPad_btnCtg': retVal = 1 / Math.tan(x); break;

            // Arcsin                                
            case 'keyPad_btnAsin': retVal = Math.asin(x); break;
            // Arccos                                
            case 'keyPad_btnAcos': retVal = Math.acos(x); break;
            // Arctag                                
            case 'keyPad_btnAtan': retVal = Math.atan(x); break;

            // Secant                                
            case 'keyPad_btnSec': retVal = 1 / Math.cos(x); break;
            // Cosecant                                
            case 'keyPad_btnCosec': retVal = 1 / Math.sin(x); break;

            // sinh                                  
            case 'keyPad_btnSinH':
                retVal = (Math.pow(Math.E, x) - Math.pow(Math.E, -x)) / 2; break;
            // cosh                                  
            case 'keyPad_btnCosinH':
                retVal = (Math.pow(Math.E, x) + Math.pow(Math.E, -x)) / 2; break;
            // coth                                  
            case 'keyPad_btnTgH':
                retVal = (Math.pow(Math.E, x) - Math.pow(Math.E, -x));
                retVal /= (Math.pow(Math.E, x) + Math.pow(Math.E, -x));
                break;
            // Secant hyperbolic                                 
            case 'keyPad_btnSecH':
                retVal = 2 / (Math.pow(Math.E, x) + Math.pow(Math.E, -x)); break;
            // Cosecant hyperbolic                                 
            case 'keyPad_btnCosecH':
                retVal = 2 / (Math.pow(Math.E, x) - Math.pow(Math.E, -x)); ; break;
            // 1+x                                
            case 'keyPad_btnOnePlusX': retVal = 1 + x; break;
            // 1-x                                
            case 'keyPad_btnOneMinusX': retVal = 1 - x; break;
            default: break;
        }
        boolClear = true;
        inputBox.val(retVal);
        inputBox.focus();
    });

Listing 7: jQuery code snippet to clear memory by clicking on the memory box (optionally, could apply to input box as well)- particular valuable convenience feature in touch-screen mobile devices (iPhone, WP7, etc.).

    // CLEAR MEM BOX BY CLICKING ON IT
    $("div#keyPad input.keyPad_TextBox").click(function () {
        var inBox = $(keyPad_UserInput);
        var mem = $(keyPad_Mem);

        switch (this.id) {
            //case 'keyPad_UserInput': $(keyPad_UserInput).val(strEmpty); break;
            case 'keyPad_Mem': $(keyPad_Mem).val(strEmpty); memVal = 0; break;
            default: break;
        }
    });

Listing 8: Available constants to be entered directly in extended mode (expanded panel).

  // CONST DATA ENTRY *******************************************************
    $("button.keyPad_btnConst").click(function () {
        var retVal = strEmpty;
        switch (this.id) {
            // PI                                    
            case 'keyPad_btnPi': retVal = Math.PI; break;
            // PI/2                                    
            case 'keyPad_btnPiDiv2': retVal = Math.PI / 2; break;
            // PI/3                                    
            case 'keyPad_btnPiDiv3': retVal = Math.PI / 3; break;
            // PI/4                                    
            case 'keyPad_btnPiDiv4': retVal = Math.PI / 4; break;
            // PI/6                                    
            case 'keyPad_btnPiDiv6': retVal = Math.PI / 6; break;
            // e                                    
            case 'keyPad_btnE': retVal = Math.E; break;
            // 1/e                                    
            case 'keyPad_btnInvE': retVal = 1 / Math.E; break;
            // SQRT(2)                                    
            case 'keyPad_btnSqrt2': retVal = Math.SQRT2; break;
            // SQRT(3)                                    
            case 'keyPad_btnSqrt3': retVal = Math.sqrt(3); break;
            // CUBE ROOT OF(3)                                    
            case 'keyPad_btnCubeRoot2': retVal = Math.pow(2, 1 / 3); break;
            // Ln(10)                                    
            case 'keyPad_btnLn10': retVal = Math.LN10; break;
            // base10: Log(e)                                    
            case 'keyPad_btnLgE': retVal = Math.LOG10E; break;
            // Sigmas: defects probability: on scale 0...1
            // 1 Sigma                                    
            case 'keyPad_btnSigma': retVal = 0.69; break;
            // 3 Sigma                                     
            case 'keyPad_btnSigma3': retVal = 0.007; break;
            // 6 Sigma                                     
            case 'keyPad_btnSigma6': retVal = 3.4 * Math.pow(10, -6); break;
            default: break;
        }
        boolClear = true;
        $(keyPad_UserInput).val(retVal);
        inputBox.focus();
    });

Listing 9: Entire CSS file:

/******************************************************************************
Project          :  Scientific Calculator
Module           :  CSS 3
Description      :  Implements HTML 5 / CSS 3 advanced features
******************************************************************************
Author           :  Alexander Bell
Copyright        :  2010 Infosoft International Inc
Date Created     :  11/20/2010
Last Modified    :  12/01/2010
******************************************************************************
DISCLAIMER: This Application is provide on AS IS basis without any warranty
You can use it at your sole risk.
******************************************************************************
TERMS OF USE     :  This module is copyrighted. You can use it provided that
                 :  you keep the original copyright note.
******************************************************************************/

body {
    margin: 0;
    padding: 0;
	font-family: Arial, Calibri, Verdana, Tahoma, Times New Roman ;
	text-align: center;
	vertical-align: middle;
	background-color: #eaeaea;
} 

/* CENTER COLUMN */
.oscCenterColumn {
    width: 480px;
    padding: 10px 0px 0px 0px;
    margin: 10px auto;
	text-align: left;
}

/* MAIN DIV W/ALL CONTENTS */
.oscMain {
 	padding:10px;
 	
 	/* make rounded corners */
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
       	
    /* add shadows */
    -moz-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
    -webkit-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
    box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
     	
    /* add gradient */
    /* WebKit */
    background: -webkit-gradient(linear, left top, left bottom, 
	from(#404040), to(#707070));
    /* Mozilla/Gecko */
    background: -moz-linear-gradient(top, #404040, #707070);
}
 
/* NEW TAGS ADDED IN HTML 5 */
header, footer, nav { display:block }

.oscTitle {
    float:right;
    margin:0px 0px 0px 0px; 
    font-size: 24px;
    font-weight:lighter;
    color: #dadada;
    vertical-align:middle;
}

.oscModel {
    text-align:center;
    height:30px;
    line-height:30px;
    background-color: #303030;
    vertical-align:middle;
}
.oscModel {
    width: 150px;
    margin:0px 0px 0px 0px;
    font-size: 24px;
    font-weight:bold;
    color: yellow;
    /* make rounded corners */
    -moz-border-radius: 20px;
    -webkit-border-radius: 20px;
    border-radius: 20px;
}
 
/* NAV */
button.oscNav 
{
    float:left;
    height:30px;
    line-height:30px;
    vertical-align:middle;
    font-size: 14px;
    font-family: Arial, Tahoma, Verdana, Calibri;
    color: #bababa;
   
    margin: 0px 0px 0px 3px;
    padding: 0px 5px 0px 5px;
    border: 1px solid olive;
  
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;  

    background: #505050;
    background: -moz-linear-gradient(top, #909090, #505050 15px, #303030 15px, #202020);
    background: -webkit-gradient(linear, left top, left bottom, from(#909090),
    color-stop(0.5, #505050), color-stop(0.5, #303030), to(#202020));
    
    cursor: pointer;
    cursor: hand;
}
a { text-decoration:none;}
button.oscNav:active {	border: solid 2px #dadada; }
button.oscNav:hover  {
    background: #454545;
    background: -moz-linear-gradient(top, #505050, #202020 20px, #303030 20px, #909090);
    background: -webkit-gradient(linear, left top, left bottom, from(##505050),
    color-stop(0.5, #202020), color-stop(0.5, #303030), to(##909090));
}

/* EXTENDER CONTROL */
.oscExtControl, .oscStackControl
{
    float:right;
    margin:0px 0px 0px 5px;
    width:60px;
    height:30px;
    line-height:30px;
    vertical-align:middle;
    text-align:center;
    background-color: olive;
    color: #dadada;
    font-size: 22px;
    font-weight:bold;
    cursor: pointer;
    cursor: hand;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
}

/* stack register content */
.oscStackRegister
{
    position:absolute;
    width:310px;
    height:30px;
    line-height:30px;
    vertical-align:middle;
    
    margin:5px 0px 0px 10px;
    font-size: 22px;
    font-weight:normal;
    text-align:center;
    color:#eaeaea;
    background-color:Olive;

    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    
    filter:alpha(opacity=90);
	-moz-opacity:0.9;
	opacity: 0.9;
	
	z-index:20;
	cursor: pointer;
    cursor: hand;
} 

/* extended functions area */
.oscExtPanel
{
    margin:0px;  
    padding: 5px 5px 5px 5px; 
    display:block; 
    background-color:#404040; 
    border: solid 1px Olive;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
}

/* DIV CONTAINING KEYS AND INPUT/MEM BOXES */
div#keyPad { width: 100%; }

/* KEYS RIGHT ALIGN */
.keys_ToRight { float:right;	}

/******** CONTROLS: KEYS, INPUT/MEM TEXT BOXES *********/
div#keyPad input, div#keyPad button 
{
    height: 40px;
    vertical-align:middle;
    line-height:40px;
    margin: 0px;
    padding: 0px;
    border: 1px solid olive;
    font-family: Arial, Tahoma, Verdana, Calibri;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
	
}
div#keyPad button {
    width: 60px;
    text-align: center;
    font-size: 20px;
    cursor: pointer;
    cursor: hand;
    color: #dadada;
    font-weight:bold;
    /* add gradient using stop-color property: not working in IE<9 */
    background:#404040;
    background: -moz-linear-gradient(top, #dadada, #505050 20px, #303030 20px, #202020);
    background: -webkit-gradient(linear, left top, left bottom, from(#dadada),
    color-stop(0.5, #505050), color-stop(0.5, #303030), to(#202020));
}
div#keyPad button:active {	border: solid 2px #707070; }
div#keyPad button:hover  {
    background: #454545;
    background: -moz-linear-gradient(top, #505050, #202020 20px, #303030 20px, #909090);
    background: -webkit-gradient(linear, left top, left bottom, from(##505050),
    color-stop(0.5, #202020), color-stop(0.5, #303030), to(##909090));
}

/* INPUT/MEM TEXT BOXES*/
div#keyPad input {
    width: 330px;
    text-align: left;
    text-indent:10px;
    font-size: 24px;
    color: #202020;
    /* add gradient */
    /* WebKit */
    background: -webkit-gradient(linear, left top, right top from(#ffffcc), to(#ffffff));
    /* Mozilla/Gecko  */
    background: -moz-linear-gradient(left top, #ffffcc, #ffffff);
}
div#keyPad input#keyPad_Mem {color: #909090;}
	  
/* ENTER BUTTON: QUAD WIDTH + 14 */
div#keyPad button#keyPad_btnEnter { width:188px; font-size: 20px; color:Yellow;}
	
/* INPUT/MEM KEYS*/
div#keyPad .keyPad_btnMemOp
{  font-size: 20px;  color: Olive;}

/* ZERO BUTTON: DOUBLE WIDTH + 4 */
div#keyPad button#keyPad_btn0
{  width: 125px;  }

/* BACKSPACE/CLEAR INPUT KEYS*/
div#keyPad button#keyPad_btnBack,
div#keyPad button#keyPad_btnClr,
div#keyPad button#keyPad_btnAllClr
{
	border-color:red;
	color:red;
}
div#keyPad button#keyPad_btnBack {font-size: 18px;}
	
/* SPECIAL FORMATTING FOR SUPER-SCRIPT KEYS */
div#keyPad button#keyPad_btnSquare,
div#keyPad button#keyPad_btnCube,
div#keyPad button#keyPad_btnExp,
div#keyPad keyPad_btnYpowX
{ font-size: 16px; }

/* CLEAR BOTH */
.clear {clear:both;}

.oscDisclaimer  
{
    margin: 5px 0px 5px 0px;
    color: #adadad;
    font-weight: normal;
    font-size: 10pt;
    text-align:center;
}

.oscNotice {
    margin-top:5px;     
    text-align:center;
    font-size: 12px;
    color: #606060;
}

.oscSpacer2, .oscSpacer3, .oscSpacer5  {clear:both; width:100%;}
.oscSpacer2 {height:2px;}
.oscSpacer3 {height:3px;}
.oscSpacer5 {height:5px;}


/* COMPATIBILITY W/OLD IE<9 */
#ie { background-color: #303030; }
/*************************************************/	 

Listing 10: JavaScript computational engine and jQuery animation enhancement:

/******************************************************************************
Project          :  ZENO-5000       | Online Scientific Calculator (OSC)
Module           :  oscZeno.js      | jQuery/Javascript
Description      :  Implements Math functions through client-side scripting
******************************************************************************
Author           :  Alexander Bell
Copyright        :  2010 Infosoft International Inc
Date Created     :  11/20/2010
Last Modified    :  12/01/2010
******************************************************************************
DISCLAIMER: This Application is provide on AS IS basis without any warranty
You can use it at your sole risk.
******************************************************************************
TERMS OF USE     :  This module is copyrighted. You can use it provided that
                 :  you keep the original copyright note.
******************************************************************************/

// ******* MAIN **************************************************************
$(document).ready(function () {

    // ON LOAD ********************************************
    $("div.oscExtControl").fadeTo(1000, 0.25,
    function () { $("div.oscExtControl").fadeTo(1000, 1.00); });
    //
    $("div.oscExtPanel").slideToggle("fast");
    $("div.oscStackRegister").slideToggle("normal");

    // SHOW STACK REGISTER CONTENT and OpCode *********************************
    $("div.oscStackControl").mouseover(function () {
        var ctl = $("div.oscStackRegister");
        var op = "";
        if (opCode == 1) op = " +";
        else if (opCode == 2) op = " -";
        else if (opCode == 3) op = " *";
        else if (opCode == 4) op = " /";
        ctl.html(stackVal + op);
        ctl.show(300);
    })
    .mouseout(function () { $("div.oscStackRegister").hide(); })
    .mouseleave(function () { $("div.oscStackRegister").hide(); });

    // close stack register div
    $("div.oscStackRegister").click(function ()
    { $("div.oscStackRegister").hide(); });
    $(this).click(function () { $("div.oscStackRegister").hide(); });

    // CLEAR MEM ON CLICK
    $("div.oscMemLabel").click(function ()
    { $(keyPad_Mem).val(strEmpty); memVal = 0; });

    // TOGGLE EXT PANEL ON CLICK
    $("div.oscExtControl").click(function () {
        var ctl = $(this);
        $("div.oscExtPanel").slideToggle("fast", function () {
            oscExtState = !oscExtState;
            if (oscExtState) ctl.html(strLess); else ctl.html(strMore);
        });
    });

    //************************************************************************
    // DATA ENTRY: NUMERIC KEYS
    $("div#keyPad button.keyPad_btnNumeric").click(function () {
        var btnVal = $(this).html();
        var inBox = $(keyPad_UserInput);

        // clear input box if flag set
        if (boolClear) { inBox.val(strEmpty); boolClear = false; }
        var str = inBox.val();

        // limit the input length
        if (str.length > maxLength) return;

        // prevent duplicate dot entry
        if (this.id == "keyPad_btnDot" && str.indexOf('.') >= 0) return;
        inBox.val(str + btnVal);
        inBox.focus();
    });

    // CONST DATA ENTRY *******************************************************
    $("button.keyPad_btnConst").click(function () {
        var retVal = strEmpty;
        switch (this.id) {
            // PI                                    
            case 'keyPad_btnPi': retVal = Math.PI; break;
            // PI/2                                    
            case 'keyPad_btnPiDiv2': retVal = Math.PI / 2; break;
            // PI/3                                    
            case 'keyPad_btnPiDiv3': retVal = Math.PI / 3; break;
            // PI/4                                    
            case 'keyPad_btnPiDiv4': retVal = Math.PI / 4; break;
            // PI/6                                    
            case 'keyPad_btnPiDiv6': retVal = Math.PI / 6; break;
            // e                                    
            case 'keyPad_btnE': retVal = Math.E; break;
            // 1/e                                    
            case 'keyPad_btnInvE': retVal = 1 / Math.E; break;
            // SQRT(2)                                    
            case 'keyPad_btnSqrt2': retVal = Math.SQRT2; break;
            // SQRT(3)                                    
            case 'keyPad_btnSqrt3': retVal = Math.sqrt(3); break;
            // CUBE ROOT OF(3)                                    
            case 'keyPad_btnCubeRoot2': retVal = Math.pow(2, 1 / 3); break;
            // Ln(10)                                    
            case 'keyPad_btnLn10': retVal = Math.LN10; break;
            // base10: Log(e)                                    
            case 'keyPad_btnLgE': retVal = Math.LOG10E; break;
            // Sigmas: defects probability: on scale 0...1
            // 1 Sigma                                    
            case 'keyPad_btnSigma': retVal = 0.69; break;
            // 3 Sigma                                     
            case 'keyPad_btnSigma3': retVal = 0.007; break;
            // 6 Sigma                                     
            case 'keyPad_btnSigma6': retVal = 3.4 * Math.pow(10, -6); break;
            default: break;
        }
        boolClear = true;
        $(keyPad_UserInput).val(retVal);
        inputBox.focus();
    });

    // BINARY OPERATION KEY ***************************************************
    $("div#keyPad button.keyPad_btnBinaryOp").click(function () {
        var inBox = $(keyPad_UserInput);
        var newOpCode = 0;

        // validate: string cannot start w/operation symbol
        if (inBox.val().indexOf('-') >= 0) return;
        if (inBox.val().indexOf('+') >= 0) return;
        if (inBox.val().indexOf('*') >= 0) return;
        if (inBox.val().indexOf('÷') >= 0) return;

        switch (this.id) {
            case 'keyPad_btnPlus': newOpCode = 1; break;
            case 'keyPad_btnMinus': newOpCode = 2; break;
            case 'keyPad_btnMult': newOpCode = 3; break;
            case 'keyPad_btnDiv': newOpCode = 4; break;
            case 'keyPad_btnYpowX': newOpCode = 5; break;
            case 'keyPad_btnPercent':
                if (opCode == 1 || opCode == 2)
                { inBox.val(stackVal * parseFloat(inBox.val()) / 100); }
                else if (opCode == 3 || opCode == 4)
                { inBox.val(parseFloat(inBox.val()) / 100); }
                else return;
                break;
            default: break;
        }
        if (opCode) { oscBinaryOperation(); }
        else { stackVal = parseFloat(inBox.val()); boolClear = true; }
        opCode = newOpCode;
        inBox.focus();
    });

    // BINARY COMPUTATION *****************************************************
    function oscBinaryOperation() {
        var inBox = $(keyPad_UserInput);
        var x2 = parseFloat(inBox.val());

        switch (opCode) {
            case 1: stackVal += x2; break;
            case 2: stackVal -= x2; break;
            case 3: stackVal *= x2; break;
            case 4: stackVal /= x2; break;
            // stack power inputBox              
            case 5: stackVal = Math.pow(stackVal, x2); break;
            default: break;
        }
        inBox.val(stackVal);
        boolClear = true;
        inBox.focus();
    }

    // UNARY OPERATIONS *******************************************************
    $("button.keyPad_btnUnaryOp").click(function () {
        var inputBox = $(keyPad_UserInput);
        var x = parseFloat(inputBox.val());
        var retVal = oscError;

        switch (this.id) {
            // +/-                                 
            case 'keyPad_btnInverseSign': retVal = -x; break;
            // 1/X                                 
            case 'keyPad_btnInverse': retVal = 1 / x; break;
            // X^2                                 
            case 'keyPad_btnSquare': retVal = x * x; break;
            // SQRT(X)                                 
            case 'keyPad_btnSquareRoot': retVal = Math.sqrt(x); break;
            // X^3                                 
            case 'keyPad_btnCube': retVal = x * x * x; break;
            // POW (X, 1/3)                                 
            case 'keyPad_btnCubeRoot': retVal = Math.pow(x, 1 / 3); break;
            // NATURAL LOG                                 
            case 'keyPad_btnLn': retVal = Math.log(x); break;
            // LOG BASE 10                                 
            case 'keyPad_btnLg': retVal = Math.log(x) / Math.LN10; break;
            // E^(X)                                 
            case 'keyPad_btnExp': retVal = Math.exp(x); break;
            // SIN                                 
            case 'keyPad_btnSin': retVal = Math.sin(x); break;
            // COS                                 
            case 'keyPad_btnCosin': retVal = Math.cos(x); break;
            // TAN                                 
            case 'keyPad_btnTg': retVal = Math.tan(x); break;
            // CTG                                 
            case 'keyPad_btnCtg': retVal = 1 / Math.tan(x); break;

            // Arcsin                                
            case 'keyPad_btnAsin': retVal = Math.asin(x); break;
            // Arccos                                
            case 'keyPad_btnAcos': retVal = Math.acos(x); break;
            // Arctag                                
            case 'keyPad_btnAtan': retVal = Math.atan(x); break;

            // Secant                                
            case 'keyPad_btnSec': retVal = 1 / Math.cos(x); break;
            // Cosecant                                
            case 'keyPad_btnCosec': retVal = 1 / Math.sin(x); break;

            // sinh                                  
            case 'keyPad_btnSinH':
                retVal = (Math.pow(Math.E, x) - Math.pow(Math.E, -x)) / 2; break;
            // cosh                                  
            case 'keyPad_btnCosinH':
                retVal = (Math.pow(Math.E, x) + Math.pow(Math.E, -x)) / 2; break;
            // coth                                  
            case 'keyPad_btnTgH':
                retVal = (Math.pow(Math.E, x) - Math.pow(Math.E, -x));
                retVal /= (Math.pow(Math.E, x) + Math.pow(Math.E, -x));
                break;
            // Secant hyperbolic                                 
            case 'keyPad_btnSecH':
                retVal = 2 / (Math.pow(Math.E, x) + Math.pow(Math.E, -x)); break;
            // Cosecant hyperbolic                                 
            case 'keyPad_btnCosecH':
                retVal = 2 / (Math.pow(Math.E, x) - Math.pow(Math.E, -x)); ; break;
            // 1+x                                
            case 'keyPad_btnOnePlusX': retVal = 1 + x; break;
            // 1-x                                
            case 'keyPad_btnOneMinusX': retVal = 1 - x; break;
            default: break;
        }
        boolClear = true;
        inputBox.val(retVal);
        inputBox.focus();
    });


    // ************************************************************************
    // COMMAND BUTTONS: BACKSPACE, CLEAR AND ALL CLEAR
    $("div#keyPad button.keyPad_btnCommand").click(function () {
        var inBox = $(keyPad_UserInput);
        var mem = $(keyPad_Mem);
        var strInput = inBox.val();
        switch (this.id) {
            // on enter calculate the result, clear opCode
            case 'keyPad_btnEnter':
                inBox.val(oscBinaryOperation()); opCode = 0; inBox.focus(); return;
                // clear input box (if not empty) or opCode          
            case 'keyPad_btnClr':
                if (strInput == strEmpty) { opCode = 0; boolClear = false; }
                else { inBox.val(strEmpty); }
                break;
            // clear the last char if input box is not empty
            case 'keyPad_btnBack': if (strInput.length > 0) {
                    inBox.val(strInput.substring(0, strInput.length - 1)); break;
                }
                // clear all          
            case 'keyPad_btnAllClr':
                inBox.val(strEmpty);
                stackVal = strEmpty;
                mem.val(strEmpty);
                opCode = 0;
                break;
            default: break;
        }
    });

    // MEMORY OPERATIONS ****************************************************************
    $("div#keyPad button.keyPad_btnMemOp").click(function () {
        var inBox = $(keyPad_UserInput);
        var mem = $(keyPad_Mem);

        try {
            memValNumeric = parseFloat(mem.val());
        }
        catch (ex)
        { memVal = strEmpty; mem.val(strEmpty); return; }


        switch (this.id) {
            // move to mem and clear input box
            case 'keyPad_btnToMem': mem.val(inBox.val()); inBox.val(strEmpty); break;
            // copy to input box, but do not clear ithe memory
            case 'keyPad_btnFromMem': inBox.val(mem.val()); break;
            // add to mem     
            case 'keyPad_btnMemPlus':
                memVal += parseFloat(inBox.val()); mem.val(memVal); 
			boolClear = true; break;
            // subtract from mem      
            case 'keyPad_btnMemMinus':
                memVal -= parseFloat(inBox.val()); mem.val(memVal); 
			boolClear = true; break;
            default: break;
        }
    });

    // CLEAR MEM BOX BY CLICKING ON IT
    $("div#keyPad input.keyPad_TextBox").click(function () {
        var inBox = $(keyPad_UserInput);
        var mem = $(keyPad_Mem);

        switch (this.id) {
            //case 'keyPad_UserInput': $(keyPad_UserInput).val(strEmpty); break;
            case 'keyPad_Mem': $(keyPad_Mem).val(strEmpty); memVal = 0; break;
            default: break;
        }
    });
})
// ***********************************************************************************

History

Online Scientific Calculator ZENO-5000 was started as an educational project, intended to demonstrate the power of emerging Internet standards and, namely: HTML 5 and CSS 3, accompanied by increasingly popular jQuery (extension to JavaScript). ZENO is implemented as rich internet application (RIA) with an extremely small digital footprint. It does not use any graphic files: all aesthetic enhancements, like color gradients, rounded corners, box shadows, etc., are achieved via new features available in HTML5/CSS 3, thus dramatically simplifying the page layout design and ensuring fast application load.

Project ZENO provides deep insight into web applications client-side coding technique. Though intended primarily for the didactic purpose, it could be well suited and customized for many practical computational tasks.

Additional Documentation Online

More reading on Rich Internet Application Development (RIA)

  1. Rich internet applications, part 1: Embedding YouTube? Video player into web page
  2. Rich internet applications, part 2: Silverlight? Media player
  3. Rich internet applications, part 3: HTML 5 video player
  4. HTML 5, CSS 3 and Inflation Calculator

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

DrABELL
President Infosoft International Inc
United States United States
Dr. A. Bell has 20+ years of Software and Electrical Engineering experience: Win/Web veteran published 300+ articles and authored 37 inventions, currently focused on: Windows 7/8, HTML5, CSS3, jQuery, .NET, ASP.NET, WPF, C#, SQL, 'Big Data', AI, Speech Technology and Mobile apps. He participated in App Innovation Contest (AIC 2102/2013) with several winning submissions. Sample pubs follow:
  1. Edumatter M12: School Math Calculators and Equation Solvers (contest winner)
  2. Engineering Calculator VOLTA-2013 (contest winner)
  3. HTML5 Best Practices: Table formatting via CSS3
  4. Engineering Calculator VOLTA-814D
  5. SQL generates large data sequence
  6. Aggregate Product function extends SQL
  7. Watch Your Mouse!
  8. Top-100 Digital Cameras
  9. WebTV Project: Embedded YouTube Player (Goog #1 YouTube API for ASP.NET)
Dr. Bell is personally credited for 10+ Enterprise level projects w/total code base exceeding 250k lines.
Follow on   Twitter

Comments and Discussions

 
GeneralCompatibility issue with future release of Internet Explorer (IE9+) PinmemberDrABELL24-Feb-11 14:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.141022.2 | Last Updated 7 Dec 2010
Article Copyright 2010 by DrABELL
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid