// Current Dimension / telemetry panel (extracted from Sidebar.js in H4 4.5). // Shows the selected dimension index + label, the [ETIQUETAR]/[NOMBRAR (IA)] // triggers, and the ANALYZE interpretation block. import { STATE, saveLabel, getMaxDimensions } from '../../core/State.js'; import { updateHUD } from '../HUD.js'; import { getHighVarianceDimensions } from '../../visualizer/ReliefMath.js'; /** @typedef {import('../types.js').PanelContext} PanelContext */ /** * Build the telemetry card and wire labeling + analysis triggers. * @param {PanelContext} ctx * @returns {HTMLElement} */ export function buildTelemetryPanel(ctx) { const { showCustomModal, showNamingModal } = ctx; const initialMaxDim = getMaxDimensions() - 1; const telemetry = document.createElement('div'); telemetry.id = 'telemetry-section'; telemetry.className = 'section-card'; telemetry.style.cssText = "text-align: center;"; telemetry.innerHTML = `
Current Dimension
IDX:
[LABEL] [🤖 NAME (AI)]
${STATE.dimensionStrengthLimit}
INTERPRETATION:
[Waiting...]
`; // Set up Dimension label prompt overlay & API analysis triggers setTimeout(() => { const handleLabeling = (e) => { e.stopPropagation(); const currentIdx = STATE.currentSelectedIndex; const prefix = (STATE.featureSpace || 'RAW').toLowerCase(); const currentLabel = STATE.dimensionLabels[`${prefix}_${currentIdx}`] || ""; const content = `

Assign a custom tag to explain the conceptual axis of Dimension ${currentIdx}.

`; showCustomModal({ title: `Label Dimension ${currentIdx}`, contentHTML: content, confirmText: "Save", cancelText: "Cancel", onConfirm: (overlay) => { const input = overlay.querySelector('#modal-label-input'); if (input) { saveLabel(currentIdx, input.value.trim()); updateHUD(); } } }); setTimeout(() => { const input = document.getElementById('modal-label-input'); if (input) { input.focus(); input.select(); } }, 50); }; const labelText = document.getElementById('hud-dim-label'); const triggerText = document.getElementById('btn-trigger-label'); const aiTriggerText = document.getElementById('btn-ai-label-trigger'); if (labelText) labelText.onclick = handleLabeling; if (triggerText) triggerText.onclick = handleLabeling; if (aiTriggerText) { aiTriggerText.onclick = (e) => { e.stopPropagation(); showNamingModal(STATE.currentSelectedIndex); }; } const analyzeBtn = document.getElementById('btn-analyze-dim'); if (analyzeBtn) { analyzeBtn.onclick = async (e) => { e.stopPropagation(); const labelEl = document.getElementById('dim-interp-label'); const inputEl = document.getElementById('telemetry-idx'); let targetIdx = STATE.currentSelectedIndex; if (inputEl) { const raw = parseInt(inputEl.value, 10); const maxDim = getMaxDimensions() - 1; if (!isNaN(raw) && raw >= 0 && raw <= maxDim) { targetIdx = raw; } else { showCustomModal({ title: "Invalid Input", contentHTML: `

Dimension must be between 0 and ${maxDim}

`, confirmText: "OK", isAlert: true }); return; } } if (labelEl) labelEl.innerHTML = '⏳ Analyzing...'; if (STATE.provider) { STATE.currentSelectedIndex = targetIdx; STATE.hoveredDimension = targetIdx; const analysis = await STATE.provider.getDimensionAnalysis(targetIdx); if (analysis) { STATE.currentAnalysis = { ...analysis, index: targetIdx }; updateHUD(); } else { if (labelEl) labelEl.innerText = "Analysis Failed"; } } }; } // Listen to AI Naming trigger from DimensionInspector (circular-dep free) document.addEventListener('open-naming-modal', (e) => { showNamingModal(e.detail.dimIndex); }); // Wire variance slider & select (Phase 5) const strengthSlider = document.getElementById('dimension-strength-slider'); const strengthVal = document.getElementById('dimension-strength-val'); const telemetryDimSelect = document.getElementById('telemetry-dim-select'); if (strengthSlider) { strengthSlider.oninput = function() { const val = parseInt(this.value, 10); STATE.dimensionStrengthLimit = val; if (strengthVal) strengthVal.textContent = val; refreshAllDimensionSelects(); }; } if (telemetryDimSelect) { telemetryDimSelect.onchange = function() { const val = parseInt(this.value, 10); STATE.currentSelectedIndex = val; const idxInput = document.getElementById('telemetry-idx'); if (idxInput) idxInput.value = val; updateHUD(); }; } refreshAllDimensionSelects(); }, 0); return telemetry; } /** * Recalcula y repopula todos los dropdowns de selección de dimensiones en la app. * Filtra según la varianza y el límite configurado en `STATE.dimensionStrengthLimit`. */ export function refreshAllDimensionSelects() { const limit = STATE.dimensionStrengthLimit || 100; const matrix = STATE.reliefData ? STATE.reliefData.matrix : null; const highVarDims = getHighVarianceDimensions(matrix, limit); const prefix = (STATE.featureSpace || 'RAW').toLowerCase(); const populateSelect = (selectEl, currentVal) => { if (!selectEl) return; selectEl.innerHTML = ''; highVarDims.forEach(({ dimIndex, variance }) => { const savedName = STATE.dimensionLabels ? STATE.dimensionLabels[`${prefix}_${dimIndex}`] : null; let label = savedName ? `#${dimIndex} [${savedName}]` : `#${dimIndex}`; if (variance > 0) { label += ` (var: ${variance.toFixed(4)})`; } const opt = document.createElement('option'); opt.value = dimIndex; opt.textContent = label; selectEl.appendChild(opt); }); // Select current value if it exists in the list if (currentVal !== undefined && Array.from(selectEl.options).some(o => parseInt(o.value) === currentVal)) { selectEl.value = currentVal; } }; // 1. Update Telemetry Panel selector const telemetrySelect = document.getElementById('telemetry-dim-select'); populateSelect(telemetrySelect, STATE.currentSelectedIndex); // 2. Update Relief Panel selector const reliefSelect = document.getElementById('inspect-dim-select'); populateSelect(reliefSelect, STATE.reliefInspectDim); // 3. Update Fullscreen Dimension Inspector selector const inspectorSelect = document.getElementById('inspector-dim-select-dropdown'); populateSelect(inspectorSelect, STATE.reliefInspectDim); } if (typeof window !== 'undefined') { window.refreshAllDimensionSelects = refreshAllDimensionSelects; }