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> |