Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>ChemCalc Pro | Advanced Chemical Calculator</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #3a7bd5; | |
| --secondary: #00d2ff; | |
| --dark: #1a1a2e; | |
| --light: #f5f7fa; | |
| --success: #28a745; | |
| --danger: #dc3545; | |
| --warning: #fd7e14; | |
| --info: #17a2b8; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| background: linear-gradient(135deg, #f5f7fa 0%, #e4e6e9 100%); | |
| min-height: 100vh; | |
| color: var(--dark); | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| header { | |
| text-align: center; | |
| margin-bottom: 30px; | |
| padding: 20px; | |
| background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%); | |
| color: white; | |
| border-radius: 10px; | |
| box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); | |
| } | |
| h1 { | |
| font-size: 2.5rem; | |
| margin-bottom: 10px; | |
| } | |
| h1 i { | |
| margin-right: 15px; | |
| } | |
| .subtitle { | |
| font-size: 1.1rem; | |
| opacity: 0.9; | |
| } | |
| .tabs { | |
| display: flex; | |
| flex-wrap: wrap; | |
| background: white; | |
| border-radius: 10px; | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); | |
| margin-bottom: 30px; | |
| overflow: hidden; | |
| } | |
| .tab-button { | |
| flex: 1; | |
| padding: 15px 20px; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| font-weight: 600; | |
| border-bottom: 3px solid transparent; | |
| } | |
| .tab-button:hover { | |
| background: rgba(0, 0, 0, 0.05); | |
| } | |
| .tab-button.active { | |
| background: rgba(58, 123, 213, 0.1); | |
| border-bottom: 3px solid var(--primary); | |
| color: var(--primary); | |
| } | |
| .tab-content { | |
| display: none; | |
| padding: 30px; | |
| background: white; | |
| border-radius: 0 0 10px 10px; | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); | |
| } | |
| .tab-content.active { | |
| display: block; | |
| animation: fadeIn 0.5s ease; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .calculator-form { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); | |
| gap: 20px; | |
| } | |
| .form-group { | |
| margin-bottom: 20px; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 8px; | |
| font-weight: 600; | |
| color: #555; | |
| } | |
| input, select { | |
| width: 100%; | |
| padding: 12px 15px; | |
| border: 1px solid #ddd; | |
| border-radius: 6px; | |
| font-size: 16px; | |
| transition: border 0.3s ease; | |
| } | |
| input:focus, select:focus { | |
| border-color: var(--primary); | |
| outline: none; | |
| box-shadow: 0 0 0 3px rgba(58, 123, 213, 0.2); | |
| } | |
| .btn { | |
| display: inline-block; | |
| padding: 12px 24px; | |
| background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%); | |
| color: white; | |
| border: none; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-size: 16px; | |
| font-weight: 600; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| } | |
| .btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15); | |
| } | |
| .btn-calculate { | |
| grid-column: 1 / -1; | |
| justify-self: center; | |
| margin-top: 20px; | |
| min-width: 200px; | |
| } | |
| .result-container { | |
| margin-top: 30px; | |
| padding: 20px; | |
| background: rgba(58, 123, 213, 0.1); | |
| border-radius: 8px; | |
| border-left: 4px solid var(--primary); | |
| display: none; | |
| } | |
| .result-container.show { | |
| display: block; | |
| animation: fadeIn 0.5s ease; | |
| } | |
| .result-title { | |
| font-weight: 700; | |
| margin-bottom: 10px; | |
| color: var(--primary); | |
| } | |
| .result-value { | |
| font-size: 1.2rem; | |
| font-weight: 600; | |
| } | |
| .periodic-table { | |
| margin-top: 30px; | |
| } | |
| .periodic-table h3 { | |
| margin-bottom: 15px; | |
| color: var(--primary); | |
| } | |
| .elements-grid { | |
| display: grid; | |
| grid-template-columns: repeat(18, 1fr); | |
| gap: 5px; | |
| margin-bottom: 30px; | |
| } | |
| .element { | |
| padding: 10px 5px; | |
| background: white; | |
| border-radius: 4px; | |
| text-align: center; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | |
| } | |
| .element:hover { | |
| transform: scale(1.05); | |
| box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); | |
| z-index: 1; | |
| } | |
| .element-symbol { | |
| font-weight: 700; | |
| font-size: 0.9rem; | |
| } | |
| .element-number { | |
| font-size: 0.6rem; | |
| opacity: 0.7; | |
| } | |
| .nonmetal { background-color: #ade8af; } | |
| .alkali { background-color: #ffb7b3; } | |
| .alkaline { background-color: #ffdfba; } | |
| .transition { background-color: #ffc8dd; } | |
| .post-transition { background-color: #b8d0eb; } | |
| .metalloid { background-color: #c2e0c6; } | |
| .halogen { background-color: #caffbf; } | |
| .noble { background-color: #cddafd; } | |
| .lanthanide { background-color: #eac4d5; } | |
| .actinide { background-color: #f1c0e8; } | |
| .history-container { | |
| margin-top: 30px; | |
| max-height: 300px; | |
| overflow-y: auto; | |
| } | |
| .history-item { | |
| padding: 10px 15px; | |
| margin-bottom: 10px; | |
| background: white; | |
| border-radius: 6px; | |
| box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
| font-size: 0.9rem; | |
| } | |
| .history-item .time { | |
| font-size: 0.8rem; | |
| color: #777; | |
| } | |
| footer { | |
| text-align: center; | |
| margin-top: 50px; | |
| padding: 20px; | |
| color: #777; | |
| font-size: 0.9rem; | |
| } | |
| @media (max-width: 768px) { | |
| .elements-grid { | |
| grid-template-columns: repeat(9, 1fr); | |
| } | |
| .tab-button { | |
| flex: 0 0 50%; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .tab-button { | |
| flex: 0 0 100%; | |
| } | |
| .elements-grid { | |
| grid-template-columns: repeat(6, 1fr); | |
| } | |
| } | |
| /* Special styling for specific calculator types */ | |
| .concentration-controls, .reaction-controls { | |
| display: flex; | |
| gap: 15px; | |
| align-items: center; | |
| } | |
| .reaction-arrow { | |
| font-size: 1.5rem; | |
| color: #777; | |
| padding: 0 10px; | |
| } | |
| .formula-display { | |
| font-size: 1.2rem; | |
| font-family: 'Courier New', monospace; | |
| padding: 10px; | |
| background: #f5f5f5; | |
| border-radius: 4px; | |
| margin: 15px 0; | |
| word-break: break-all; | |
| } | |
| .advanced-options { | |
| margin-top: 20px; | |
| padding-top: 20px; | |
| border-top: 1px solid #eee; | |
| } | |
| .toggle-advanced { | |
| background: none; | |
| border: none; | |
| color: var(--primary); | |
| cursor: pointer; | |
| font-weight: 600; | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 10px; | |
| } | |
| .toggle-advanced i { | |
| margin-right: 5px; | |
| transition: transform 0.3s ease; | |
| } | |
| .toggle-advanced.collapsed i { | |
| transform: rotate(-90deg); | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <h1><i class="fas fa-atom"></i> ChemCalc Pro</h1> | |
| <p class="subtitle">Advanced Chemical Calculations for Professionals</p> | |
| </header> | |
| <div class="tabs"> | |
| <div class="tab-button active" data-tab="molar-mass"><i class="fas fa-weight-hanging"></i> Molar Mass</div> | |
| <div class="tab-button" data-tab="concentration"><i class="fas fa-flask"></i> Concentration</div> | |
| <div class="tab-button" data-tab="stoichiometry"><i class="fas fa-balance-scale"></i> Stoichiometry</div> | |
| <div class="tab-button" data-tab="gas-laws"><i class="fas fa-wind"></i> Gas Laws</div> | |
| <div class="tab-button" data-tab="thermochemistry"><i class="fas fa-temperature-high"></i> Thermochemistry</div> | |
| <div class="tab-button" data-tab="redox"><i class="fas fa-bolt"></i> Redox</div> | |
| </div> | |
| <!-- Molar Mass Calculator --> | |
| <div id="molar-mass" class="tab-content active"> | |
| <h2><i class="fas fa-weight-hanging"></i> Molar Mass Calculator</h2> | |
| <p>Calculate the molar mass of any chemical compound by entering its formula.</p> | |
| <div class="calculator-form"> | |
| <div class="form-group"> | |
| <label for="compound-formula">Chemical Formula</label> | |
| <input type="text" id="compound-formula" placeholder="e.g. H2O, C6H12O6, Ca(OH)2"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="compound-mass">Mass (optional)</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="compound-mass" placeholder="e.g. 5"> | |
| <select id="mass-unit"> | |
| <option value="g">g</option> | |
| <option value="mg">mg</option> | |
| <option value="kg">kg</option> | |
| </select> | |
| </div> | |
| </div> | |
| <button id="calculate-mass" class="btn btn-calculate">Calculate Molar Mass</button> | |
| </div> | |
| <div id="mass-result" class="result-container"> | |
| <div class="result-title">Results</div> | |
| <div id="mass-value" class="result-value"></div> | |
| <div id="moles-value" class="result-value" style="margin-top: 10px;"></div> | |
| <div id="composition" style="margin-top: 15px;"></div> | |
| </div> | |
| <div class="periodic-table"> | |
| <h3>Periodic Table</h3> | |
| <p>Click on elements to add them to the formula</p> | |
| <div class="elements-grid" id="periodic-elements"></div> | |
| </div> | |
| </div> | |
| <!-- Concentration Calculator --> | |
| <div id="concentration" class="tab-content"> | |
| <h2><i class="fas fa-flask"></i> Concentration Calculator</h2> | |
| <p>Calculate concentration, mass, volume, or dilution of solutions.</p> | |
| <div class="calculator-form"> | |
| <div class="form-group"> | |
| <label>Calculation Type</label> | |
| <select id="concentration-type" class="form-control"> | |
| <option value="conc-from-mass">Concentration from Mass</option> | |
| <option value="mass-from-conc">Mass from Concentration</option> | |
| <option value="dilution">Dilution</option> | |
| <option value="mole-fraction">Mole Fraction</option> | |
| </select> | |
| </div> | |
| <div id="conc-inputs"> | |
| <div class="form-group"> | |
| <label for="solute-formula">Solute Formula</label> | |
| <input type="text" id="solute-formula" placeholder="e.g. NaCl"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="solute-mass">Mass of Solute</label> | |
| <input type="number" id="solute-mass" placeholder="in grams"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="solution-volume">Solution Volume</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="solution-volume" placeholder="e.g. 250"> | |
| <select id="vol-unit"> | |
| <option value="L">L</option> | |
| <option value="mL">mL</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="dilution-inputs" style="display: none;"> | |
| <div class="form-group"> | |
| <label for="initial-conc">Initial Concentration</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="initial-conc"> | |
| <select id="initial-conc-unit"> | |
| <option value="M">M</option> | |
| <option value="mM">mM</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label for="initial-vol">Initial Volume</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="initial-vol"> | |
| <select id="initial-vol-unit"> | |
| <option value="L">L</option> | |
| <option value="mL">mL</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="conc-advanced" class="advanced-options" style="display: none;"> | |
| <div class="form-group"> | |
| <label for="solution-density">Solution Density (g/mL)</label> | |
| <input type="number" id="solution-density" placeholder="Optional"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="solvent-mass">Solvent Mass (g)</label> | |
| <input type="number" id="solvent-mass" placeholder="Optional"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="solution-temp">Temperature (°C)</label> | |
| <input type="number" id="solution-temp" placeholder="25"> | |
| </div> | |
| </div> | |
| <button type="button" class="toggle-advanced" id="toggle-conc-advanced"> | |
| <i class="fas fa-chevron-down"></i> Advanced Options | |
| </button> | |
| <button id="calculate-conc" class="btn btn-calculate">Calculate</button> | |
| </div> | |
| <div id="conc-result" class="result-container"> | |
| <div class="result-title">Results</div> | |
| <div id="conc-value" class="result-value"></div> | |
| <div id="conc-details" style="margin-top: 15px;"></div> | |
| </div> | |
| </div> | |
| <!-- Stoichiometry Calculator --> | |
| <div id="stoichiometry" class="tab-content"> | |
| <h2><i class="fas fa-balance-scale"></i> Stoichiometry Calculator</h2> | |
| <p>Balance chemical equations and perform stoichiometric calculations.</p> | |
| <div class="calculator-form"> | |
| <div class="form-group"> | |
| <label>Reaction Type</label> | |
| <select id="reaction-type" class="form-control"> | |
| <option value="balance">Balance Equation</option> | |
| <option value="limiting-reactant">Limiting Reactant</option> | |
| <option value="product-yield">Product Yield</option> | |
| </select> | |
| </div> | |
| <div id="reaction-inputs"> | |
| <div class="form-group balanced-equation"> | |
| <label>Enter Chemical Equation</label> | |
| <div class="formula-display" id="equation-display"></div> | |
| <div class="reaction-controls"> | |
| <input type="text" id="reactant1" placeholder="Reactant 1 (e.g. H2)"> | |
| <div class="reaction-arrow">+</div> | |
| <input type="text" id="reactant2" placeholder="Reactant 2 (e.g. O2)"> | |
| <div class="reaction-arrow"> | |
| <select id="reaction-direction"> | |
| <option value="→">→</option> | |
| <option value="↔">↔</option> | |
| </select> | |
| </div> | |
| <input type="text" id="product1" placeholder="Product 1 (e.g. H2O)"> | |
| <div class="reaction-arrow">+</div> | |
| <input type="text" id="product2" placeholder="Product 2 (optional)"> | |
| </div> | |
| </div> | |
| <div id="stoich-inputs" style="display: none;"> | |
| <div class="form-group"> | |
| <label for="given-quantity">Given Quantity</label> | |
| <input type="number" id="given-quantity" placeholder="Amount"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="given-compound">Given Compound</label> | |
| <input type="text" id="given-compound" placeholder="Formula"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="desired-compound">Desired Compound</label> | |
| <input type="text" id="desired-compound" placeholder="Formula"> | |
| </div> | |
| </div> | |
| </div> | |
| <button id="balance-reaction" class="btn btn-calculate">Balance Equation</button> | |
| <div id="stoich-result" class="result-container"> | |
| <div class="result-title">Results</div> | |
| <div id="balanced-equation" class="result-value"></div> | |
| <div id="stoich-details" style="margin-top: 15px;"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Gas Laws Calculator --> | |
| <div id="gas-laws" class="tab-content"> | |
| <h2><i class="fas fa-wind"></i> Gas Laws Calculator</h2> | |
| <p>Perform calculations using the ideal gas law and other gas equations.</p> | |
| <div class="calculator-form"> | |
| <div class="form-group"> | |
| <label>Gas Law</label> | |
| <select id="gas-law" class="form-control"> | |
| <option value="ideal-gas">Ideal Gas Law (PV=nRT)</option> | |
| <option value="boyles">Boyle's Law (P₁V₁=P₂V₂)</option> | |
| <option value="charles">Charles's Law (V₁/T₁=V₂/T₂)</option> | |
| <option value="gay-lussac">Gay-Lussac's Law (P₁/T₁=P₂/T₂)</option> | |
| <option value="combined">Combined Gas Law (P₁V₁/T₁=P₂V₂/T₂)</option> | |
| <option value="density">Gas Density (d=PM/RT)</option> | |
| </select> | |
| </div> | |
| <div id="ideal-gas-inputs"> | |
| <div class="form-group"> | |
| <label for="gas-pressure">Pressure (P)</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="gas-pressure" placeholder="e.g. 1"> | |
| <select id="pressure-unit"> | |
| <option value="atm">atm</option> | |
| <option value="mmHg">mmHg</option> | |
| <option value="kPa">kPa</option> | |
| <option value="bar">bar</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label for="gas-volume">Volume (V)</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="gas-volume" placeholder="e.g. 22.4"> | |
| <select id="volume-unit"> | |
| <option value="L">L</option> | |
| <option value="mL">mL</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label for="gas-moles">Moles (n)</label> | |
| <input type="number" id="gas-moles" placeholder="e.g. 1"> | |
| </div> | |
| <div class="form-group"> | |
| <label for="gas-temp">Temperature (T)</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="gas-temp" placeholder="e.g. 273"> | |
| <select id="temp-unit"> | |
| <option value="K">K</option> | |
| <option value="°C">°C</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <button id="calculate-gas" class="btn btn-calculate">Calculate</button> | |
| <div id="gas-result" class="result-container"> | |
| <div class="result-title">Results</div> | |
| <div id="gas-value" class="result-value"></div> | |
| <div id="gas-details" style="margin-top: 15px;"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Thermochemistry Calculator --> | |
| <div id="thermochemistry" class="tab-content"> | |
| <h2><i class="fas fa-temperature-high"></i> Thermochemistry Calculator</h2> | |
| <p>Calculate enthalpy, heat transfer, and other thermochemical properties.</p> | |
| <div class="calculator-form"> | |
| <div class="form-group"> | |
| <label>Calculation Type</label> | |
| <select id="thermo-type" class="form-control"> | |
| <option value="enthalpy">Enthalpy Change</option> | |
| <option value="heat">Heat Transfer (q=mcΔT)</option> | |
| <option value="hess">Hess's Law</option> | |
| <option value="calorimetry">Calorimetry</option> | |
| </select> | |
| </div> | |
| <!-- Enthalpy inputs --> | |
| <div id="enthalpy-inputs"> | |
| <div class="form-group"> | |
| <label for="reaction-enthalpy">Reaction Enthalpy (ΔH°)</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="reaction-enthalpy" placeholder="kJ/mol"> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label for="moles-reacted">Moles Reacted</label> | |
| <input type="number" id="moles-reacted" placeholder="mol"> | |
| </div> | |
| </div> | |
| <!-- Heat inputs --> | |
| <div id="heat-inputs" style="display: none;"> | |
| <div class="form-group"> | |
| <label for="thermo-mass">Mass</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="thermo-mass" placeholder="g"> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label for="specific-heat">Specific Heat Capacity (c)</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="specific-heat" placeholder="J/g°C (4.18 for water)"> | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label for="temp-change">Temperature Change (ΔT)</label> | |
| <div class="concentration-controls"> | |
| <input type="number" id="temp-change" placeholder="°C"> | |
| </div> | |
| </div> | |
| </div> | |
| <button id="calculate-thermo" class="btn btn-calculate">Calculate</button> | |
| <div id="thermo-result" class="result-container"> | |
| <div class="result-title">Results</div> | |
| <div id="thermo-value" class="result-value"></div> | |
| <div id="thermo-details" style="margin-top: 15px;"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Redox Calculator --> | |
| <div id="redox" class="tab-content"> | |
| <h2><i class="fas fa-bolt"></i> Redox Reaction Calculator</h2> | |
| <p>Balance redox reactions and calculate electrochemical properties.</p> | |
| <div class="calculator-form"> | |
| <div class="form-group"> | |
| <label>Calculation Type</label> | |
| <select id="redox-type" class="form-control"> | |
| <option value="balance-redox">Balance Redox Reaction</option> | |
| <option value="cell-potential">Cell Potential</option> | |
| <option value="nernst">Nernst Equation</option> | |
| </select> | |
| </div> | |
| <div id="redox-reaction-inputs"> | |
| <div class="form-group"> | |
| <label>Redox Reaction (Half-Reactions)</label> | |
| <div class="reaction-controls"> | |
| <input type="text" id="redox-reactant1" placeholder="Oxidation (e.g. Fe → Fe²⁺)"> | |
| <div class="reaction-arrow">+</div> | |
| <input type="text" id="redox-reactant2" placeholder="Reduction (e.g. O2 + 4e⁻ → 2O²⁻)"> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="redox-advanced" class="advanced-options" style="display: none;"> | |
| <div class="form-group"> | |
| <label for="redox-medium">Medium</label> | |
| <select id="redox-medium"> | |
| <option value="acidic">Acidic</option> | |
| <option value="basic">Basic</option> | |
| <option value="neutral">Neutral</option> | |
| </select> | |
| </div> | |
| <div class="form-group"> | |
| <label for="redox-temp">Temperature (°C)</label> | |
| <input type="number" id="redox-temp" value="25"> | |
| </div> | |
| </div> | |
| <button type="button" class="toggle-advanced" id="toggle-redox-advanced"> | |
| <i class="fas fa-chevron-down"></i> Advanced Options | |
| </button> | |
| <button id="calculate-redox" class="btn btn-calculate">Balance Reaction</button> | |
| <div id="redox-result" class="result-container"> | |
| <div class="result-title">Results</div> | |
| <div id="redox-value" class="result-value"></div> | |
| <div id="redox-details" style="margin-top: 15px;"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="history-container"> | |
| <h3>Calculation History</h3> | |
| <div id="history-list"></div> | |
| </div> | |
| <footer> | |
| <p>ChemCalc Pro © 2023 | Advanced Chemical Calculator for Professionals</p> | |
| <p>Disclaimer: Results should be verified with experimental data.</p> | |
| </footer> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Tab functionality | |
| const tabButtons = document.querySelectorAll('.tab-button'); | |
| const tabContents = document.querySelectorAll('.tab-content'); | |
| tabButtons.forEach(button => { | |
| button.addEventListener('click', () => { | |
| const tabId = button.getAttribute('data-tab'); | |
| // Update active tab button | |
| tabButtons.forEach(btn => btn.classList.remove('active')); | |
| button.classList.add('active'); | |
| // Show corresponding content | |
| tabContents.forEach(content => { | |
| content.classList.remove('active'); | |
| if(content.id === tabId) { | |
| content.classList.add('active'); | |
| } | |
| }); | |
| }); | |
| }); | |
| // Advanced options toggle | |
| const toggleConcAdvanced = document.getElementById('toggle-conc-advanced'); | |
| const concAdvanced = document.getElementById('conc-advanced'); | |
| toggleConcAdvanced.addEventListener('click', () => { | |
| concAdvanced.style.display = concAdvanced.style.display === 'none' ? 'block' : 'none'; | |
| toggleConcAdvanced.classList.toggle('collapsed'); | |
| }); | |
| const toggleRedoxAdvanced = document.getElementById('toggle-redox-advanced'); | |
| const redoxAdvanced = document.getElementById('redox-advanced'); | |
| toggleRedoxAdvanced.addEventListener('click', () => { | |
| redoxAdvanced.style.display = redoxAdvanced.style.display === 'none' ? 'block' : 'none'; | |
| toggleRedoxAdvanced.classList.toggle('collapsed'); | |
| }); | |
| // Periodic table elements | |
| const periodicElements = document.getElementById('periodic-elements'); | |
| const compoundFormula = document.getElementById('compound-formula'); | |
| const elements = [ | |
| { symbol: 'H', name: 'Hydrogen', number: 1, group: 'nonmetal' }, | |
| { symbol: 'He', name: 'Helium', number: 2, group: 'noble' }, | |
| { symbol: 'Li', name: 'Lithium', number: 3, group: 'alkali' }, | |
| { symbol: 'Be', name: 'Beryllium', number: 4, group: 'alkaline' }, | |
| { symbol: 'B', name: 'Boron', number: 5, group: 'metalloid' }, | |
| { symbol: 'C', name: 'Carbon', number: 6, group: 'nonmetal' }, | |
| { symbol: 'N', name: 'Nitrogen', number: 7, group: 'nonmetal' }, | |
| { symbol: 'O', name: 'Oxygen', number: 8, group: 'nonmetal' }, | |
| { symbol: 'F', name: 'Fluorine', number: 9, group: 'halogen' }, | |
| { symbol: 'Ne', name: 'Neon', number: 10, group: 'noble' }, | |
| { symbol: 'Na', name: 'Sodium', number: 11, group: 'alkali' }, | |
| { symbol: 'Mg', name: 'Magnesium', number: 12, group: 'alkaline' }, | |
| { symbol: 'Al', name: 'Aluminum', number: 13, group: 'post-transition' }, | |
| { symbol: 'Si', name: 'Silicon', number: 14, group: 'metalloid' }, | |
| { symbol: 'P', name: 'Phosphorus', number: 15, group: 'nonmetal' }, | |
| { symbol: 'S', name: 'Sulfur', number: 16, group: 'nonmetal' }, | |
| { symbol: 'Cl', name: 'Chlorine', number: 17, group: 'halogen' }, | |
| { symbol: 'Ar', name: 'Argon', number: 18, group: 'noble' }, | |
| { symbol: 'K', name: 'Potassium', number: 19, group: 'alkali' }, | |
| { symbol: 'Ca', name: 'Calcium', number: 20, group: 'alkaline' }, | |
| { symbol: 'Sc', name: 'Scandium', number: 21, group: 'transition' }, | |
| { symbol: 'Ti', name: 'Titanium', number: 22, group: 'transition' }, | |
| { symbol: 'V', name: 'Vanadium', number: 23, group: 'transition' }, | |
| { symbol: 'Cr', name: 'Chromium', number: 24, group: 'transition' }, | |
| { symbol: 'Mn', name: 'Manganese', number: 25, group: 'transition' }, | |
| { symbol: 'Fe', name: 'Iron', number: 26, group: 'transition' }, | |
| { symbol: 'Co', name: 'Cobalt', number: 27, group: 'transition' }, | |
| { symbol: 'Ni', name: 'Nickel', number: 28, group: 'transition' }, | |
| { symbol: 'Cu', name: 'Copper', number: 29, group: 'transition' }, | |
| { symbol: 'Zn', name: 'Zinc', number: 30, group: 'transition' }, | |
| { symbol: 'Ga', name: 'Gallium', number: 31, group: 'post-transition' }, | |
| { symbol: 'Ge', name: 'Germanium', number: 32, group: 'metalloid' }, | |
| { symbol: 'As', name: 'Arsenic', number: 33, group: 'metalloid' }, | |
| { symbol: 'Se', name: 'Selenium', number: 34, group: 'nonmetal' }, | |
| { symbol: 'Br', name: 'Bromine', number: 35, group: 'halogen' }, | |
| { symbol: 'Kr', name: 'Krypton', number: 36, group: 'noble' }, | |
| { symbol: 'Rb', name: 'Rubidium', number: 37, group: 'alkali' }, | |
| { symbol: 'Sr', name: 'Strontium', number: 38, group: 'alkaline' }, | |
| { symbol: 'Y', name: 'Yttrium', number: 39, group: 'transition' }, | |
| { symbol: 'Zr', name: 'Zirconium', number: 40, group: 'transition' }, | |
| { symbol: 'Nb', name: 'Niobium', number: 41, group: 'transition' }, | |
| { symbol: 'Mo', name: 'Molybdenum', number: 42, group: 'transition' }, | |
| { symbol: 'Tc', name: 'Technetium', number: 43, group: 'transition' }, | |
| { symbol: 'Ru', name: 'Ruthenium', number: 44, group: 'transition' }, | |
| { symbol: 'Rh', name: 'Rhodium', number: 45, group: 'transition' }, | |
| { symbol: 'Pd', name: 'Palladium', number: 46, group: 'transition' }, | |
| { symbol: 'Ag', name: 'Silver', number: 47, group: 'transition' }, | |
| { symbol: 'Cd', name: 'Cadmium', number: 48, group: 'transition' }, | |
| { symbol: 'In', name: 'Indium', number: 49, group: 'post-transition' }, | |
| { symbol: 'Sn', name: 'Tin', number: 50, group: 'post-transition' }, | |
| { symbol: 'Sb', name: 'Antimony', number: 51, group: 'metalloid' }, | |
| { symbol: 'Te', name: 'Tellurium', number: 52, group: 'metalloid' }, | |
| { symbol: 'I', name: 'Iodine', number: 53, group: 'halogen' }, | |
| { symbol: 'Xe', name: 'Xenon', number: 54, group: 'noble' }, | |
| { symbol: 'Cs', name: 'Cesium', number: 55, group: 'alkali' }, | |
| { symbol: 'Ba', name: 'Barium', number: 56, group: 'alkaline' }, | |
| { symbol: 'La', name: 'Lanthanum', number: 57, group: 'lanthanide' }, | |
| { symbol: 'Ce', name: 'Cerium', number: 58, group: 'lanthanide' }, | |
| { symbol: 'Pr', name: 'Praseodymium', number: 59, group: 'lanthanide' }, | |
| { symbol: 'Nd', name: 'Neodymium', number: 60, group: 'lanthanide' }, | |
| { symbol: 'Pm', name: 'Promethium', number: 61, group: 'lanthanide' }, | |
| { symbol: 'Sm', name: 'Samarium', number: 62, group: 'lanthanide' }, | |
| { symbol: 'Eu', name: 'Europium', number: 63, group: 'lanthanide' }, | |
| { symbol: 'Gd', name: 'Gadolinium', number: 64, group: 'lanthanide' }, | |
| { symbol: 'Tb', name: 'Terbium', number: 65, group: 'lanthanide' }, | |
| { symbol: 'Dy', name: 'Dysprosium', number: 66, group: 'lanthanide' }, | |
| { symbol: 'Ho', name: 'Holmium', number: 67, group: 'lanthanide' }, | |
| { symbol: 'Er', name: 'Erbium', number: 68, group: 'lanthanide' }, | |
| { symbol: 'Tm', name: 'Thulium', number: 69, group: 'lanthanide' }, | |
| { symbol: 'Yb', name: 'Ytterbium', number: 70, group: 'lanthanide' }, | |
| { symbol: 'Lu', name: 'Lutetium', number: 71, group: 'lanthanide' }, | |
| { symbol: 'Hf', name: 'Hafnium', number: 72, group: 'transition' }, | |
| { symbol: 'Ta', name: 'Tantalum', number: 73, group: 'transition' }, | |
| { symbol: 'W', name: 'Tungsten', number: 74, group: 'transition' }, | |
| { symbol: 'Re', name: 'Rhenium', number: 75, group: 'transition' }, | |
| { symbol: 'Os', name: 'Osmium', number: 76, group: 'transition' }, | |
| { symbol: 'Ir', name: 'Iridium', number: 77, group: 'transition' }, | |
| { symbol: 'Pt', name: 'Platinum', number: 78, group: 'transition' }, | |
| { symbol: 'Au', name: 'Gold', number: 79, group: 'transition' }, | |
| { symbol: 'Hg', name: 'Mercury', number: 80, group: 'transition' }, | |
| { symbol: 'Tl', name: 'Thallium', number: 81, group: 'post-transition' }, | |
| { symbol: 'Pb', name: 'Lead', number: 82, group: 'post-transition' }, | |
| { symbol: 'Bi', name: 'Bismuth', number: 83, group: 'post-transition' }, | |
| { symbol: 'Po', name: 'Polonium', number: 84, group: 'metalloid' }, | |
| { symbol: 'At', name: 'Astatine', number: 85, group: 'halogen' }, | |
| { symbol: 'Rn', name: 'Radon', number: 86, group: 'noble' }, | |
| { symbol: 'Fr', name: 'Francium', number: 87, group: 'alkali' }, | |
| { symbol: 'Ra', name: 'Radium', number: 88, group: 'alkaline' }, | |
| { symbol: 'Ac', name: 'Actinium', number: 89, group: 'actinide' }, | |
| { symbol: 'Th', name: 'Thorium', number: 90, group: 'actinide' }, | |
| { symbol: 'Pa', name: 'Protactinium', number: 91, group: 'actinide' }, | |
| { symbol: 'U', name: 'Uranium', number: 92, group: 'actinide' }, | |
| { symbol: 'Np', name: 'Neptunium', number: 93, group: 'actinide' }, | |
| { symbol: 'Pu', name: 'Plutonium', number: 94, group: 'actinide' }, | |
| // ... more elements if needed | |
| ]; | |
| // Create periodic table | |
| elements.forEach(element => { | |
| const elementDiv = document.createElement('div'); | |
| elementDiv.className = `element ${element.group}`; | |
| elementDiv.innerHTML = ` | |
| <div class="element-symbol">${element.symbol}</div> | |
| <div class="element-number">${element.number}</div> | |
| `; | |
| elementDiv.title = element.name; | |
| elementDiv.addEventListener('click', () => { | |
| if (compoundFormula) { | |
| compoundFormula.value += element.symbol; | |
| compoundFormula.focus(); | |
| } | |
| }); | |
| periodicElements.appendChild(elementDiv); | |
| }); | |
| // Molar mass calculation | |
| const molarMasses = { | |
| 'H': 1.008, 'He': 4.0026, 'Li': 6.94, 'Be': 9.0122, 'B': 10.81, | |
| 'C': 12.011, 'N': 14.007, 'O': 15.999, 'F': 18.998, 'Ne': 20.180, | |
| 'Na': 22.990, 'Mg': 24.305, 'Al': 26.982, 'Si': 28.085, 'P': 30.974, | |
| 'S': 32.06, 'Cl': 35.45, 'Ar': 39.948, 'K': 39.098, 'Ca': 40.078, | |
| 'Sc': 44.956, 'Ti': 47.867, 'V': 50.942, 'Cr': 51.996, 'Mn': 54.938, | |
| 'Fe': 55.845, 'Co': 58.933, 'Ni': 58.693, 'Cu': 63.546, 'Zn': 65.38, | |
| 'Ga': 69.723, 'Ge': 72.630, 'As': 74.922, 'Se': 78.971, 'Br': 79.904, | |
| 'Kr': 83.798, 'Rb': 85.468, 'Sr': 87.62, 'Y': 88.906, 'Zr': 91.224, | |
| 'Nb': 92.906, 'Mo': 95.95, 'Tc': 98, 'Ru': 101.07, 'Rh': 102.91, | |
| 'Pd': 106.42, 'Ag': 107.87, 'Cd': 112.41, 'In': 114.82, 'Sn': 118.71, | |
| 'Sb': 121.76, 'Te': 127.60, 'I': 126.90, 'Xe': 131.29, 'Cs': 132.91, | |
| 'Ba': 137.33, 'La': 138.91, 'Ce': 140.12, 'Pr': 140.91, 'Nd': 144.24, | |
| 'Pm': 145, 'Sm': 150.36, 'Eu': 151.96, 'Gd': 157.25, 'Tb': 158.93, | |
| 'Dy': 162.50, 'Ho': 164.93, 'Er': 167.26, 'Tm': 168.93, 'Yb': 173.05, | |
| 'Lu': 174.97, 'Hf': 178.49, 'Ta': 180.95, 'W': 183.84, 'Re': 186.21, | |
| 'Os': 190.23, 'Ir': 192.22, 'Pt': 195.08, 'Au': 196.97, 'Hg': 200.59, | |
| 'Tl': 204.38, 'Pb': 207.2, 'Bi': 208.98, 'Po': 209, 'At': 210, 'Rn': 222, | |
| 'Fr': 223, 'Ra': 226, 'Ac': 227, 'Th': 232.04, 'Pa': 231.04, 'U': 238.03, | |
| 'Np': 237, 'Pu': 244 | |
| }; | |
| document.getElementById('calculate-mass').addEventListener('click', calculateMolarMass); | |
| function calculateMolarMass() { | |
| const formula = document.getElementById('compound-formula').value.trim(); | |
| const massStr = document.getElementById('compound-mass').value; | |
| const massUnit = document.getElementById('mass-unit').value; | |
| if (!formula) { | |
| alert('Please enter a chemical formula'); | |
| return; | |
| } | |
| try { | |
| // Parse the chemical formula | |
| const parsedFormula = parseFormula(formula); | |
| let totalMass = 0; | |
| let compositionHTML = '<div>Elemental Composition:</div><ul>'; | |
| // Calculate molar mass | |
| for (const element in parsedFormula) { | |
| const count = parsedFormula[element]; | |
| const elementMass = molarMasses[element] || 0; | |
| totalMass += elementMass * count; | |
| // Add to composition list | |
| const elementObj = elements.find(e => e.symbol === element); | |
| const percent = ((elementMass * count) / totalMass * 100).toFixed(2); | |
| compositionHTML += `<li>${element} (${elementObj?.name || 'Unknown'}): ${count} atom${count > 1 ? 's' : ''} (${percent}%)</li>`; | |
| } | |
| compositionHTML += '</ul>'; | |
| // Display results | |
| const resultDiv = document.getElementById('mass-result'); | |
| document.getElementById('mass-value').textContent = `Molar Mass: ${totalMass.toFixed(4)} g/mol`; | |
| // Calculate moles if mass was provided | |
| if (massStr) { | |
| const mass = parseFloat(massStr); | |
| let convertedMass = mass; | |
| // Convert units if needed | |
| switch(massUnit) { | |
| case 'mg': convertedMass = mass / 1000; break; | |
| case 'kg': convertedMass = mass * 1000; break; | |
| } | |
| const moles = convertedMass / totalMass; | |
| document.getElementById('moles-value').textContent = `Moles: ${moles.toFixed(6)} mol`; | |
| } else { | |
| document.getElementById('moles-value').textContent = ''; | |
| } | |
| document.getElementById('composition').innerHTML = compositionHTML; | |
| resultDiv.classList.add('show'); | |
| // Add to history | |
| addToHistory(`Calculated molar mass for ${formula}: ${totalMass.toFixed(4)} g/mol`); | |
| } catch (error) { | |
| alert('Error parsing formula: ' + error.message); | |
| } | |
| } | |
| // Helper function to parse chemical formulas | |
| function parseFormula(formula) { | |
| const elements = {}; | |
| let currentElement = ''; | |
| let currentCount = 0; | |
| let i = 0; | |
| while (i < formula.length) { | |
| const c = formula[i]; | |
| // Check for uppercase letter (new element) | |
| if (c === c.toUpperCase() && c !== c.toLowerCase()) { | |
| // If we have a current element, add it to the result | |
| if (currentElement) { | |
| elements[currentElement] = (elements[currentElement] || 0) + (currentCount || 1); | |
| } | |
| // Start new element | |
| currentElement = c; | |
| i++; | |
| // Check for lowercase letters (element symbol with 2 letters) | |
| while (i < formula.length && formula[i] === formula[i].toLowerCase() && formula[i] !== formula[i].toUpperCase()) { | |
| currentElement += formula[i]; | |
| i++; | |
| } | |
| currentCount = 0; | |
| } | |
| // Check for digits (count of atoms) | |
| else if (c >= '0' && c <= '9') { | |
| currentCount = currentCount * 10 + parseInt(c); | |
| i++; | |
| } | |
| // Check for parentheses (grouping) | |
| else if (c === '(') { | |
| // If we have a current element, add it to the result | |
| if (currentElement) { | |
| elements[currentElement] = (elements[currentElement] || 0) + (currentCount || 1); | |
| } | |
| // Parse the group inside parentheses | |
| const groupEnd = findMatchingClosingParenthesis(formula, i); | |
| const groupContent = formula.substring(i + 1, groupEnd); | |
| const parsedGroup = parseFormula(groupContent); | |
| // Parse the count after the group | |
| let groupCount = 0; | |
| let j = groupEnd + 1; | |
| while (j < formula.length && formula[j] >= '0' && formula[j] <= '9') { | |
| groupCount = groupCount * 10 + parseInt(formula[j]); | |
| j++; | |
| } | |
| groupCount = groupCount || 1; | |
| // Add all elements from the group to the result | |
| for (const element in parsedGroup) { | |
| elements[element] = (elements[element] || 0) + parsedGroup[element] * groupCount; | |
| } | |
| i = j; | |
| currentElement = ''; | |
| currentCount = 0; | |
| } | |
| else { | |
| throw new Error(`Invalid character in formula: ${c}`); | |
| } | |
| } | |
| // Add the last element if it exists | |
| if (currentElement) { | |
| elements[currentElement] = (elements[currentElement] || 0) + (currentCount || 1); | |
| } | |
| return elements; | |
| } | |
| function findMatchingClosingParenthesis(str, pos) { | |
| let depth = 1; | |
| for (let i = pos + 1; i < str.length; i++) { | |
| if (str[i] === '(') depth++; | |
| else if (str[i] === ')') depth--; | |
| if (depth === 0) return i; | |
| } | |
| throw new Error('No matching closing parenthesis found'); | |
| } | |
| // Concentration calculator | |
| const concTypeSelect = document.getElementById('concentration-type'); | |
| concTypeSelect.addEventListener('change', updateConcInputs); | |
| function updateConcInputs() { | |
| const type = concTypeSelect.value; | |
| const concInputs = document.getElementById('conc-inputs'); | |
| const dilutionInputs = document.getElementById('dilution-inputs'); | |
| if (type === 'dilution') { | |
| concInputs.style.display = 'none'; | |
| dilutionInputs.style.display = 'block'; | |
| } else { | |
| concInputs.style.display = 'block'; | |
| dilutionInputs.style.display = 'none'; | |
| } | |
| } | |
| document.getElementById('calculate-conc').addEventListener('click', calculateConcentration); | |
| function calculateConcentration() { | |
| const type = concTypeSelect.value; | |
| const resultDiv = document.getElementById('conc-result'); | |
| try { | |
| if (type === 'dilution') { | |
| const initialConc = parseFloat(document.getElementById('initial-conc').value); | |
| const initialConcUnit = document.getElementById('initial-conc-unit').value; | |
| const initialVol = parseFloat(document.getElementById('initial-vol').value); | |
| const initialVolUnit = document.getElementById('initial-vol-unit').value; | |
| if (!initialConc || !initialVol) { | |
| alert('Please enter both initial concentration and volume'); | |
| return; | |
| } | |
| // Convert units if needed | |
| let conc = initialConc; | |
| if (initialConcUnit === 'mM') conc = conc / 1000; | |
| let vol = initialVol; | |
| if (initialVolUnit === 'mL') vol = vol / 1000; | |
| // Calculate dilution (M1V1 = M2V2) assuming final volume is known | |
| // For simplicity, we'll calculate final concentration based on assuming final volume is known from dilution | |
| // In a real app, you'd want more detailed inputs | |
| const finalConc = (conc * vol) / (vol + vol); // Assuming doubling volume | |
| document.getElementById('conc-value').innerHTML = ` | |
| <div>Initial Concentration: ${initialConc} ${initialConcUnit}</div> | |
| <div>Final Concentration: ${finalConc.toFixed(6)} M</div | |
| </html> |