Writing a javascript calculator



Good day, friends!

In this article, we, as the name implies, will write a simple JavaScript calculator.

The desire to write a calculator came to me after watching one tutorial on creating a “simple calculator”, which turned out to be far from simple and really could not do anything.

Our calculator will be true simple (42 lines of code, including spaces between blocks), but fully functional and scalable. This wonderful library (Math.js)

will be used for calculations . Without further introduction, we get down to business.



Our markup looks like this:

<!-- head -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/6.6.4/math.js"></script>

<!-- body -->
<div class="calculator">
    <output></output>
</div>

Here we connect the library, create a container for the calculator and a field for the input characters and the result.

We connect styles:
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  height: 100vh;
  background: radial-gradient(circle, skyblue, steelblue);
  display: flex;
  justify-content: center;
  align-items: center;
}

.calculator {
  width: 320px;
  height: 480px;
  background: #eee;
  border-radius: 5px;
  box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.2), -2px -2px 3px rgba(0, 0, 0, 0.2);
}

output {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 300px;
  height: 40px;
  background: #fff;
  margin: 10px auto;
  border-radius: 5px;
  font-size: 1.4em;
  font-weight: bold;
  box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.3),
    inset -1px -1px 1px rgba(0, 0, 0, 0.3);
}

.keyboard {
  height: 440px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-evenly;
  align-items: flex-start;
}

button {
  margin: 0.5em 1em;
  width: 40px;
  height: 40px;
  display: flex;
  justify-content: center;
  align-items: center;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1em;
  font-weight: bold;
}


Here is what we have at the moment:



Buttons will be generated programmatically.

We pass to the script.

We define a field for outputting the result and create a container for the keyboard:

const output = document.querySelector('output')

const div = document.createElement('div')
div.classList.add('keyboard')
document.querySelector('.calculator').appendChild(div)

Our line with characters looks like this:

'C CE % / 7 8 9 * 4 5 6 - 1 2 3 + 0 ( ) ='

Convert this string to an array and create buttons:

//    
//      ,       "CE"
'C CE % / 7 8 9 * 4 5 6 - 1 2 3 + 0 ( ) ='.split(' ')
    //   
    //   
    //      
    //      "value" 
    .map(symbol => {
        div.insertAdjacentHTML('beforeend', `<button value="${symbol}">${symbol}</button>`)
    })

We find the created buttons and add a click event handler to them:

document.querySelectorAll('button').forEach(button => {
    button.addEventListener('click', function () {
        //          
        calc(this.value)
    })
})

We also want to be able to enter characters using the keyboard. To do this, we need to add the “keystroke” event handler to the “Document” or “Window” object, then filter out unnecessary values ​​of the “key” property of the key, for example, using a regular expression:

document.addEventListener('keydown', event => {
    if ((event.key).match(/[0-9%\/*\-+\(\)=]|Backspace|Enter/)) calc(event.key)
})

The match method in this case plays the role of a filter: it does not allow passing an argument to the calc function that does not match the condition specified in it.

The condition itself is as follows: if the value of event.key is one of the characters indicated in square brackets ([]; a number from 0 to 9, signs of division, multiplication, addition, subtraction, opening, closing parentheses or an equal sign; backslash - escaping) or (| - alteration) Backspace, or Enter, then we call calc with event.key as a parameter, otherwise we do nothing (Shift is also successfully discarded).

Our main (and only) calc function is as follows (code should be read from bottom to top):

//       
function calc(value) {
    //      Enter
    if (value.match(/=|Enter/)) {
        //   
        try {
            //   
            //     "evaluate"  "math"
            // Math.trunc      
            output.textContent = Math.trunc(math.evaluate(output.textContent))
            
        //    
        } catch {
            //   
            let oldValue = output.textContent
            //   
            let newValue = ' '
            //      
            output.textContent = newValue
            //       
            setTimeout(() => {
                output.textContent = oldValue
            }, 1500)
        }
        
    //    "C"
    } else if (value === 'C') {
        //  
        output.textContent = ''
    
    //    ""  Backspace
    } else if (value.match(/CE|Backspace/)) {
        //     
        output.textContent = output.textContent.substring(0, output.textContent.length - 1)
        
    //     ()   
    } else {
        //     
        output.textContent += value
    }
}

In conclusion, a couple of words about the declared scalability and full functionality.

The evaluate method (formerly eval) and other Math.js methods have very great capabilities. Based on these features, we can easily expand the functionality of our calculator by adding new characters and operators to it, providing the possibility of working with floating-point numbers (adjusting the number of decimal places using the switch and the “toFixed” method), etc.

Result:



GitHub code .

Thank you for attention. I hope you find something useful for yourself. Have a nice weekend and happy coding.

All Articles