/** * MatrixBuilder — Size selector (2x2/3x3/4x4), input grid, operation buttons */ const MatrixBuilder = (() => { let container = null; let currentSize = 3; function render() { container.innerHTML = `
`; renderGrid(); } function renderGrid() { const gridContainer = document.getElementById('matrixGridContainer'); if (!gridContainer) return; let html = `
`; for (let i = 0; i < currentSize; i++) { for (let j = 0; j < currentSize; j++) { html += ``; } } html += '
'; gridContainer.innerHTML = html; } function getMatrix() { const M = []; let hasEmpty = false; for (let i = 0; i < currentSize; i++) { const row = []; for (let j = 0; j < currentSize; j++) { const cell = document.getElementById(`cell-${i}-${j}`); if (!cell) return null; const val = cell.value.trim(); if (val === '') { cell.classList.add('matrix-grid__cell--error'); hasEmpty = true; } else { cell.classList.remove('matrix-grid__cell--error'); } const num = parseFloat(val); if (isNaN(num)) { cell.classList.add('matrix-grid__cell--error'); hasEmpty = true; } row.push(num || 0); } M.push(row); } if (hasEmpty) { showError('Completá todas las celdas con valores numéricos.'); return null; } hideError(); return M; } function showError(msg) { const el = document.getElementById('matrixError'); if (el) { el.textContent = msg; el.classList.add('error-message--visible'); } } function hideError() { const el = document.getElementById('matrixError'); if (el) el.classList.remove('error-message--visible'); } function showResult(title, value, steps) { const resultEl = document.getElementById('matrixResult'); const titleEl = document.getElementById('resultTitle'); const valueEl = document.getElementById('resultValue'); const stepsEl = document.getElementById('resultSteps'); titleEl.textContent = title; resultEl.classList.add('matrix-result--visible'); // Render value if (typeof value === 'number') { if (typeof KatexRenderer !== 'undefined') { KatexRenderer.renderDisplay(valueEl, `\\text{${title}} = ${MathEngine.fmtNum(value)}`); } else { valueEl.textContent = `${title} = ${value}`; } } else if (Array.isArray(value) && Array.isArray(value[0])) { if (typeof KatexRenderer !== 'undefined') { KatexRenderer.renderDisplay(valueEl, MathEngine.matToLatex(value)); } else { valueEl.textContent = JSON.stringify(value); } } else if (Array.isArray(value)) { if (typeof KatexRenderer !== 'undefined') { KatexRenderer.renderDisplay(valueEl, MathEngine.vecToLatex(value)); } else { valueEl.textContent = JSON.stringify(value); } } else if (typeof value === 'object' && value !== null) { valueEl.textContent = JSON.stringify(value); } else if (typeof KatexRenderer !== 'undefined') { KatexRenderer.renderDisplay(valueEl, String(value)); } else { valueEl.textContent = String(value); } // Render steps stepsEl.innerHTML = ''; if (steps && steps.length > 0) { const ol = document.createElement('ol'); ol.className = 'matrix-result__steps'; steps.forEach((step, idx) => { const li = document.createElement('li'); li.className = 'matrix-result__step'; const descDiv = document.createElement('div'); descDiv.textContent = step.desc; const exprDiv = document.createElement('div'); if (typeof KatexRenderer !== 'undefined') { KatexRenderer.renderDisplay(exprDiv, step.latex || step.expression || ''); } else { exprDiv.textContent = step.latex || step.expression || ''; } li.appendChild(descDiv); li.appendChild(exprDiv); ol.appendChild(li); }); stepsEl.appendChild(ol); } } function executeOperation(op) { const M = getMatrix(); if (!M) return; let result; try { const ME = MathEngine; switch (op) { case 'determinant': if (currentSize === 2) result = ME.determinant.det2x2(M); else if (currentSize === 3) result = ME.determinant.det3x3Sarrus(M); else result = ME.determinant.det(M); break; case 'det-sarrus': if (currentSize !== 3) { showError('Sarrus solo aplica a matrices 3×3.'); return; } result = ME.determinant.det3x3Sarrus(M); break; case 'det-triangular': result = ME.determinant.detByTriangularization(M); break; case 'transpose': result = ME.matrix.transpose(M); break; case 'trace': result = ME.matrix.trace(M); break; case 'rank': result = ME.system.rank(M); break; case 'inverse': if (currentSize === 2) result = ME.inverse.inverse2x2(M); else result = ME.inverse.inverse(M); break; default: showError('Operación no reconocida.'); return; } if (result.error) { showError(result.error); return; } const titles = { 'determinant': 'Determinante', 'det-sarrus': 'Determinante (Sarrus)', 'det-triangular': 'Determinante (Triangularización)', 'transpose': 'Traspuesta', 'trace': 'Traza', 'rank': 'Rango', 'inverse': 'Inversa' }; showResult(titles[op] || op, result.value, result.steps); } catch (e) { showError('Error: ' + e.message); } } function clearGrid() { for (let i = 0; i < currentSize; i++) for (let j = 0; j < currentSize; j++) { const cell = document.getElementById(`cell-${i}-${j}`); if (cell) { cell.value = ''; cell.classList.remove('matrix-grid__cell--error'); } } const resultEl = document.getElementById('matrixResult'); if (resultEl) resultEl.classList.remove('matrix-result--visible'); hideError(); } function fillExample() { const examples = { 2: [[1, 2], [3, 4]], 3: [[1, 2, 3], [4, 5, 2], [6, 3, 1]], 4: [[1, 2, 0, 1], [3, 0, 1, 2], [1, 1, 2, 0], [2, 3, 1, 1]] }; const ex = examples[currentSize]; for (let i = 0; i < currentSize; i++) for (let j = 0; j < currentSize; j++) { const cell = document.getElementById(`cell-${i}-${j}`); if (cell) cell.value = ex[i][j]; } } function handleSizeChange(e) { currentSize = parseInt(e.target.value); renderGrid(); const resultEl = document.getElementById('matrixResult'); if (resultEl) resultEl.classList.remove('matrix-result--visible'); hideError(); } function handleOpClick(e) { const btn = e.target.closest('[data-op]'); if (!btn) return; executeOperation(btn.dataset.op); } function handleActionClick(e) { const btn = e.target.closest('[data-action]'); if (!btn) return; const action = btn.dataset.action; if (action === 'clear') clearGrid(); else if (action === 'example') fillExample(); } function init(el) { container = el; render(); container.addEventListener('change', (e) => { if (e.target.id === 'matrixSize') handleSizeChange(e); }); container.addEventListener('click', handleOpClick); container.addEventListener('click', handleActionClick); } function destroy() { if (container) { container.innerHTML = ''; } container = null; } return { init, destroy, clearGrid, fillExample }; })();