summaryrefslogtreecommitdiff
path: root/web-timeplot/src/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'web-timeplot/src/main.js')
-rw-r--r--web-timeplot/src/main.js275
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; }
+});