Build a Advanced Math Scientific Calculator in Vanilla Javascript Full Project For Beginners

Build a Advanced Math Scientific Calculator in Vanilla Javascript Full Project For Beginners

 

Welcome folks today in this blog post we will be building a advanced scientific calculator in vanilla javascript. All the full source code of the application will be given below.

 

 

Get Started

 

 

In order to get started you need to create an index.html file and copy paste the following code

 

index.html

 

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link rel="stylesheet" href="style.css">
    <title>Calculator</title>
</head>

<body>
    <script src="script.js"></script>
    <div class="container">
        <form name="calculator">
            <input type="" id="scn" size="10" readonly maxlength="50" name="display" class="screen">
        </form>
        <div class="container shape">
            <div class="breaks">
                <input type="button" value="shift" class="bt blue" id="to_shift" onclick="Shift()">
                <input type="button" value="sin" class="bt black" id="sin" onclick="handleTrig(this.value)">
                <input type="button" value="cos" class="bt black" id="cos" onclick="handleTrig(this.value)">
                <input type="button" value="tan" class="bt black" id="tan" onclick="handleTrig(this.value)">
                <input type="button" value="log" class="bt black" onclick="handleTrig(this.value)">
            </div>
            <div class="breaks">
                <input type="button" value="√" class="bt silver" onclick="handleOperator(this.value+'(')">
                <input type="button" value="^" class="bt silver" onclick="handleOperator(this.value)">
                <input type="button" value="mod" class="bt silver" onclick="handleOperator(this.value)">
                <input type="button" value="abs" class="bt silver" onclick="handleTrig(this.value)">
                <input type="button" value="ln" class="bt silver" onclick="handleTrig(this.value)">
            </div>
            <div class="breaks">
                <input type="button" value="%" onclick="handleOperator(this.value)">
                <input type="button" value="(" onclick="AddBrace(this.value)">
                <input type="button" value=")" onclick="AddBrace(this.value)">
                <input type="button" value="!" onclick="handleOperator(this.value)">
                <input type="button" value="±" onclick="negate()">
            </div>
            <div class="breaks">
                <input type="button" value="7" class="work" onclick="AddValue(this.value)">
                <input type="button" value="8" class="work" onclick="AddValue(this.value)">
                <input type="button" value="9" class="work" onclick="AddValue(this.value)">
                <input type="button" value="Del" id="red" onclick="Del()">
                <input type="button" value="Clr" id="red" onclick="Clear()">
            </div>
            <div class="breaks ">
                <input type="button" value="4" class="work white" onclick="AddValue(this.value)">
                <input type="button" value="5" class="work white" onclick="AddValue(this.value)">
                <input type="button" value="6" class="work white" onclick="AddValue(this.value)">
                <input type="button" value="x" onclick="handleOperator(this.value)">
                <input type="button" value="÷" id="normal" onclick="handleOperator(this.value)">
            </div>
            <div class="breaks">
                <input type="button" value="1" class="work white" onclick="AddValue(this.value)">
                <input type="button" value="2" class="work white" onclick="AddValue(this.value)">
                <input type="button" value="3" class="work white" onclick="AddValue(this.value)">
                <input type="button" value="+" class="white" onclick="handleOperator(this.value)">
                <input type="button" value="-" class="white" onclick="handleOperator(this.value)">
            </div>
            <div class="breaks">
                <input type="button" value="e" class="work white" id="exp" onclick="handleConst(this.value)">
                <input type="button" value="0" class="work white" onclick="AddValue(this.value)">
                <input type="button" value="." class="work white" onclick="AddPoint(this.value)">
                <input type="button" value="π" class="bt white" onclick="handleConst(this.value)">
                <input type="button" value="=" class="bt white" id="eval" onclick="Evaluate()">
            </div>
        </div>
    </div>
</body>

</html>

 

 

Now make a style.css file styling the calculator and copy paste the following code

 

style.css

 

/* @font-face {
    font-family: Title;
    src: url(fonts/calculator.ttf);
} */
@font-face {
    font-family: 'Digital-7';
    src: url('digital-7/digital-7.ttf');
    font-weight: normal;
    font-style: normal;
}

body {
    background: #e8e8e9;
}

input[type="button"] {
    border: 0px solid #ccc;
    padding: 15px;
    width: 5vw;
    box-shadow: 1.5px 1.6px 5px -2.9px;
}

.container {
    display: flex;
    flex-direction: column;
    background: #fff;
    width: 30.5vw;
    align-items: center;
    margin: 30px auto;
    padding: 0;
}

.work {
    background: rgb(27, 20, 20);
    color: #fff;
}

.shape {
    /* background: red; */
    /* margin-bottom: 50px; */
    height: 66vh;
}

.breaks {
    display: flex;
    width: 30.5vw;
    /* margin-top: 10px; */
    margin-bottom: 20px;
    flex-direction: row;
    align-items: center;
    justify-content: space-around;
}

.screen {
    width: 30vw;
    height: 15vh;
    background: rgb(27, 20, 20);
    font-family: Digital-7;
    font-size: 34px;
    color: #fff;
    text-align: right;
}

.inputs {
    display: flex;
}

#red {
    background: rgb(153, 6, 6);
    color: #fff;
}

#normal {
    background: rgb(216, 215, 215);
    border: 0px solid #ccc;
    padding: 15px;
    width: 5vw;
    box-shadow: 1.5px 1.6px 5px -2.9px;
}

 

See also  Javascript Project to Validate Data inside Input Text Fields Using Regular Expression Full Project For Beginners

 

Now make a script.js file javascript file and copy paste the following code

 

script.js

 

//operators object
operators = {
    "(": {
        "pre": 0,
        "rule": 0,
        "unary": 0
    },
    "+": {
        "pre": 2,
        "rule": 0,
        "unary": 0,
        "func": (a, b) => {
            return a + b;
        }
    },
    "-": {
        "pre": 2,
        "rule": 0,
        "unary": 0,
        "func": (a, b) => {
            return a - b;
        }
    },
    "mod": {
        "pre": 2,
        "rule": 0,
        "unary": 0,
        "func": (a, b) => {
            return a % b;
        }
    },
    "x": {
        "pre": 3,
        "rule": 0,
        "unary": 0,
        "func": (a, b) => {
            return a * b;
        }
    },
    "÷": {
        "pre": 3,
        "rule": 0,
        "unary": 0,
        "func": (a, b) => {
            return a / b;
        }
    },
    "^": {
        "pre": 6,
        "rule": 1,
        "unary": 0,
        "func": (a, b) => {
            return Math.pow(a, b);
        }
    },
    "√(": {
        "pre": 6,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.sqrt(n);
        }
    },
    "%": {
        "pre": 6,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return n / 100;
        }
    },
    "!": {
        "pre": 6,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            let x = n;
            if (n === 0 || n === 1) {
                return 1;
            } else {
                for (let i = n - 1; i > 0; i--) {
                    x *= i;
                }
            }
            return x;
        }
    },
    "e(": {
        "pre": 6,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.exp(n);
        }
    },
    "sin(": {
        "pre": 5,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.sin(n * Math.PI / 180);
        },

    },
    "cos(": {
        "pre": 5,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.cos(n * Math.PI / 180);
        }
    },
    "tan(": {
        "pre": 5,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.tan(n * Math.PI / 180)
        }
    },
    "asin(": {
        "pre": 5,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.asin(n) * 180 / Math.PI;
        }
    },
    "acos(": {
        "pre": 5,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.acos(n) * 180 / Math.PI;
        }
    },
    "atan(": {
        "pre": 5,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.atan(n) * 180 / Math.PI;
        }
    },
    "log(": {
        "pre": 5,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.log10(n);
        }
    },
    "ln(": {
        "pre": 5,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.log(n);
        }
    },
    "abs(": {
        "pre": 5,
        "rule": 1,
        "unary": 1,
        "func": (n) => {
            return Math.cos(n)
        }
    },
    ")": {
        "pre": -1,
        "rule": 0,
        "unary": 0
    }
};

Ops = ["+", "-", "x", "÷", "^", "√(", "mod", "!", "%"];
trigs = ["e(", "sin(", "cos(", "tan(", "log(", "abs(", "ln(", "acos(", "asin(", "atan("];

isOperand = function (_in) {
    return !isNaN(_in);
};

isOperator = function (o_p) {
    return Ops.includes(o_p);
};

isDigit = function (n) {
    let numReg = /[0-9]/i;
    return numReg.test(n);
};


peek = function (arr_) {
    return arr_[arr_.length - 1];
};

isTrig = function (t) {
    return trigs.includes(t);
};

function parseToPostfix(_infix) {
    let _post = [];
    let _stack = [];

    for (i = 0; i < _infix.length; i++) {
        let tok = _infix[i];
        if (isOperand(tok)) {
            _post.push(tok);
        } else if (tok === "(") {
            _stack.push(tok);
        } else if (tok === ")") {
            while (_stack.length > 0 && peek(_stack) !== "(") {
                _post.push(_stack.pop());
            }
            _stack.pop();
        } else if (isOperator(tok) || isTrig(tok)) {
            a = tok;
            b = peek(_stack);

            while (_stack.length > 0 && b !== "(" && ((!operators[a].rule && (operators[a].pre <= operators[b].pre)) ||
                    (operators[a].rule && (operators[a].pre < operators[b].pre)))) {
                _post.push(_stack.pop());
                b = peek(_stack);
            }
            _stack.push(a);
        }
    }

    while (_stack.length > 0) {
        let v = _stack.pop();
        if (v !== "(" && v !== ")") {
            _post.push(v);
        }
    }
    return _post;
}

function Eval(_postfix) {
    if (!_postfix.includes("(") && !_postfix.includes(")")) {
        let _out = [];
        for (i = 0; i < _postfix.length; i++) {
            let t = _postfix[i];
            if (isOperand((t))) {
                _out.push(t);
            } else {
                if (operators[t].unary) {
                    e = Number(_out.pop());
                    _out.push(operators[t].func(e).toString());
                } else {
                    a = Number(_out.pop());
                    b = Number(_out.pop());
                    _out.push(operators[t].func(b, a).toString());
                }
            }
        }
        return _out[0];
    }
}

shift_on = false;
ins = [];
_syntax = [];

function AddValue(str) {
    let val = str.toString();
    let pk = peek(ins);
    if (pk === null || pk === undefined) {
        ins.push(val);
    } else if (pk.includes(".") || isDigit(pk)) {
        ins.push(ins.pop().toString() + val);
    } else if (pk === "-" || pk === "+") {
        let dp = ins[ins.length - 2];
        if (dp === undefined || dp === null || dp === "(" || isOperator(dp) || dp[dp.length - 1] === "(") {
            ins.push(ins.pop().toString() + val);
        } else {
            ins.push(str);
        }
    } else {
        ins.push(str);
    }
    _isnegated = false;
    display();
}


function handleTrig(trig) {
    if (shift_on) {
        switch (trig.substring(0, 3)) {
            case "sin":
                ins.push(trigs[7]);
                break;
            case "cos":
                ins.push(trigs[6]);
                break;
            case "tan":
                ins.push(trigs[8]);
                break;
        }
    } else {
        for (i = 0; i < 6; i++) {
            let temp = trigs[i].substring(0, trigs[i].length - 1);
            if (trig === temp) {
                ins.push(trigs[i]);
                break;
            }
        }
    }
    _isnegated = false;
    display();
}

//operators handler
function handleOperator(op) {
    for (let i = 0; i < Ops.length; i++) {
        if (Ops[i] === op) {
            ins.push(Ops[i]);
        }
    }
    _isnegated = false;
    display();
}

//constants control handler
function handleConst(constant) {
    if (shift_on && constant === "eⁿ") {
        ins.push("e(");
    } else {
        ins.push(constant);
    }
    _isnegated = false;
    display();
}

//point or float sign control//
function AddPoint(str) {
    let peek = ins[ins.length - 1];
    if (peek === null || peek === undefined) {
        ins.push(str);
    } else if (!peek.includes(".")) {
        if (isOperand(peek)) {
            ins.push(ins.pop().toString() + str);
        } else {
            ins.push(str);
        }
    }
    _isnegated = false;
    display();
}

//braces control handler
function AddBrace(str) {
    ins.push(str);
    display();
}

_isnegated = false;

//negator --- denagator
function negate() {
    let current = peek(ins);

    function getNegationValue() {
        let val = `${ins[ins.length - 3]}${ins[ins.length - 2]}${current}`;
        return val.startsWith("(") && val[1] === "-" && val.endsWith(")") && _isnegated;
    }

    if (isOperand(current) && !_isnegated) {

        let cur = "-" + ins.pop();
        ins.push("(");
        ins.push(cur);
        ins.push(")");
        _isnegated = true;
    } else if (_isnegated && getNegationValue()) {
        ins.pop();
        let k = ins.pop();
        k = k.substring(1, k.length);
        ins.pop();
        ins.push(k);
        _isnegated = false;
    }
    display();
}

function resolveConsts() {
    let _const = ["e", "π"];

    for (i = 0; i < ins.length; i++) {
        let curr = ins[i];
        if (_const.includes(curr)) {
            if (isOperand(ins[i - 1]) || ins[i - 1] === ")") {
                ins.splice(i, 0, "x");
                ins[i + 1] = (curr === _const[0]) ? Math.E : Math.PI;
            } else if (ins[i - 1] === "-" || ins[i - 1] === "+") {
                let dp = ins[i - 2];
                if (dp === undefined || dp === null || dp === "(" || isOperator(dp) || dp[dp.length - 1] === "(") {
                    let op = ins[i - 1];
                    ins.splice(i - 1, 2, op + ((curr === _const[0]) ? Math.E : Math.PI));
                }
            }
        }
    }
}

function Evaluate() {
    resolveConsts();
    let output = parseToPostfix(ins);
    let result = Eval(output);
    ins = [];
    ins.push(result);
    _isnegated = false;
    display();
}

function Shift() {
    let sb = document.getElementById("to_shift");
    let _sin = document.getElementById("sin");
    let _cos = document.getElementById("cos");
    let _tan = document.getElementById("tan");
    let _e = document.getElementById("exp");

    if (shift_on === true) {
        _sin.value = "sin";
        _cos.value = "cos";
        _tan.value = "tan";
        _e.value = "e";
        sb.style.color = "white";
        sb.style.backgroundColor = "steelblue";
        shift_on = false;
    } else {
        _sin.value = "sin¯¹";
        _cos.value = "cos¯¹";
        _tan.value = "tan¯¹";
        _e.value = "eⁿ";
        sb.style.color = "red";
        sb.style.backgroundColor = "darkblue";
        shift_on = true;
    }
}

//handles deletion//
function Del() {
    let top = peek(ins);
    if (top !== undefined) {
        if (isOperand(top)) {
            let tp = top.substring(0, top.length - 1)
            if (tp === "") {
                ins.pop();
            } else {
                ins.pop();
                ins.push(tp);
            }
        } else {
            ins.pop();
        }
    }
    display();
}

//clears input screen//
function Clear() {
    ins = [];
    _isnegated = false;
    display();
}

function display() {
    let v = ins.join();
    calculator.display.value = st(v).toString();
}

let st = function (v) {
    return v.replace(/,/g, "");
};

 

See also  Javascript Program to Find Union of Two Sets Data Structure in Browser Full Project For Beginners

 

Now if you open the index.html file you will see the below output

 

Leave a Reply