├── calculator.jpg ├── README.md ├── index.html ├── .gitignore ├── style.css └── calculator.js /calculator.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxica/Calculator-JavaScript/HEAD/calculator.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Calculator-JavaScript 2 | 3 | ![Calculator](https://github.com/oxica/Calculator-JavaScript/blob/main/calculator.jpg) -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Calculator - JavaScript 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
0
20 |
21 |
22 |
23 | 24 | 25 |
26 |
27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | *{ 2 | padding: 0; 3 | margin: 0; 4 | background-origin: padding-box; 5 | font-family: 'Poppins', sans-serif; 6 | } 7 | 8 | html{ 9 | font-size: 16px; 10 | background-color: #6fc7bb; 11 | } 12 | 13 | .calculator{ 14 | position: absolute; 15 | 16 | top: 50%; 17 | left: 50%; 18 | 19 | transform: translate(-50%, -50%); 20 | } 21 | 22 | .calc-container{ 23 | background-color: rgba(14, 15, 14, 0.867); 24 | 25 | width: 300px; 26 | height: auto; 27 | 28 | border-radius: 30px 30px 30px 30px; 29 | } 30 | 31 | .output{ 32 | width: 100%;; 33 | } 34 | 35 | .operation{ 36 | width: 300px; 37 | height: 70px; 38 | 39 | color: #878787; 40 | 41 | font-size: 1.9em; 42 | font-weight: bold; 43 | 44 | position: relative; 45 | overflow: hidden; 46 | } 47 | .operation .value{ 48 | position: absolute; 49 | 50 | bottom: 5px; 51 | right : 10px; 52 | 53 | white-space: nowrap; 54 | overflow: hidden; 55 | } 56 | 57 | .result{ 58 | width: 300px; 59 | height: 140px; 60 | 61 | color: #FFF; 62 | 63 | font-size: 2.7em; 64 | font-weight: bold; 65 | 66 | overflow: hidden; 67 | position: relative; 68 | } 69 | 70 | .result .value{ 71 | position: absolute; 72 | 73 | top: 50%; 74 | transform: translateY(-50%); 75 | right : 10px; 76 | 77 | white-space: nowrap; 78 | overflow: hidden; 79 | } 80 | 81 | 82 | .input{ 83 | background-color: #FFF; 84 | 85 | border-radius: 0 0 25px 25px; 86 | border: 1px solid #1d1d1d; 87 | height: 340px; 88 | } 89 | 90 | .row { 91 | display: flex; 92 | justify-content: space-around; 93 | align-items: center; 94 | } 95 | 96 | .row button{ 97 | width: 50px; 98 | height: 50px; 99 | 100 | font-size: 1.5em; 101 | 102 | border: none; 103 | border-radius: 50%; 104 | background-color: transparent; 105 | 106 | margin : 8px; 107 | 108 | cursor: pointer; 109 | } 110 | 111 | .row button:hover{ 112 | font-weight: bold; 113 | } 114 | 115 | .row #calculate{ 116 | color: #FFF; 117 | background-color: #46e0bc; 118 | width : 121px; 119 | border-radius: 50px; 120 | } 121 | .row #delete{ 122 | color: #FFF; 123 | background-color: #ec6e4e; 124 | } 125 | 126 | #division, #multiplication, #subtraction, #addition { 127 | color: #18b893; 128 | } -------------------------------------------------------------------------------- /calculator.js: -------------------------------------------------------------------------------- 1 | const input_element = document.querySelector(".input"); 2 | const output_operation_element = document.querySelector(".operation .value"); 3 | const output_result_element = document.querySelector(".result .value"); 4 | 5 | let calculator_buttons = [ 6 | { 7 | name : "delete", 8 | symbol : "⌫", 9 | formula : false, 10 | type : "key" 11 | },{ 12 | name : "clear", 13 | symbol : "C", 14 | formula : false, 15 | type : "key" 16 | },{ 17 | name : "percent", 18 | symbol : "%", 19 | formula : "/100", 20 | type : "number" 21 | },{ 22 | name : "division", 23 | symbol : "÷", 24 | formula : "/", 25 | type : "operator" 26 | },{ 27 | name : "7", 28 | symbol : 7, 29 | formula : 7, 30 | type : "number" 31 | },{ 32 | name : "8", 33 | symbol : 8, 34 | formula : 8, 35 | type : "number" 36 | },{ 37 | name : "9", 38 | symbol : 9, 39 | formula : 9, 40 | type : "number" 41 | },{ 42 | name : "multiplication", 43 | symbol : "×", 44 | formula : "*", 45 | type : "operator" 46 | },{ 47 | name : "4", 48 | symbol : 4, 49 | formula : 4, 50 | type : "number" 51 | },{ 52 | name : "5", 53 | symbol : 5, 54 | formula : 5, 55 | type : "number" 56 | },{ 57 | name : "6", 58 | symbol : 6, 59 | formula : 6, 60 | type : "number" 61 | },{ 62 | name : "addition", 63 | symbol : "+", 64 | formula : "+", 65 | type : "operator" 66 | },,{ 67 | name : "1", 68 | symbol : 1, 69 | formula : 1, 70 | type : "number" 71 | },{ 72 | name : "2", 73 | symbol : 2, 74 | formula : 2, 75 | type : "number" 76 | },{ 77 | name : "3", 78 | symbol : 3, 79 | formula : 3, 80 | type : "number" 81 | },{ 82 | name : "subtraction", 83 | symbol : "–", 84 | formula : "-", 85 | type : "operator" 86 | },{ 87 | name : "0", 88 | symbol : 0, 89 | formula : 0, 90 | type : "number" 91 | },{ 92 | name : "comma", 93 | symbol : ".", 94 | formula : ".", 95 | type : "number" 96 | },{ 97 | name : "calculate", 98 | symbol : "=", 99 | formula : "=", 100 | type : "calculate" 101 | } 102 | ]; 103 | 104 | let data = { 105 | operation : [], 106 | result : [], 107 | } 108 | 109 | function createCalculatorButtons(){ 110 | const btns_per_row = 4; 111 | let added_btns = 0; 112 | 113 | calculator_buttons.forEach( (button, index) => { 114 | if( added_btns % btns_per_row == 0 ){ 115 | input_element.innerHTML += `
`; 116 | } 117 | 118 | const row = document.querySelector(".row:last-child"); 119 | row.innerHTML += ``; 122 | 123 | added_btns++; 124 | }); 125 | } 126 | createCalculatorButtons(); 127 | 128 | input_element.addEventListener("click", event => { 129 | const target_btn = event.target; 130 | 131 | calculator_buttons.forEach( button => { 132 | if( button.name == target_btn.id ) calculator(button); 133 | }); 134 | 135 | }); 136 | 137 | function calculator( button ){ 138 | if( button.type == "operator" ){ 139 | data.operation.push(button.symbol); 140 | data.result.push(button.formula); 141 | } 142 | else if( button.type == "number" ){ 143 | data.operation.push(button.symbol); 144 | data.result.push(button.formula); 145 | } 146 | else if( button.type == "key" ){ 147 | if( button.name == "clear" ){ 148 | data.operation = []; 149 | data.result = []; 150 | updateOutputResult(0); 151 | } 152 | else if( button.name == "delete" ){ 153 | data.result.pop(); 154 | data.operation.pop(); 155 | } 156 | } 157 | else if( button.type == "calculate" ){ 158 | 159 | // PUSH WHAT'S LEFT IN TEMP TO RESULT AND JOIN RESULT 160 | let result_joined = data.result.join(''); 161 | 162 | // CLEAR ALL ARRAYS, NO NEED TO SAVE ANYTHING ANYMORE 163 | data.operation = []; 164 | data.result = []; 165 | 166 | // CHECK IF THERE WAS A SYNATX ERROR IN THE operation 167 | let result_final; 168 | try { 169 | result_final = eval(result_joined); 170 | } catch (error) { 171 | if (error instanceof SyntaxError) { 172 | result_final = "Syntax Error!" 173 | updateOutputResult( result_final ); 174 | return; 175 | } 176 | } 177 | 178 | // FORMAT THE RESULT 179 | result_final = formatResult(result_final); 180 | 181 | // SAVE RESULT FOR ANY FUTURE USE 182 | data.operation.push(result_final); 183 | data.result.push(result_final); 184 | 185 | // UPDATE OUTPUT 186 | updateOutputResult( result_final ); 187 | 188 | return; 189 | } 190 | 191 | updateOutputOperation( data.operation.join('') ); 192 | } 193 | 194 | function updateOutputOperation(operation){ 195 | output_operation_element.innerHTML = operation; 196 | } 197 | 198 | function updateOutputResult(result){ 199 | output_result_element.innerHTML = result; 200 | } 201 | 202 | function digitCounter(number){ 203 | return number.toString().length; 204 | } 205 | 206 | function isFloat(number){ 207 | return number % 1 != 0; 208 | } 209 | 210 | const max_output_number_length = 10; 211 | const output_precision = 5; 212 | 213 | function formatResult( result ){ 214 | if( digitCounter(result) > max_output_number_length){ 215 | if( isFloat(result) ){ 216 | const result_int = parseInt(result); 217 | const result_int_length = digitCounter(result_int); 218 | 219 | if( result_int_length > max_output_number_length ){ 220 | return result.toPrecision(output_precision); 221 | }else{ 222 | const num_digits_after_point = max_output_number_length - result_int_length; 223 | return result.toFixed(num_digits_after_point); 224 | } 225 | }else{ 226 | return result.toPrecision(output_precision); 227 | } 228 | }else{ 229 | return result; 230 | } 231 | } --------------------------------------------------------------------------------