ウェブ家の備忘録

ウェブデザイナーの備忘録

HTMLでリアルな計算機

作者 Mark Cruz

f:id:sirakabaararagi:20200913163921p:plain

 

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

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width-device-width,initian-scale=1.0">
  <title></title>
  <link rel="stylesheet" type="text/css" href="style5.css"> </head>

<body>
  <script type="text/javascript" src="style5.js"></script>
  <div class="calculator">
    <div class="screen-wrapper">
      <div id="screen">
        <div id="expression"><span id="typed-cursor" /></div>
        <div id="result">0</div>
      </div>
    </div>
    <table class="keys">
      <tbody>
        <tr>
          <td class="red key" data-func="clear">C</td>
          <td class="red key" data-func="cancel_entry">CE</td>
          <td class="gray key power" data-token="op_pow">x<span>y</span></td>
          <td class="gray key divide" data-token="op_divide">&divide;</td>
        </tr>
        <tr>
          <td class="blue key" data-token="num_7">7</td>
          <td class="blue key" data-token="num_8">8</td>
          <td class="blue key" data-token="num_9">9</td>
          <td class="gray key" data-token="op_multiply">&times;</td>
        </tr>
        <tr>
          <td class="blue key" data-token="num_4">4</td>
          <td class="blue key" data-token="num_5">5</td>
          <td class="blue key" data-token="num_6">6</td>
          <td class="gray key substract" data-token="op_substract">&ndash;</td>
        </tr>
        <tr>
          <td class="blue key" data-token="num_1">1</td>
          <td class="blue key" data-token="num_2">2</td>
          <td class="blue key" data-token="num_3">3</td>
          <td class="gray key add" data-token="op_add" rowspan="2">+</td>
        </tr>
        <tr>
          <td class="blue key" data-token="num_dot">.</td>
          <td class="blue key" data-token="num_0">0</td>
          <td class="blue key eval" data-func="eval">=</td>
        </tr>
      </tbody>
    </table>
    <p class="footer">Ricky PANGET Moran CALCULATOR</p>
  </div>
</body>

</html>
CSS
html {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

body {
  padding: 0;
  margin: 0;
  background-image: linear-gradient( to right, rgb(190, 195, 199) 0%, rgb(236, 240, 241) 40%, rgb(236, 240, 241) 60%, rgb(189, 195, 199) 100%);
}

.calculator {
  width: 250px;
  background-color: rgb(55, 33, 90);
  background-image: linear-gradient( to right, rgb(51, 75, 99) 0%, rgb(75, 101, 128) 40%, rgb(75, 101, 128) 60%, rgb(51, 75, 99) 100%);
  border-width: 1px;
  border-style: solid;
  border-top-color: rgba(255, 255, 255, 0.6);
  border-bottom-color: red;
  border-right-color: red;
  border-left-color: red;
  border-radius: 8px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.4), inset 0 0 3px 4px rgba(0, 0, 0, 0.5);
  border-top: 4px solid rgba(255, 255, 255, 0.2);
}
/* Screen
-------------------------------*/
.screen-wrapper {
  margin: 15px;
  padding: 3px;
  background-color: rgba(0, 0, 0, 0.3);
  box-shadow: 0 2px 2px rgba(255, 255, 255, 0.5);
  border-radius: 5px;
}

#screen {
  height: 60px;
  background-image: linear-gradient(to bottom, rgb(255, 204, 0) 0%, rgb(255, 222, 116) 100%);
  border-radius: 30%/7%;
  box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.6);
  padding: 8px 5px;
}

#expression {
  font-family: 'Press Start 2P', cursive;
  font-size: 12px;
  height: 20px;
  line-height: 20px;
  overflow: hidden;
  white-space: nowrap;
  display: flex;
  align-items: center;
}

#result {
  font-family: 'Press Start 2P', cursive;
  font-size: 28px;
  text-align: right;
  margin-top: 10px;
  white-space: nowrap;
}

#typed-cursor {
  border-right: 3px solid black;
  height: 14px;
  animation: 1s blink step-end infinite;
}

@keyframes blink {
  from, to {
    border-color: transparent;
  }

  50% {
    border-color: black;
  }
}

.keys {
  width: 100%;
  border-spacing: 12px;
}

.key {
  width: 25%;
  cursor: pointer;
  font-family: 'Open Sans', sans-serif;
  color: rgb(236, 240, 241);
  font-size: 18px;
  text-align: center;
  padding: 8px 0;
  border-radius: 5px;
  border-width: 3px;
  border-style: solid;
  border-top-color: rgba(255, 255, 255, 0.2);
  border-left-color: rgba(0, 0, 0, 0.1);
  border-right-color: rgba(0, 0, 0, 0.1);
  border-bottom-color: rgba(0, 0, 0, 0.3);
  box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.7);
  transition: all 0.2s ease-out;
  &: hover {
border: 3px solid rgba(226, 154, 26, 0.6);
  box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.7), inset 0 0 6px rgba(0, 0, 0, 0.4);
  color: rgba(226, 170, 26, 1);
  text-shadow: 0 0 10px rgba(255, 218, 153, 1);
}
&.red {
  background-image: linear-gradient( to bottom, rgb(150, 52, 52) 0%, rgb(190, 77, 77) 50%, rgb(150, 52, 52) 100%);
}
&.blue {
  background-image: linear-gradient( to bottom, rgb(44, 62, 80) 0%, rgb(58, 80, 102) 50%, rgb(44, 62, 80) 100%);
}
&.gray {
  background-image: linear-gradient( to bottom, rgb(110, 133, 151) 0%, rgb(130, 155, 175) 50%, rgb(110, 133, 151) 100%);
}
&.substract,
&.divide,
&.add,
&.eval {
  font-size: 28px;
  line-height: 18px;
}
&.substract {
  vertical-align: top;
}

span {
  font-size: 10px;
  vertical-align: top;
}
}

.footer {
  font-family: 'Open Sans', sans-serif;
  font-size: 12px;
  text-align: center;
  color: rgba(0, 0, 0, 0.5);
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.17);
}
JavaScript
window.onload = function() {
  new Calculator();
};
/**
 * Calculator class
 */
function Calculator() {
  this.op_add = '+';
  this.op_substract = '-';
  this.op_multiply = '*';
  this.op_divide = '/';
  this.op_pow = '^';
  this.num_1 = 1;
  this.num_2 = 2;
  this.num_3 = 3;
  this.num_4 = 4;
  this.num_5 = 5;
  this.num_6 = 6;
  this.num_7 = 7;
  this.num_8 = 8;
  this.num_9 = 9;
  this.num_0 = 0;
  this.num_dot = '.';
  this.screen = new Screen(this);
  this.keys = new Keyboard(this);
}
Calculator.prototype.infixToPostfix = function(infix) {
  var length = infix.length;
  var stack = new Array(); // Holds operators
  var postfix = ""; // The result expression
  var chars = infix.split('');
  // Each character
  for(var i = 0; i < length; i++) {
    var curChar = chars[i],
      nextChar = '';
    // Get the next char (unless it's the last char)
    if(i < length - 1) {
      nextChar = chars[i + 1];
    }
    // Operators
    if(!this.isInt(chars[i]) && chars[i] !== ".") {
      while(stack.length > 0) {
        if(this.comparePrecedence(stack.peek(), curChar)) {
          postfix += stack.pop() + " ";
        } else {
          break;
        }
      }
      stack.push(curChar);
    }
    // Operands
    else {
      if(this.isInt(nextChar) || nextChar === '.') postfix += curChar;
      else postfix += curChar + " ";
    }
  }
  // Pop the remaining operators
  while(stack.length > 0) {
    postfix += stack.pop() + " ";
  }
  return postfix.trim();
};
Calculator.prototype.postfixEval = function(postfix) {
  var resultStack = new Array();
  var postfix = postfix.split(" ");
  var length = postfix.length;
  var decimal;
  var curElement;
  // Each element
  for(var i = 0; i < length; i++) {
    curElement = postfix[i];
    // Operand
    if(this.isFloat(curElement)) {
      var decimal = parseFloat(curElement);
      resultStack.push(decimal);
    }
    // Operator
    else {
      var result = this.applyOperator(resultStack.pop(), resultStack.pop(), curElement);
      resultStack.push(result);
    }
  }
  return resultStack.pop();
};
Calculator.prototype.comparePrecedence = function(op_a, op_b) {
  var precedence = ['+', '-', '*', '/', '^', '(', ')'];
  return precedence.indexOf(op_a) > precedence.indexOf(op_b);
};
Calculator.prototype.applyOperator = function(b, a, operator) {
  switch(operator) {
    case "+":
      return a + b;
    case "-":
      return a - b;
    case "*":
      return a * b;
    case "/":
      return a / b;
    case "^":
      return Math.pow(a, b);
  }
}
Calculator.prototype.isInt = function(num) {
  return !isNaN(parseInt(num));
};
Calculator.prototype.isFloat = function(num) {
  return !isNaN(parseFloat(num));
};
/**
 * Screen class
 */
function Screen(calculator) {
  this.calculator = calculator;
  this.expressionHolder = document.getElementById('expression');
  this.expression = '';
  this.result = document.getElementById('result');
  this.cursor = new Cursor(this);
}
Screen.prototype.appendToExpression = function(token) {
  var value = this.calculator[token];
  this.expressionHolder.innerHTML += value;
  this.expressionHolder.scrollLeft = this.expressionHolder.scrollWidth;
  this.expression += value;
  this.cursor.moveToEnd();
};
Screen.prototype.setResult = function(number) {
  this.result.innerHTML = number.toString().slice(0, 11);
  this.expression = number.toString();
  this.expressionHolder.innerHTML = number;
  this.cursor.moveToEnd();
};
Screen.prototype.clear = function() {
  this.result.innerHTML = 0;
  this.expressionHolder.innerHTML = '';
  this.expression = '';
  this.cursor.moveToStart();
};
Screen.prototype.cancelEntry = function() {
  this.expressionHolder.innerHTML = '';
  this.expression = '';
  this.cursor.moveToStart();
};
/**
 * Cursor class
 */
function Cursor(screen) {
  this.screen = screen;
  this.pos = 0;
}
Cursor.prototype.moveTo = function(pos) {
  if(pos >= 0 && pos <= this.screen.expression.length) {
    // Remove current cursor
    try {
      document.getElementById('expression').removeChild(document.getElementById('typed-cursor'));
    } catch(e) {}
    // Recreate it
    var cursor = '';
    var expression = this.screen.expression;
    expression = expression.substring(0, pos) + cursor + expression.substring(pos, expression.length);
    this.pos = pos;
    document.getElementById('expression').innerHTML = expression;
  }
};
Cursor.prototype.moveToEnd = function() {
  this.moveTo(this.screen.expression.length);
};
Cursor.prototype.moveToStart = function() {
  this.moveTo(0);
};
/**
 * Keyboard class
 */
function Keyboard(calculator) {
  this.calculator = calculator;
  this.keys = document.querySelectorAll('.key');
  for(var i = 0; i < this.keys.length; i++) {
    var self = this;
    this.keys[i].onclick = function() {
      self.keyPress(this);
    };
  }
}
Keyboard.prototype.keyPress = function(key) {
  if(key.getAttribute("data-func") === null) {
    this.calculator.screen.appendToExpression(key.getAttribute("data-token"));
  } else {
    this['key_' + key.getAttribute("data-func")]();
  }
};
// Calculator key actions
Keyboard.prototype.key_eval = function() {
  var postfix = this.calculator.infixToPostfix(this.calculator.screen.expression);
  this.calculator.screen.setResult(this.calculator.postfixEval(postfix));
};
Keyboard.prototype.key_clear = function() {
  this.calculator.screen.clear();
};
Keyboard.prototype.key_cancel_entry = function() {
  this.calculator.screen.cancelEntry();
};
Array.prototype.peek = function() {
  return this[this.length - 1];
};