Browse Source
added a basic data explorer to the main working code. Use the Key (i) to launch it.
refactor/modularize
added a basic data explorer to the main working code. Use the Key (i) to launch it.
refactor/modularize
3 changed files with 208 additions and 6 deletions
@ -0,0 +1,148 @@ |
|||
// In src/dataExplorer.js
|
|||
|
|||
import { appState } from './state.js'; |
|||
|
|||
// --- DOM Elements ---
|
|||
const panel = document.getElementById('data-explorer-panel'); |
|||
const closeBtn = document.getElementById('close-explorer-btn'); |
|||
const footer = document.getElementById('explorer-footer'); |
|||
const plotBtn = document.getElementById('plot-selected-btn'); |
|||
|
|||
const tabs = { |
|||
tree: { btn: document.getElementById('tab-btn-tree'), panel: document.getElementById('tab-panel-tree') }, |
|||
grid: { btn: document.getElementById('tab-btn-grid'), panel: document.getElementById('tab-panel-grid') }, |
|||
plot: { btn: document.getElementById('tab-btn-plot'), panel: document.getElementById('tab-panel-plot') }, |
|||
}; |
|||
|
|||
const gridDiv = document.getElementById('data-grid'); |
|||
const chartCanvas = document.getElementById('data-chart'); |
|||
|
|||
let gridApi = null; // This will hold the grid's API
|
|||
let chartInstance = null; |
|||
let currentGridData = null; |
|||
|
|||
// --- AG Grid Configuration ---
|
|||
const gridOptions = { |
|||
rowData: [], |
|||
columnDefs: [], |
|||
defaultColDef: { |
|||
sortable: true, |
|||
filter: true, |
|||
resizable: true, |
|||
}, |
|||
// The onGridReady callback is no longer needed with the new createGrid method.
|
|||
}; |
|||
|
|||
// --- Chart.js Configuration ---
|
|||
function createChart(data, label) { |
|||
if (chartInstance) { |
|||
chartInstance.destroy(); |
|||
} |
|||
chartInstance = new Chart(chartCanvas, { |
|||
type: 'line', |
|||
data: { |
|||
labels: data.map((_, i) => i), |
|||
datasets: [{ |
|||
label: label, |
|||
data: data, |
|||
borderColor: 'rgba(75, 192, 192, 1)', |
|||
tension: 0.1, |
|||
}] |
|||
}, |
|||
options: { |
|||
responsive: true, |
|||
maintainAspectRatio: false, |
|||
} |
|||
}); |
|||
} |
|||
|
|||
// --- Core Functions ---
|
|||
|
|||
function switchTab(targetTab) { |
|||
Object.values(tabs).forEach(tab => { |
|||
tab.panel.classList.add('hidden'); |
|||
tab.btn.classList.remove('border-blue-500'); |
|||
tab.btn.classList.add('text-gray-500', 'dark:text-gray-400'); |
|||
}); |
|||
|
|||
tabs[targetTab].panel.classList.remove('hidden'); |
|||
tabs[targetTab].btn.classList.add('border-blue-500'); |
|||
tabs[targetTab].btn.classList.remove('text-gray-500', 'dark:text-gray-400'); |
|||
|
|||
footer.classList.toggle('hidden', targetTab !== 'grid'); |
|||
} |
|||
|
|||
function createTreeView(data) { |
|||
const pre = document.createElement('pre'); |
|||
pre.textContent = JSON.stringify(data, (key, value) => { |
|||
if (key.startsWith('_')) return undefined; |
|||
return value; |
|||
}, 2); |
|||
return pre; |
|||
} |
|||
|
|||
export function showExplorer() { |
|||
panel.classList.remove('hidden'); |
|||
updateExplorer(); |
|||
} |
|||
|
|||
export function hideExplorer() { |
|||
panel.classList.add('hidden'); |
|||
} |
|||
|
|||
export function updateExplorer() { |
|||
if (panel.classList.contains('hidden')) return; |
|||
const frame = appState.vizData?.radarFrames[appState.currentFrame]; |
|||
if (!frame) return; |
|||
tabs.tree.panel.innerHTML = ''; |
|||
tabs.tree.panel.appendChild(createTreeView({ |
|||
currentFrame: appState.currentFrame, |
|||
frameData: frame |
|||
})); |
|||
} |
|||
|
|||
export function displayInGrid(data, title) { |
|||
if (!data || data.length === 0 || !gridApi) return; |
|||
|
|||
currentGridData = data; |
|||
const columns = Object.keys(data[0]).map(key => ({ field: key })); |
|||
|
|||
gridApi.setGridOption('columnDefs', columns); |
|||
gridApi.setGridOption('rowData', data); |
|||
|
|||
tabs.grid.btn.textContent = `Grid View: ${title}`; |
|||
switchTab('grid'); |
|||
} |
|||
|
|||
// --- Event Listeners ---
|
|||
closeBtn.addEventListener('click', hideExplorer); |
|||
|
|||
Object.keys(tabs).forEach(key => { |
|||
tabs[key].btn.addEventListener('click', () => switchTab(key)); |
|||
}); |
|||
|
|||
plotBtn.addEventListener('click', () => { |
|||
// --- START: MODIFIED LOGIC ---
|
|||
const focusedCell = gridApi.getFocusedCell(); |
|||
if (!focusedCell) { |
|||
alert("Please click a column header to select it for plotting."); |
|||
return; |
|||
} |
|||
|
|||
const colId = focusedCell.column.getColId(); |
|||
// --- END: MODIFIED LOGIC ---
|
|||
|
|||
const plotData = currentGridData.map(row => row[colId]).filter(val => typeof val === 'number'); |
|||
|
|||
if (plotData.length > 0) { |
|||
createChart(plotData, colId); |
|||
switchTab('plot'); |
|||
} else { |
|||
alert("The selected column contains no numeric data to plot."); |
|||
} |
|||
}); |
|||
|
|||
// --- START: THIS IS THE MAIN FIX ---
|
|||
// Initialize the grid using the new createGrid method and store its API.
|
|||
gridApi = agGrid.createGrid(gridDiv, gridOptions); |
|||
// --- END: THIS IS THE MAIN FIX ---
|
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue