Area and Volume Calculator
Three tools in one: area of 2D shapes, volume of 3D solids, and a missing-dimension solver.
Every answer comes with the full working shown step by step.
Area of a 2D shape
Pick a shape, enter its dimensions. The calculator shows each step.
Volume of a 3D solid
Pick a solid, enter its dimensions. The calculator shows each step.
Find a missing dimension
Know the area or volume but not one side? Enter what you know and solve backwards.
"use strict"; /* === PURE FUNCTIONS (extracted by tests/test_tool.js; keep DOM-free) === */ var AV_PI = Math.PI; function avRound2(v){ return Math.round(v * 100) / 100; } function avArea(kind, d){ /* d: dimension object. Returns {exact, exactText, decimal} or {error} */ function pos(v){ return !(!(typeof v === 'number') || !isFinite(v) || !(v > 0)); } if (kind === 'rect'){ if (!pos(d.l) || !pos(d.w)) return { error: 'Length and width must be positive numbers.' }; var A = d.l * d.w; return { exact: A, exactText: String(avRound2(A)), decimal: avRound2(A), unit: 'square units', steps: ['A = l \u00D7 w', 'A = ' + d.l + ' \u00D7 ' + d.w + ' = ' + avRound2(A)] }; } if (kind === 'tri'){ if (!pos(d.b) || !pos(d.h)) return { error: 'Base and height must be positive numbers.' }; var At = d.b * d.h / 2; return { exact: At, exactText: String(avRound2(At)), decimal: avRound2(At), unit: 'square units', steps: ['A = \u00BD \u00D7 b \u00D7 h', 'A = \u00BD \u00D7 ' + d.b + ' \u00D7 ' + d.h + ' = ' + avRound2(At), 'Remember: \u201Ctriangle takes half\u201D.'] }; } if (kind === 'para'){ if (!pos(d.b) || !pos(d.h)) return { error: 'Base and height must be positive numbers.' }; var Ap = d.b * d.h; return { exact: Ap, exactText: String(avRound2(Ap)), decimal: avRound2(Ap), unit: 'square units', steps: ['A = b \u00D7 h', 'A = ' + d.b + ' \u00D7 ' + d.h + ' = ' + avRound2(Ap), 'Use the vertical height, not the slanted side.'] }; } if (kind === 'trap'){ if (!pos(d.b1) || !pos(d.b2) || !pos(d.h)) return { error: 'Both bases and the height must be positive numbers.' }; var Az = (d.b1 + d.b2) * d.h / 2; return { exact: Az, exactText: String(avRound2(Az)), decimal: avRound2(Az), unit: 'square units', steps: ['A = \u00BD \u00D7 (b\u2081 + b\u2082) \u00D7 h', 'A = \u00BD \u00D7 (' + d.b1 + ' + ' + d.b2 + ') \u00D7 ' + d.h + ' = ' + avRound2(Az)] }; } if (kind === 'circ' || kind === 'circd'){ var r = (kind === 'circ') ? d.r : d.d / 2; if (!pos(r)) return { error: (kind === 'circ' ? 'Radius' : 'Diameter') + ' must be a positive number.' }; var coef = r * r; return { exact: coef * AV_PI, exactText: (coef === 1 ? '\u03C0' : coef + '\u03C0'), decimal: avRound2(coef * AV_PI), unit: 'square units', steps: (kind === 'circd' ? ['Halve the diameter first: r = ' + d.d + ' \u00F7 2 = ' + r + '.'] : []) .concat(['A = \u03C0r\u00B2 = \u03C0 \u00D7 ' + r + '\u00B2 = ' + (coef === 1 ? '\u03C0' : coef + '\u03C0'), 'Decimal: ' + (coef === 1 ? '\u03C0' : coef + '\u03C0') + ' \u2248 ' + avRound2(coef * AV_PI)]) }; } return { error: 'Unknown shape.' }; } function avVolume(kind, d){ function pos(v){ return !(!(typeof v === 'number') || !isFinite(v) || !(v > 0)); } if (kind === 'cube'){ if (!pos(d.s)) return { error: 'Side length must be a positive number.' }; var V = d.s * d.s * d.s; return { exact: V, exactText: String(avRound2(V)), decimal: avRound2(V), unit: 'cubic units', steps: ['V = s\u00B3 = ' + d.s + ' \u00D7 ' + d.s + ' \u00D7 ' + d.s + ' = ' + avRound2(V)] }; } if (kind === 'prism'){ if (!pos(d.l) || !pos(d.w) || !pos(d.h)) return { error: 'All three edges must be positive numbers.' }; var Vp = d.l * d.w * d.h; return { exact: Vp, exactText: String(avRound2(Vp)), decimal: avRound2(Vp), unit: 'cubic units', steps: ['Base area = ' + d.l + ' \u00D7 ' + d.w + ' = ' + avRound2(d.l * d.w), 'V = (base area) \u00D7 height = ' + avRound2(d.l * d.w) + ' \u00D7 ' + d.h + ' = ' + avRound2(Vp)] }; } if (kind === 'cyl'){ if (!pos(d.r) || !pos(d.h)) return { error: 'Radius and height must be positive numbers.' }; var coef = d.r * d.r * d.h; return { exact: coef * AV_PI, exactText: (coef === 1 ? '\u03C0' : coef + '\u03C0'), decimal: avRound2(coef * AV_PI), unit: 'cubic units', steps: ['V = (area of circular base) \u00D7 height = \u03C0r\u00B2h', 'V = \u03C0 \u00D7 ' + d.r + '\u00B2 \u00D7 ' + d.h + ' = ' + (coef === 1 ? '\u03C0' : coef + '\u03C0'), 'Decimal: \u2248 ' + avRound2(coef * AV_PI)] }; } return { error: 'Unknown solid.' }; } function avMissing(kind, d){ function pos(v){ return !(!(typeof v === 'number') || !isFinite(v) || !(v > 0)); } if (kind === 'rectw'){ if (!pos(d.A) || !pos(d.l)) return { error: 'Area and length must be positive numbers.' }; var w = d.A / d.l; return { value: avRound2(w), label: 'width', steps: ['w = A \u00F7 l = ' + d.A + ' \u00F7 ' + d.l + ' = ' + avRound2(w)] }; } if (kind === 'trih'){ if (!pos(d.A) || !pos(d.b)) return { error: 'Area and base must be positive numbers.' }; var h = 2 * d.A / d.b; return { value: avRound2(h), label: 'height', steps: ['From A = \u00BD \u00D7 b \u00D7 h: h = 2A \u00F7 b', 'h = (2 \u00D7 ' + d.A + ') \u00F7 ' + d.b + ' = ' + avRound2(h)] }; } if (kind === 'circr'){ if (!pos(d.A)) return { error: 'Area must be a positive number.' }; var r = Math.sqrt(d.A / AV_PI); return { value: avRound2(r), label: 'radius', steps: ['From A = \u03C0r\u00B2: r = \u221A(A \u00F7 \u03C0)', 'r = \u221A(' + d.A + ' \u00F7 \u03C0) = \u221A' + avRound2(d.A / AV_PI) + ' = ' + avRound2(r)] }; } if (kind === 'cylh'){ if (!pos(d.V) || !pos(d.r)) return { error: 'Volume and radius must be positive numbers.' }; var hh = d.V / (AV_PI * d.r * d.r); return { value: avRound2(hh), label: 'height', steps: ['From V = \u03C0r\u00B2h: h = V \u00F7 (\u03C0r\u00B2)', 'h = ' + d.V + ' \u00F7 (\u03C0 \u00D7 ' + d.r + '\u00B2) = ' + avRound2(hh)] }; } return { error: 'Unknown problem type.' }; } /* === END PURE FUNCTIONS === */
/* ---------- DOM wiring ---------- */ function el(id){ return document.getElementById(id); } function showErr(id, msg){ var e = el(id); if (msg){ e.textContent = msg; e.classList.add('show'); } else { e.classList.remove('show'); } } function stepList(ulEl, steps){ ulEl.innerHTML = steps.map(function(s){ return '
'; }).join(''); } function numOrNull(v){ var n = parseFloat(String(v).trim()); return (String(v).trim() === '' || !isFinite(n)) ? null : n; }
var SHAPES_A = { rect: { fb: 'A = l \u00D7 w', dims: [['l','Length'],['w','Width']] }, tri: { fb: 'A = \u00BD \u00D7 b \u00D7 h', dims: [['b','Base'],['h','Height']] }, para: { fb: 'A = b \u00D7 h (vertical height, not the slanted side)', dims: [['b','Base'],['h','Height']] }, trap: { fb: 'A = \u00BD \u00D7 (b\u2081 + b\u2082) \u00D7 h', dims: [['b1','Base 1'],['b2','Base 2'],['h','Height']] }, circ: { fb: 'A = \u03C0r\u00B2 (radius, not diameter)', dims: [['r','Radius']] }, circd: { fb: 'A = \u03C0r\u00B2 \u2014 halve the diameter first', dims: [['d','Diameter']] } }; var SHAPES_V = { cube: { fb: 'V = s\u00B3', dims: [['s','Side length']] }, prism: { fb: 'V = l \u00D7 w \u00D7 h = (base area) \u00D7 height', dims: [['l','Length'],['w','Width'],['h','Height']] }, cyl: { fb: 'V = \u03C0r\u00B2h = (circular base area) \u00D7 height', dims: [['r','Radius'],['h','Height']] } }; var SHAPES_M = { rectw: { fb: 'w = A \u00F7 l', dims: [['A','Area'],['l','Length']] }, trih: { fb: 'h = 2A \u00F7 b', dims: [['A','Area'],['b','Base']] }, circr: { fb: 'r = \u221A(A \u00F7 \u03C0)', dims: [['A','Area']] }, cylh: { fb: 'h = V \u00F7 (\u03C0r\u00B2)', dims: [['V','Volume'],['r','Radius']] } };
function buildDims(containerId, def, prefix){ var c = el(containerId); c.innerHTML = def.dims.map(function(dm){ return '
'; }).join(''); } function readDims(def, prefix){ var d = {}, bad = false; def.dims.forEach(function(dm){ var v = numOrNull(el(prefix + dm[0]).value); if (v === null) bad = true; d[dm[0]] = v; }); return bad ? null : d; } function wireCalc(kind){ var sel = el(kind === 'A' ? 'shapeA' : kind === 'V' ? 'shapeV' : 'shapeM'); var defs = kind === 'A' ? SHAPES_A : kind === 'V' ? SHAPES_V : SHAPES_M; function refresh(){ var def = defs[sel.value]; el(kind === 'A' ? 'fbA' : kind === 'V' ? 'fbV' : 'fbM').textContent = def.fb; buildDims(kind === 'A' ? 'dimsA' : kind === 'V' ? 'dimsV' : 'dimsM', def, 'in' + kind); } sel.addEventListener('change', refresh); refresh(); return function(){ var def = defs[sel.value]; var d = readDims(def, 'in' + kind); var errId = 'err' + kind, resId = 'res' + kind, ansId = 'ans' + kind, stepsId = 'steps' + kind; showErr(errId, ''); if (!d){ showErr(errId, 'Please enter all dimensions as positive numbers.'); el(resId).classList.remove('show'); return; } var r = kind === 'M' ? avMissing(sel.value, d) : kind === 'V' ? avVolume(sel.value, d) : avArea(sel.value, d); if (r.error){ showErr(errId, r.error); el(resId).classList.remove('show'); return; } if (kind === 'M'){ el(ansId).innerHTML = 'The ' + r.label + ' is ' + r.value + ''; } else { el(ansId).innerHTML = (kind === 'A' ? 'Area' : 'Volume') + ' = ' + r.exactText + '' + ' \u2248 ' + r.decimal + ' ' + r.unit; } stepList(el(stepsId), r.steps); el(resId).classList.add('show'); }; }
document.querySelectorAll('.tabbtn').forEach(function(btn){ btn.addEventListener('click', function(){ document.querySelectorAll('.tabbtn').forEach(function(b){ b.classList.remove('active'); }); document.querySelectorAll('.panel').forEach(function(p){ p.classList.remove('active'); }); btn.classList.add('active'); el(btn.dataset.tab).classList.add('active'); }); });
el('calcA').addEventListener('click', wireCalc('A')); el('calcV').addEventListener('click', wireCalc('V')); el('calcM').addEventListener('click', wireCalc('M'));