summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgrothedev <grothedev@gmail.com>2025-10-02 20:27:45 -0400
committergrothedev <grothedev@gmail.com>2025-10-02 20:27:45 -0400
commitebcacda7c62454806740dd62260e46d6597692a7 (patch)
tree0dd32343bf2982c5a2b6c4f0baea04613cdcdb04
parent39124e6854b2740e9f30c058e873355dfd739a4e (diff)
adapt to my js architecture
-rw-r--r--web-timeplot/src/main.js427
-rw-r--r--web-timeplot/src/template-for-standard-site.js75
2 files changed, 324 insertions, 178 deletions
diff --git a/web-timeplot/src/main.js b/web-timeplot/src/main.js
index 0d065f7..abcd72f 100644
--- a/web-timeplot/src/main.js
+++ b/web-timeplot/src/main.js
@@ -2,219 +2,290 @@ import { Application } from 'pixi.js';
import { WaterfallGraph } from './waterfall.js';
import { PerformanceMetrics } from './metrics.js';
-class TimePlot {
- constructor() {
- this.app = null;
- this.graphs = [];
- this.metrics = new PerformanceMetrics(60, 10000);
- this.showMetrics = true;
- this.showGrid = true;
- this.time = 0;
- }
-
- async init() {
- const container = document.getElementById('canvas-container');
-
- // Try WebGPU first, fallback to WebGL
- let preferredRenderer = 'webgpu';
- let preference = 'webgpu';
-
- // Check WebGPU availability
- if (!navigator.gpu) {
- console.log('WebGPU not available, using WebGL');
- preferredRenderer = 'webgl';
- preference = 'webgl';
- }
+// ============================================================================
+// GLOBAL STATE
+// ============================================================================
+
+let env = {};
+let cfg = {
+ showGrid: true,
+ showMetrics: true,
+ rollingWindow: 60,
+ historyCapacity: 10000,
+};
+
+let dom = {
+ container: null,
+ controls: {},
+ display: {},
+};
+
+let app = null; // PixiJS Application
+let graphs = [];
+let metrics = null;
+let time = 0;
+
+// ============================================================================
+// APPLICATION ENTRY POINT
+// ============================================================================
+
+document.addEventListener('DOMContentLoaded', async function() {
+ log('TimePlot starting...');
+
+ log('init DOM');
+ await initDOM();
+
+ log('init config');
+ await initCfg();
+
+ log('init PixiJS renderer');
+ await initRenderer();
+
+ log('init graphs');
+ await initGraphs();
+
+ log('init services');
+ await initServices();
+
+ log('setup controls');
+ await setupControls();
+
+ log('TimePlot ready');
+});
+
+// ============================================================================
+// INITIALIZATION FUNCTIONS
+// ============================================================================
+
+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');
+}
+async function initCfg() {
+ const localCfg = localStorage.getItem('timeplot-cfg');
+ if (localCfg) {
try {
- this.app = new Application();
-
- await this.app.init({
- preference: preference,
- width: window.innerWidth,
- height: window.innerHeight - 60, // Account for controls
- backgroundColor: 0x1a1a26,
- antialias: true,
- autoDensity: true,
- resolution: window.devicePixelRatio || 1,
- });
-
- container.appendChild(this.app.canvas);
-
- // Display actual renderer type
- const rendererType = this.app.renderer.type;
- document.getElementById('renderer-type').textContent = rendererType;
- console.log('Using renderer:', rendererType);
-
- // Create two waterfall graphs side by side
- this.setupGraphs();
- this.setupControls();
- this.setupKeyboard();
- this.handleResize();
-
- // Start animation loop
- this.app.ticker.add(() => this.update());
-
- console.log('TimePlot initialized successfully');
-
- } catch (error) {
- console.error('Failed to initialize PixiJS:', error);
-
- // Ultimate fallback
- if (preference === 'webgpu') {
- console.log('Retrying with WebGL...');
- this.init(); // Retry will use WebGL
- }
+ const parsed = JSON.parse(localCfg);
+ cfg = { ...cfg, ...parsed };
+ log('Loaded config from localStorage');
+ } catch (e) {
+ log('Failed to parse config, using defaults');
}
}
+}
- setupGraphs() {
- const width = this.app.screen.width;
- const height = this.app.screen.height;
-
- // Left graph
- const graph1 = new WaterfallGraph({
- x: 0,
- y: 0,
- width: width / 2,
- height: height,
- title: 'Frequency vs Time',
- color: 0xff6666,
- });
+function saveCfg() {
+ localStorage.setItem('timeplot-cfg', JSON.stringify(cfg));
+}
- // Right graph
- const graph2 = new WaterfallGraph({
- x: width / 2,
- y: 0,
- width: width / 2,
- height: height,
- title: 'Position vs Time',
- color: 0x66ff66,
+async function initRenderer() {
+ // Check WebGPU availability
+ let preference = 'webgpu';
+ if (!navigator.gpu) {
+ log('WebGPU not available, using WebGL');
+ preference = 'webgl';
+ }
+ console.log(navigator.gpu);
+ console.log(navigator);
+
+ try {
+ app = new Application();
+
+ await app.init({
+ preference: preference,
+ width: window.innerWidth,
+ height: window.innerHeight - 60, // Account for controls
+ backgroundColor: 0x1a1a26,
+ antialias: true,
+ autoDensity: true,
+ resolution: window.devicePixelRatio || 1,
});
- this.graphs.push(graph1, graph2);
- this.graphs.forEach(graph => {
- this.app.stage.addChild(graph.container);
- });
+ dom.container.appendChild(app.canvas);
+
+ // Display actual renderer type
+ const rendererType = app.renderer.type;
+ dom.display.rendererType.textContent = rendererType;
+ log(`Using renderer: ${rendererType}`);
+
+ // Handle window resize
+ window.addEventListener('resize', handleResize);
+
+ } catch (error) {
+ log(`Failed to initialize renderer: ${error}`);
+ throw error;
}
+}
- setupControls() {
- document.getElementById('toggle-grid').addEventListener('click', () => {
- this.toggleGrid();
- });
+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,
+ });
+
+ graphs.push(graph1, graph2);
+ graphs.forEach(graph => {
+ app.stage.addChild(graph.container);
+ graph.setGridVisible(cfg.showGrid);
+ });
+}
- document.getElementById('toggle-metrics').addEventListener('click', () => {
- this.toggleMetrics();
- });
+async function initServices() {
+ // Initialize performance metrics
+ metrics = new PerformanceMetrics(cfg.rollingWindow, cfg.historyCapacity);
- document.getElementById('export-metrics').addEventListener('click', () => {
- this.exportMetrics();
- });
+ // Start animation loop
+ app.ticker.add(update);
- this.updateControlButtons();
- }
+ log('Services initialized');
+}
- setupKeyboard() {
- window.addEventListener('keydown', (e) => {
- switch(e.key.toLowerCase()) {
- case 'g':
- this.toggleGrid();
- break;
- case 'm':
- this.toggleMetrics();
- break;
- case 'e':
- this.exportMetrics();
- break;
- }
- });
- }
+function setupControls() {
+ // Button controls
+ dom.controls.gridBtn.addEventListener('click', toggleGrid);
+ dom.controls.metricsBtn.addEventListener('click', toggleMetrics);
+ dom.controls.exportBtn.addEventListener('click', exportMetrics);
- handleResize() {
- window.addEventListener('resize', () => {
- const width = window.innerWidth;
- const height = window.innerHeight - 60;
+ // Keyboard controls
+ window.addEventListener('keydown', handleKeyboard);
- this.app.renderer.resize(width, height);
+ // Update button states
+ updateControlButtons();
+}
- // Update graphs
- this.graphs[0]?.resize(0, 0, width / 2, height);
- this.graphs[1]?.resize(width / 2, 0, width / 2, height);
- });
+// ============================================================================
+// EVENT HANDLERS
+// ============================================================================
+
+function handleKeyboard(e) {
+ switch(e.key.toLowerCase()) {
+ case 'g':
+ toggleGrid();
+ break;
+ case 'm':
+ toggleMetrics();
+ break;
+ case 'e':
+ exportMetrics();
+ break;
}
+}
- update() {
- this.metrics.beginFrame();
- this.metrics.beginUpdate();
+function handleResize() {
+ const width = window.innerWidth;
+ const height = window.innerHeight - 60;
- this.time += 0.016; // ~60fps increment
+ app.renderer.resize(width, height);
- // Update each graph
- this.graphs.forEach((graph, idx) => {
- graph.update(this.time, idx);
- });
+ // 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);
+}
- const updateMs = this.metrics.endUpdate();
+// ============================================================================
+// MAIN UPDATE LOOP
+// ============================================================================
- this.metrics.beginRender();
+function update() {
+ metrics.beginFrame();
+ metrics.beginUpdate();
- // Rendering happens automatically via PixiJS
+ time += 0.016; // ~60fps increment
- const renderMs = this.metrics.endRender();
+ // Update each graph
+ graphs.forEach((graph, idx) => {
+ graph.update(time, idx);
+ });
- // Calculate total vertices (estimate)
- const vertexCount = this.graphs.reduce((sum, g) => sum + g.getVertexCount(), 0);
- const lineCount = this.graphs.reduce((sum, g) => sum + g.getLineCount(), 0);
+ const updateMs = metrics.endUpdate();
- this.metrics.endFrame(updateMs, renderMs, vertexCount, lineCount);
+ metrics.beginRender();
+ // Rendering happens automatically via PixiJS
+ const renderMs = metrics.endRender();
- // Update UI
- if (this.showMetrics) {
- this.updateMetricsDisplay();
- }
- }
+ // Calculate stats
+ const vertexCount = graphs.reduce((sum, g) => sum + g.getVertexCount(), 0);
+ const lineCount = graphs.reduce((sum, g) => sum + g.getLineCount(), 0);
- toggleGrid() {
- this.showGrid = !this.showGrid;
- this.graphs.forEach(graph => graph.setGridVisible(this.showGrid));
- this.updateControlButtons();
- console.log('Grid:', this.showGrid ? 'ON' : 'OFF');
- }
+ metrics.endFrame(updateMs, renderMs, vertexCount, lineCount);
- toggleMetrics() {
- this.showMetrics = !this.showMetrics;
- this.updateControlButtons();
- console.log('Metrics:', this.showMetrics ? 'ON' : 'OFF');
+ // Update UI
+ if (cfg.showMetrics) {
+ updateMetricsDisplay();
}
- exportMetrics() {
- const csv = this.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);
- console.log('Metrics exported');
- }
+ console.log(metrics);
+}
- updateMetricsDisplay() {
- const display = document.getElementById('metrics-display');
- if (display) {
- display.textContent = this.metrics.formatSummary();
- }
- }
+// ============================================================================
+// UI CONTROL FUNCTIONS
+// ============================================================================
+
+function toggleGrid() {
+ cfg.showGrid = !cfg.showGrid;
+ graphs.forEach(graph => graph.setGridVisible(cfg.showGrid));
+ updateControlButtons();
+ saveCfg();
+ log(`Grid: ${cfg.showGrid ? 'ON' : 'OFF'}`);
+}
- updateControlButtons() {
- const gridBtn = document.getElementById('toggle-grid');
- const metricsBtn = document.getElementById('toggle-metrics');
+function toggleMetrics() {
+ cfg.showMetrics = !cfg.showMetrics;
+ updateControlButtons();
+ saveCfg();
+ log(`Metrics: ${cfg.showMetrics ? 'ON' : 'OFF'}`);
+}
- gridBtn.classList.toggle('active', this.showGrid);
- metricsBtn.classList.toggle('active', this.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();
}
}
-// Initialize the application
-const app = new TimePlot();
-app.init().catch(console.error);
+function updateControlButtons() {
+ dom.controls.gridBtn.classList.toggle('active', cfg.showGrid);
+ dom.controls.metricsBtn.classList.toggle('active', cfg.showMetrics);
+}
+
+// ============================================================================
+// UTILITIES
+// ============================================================================
+
+function log(msg) {
+ console.log(`[TimePlot] ${msg}`);
+}
diff --git a/web-timeplot/src/template-for-standard-site.js b/web-timeplot/src/template-for-standard-site.js
new file mode 100644
index 0000000..54aacc7
--- /dev/null
+++ b/web-timeplot/src/template-for-standard-site.js
@@ -0,0 +1,75 @@
+//import { setupRenderSystem } from './render.js';
+
+let ENVURL = "" //remote server from which to grab env
+let env = {};
+let cfg = {}; //the user config
+let dom = {
+ input: {},
+ label: {},
+ box: {}, //an info-containing box
+ icon: {},
+ info: {}
+};
+
+
+//APP START HERE
+$(document).ready(async function() {
+ console.log('asdf');
+ //the core loop of the client application
+ // 1. setup relationship with DOM and grab references to its elements
+ log('init DOM');
+ await initDOM();
+
+ log('init cfg');
+ await initCfg();
+
+ log('get env vars');
+ await getServerEnvVars();
+
+ log('init services');
+ await initServices();
+
+ //setupRenderSystem();
+
+
+});
+
+//gets user config from local storage if there is any
+function initCfg(){
+ let localCfg = localStorage.getItem('cfg');
+ if (localCfg) {
+ try {
+ cfg = JSON.parse(localCfg);
+ } catch (e) {
+ cfg = {};
+ }
+ } else {
+
+ }
+}
+
+async function getServerEnvVars(){
+ await axios.get(`${ENVURL}`).then((res)=>{
+ env = res.data;
+ //log(env);
+ }).catch((err)=>{
+ //log(err);
+ });
+ log('')
+}
+
+function initServices(){
+ //connect to websocket server
+ //grab endpoints from cfg
+}
+
+function initDOM(){
+ dom.body = $('body')[0];
+}
+
+function log(msg, lvl=1){
+ if (dom.debugInfo){
+ dom.debugInfo.innerHTML = msg; //TODO running log + timestamp
+ }
+ console.log(msg);
+} \ No newline at end of file