diff options
Diffstat (limited to 'web-timeplot/src/main.js')
| -rw-r--r-- | web-timeplot/src/main.js | 275 |
1 files changed, 26 insertions, 249 deletions
diff --git a/web-timeplot/src/main.js b/web-timeplot/src/main.js index c9d11fb..e435193 100644 --- a/web-timeplot/src/main.js +++ b/web-timeplot/src/main.js @@ -1,8 +1,6 @@ import { Application } from 'pixi.js'; -import { WaterfallGraph } from './waterfall.js'; -import { PerformanceMetrics } from './metrics.js'; +import * as PIXI from 'pixi.js'; import { StateManager } from './state.js'; -import { example8_InteractiveDemo} from './example-usage.js'; // ============================================================================ // GLOBAL STATE @@ -14,26 +12,17 @@ const state = new StateManager(); // DOM references let dom = { container: null, - controls: {}, - display: {}, }; // Application instances let app = null; // PixiJS Application -let metrics = null; -let graphs = []; // Keep PixiJS graph instances outside reactive state - -// Vertical zoom dragging state -let isDraggingVerticalZoom = false; -let dragStartY = 0; -let dragStartZoom = 1.0; // ============================================================================ // APPLICATION ENTRY POINT // ============================================================================ document.addEventListener('DOMContentLoaded', async function() { - log('TimePlot starting...'); + log('Framework starting...'); log('init DOM'); await initDOM(); @@ -41,19 +30,10 @@ document.addEventListener('DOMContentLoaded', async function() { log('init PixiJS renderer'); await initRenderer(); - log('init graphs'); - await initGraphs(); - log('init services'); await initServices(); - log('setup controls'); - await setupControls(); - - log('setup state listeners'); - await setupStateListeners(); - - log('TimePlot ready'); + log('Framework ready - start prototyping!'); }); // ============================================================================ @@ -62,12 +42,10 @@ document.addEventListener('DOMContentLoaded', async function() { async function initDOM() { dom.container = document.getElementById('canvas-container'); - dom.controls.gridBtn = document.getElementById('toggle-grid'); - dom.controls.metricsBtn = document.getElementById('toggle-metrics'); - dom.controls.exportBtn = document.getElementById('export-metrics'); - dom.display.rendererType = document.getElementById('renderer-type'); - dom.display.metrics = document.getElementById('metrics-display'); - dom.display.timeScale = document.getElementById('time-scale'); + + if (!dom.container) { + throw new Error('Canvas container not found'); + } } async function initRenderer() { @@ -84,7 +62,7 @@ async function initRenderer() { await app.init({ preference: preference, width: window.innerWidth, - height: window.innerHeight - 60, // Account for controls + height: window.innerHeight, backgroundColor: 0x1a1a26, antialias: true, autoDensity: true, @@ -96,7 +74,6 @@ async function initRenderer() { // Store renderer info in state const rendererType = app.renderer.type; state.state.rendering.rendererType = rendererType; - dom.display.rendererType.textContent = rendererType; log(`Using renderer: ${rendererType}`); // Store canvas dimensions in state @@ -112,159 +89,26 @@ async function initRenderer() { } } -async function initGraphs() { - const width = app.screen.width; - const height = app.screen.height; - - // Left graph - const graph1 = new WaterfallGraph({ - x: 0, - y: 0, - width: width / 2, - height: height, - title: 'Frequency vs Time', - color: 0xff6666, - }); - - // Right graph - const graph2 = new WaterfallGraph({ - x: width / 2, - y: 0, - width: width / 2, - height: height, - title: 'Position vs Time', - color: 0x66ff66, - }); - - // Store graphs locally (PixiJS objects shouldn't be proxied) - graphs = [graph1, graph2]; - - // Add to stage - graphs.forEach(graph => { - app.stage.addChild(graph.container); - graph.setGridVisible(state.state.userPrefs.showGrid); - }); -} - async function initServices() { - // Initialize performance metrics - metrics = new PerformanceMetrics( - state.state.userPrefs.rollingWindow, - state.state.userPrefs.historyCapacity - ); - // Start animation loop app.ticker.add(update); log('Services initialized'); } -function setupControls() { - // Register input actions - state.registerAction('toggleGrid', toggleGrid); - state.registerAction('toggleMetrics', toggleMetrics); - state.registerAction('exportMetrics', exportMetrics); - - // Map keyboard keys to actions - state.mapKey('KeyG', 'toggleGrid'); - state.mapKey('KeyM', 'toggleMetrics'); - state.mapKey('KeyE', 'exportMetrics'); - - // Button controls - dom.controls.gridBtn.addEventListener('click', () => state.executeAction('toggleGrid')); - dom.controls.metricsBtn.addEventListener('click', () => state.executeAction('toggleMetrics')); - dom.controls.exportBtn.addEventListener('click', () => state.executeAction('exportMetrics')); - - // Keyboard controls via state's input action system - window.addEventListener('keydown', (e) => state.handleKeyboardEvent(e)); - - // Mouse controls for time scaling - dom.container.addEventListener('mousedown', handleMouseDown); - window.addEventListener('mousemove', handleMouseMove); - window.addEventListener('mouseup', handleMouseUp); - dom.container.addEventListener('contextmenu', (e) => e.preventDefault()); // Prevent context menu - - // Update button states - updateControlButtons(); -} - -function setupStateListeners() { - // React to showGrid changes - state.on('userPrefs.showGrid', ({ value }) => { - graphs.forEach(graph => graph.setGridVisible(value)); - updateControlButtons(); - log(`Grid: ${value ? 'ON' : 'OFF'}`); - }); - - // React to showMetrics changes - state.on('userPrefs.showMetrics', ({ value }) => { - updateControlButtons(); - log(`Metrics: ${value ? 'ON' : 'OFF'}`); - }); - - // React to vertical scale changes - state.on('time.verticalScale', ({ value }) => { - graphs.forEach(graph => graph.setVerticalScale(value)); - updateVerticalZoomDisplay(); - }); - - // React to pause state changes - state.on('time.isPaused', ({ value }) => { - log(`Time ${value ? 'PAUSED' : 'RESUMED'}`); - }); - - // React to speed changes - state.on('time.speed', ({ value }) => { - log(`Time speed: ${value.toFixed(1)}x`); - }); -} - // ============================================================================ // EVENT HANDLERS // ============================================================================ function handleResize() { const width = window.innerWidth; - const height = window.innerHeight - 60; + const height = window.innerHeight; app.renderer.resize(width, height); // Update state state.state.uiConfig.canvasWidth = width; state.state.uiConfig.canvasHeight = height; - - // Update graphs - if (graphs[0]) graphs[0].resize(0, 0, width / 2, height); - if (graphs[1]) graphs[1].resize(width / 2, 0, width / 2, height); -} - -function handleMouseDown(e) { - // Middle mouse button (button = 1) - if (e.button === 1) { - e.preventDefault(); - isDraggingVerticalZoom = true; - dragStartY = e.clientY; - dragStartZoom = state.state.time.verticalScale; - dom.container.style.cursor = 'ns-resize'; - } -} - -function handleMouseMove(e) { - if (!isDraggingVerticalZoom) return; - - const deltaY = dragStartY - e.clientY; // Inverted: drag up = zoom in - const sensitivity = 0.005; // Adjust sensitivity - const newZoom = dragStartZoom + (deltaY * sensitivity); - - // Update state (which will trigger graph updates via state listener) - state.state.time.verticalScale = Math.max(0.2, Math.min(3.0, newZoom)); -} - -function handleMouseUp(e) { - if (e.button === 1) { - isDraggingVerticalZoom = false; - dom.container.style.cursor = 'default'; - } } // ============================================================================ @@ -272,103 +116,36 @@ function handleMouseUp(e) { // ============================================================================ function update() { - metrics.beginFrame(); - metrics.beginUpdate(); - // Update time using state manager state.incrementTime(0.016); // ~60fps increment state.updateRealElapsed(); state.state.rendering.frameCounter++; - // Update each graph - graphs.forEach((graph, idx) => { - graph.update(state.state.time.current, idx); - }); - - const updateMs = metrics.endUpdate(); - - metrics.beginRender(); - // Rendering happens automatically via PixiJS - const renderMs = metrics.endRender(); - - // Calculate stats - const vertexCount = graphs.reduce((sum, g) => sum + g.getVertexCount(), 0); - const lineCount = graphs.reduce((sum, g) => sum + g.getLineCount(), 0); - - metrics.endFrame(updateMs, renderMs, vertexCount, lineCount); - - // Update health metrics in state (silently to avoid spamming events) - const currentHealth = state.state.health; - currentHealth.updateMs = updateMs; - currentHealth.renderMs = renderMs; - currentHealth.vertexCount = vertexCount; - currentHealth.lineCount = lineCount; - currentHealth.fps = metrics.getFPS(); - - // Update UI less frequently to prevent flickering - const frameCounter = state.state.rendering.frameCounter; - const interval = state.state.userPrefs.metricsUpdateInterval; - if (state.state.userPrefs.showMetrics && frameCounter % interval === 0) { - updateMetricsDisplay(); - } + // YOUR PROTOTYPE CODE GOES HERE + // Example: + // yourSprite.x += 1; + // yourGraphics.rotation += 0.01; } // ============================================================================ -// UI CONTROL FUNCTIONS +// UTILITIES // ============================================================================ -function toggleGrid() { - state.togglePref('showGrid'); -} - -function toggleMetrics() { - state.togglePref('showMetrics'); -} - -function exportMetrics() { - const csv = metrics.exportToCSV(); - const blob = new Blob([csv], { type: 'text/csv' }); - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = `timeplot-metrics-${Date.now()}.csv`; - a.click(); - URL.revokeObjectURL(url); - log('Metrics exported'); -} - -function updateMetricsDisplay() { - if (dom.display.metrics) { - dom.display.metrics.textContent = metrics.formatSummary(); - } -} - -function updateControlButtons() { - dom.controls.gridBtn.classList.toggle('active', state.state.userPrefs.showGrid); - dom.controls.metricsBtn.classList.toggle('active', state.state.userPrefs.showMetrics); -} - -function updateVerticalZoomDisplay() { - if (dom.display.timeScale) { - const zoom = state.state.time.verticalScale; - dom.display.timeScale.textContent = `${zoom.toFixed(2)}x`; - - // Color code: zoomed out = blue, normal = white, zoomed in = orange - if (zoom < 0.8) { - dom.display.timeScale.style.color = '#6af'; // Zoomed out (see more history) - } else if (zoom > 1.2) { - dom.display.timeScale.style.color = '#fa6'; // Zoomed in (see less history) - } else { - dom.display.timeScale.style.color = '#fff'; - } - } +function log(msg) { + console.log(`[Framework] ${msg}`); } // ============================================================================ -// UTILITIES +// EXPORTS FOR PROTOTYPING // ============================================================================ -function log(msg) { - console.log(`[TimePlot] ${msg}`); -} +// Export immediately available objects +window.PIXI = PIXI; +window.state = state; +window.log = log; + +// Export app after initialization (using a getter) +Object.defineProperty(window, 'pixiApp', { + get() { return app; } +}); |
