Kalkulator w przeglądarce z JavaScript

Pokażę jak to dzięki pomocy jednej funkcji JavaScript – eval() i podstawowej znajomości HTML, CSS i JavaScript można zbudować kalkulator w przeglądarce internetowej.

Od prostej wersji z obliczeniami w konsoli:

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

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Calculator</title>
</head>

<body>
  <p>
    <button onclick="
      calculation +='1';
      console.log(calculation);
      ">
      1
    </button>
    <button onclick="
    calculation +='2';
    console.log(calculation);
    ">
      2
    </button>
    <button onclick="
    calculation +='3';
    console.log(calculation);
    ">
      3
    </button>
    <button onclick="
    calculation += ' + ';
    ">
      +
    </button>
  </p>
  <p>
    <button onclick="
      calculation +='4';
      console.log(calculation);
      ">
      4
    </button>
    <button onclick="
      calculation +='5';
      console.log(calculation);
      ">
      5
    </button>
    <button onclick="
      calculation +='6';
      console.log(calculation);
      ">
      6
    </button>
    <button onclick="
      calculation += ' - ';
      ">
      -
    </button>
  </p>
  <p>
    <button onclick="
      calculation +='7';
      console.log(calculation);
      ">
      7
    </button>
    <button onclick="
      calculation +='8';
      console.log(calculation);
      ">
      8
    </button>
    <button onclick="
      calculation +='9';
      console.log(calculation);
      ">
      9
    </button>
    <button onclick="
      calculation += ' * ';
      ">
      *
    </button>
  </p>
  <p>
    <button onclick="
    calculation +='0';
    console.log(calculation);
    ">
      0
    </button>
    <button onclick="
calculation += '.';
">
      .
    </button>

    <button onclick="
    calculation = eval(calculation);
    console.log(calculation);
    ">
      =
    </button>

    <button onclick="
      calculation += ' / ';
      ">
      /
    </button>
  </p>
  <p>
    <button onclick="
    calculation = '';
    console.log(0);
    ">
      Clear
    </button>
  </p>

  <script>
    let calculation = "";
  </script>
</body>

</html>

 

 

Z dodaniem domyślnych stylów i animacji z Bootstrap-a:

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Calculator</title>
  <!-- Add Bootstrap CSS -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
  <style>
    .calc-button {
      width: 60px;
      height: 60px;
      margin: 5px;
    }

    .display {
      font-size: 2rem;
      margin-bottom: 20px;
      text-align: right;
      padding: 10px;
    }
  </style>
</head>

<body class="bg-light">

  <div class="container mt-5">
    <div class="row justify-content-center">
      <div class="col-md-4">
        <div class="card p-3 shadow">
          <div class="display bg-white border rounded" id="display">0</div>

          <div class="d-flex justify-content-between">
            <button class="btn btn-primary calc-button" onclick="updateCalculation('1')">1</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('2')">2</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('3')">3</button>
            <button class="btn btn-warning calc-button" onclick="updateCalculation(' + ')">+</button>
          </div>

          <div class="d-flex justify-content-between">
            <button class="btn btn-primary calc-button" onclick="updateCalculation('4')">4</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('5')">5</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('6')">6</button>
            <button class="btn btn-warning calc-button" onclick="updateCalculation(' - ')">-</button>
          </div>

          <div class="d-flex justify-content-between">
            <button class="btn btn-primary calc-button" onclick="updateCalculation('7')">7</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('8')">8</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('9')">9</button>
            <button class="btn btn-warning calc-button" onclick="updateCalculation(' * ')">*</button>
          </div>

          <div class="d-flex justify-content-between">
            <button class="btn btn-primary calc-button" onclick="updateCalculation('0')">0</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('.')">.</button>
            <button class="btn btn-success calc-button" onclick="calculate()">=</button>
            <button class="btn btn-warning calc-button" onclick="updateCalculation(' / ')">/</button>
          </div>

          <div class="d-flex justify-content-center">
            <button class="btn btn-danger calc-button" onclick="clearCalculation()">Clear</button>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- Add Bootstrap JS -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>

  <script>
    let calculation = '';

    function updateCalculation(value) {
      calculation += value;
      document.getElementById('display').innerText = calculation;
    }

    function calculate() {
      try {
        calculation = eval(calculation);
        document.getElementById('display').innerText = calculation;
      } catch (e) {
        document.getElementById('display').innerText = 'Error';
      }
    }

    function clearCalculation() {
      calculation = '';
      document.getElementById('display').innerText = '0';
    }
  </script>
</body>

</html>

 

Później dodaniem więcej animacji korzystając z biblioteki jQuery:

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Calculator</title>

  <!-- Add Bootstrap CSS -->
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
  <!-- Add jQuery -->
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <!-- Add jQuery UI for animations -->
  <link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet">
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>

  <style>
    .calc-button {
      width: 70px;
      height: 70px;
      margin: 8px;
      font-size: 1.5rem;
    }

    .display {
      font-size: 2.5rem;
      margin-bottom: 20px;
      text-align: right;
      padding: 15px;
      background-color: #f8f9fa;
    }

    .container {
      margin-top: 50px;
    }

    .btn-primary,
    .btn-warning,
    .btn-danger,
    .btn-success {
      transition: transform 0.1s ease;
    }
  </style>
</head>

<body class="bg-light">

  <div class="container">
    <div class="row justify-content-center">
      <div class="col-md-4">
        <div class="card p-4 shadow-lg rounded">
          <div class="display border rounded" id="display">0</div>

          <div class="d-flex justify-content-between">
            <button class="btn btn-primary calc-button" onclick="updateCalculation('1')">1</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('2')">2</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('3')">3</button>
            <button class="btn btn-warning calc-button" onclick="updateCalculation(' + ')">+</button>
          </div>

          <div class="d-flex justify-content-between">
            <button class="btn btn-primary calc-button" onclick="updateCalculation('4')">4</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('5')">5</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('6')">6</button>
            <button class="btn btn-warning calc-button" onclick="updateCalculation(' - ')">-</button>
          </div>

          <div class="d-flex justify-content-between">
            <button class="btn btn-primary calc-button" onclick="updateCalculation('7')">7</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('8')">8</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('9')">9</button>
            <button class="btn btn-warning calc-button" onclick="updateCalculation(' * ')">*</button>
          </div>

          <div class="d-flex justify-content-between">
            <button class="btn btn-primary calc-button" onclick="updateCalculation('0')">0</button>
            <button class="btn btn-primary calc-button" onclick="updateCalculation('.')">.</button>
            <button class="btn btn-success calc-button" onclick="calculate()">=</button>
            <button class="btn btn-warning calc-button" onclick="updateCalculation(' / ')">/</button>
          </div>

          <div class="d-flex justify-content-center">
            <button class="btn btn-danger calc-button" onclick="clearCalculation()">Clear</button>
          </div>
        </div>
      </div>
    </div>
  </div>

  <!-- Add Bootstrap JS -->
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>

  <script>
    let calculation = '';

    function updateCalculation(value) {
      // Add animations for button press
      animateButton(value);

      calculation += value;
      $("#display").text(calculation);
    }

    function calculate() {
      try {
        calculation = eval(calculation);
        $("#display").text(calculation).effect("bounce", { times: 3 }, 500);
      } catch (e) {
        $("#display").text('Error').effect("shake", { times: 3 }, 500);
      }
    }

    function clearCalculation() {
      calculation = '';
      $("#display").text('0').fadeOut(100).fadeIn(100);
    }

    // Add animation for button clicks
    function animateButton(value) {
      $(".btn").each(function () {
        if ($(this).text() === value) {
          $(this).addClass("pressed");
          $(this).css("transform", "scale(0.95)");
          setTimeout(() => {
            $(this).css("transform", "scale(1)");
          }, 100);
        }
      });
    }

    // Animation for button press style
    $(".btn").on("mousedown", function () {
      $(this).css("transform", "scale(0.95)");
    });
    $(".btn").on("mouseup", function () {
      $(this).css("transform", "scale(1)");
    });
  </script>

</body>

</html>

 

Kończąc na kalkulatorze z motywem prosto z Matrix-a:

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Matrix Calculator</title>

  <style>
    body,
    html {
      margin: 0;
      padding: 0;
      height: 100%;
      background-color: #000;
      color: #00ff00;
      font-family: 'Courier New', monospace;
      overflow: hidden;
    }

    #matrix-bg {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: 1;
      pointer-events: none;
    }

    .matrix-column {
      position: absolute;
      top: -50px;
      font-size: 14px;
      line-height: 1.5;
    }

    .container {
      position: relative;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      z-index: 2;
    }

    .calculator {
      background-color: rgba(0, 20, 0, 0.8);
      border: 2px solid #00ff00;
      border-radius: 10px;
      padding: 20px;
      box-shadow: 0 0 20px #00ff00;
      transition: all 0.5s ease;
    }

    .calculator:hover {
      transform: scale(1.05);
      box-shadow: 0 0 30px #00ff00;
    }

    .display {
      width: 240px;
      height: 60px;
      margin-bottom: 20px;
      text-align: right;
      padding: 15px;
      background-color: #001400;
      color: #00ff00;
      border-radius: 5px;
      border: 1px solid #00ff00;
      text-shadow: 0 0 5px #00ff00;
      transition: all 0.5s ease;
      overflow-x: scroll;
      overflow-y: hidden;
      white-space: nowrap;
      font-size: 2.5rem;
      display: flexbox;
      align-items: center;
      justify-content: flex-end;
      cursor: text;
      user-select: text;
    }

    .display-content {
      transition: all 0.3s ease;
    }

    .display.animate .display-content {
      animation: pulse 0.5s;
    }

    @keyframes pulse {
      0% {
        transform: scale(1);
      }

      50% {
        transform: scale(1.1);
      }

      100% {
        transform: scale(1);
      }
    }

    .btn {
      width: 60px;
      height: 60px;
      margin: 5px;
      font-size: 1.2rem;
      background-color: #001400;
      color: #00ff00;
      border: 1px solid #00ff00;
      border-radius: 5px;
      transition: all 0.3s ease;
      position: relative;
      overflow: hidden;
    }

    .btn::before {
      content: '';
      position: absolute;
      top: 50%;
      left: 50%;
      width: 0;
      height: 0;
      background-color: rgba(0, 255, 0, 0.5);
      border-radius: 50%;
      transform: translate(-50%, -50%);
      transition: width 0.6s ease, height 0.6s ease;
    }

    .btn:hover {
      color: #000;
      box-shadow: 0 0 15px #00ff00;
    }

    .btn:hover::before {
      width: 200%;
      height: 200%;
    }

    .btn:active {
      transform: scale(0.95);
      box-shadow: 0 0 5px #00ff00;
    }

    .btn span {
      position: relative;
      z-index: 1;
    }

    @keyframes glowPulse {
      0% {
        box-shadow: 0 0 5px #00ff00;
      }

      50% {
        box-shadow: 0 0 20px #00ff00;
      }

      100% {
        box-shadow: 0 0 5px #00ff00;
      }
    }

    .btn:focus {
      outline: none;
      animation: glowPulse 1s infinite;
    }

    .display:focus {
      outline: none;
      box-shadow: 0 0 15px #00ff00;
    }
  </style>
</head>

<body>
  <div id="matrix-bg"></div>

  <div class="container">
    <div class="calculator">
      <div class="display" id="display">
        <div class="display-content">0</div>
      </div>
      <div>
        <button class="btn" data-value="7"><span>7</span></button>
        <button class="btn" data-value="8"><span>8</span></button>
        <button class="btn" data-value="9"><span>9</span></button>
        <button class="btn" data-value="+"><span>+</span></button>
      </div>
      <div>
        <button class="btn" data-value="4"><span>4</span></button>
        <button class="btn" data-value="5"><span>5</span></button>
        <button class="btn" data-value="6"><span>6</span></button>
        <button class="btn" data-value="-"><span>-</span></button>
      </div>
      <div>
        <button class="btn" data-value="1"><span>1</span></button>
        <button class="btn" data-value="2"><span>2</span></button>
        <button class="btn" data-value="3"><span>3</span></button>
        <button class="btn" data-value="*"><span>*</span></button>
      </div>
      <div>
        <button class="btn" data-value="0"><span>0</span></button>
        <button class="btn" data-value="."><span>.</span></button>
        <button class="btn" data-value="="><span>=</span></button>
        <button class="btn" data-value="/"><span>/</span></button>
      </div>
      <div>
        <button class="btn" data-value="clear"><span>Clear</span></button>
      </div>
    </div>
  </div>

  <script>
    const matrixBg = document.getElementById('matrix-bg');
    const display = document.getElementById('display');
    const displayContent = display.querySelector('.display-content');
    const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()_+-=[]{}|;:,.<>?';
    const rows = Math.floor((window.innerHeight + 50) / 20);
    let calculation = '';
    let isDisplayFocused = false;

    function createColumn() {
      const column = document.createElement('div');
      column.className = 'matrix-column';
      column.style.left = `${Math.random() * window.innerWidth}px`;
      let y = -50;
      let output = '';
      for (let j = 0; j < rows; j++) {
        output += characters[Math.floor(Math.random() * characters.length)] + '<br><br>';
      }
      column.innerHTML = output;
      matrixBg.appendChild(column);

      function updateColumn() {
        y += 5;
        if (y > window.innerHeight) {
          matrixBg.removeChild(column);
        } else {
          column.style.transform = `translateY(${y}px)`;
          requestAnimationFrame(updateColumn);
        }
      }
      requestAnimationFrame(updateColumn);
    }

    function startMatrixEffect() {
      createColumn();
      setTimeout(startMatrixEffect, Math.random() * 500);
    }

    for (let i = 0; i < 5; i++) {
      setTimeout(startMatrixEffect, i * 200);
    }

    function updateDisplay() {
      const scrollPosition = display.scrollLeft;
      displayContent.textContent = calculation || '0';
      display.classList.add('animate');
      setTimeout(() => display.classList.remove('animate'), 500);

      if (!isDisplayFocused) {
        display.scrollLeft = display.scrollWidth;
      } else {
        display.scrollLeft = scrollPosition;
      }
    }

    function handleButtonClick(e) {
      const btn = e.target.closest('.btn');
      if (!btn) return;

      btn.classList.add('active');
      setTimeout(() => btn.classList.remove('active'), 200);

      const value = btn.dataset.value;
      if (value === '=') {
        try {
          calculation = eval(calculation).toString();
        } catch (error) {
          calculation = 'Error';
        }
      } else if (value === 'clear') {
        calculation = '';
      } else {
        calculation += value;
      }
      updateDisplay();
    }

    document.querySelector('.calculator').addEventListener('click', handleButtonClick);

    // Make the display focusable
    display.tabIndex = 0;

    // Track focus state
    display.addEventListener('focus', () => {
      isDisplayFocused = true;
    });

    display.addEventListener('blur', () => {
      isDisplayFocused = false;
    });

    // Prevent default calculator behavior when interacting with the display
    display.addEventListener('mousedown', (e) => {
      e.stopPropagation();
    });

    display.addEventListener('touchstart', (e) => {
      e.stopPropagation();
    });

    // Prevent keyboard input on the display
    display.addEventListener('keydown', (e) => {
      e.preventDefault();
    });

    let lastTime = 0;
    function animate(currentTime) {
      if (currentTime - lastTime > 500) {
        createColumn();
        lastTime = currentTime;
      }
      requestAnimationFrame(animate);
    }
    requestAnimationFrame(animate);
  </script>
</body>

</html>

 

Tutaj link do repozytorium z wszystkimi wersjami aplikacji: kalkulator-github

 

Oraz proste demo z działania: