summaryrefslogtreecommitdiff
path: root/src/example-usage.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/example-usage.js')
-rw-r--r--src/example-usage.js535
1 files changed, 535 insertions, 0 deletions
diff --git a/src/example-usage.js b/src/example-usage.js
new file mode 100644
index 0000000..67eff4b
--- /dev/null
+++ b/src/example-usage.js
@@ -0,0 +1,535 @@
+/**
+ * Example Usage: Complete examples of the new architecture
+ *
+ * This file demonstrates how to use the separated data/visualization architecture:
+ * - TimeSeriesPlot: Pure visualization
+ * - DataSource: Data generation/provision
+ * - Connections: Links between them
+ */
+
+import { Application } from 'pixi.js';
+import { TimeSeriesPlot } from './timeseries-plot.js';
+import {
+ SyntheticDataSource,
+ FunctionDataSource,
+ StreamingDataSource,
+ WebSocketDataSource,
+} from './data-sources.js';
+import {
+ DirectConnection,
+ BufferedConnection,
+ ConnectionManager,
+ connectSyntheticData,
+ connectFunction,
+ createConnectedPlot,
+} from './plot-connections.js';
+import {
+ TestDataFactory,
+ SineWaveGenerator,
+ PerlinNoiseGenerator,
+ ChirpGenerator,
+} from './test-data-generators.js';
+
+// ============================================================================
+// Example 1: Simple Setup - One plot, one data source
+// ============================================================================
+
+export async function example1_SimpleSetup() {
+ console.log('=== Example 1: Simple Setup ===');
+
+ // Create PixiJS app
+ const app = new Application();
+ await app.init({
+ width: 800,
+ height: 600,
+ backgroundColor: 0x1a1a26,
+ });
+ document.body.appendChild(app.canvas);
+
+ // Create plot (visualization only)
+ const plot = new TimeSeriesPlot({
+ x: 0,
+ y: 0,
+ width: 800,
+ height: 600,
+ title: 'Simple Sine Wave',
+ showGrid: true,
+ });
+ app.stage.addChild(plot.container);
+
+ // Create data source
+ const generator = TestDataFactory.createSimpleSine(30);
+ const source = new SyntheticDataSource({
+ generator: generator,
+ pointsPerLine: 100,
+ width: 800,
+ lineInterval: 100, // New line every 100ms
+ });
+
+ // Connect source to plot
+ const connection = new DirectConnection(source, plot);
+ connection.connect();
+
+ // Update plot every frame
+ app.ticker.add(() => {
+ plot.update();
+ });
+
+ return { app, plot, source, connection };
+}
+
+// ============================================================================
+// Example 2: Quick Setup Using Helper Functions
+// ============================================================================
+
+export async function example2_QuickSetup() {
+ console.log('=== Example 2: Quick Setup ===');
+
+ const app = new Application();
+ await app.init({
+ width: 800,
+ height: 600,
+ backgroundColor: 0x1a1a26,
+ });
+ document.body.appendChild(app.canvas);
+
+ // One-liner setup!
+ const { plot, source, connection } = createConnectedPlot(
+ app,
+ {
+ x: 0,
+ y: 0,
+ width: 800,
+ height: 600,
+ title: 'Quick Setup',
+ },
+ {
+ generator: TestDataFactory.createComplexPattern(30),
+ lineInterval: 100,
+ }
+ );
+
+ app.ticker.add(() => plot.update());
+
+ return { app, plot, source, connection };
+}
+
+// ============================================================================
+// Example 3: Multiple Plots with Different Data Sources
+// ============================================================================
+
+export async function example3_MultiplePlots() {
+ console.log('=== Example 3: Multiple Plots ===');
+
+ const app = new Application();
+ await app.init({
+ width: 1600,
+ height: 600,
+ backgroundColor: 0x1a1a26,
+ });
+ document.body.appendChild(app.canvas);
+
+ const width = 800;
+ const height = 600;
+
+ // Left plot: Sine wave
+ const plot1 = new TimeSeriesPlot({
+ x: 0,
+ y: 0,
+ width: width,
+ height: height,
+ title: 'Sine Wave',
+ color: 0xff6666,
+ });
+
+ // Right plot: Perlin noise
+ const plot2 = new TimeSeriesPlot({
+ x: width,
+ y: 0,
+ width: width,
+ height: height,
+ title: 'Perlin Noise',
+ color: 0x66ff66,
+ });
+
+ app.stage.addChild(plot1.container);
+ app.stage.addChild(plot2.container);
+
+ // Connect different data sources
+ const conn1 = connectSyntheticData(
+ TestDataFactory.createSimpleSine(30),
+ plot1,
+ { lineInterval: 100 }
+ );
+
+ const conn2 = connectSyntheticData(
+ TestDataFactory.createSmoothNoise(30),
+ plot2,
+ { lineInterval: 100 }
+ );
+
+ app.ticker.add(() => {
+ plot1.update();
+ plot2.update();
+ });
+
+ return { app, plots: [plot1, plot2], connections: [conn1, conn2] };
+}
+
+// ============================================================================
+// Example 4: Using Function-Based Data Source
+// ============================================================================
+
+export async function example4_FunctionSource() {
+ console.log('=== Example 4: Function Source ===');
+
+ const app = new Application();
+ await app.init({ width: 800, height: 600, backgroundColor: 0x1a1a26 });
+ document.body.appendChild(app.canvas);
+
+ const plot = new TimeSeriesPlot({
+ x: 0,
+ y: 0,
+ width: 800,
+ height: 600,
+ title: 'Custom Function',
+ });
+ app.stage.addChild(plot.container);
+
+ // Define a custom function: (x, t) => y
+ // x is normalized 0-1 across the width
+ // t is time in seconds
+ const customFunc = (x, t) => {
+ // Create an interference pattern
+ const wave1 = Math.sin(x * 10 + t * 2);
+ const wave2 = Math.sin(x * 15 - t * 3);
+ const wave3 = Math.cos(x * 8 + t * 1.5);
+ return (wave1 + wave2 + wave3) / 3;
+ };
+
+ const connection = connectFunction(customFunc, plot, {
+ lineInterval: 100,
+ amplitude: 30,
+ });
+
+ app.ticker.add(() => plot.update());
+
+ return { app, plot, connection };
+}
+
+// ============================================================================
+// Example 5: Swapping Data Sources at Runtime
+// ============================================================================
+
+export async function example5_SwappingSources() {
+ console.log('=== Example 5: Swapping Sources ===');
+
+ const app = new Application();
+ await app.init({ width: 800, height: 600, backgroundColor: 0x1a1a26 });
+ document.body.appendChild(app.canvas);
+
+ const plot = new TimeSeriesPlot({
+ x: 0,
+ y: 0,
+ width: 800,
+ height: 600,
+ title: 'Dynamic Source Switching',
+ });
+ app.stage.addChild(plot.container);
+
+ // Start with sine wave
+ let currentConnection = connectSyntheticData(
+ TestDataFactory.createSimpleSine(30),
+ plot,
+ { lineInterval: 100 }
+ );
+
+ app.ticker.add(() => plot.update());
+
+ // Function to switch to a different data source
+ const switchToSource = (generator, title) => {
+ // Disconnect current source
+ currentConnection.disconnect();
+
+ // Connect new source
+ currentConnection = connectSyntheticData(generator, plot, {
+ lineInterval: 100,
+ });
+
+ plot.setTitle(title);
+ console.log(`Switched to: ${title}`);
+ };
+
+ // Example: Switch sources every 5 seconds
+ let sourceIndex = 0;
+ const sources = [
+ { gen: TestDataFactory.createSimpleSine(30), title: 'Sine Wave' },
+ { gen: TestDataFactory.createComplexPattern(30), title: 'Complex Pattern' },
+ { gen: TestDataFactory.createSmoothNoise(30), title: 'Perlin Noise' },
+ { gen: TestDataFactory.createFrequencySweep(30), title: 'Frequency Sweep' },
+ ];
+
+ setInterval(() => {
+ sourceIndex = (sourceIndex + 1) % sources.length;
+ const source = sources[sourceIndex];
+ switchToSource(source.gen, source.title);
+ }, 5000);
+
+ return { app, plot, switchToSource };
+}
+
+// ============================================================================
+// Example 6: Streaming Data with Buffering
+// ============================================================================
+
+export async function example6_StreamingData() {
+ console.log('=== Example 6: Streaming Data ===');
+
+ const app = new Application();
+ await app.init({ width: 800, height: 600, backgroundColor: 0x1a1a26 });
+ document.body.appendChild(app.canvas);
+
+ const plot = new TimeSeriesPlot({
+ x: 0,
+ y: 0,
+ width: 800,
+ height: 600,
+ title: 'Streaming Data (Buffered)',
+ });
+ app.stage.addChild(plot.container);
+
+ // Create streaming source (emits individual points)
+ const generator = new SineWaveGenerator({
+ frequency: 2.0,
+ amplitude: 1.0,
+ sampleRate: 60,
+ });
+
+ const source = new StreamingDataSource({
+ generator: generator,
+ sampleRate: 60, // 60 points per second
+ });
+
+ // Use buffered connection to assemble points into lines
+ const connection = new BufferedConnection(source, plot, {
+ bufferSize: 100, // Buffer 100 points before creating a line
+ bufferTimeout: 1000, // Or timeout after 1 second
+ });
+ connection.connect();
+
+ app.ticker.add(() => plot.update());
+
+ return { app, plot, source, connection };
+}
+
+// ============================================================================
+// Example 7: Connection Manager (Managing Multiple Connections)
+// ============================================================================
+
+export async function example7_ConnectionManager() {
+ console.log('=== Example 7: Connection Manager ===');
+
+ const app = new Application();
+ await app.init({ width: 800, height: 600, backgroundColor: 0x1a1a26 });
+ document.body.appendChild(app.canvas);
+
+ const plot = new TimeSeriesPlot({
+ x: 0,
+ y: 0,
+ width: 800,
+ height: 600,
+ title: 'Managed Connections',
+ });
+ app.stage.addChild(plot.container);
+
+ // Create connection manager
+ const manager = new ConnectionManager();
+
+ // Add first connection
+ const source1 = new SyntheticDataSource({
+ generator: TestDataFactory.createSimpleSine(30),
+ pointsPerLine: 100,
+ width: 800,
+ lineInterval: 100,
+ });
+
+ const connId1 = manager.connect(source1, plot, { type: 'direct' });
+ console.log('Connection ID:', connId1);
+
+ app.ticker.add(() => plot.update());
+
+ // Later: disconnect and switch to different source
+ setTimeout(() => {
+ manager.disconnect(connId1);
+
+ const source2 = new SyntheticDataSource({
+ generator: TestDataFactory.createFrequencySweep(30),
+ pointsPerLine: 100,
+ width: 800,
+ lineInterval: 100,
+ });
+
+ const connId2 = manager.connect(source2, plot, { type: 'direct' });
+ plot.setTitle('Frequency Sweep');
+ console.log('Switched to connection:', connId2);
+ }, 5000);
+
+ return { app, plot, manager };
+}
+
+// ============================================================================
+// Example 8: Complete Interactive Demo
+// ============================================================================
+
+export async function example8_InteractiveDemo() {
+ console.log('=== Example 8: Interactive Demo ===');
+
+ const app = new Application();
+ await app.init({
+ width: 1600,
+ height: 800,
+ backgroundColor: 0x1a1a26,
+ });
+ document.body.appendChild(app.canvas);
+
+ // Create two plots
+ const plot1 = new TimeSeriesPlot({
+ x: 0,
+ y: 0,
+ width: 800,
+ height: 800,
+ title: 'Plot 1 - Press 1-5 to change',
+ color: 0xff6666,
+ });
+
+ const plot2 = new TimeSeriesPlot({
+ x: 800,
+ y: 0,
+ width: 800,
+ height: 800,
+ title: 'Plot 2 - Press 6-0 to change',
+ color: 0x66ff66,
+ });
+
+ app.stage.addChild(plot1.container);
+ app.stage.addChild(plot2.container);
+
+ // Connection manager
+ const manager = new ConnectionManager();
+
+ // Available data sources
+ const dataSources = {
+ sine: () => TestDataFactory.createSimpleSine(30),
+ complex: () => TestDataFactory.createComplexPattern(30),
+ noise: () => TestDataFactory.createSmoothNoise(30),
+ sweep: () => TestDataFactory.createFrequencySweep(30),
+ burst: () => TestDataFactory.createBurstySignal(30),
+ };
+
+ // Track current connections
+ let conn1Id = null;
+ let conn2Id = null;
+
+ // Helper to switch source
+ const switchSource = (plot, generatorFunc, title) => {
+ // Disconnect old connection
+ const connId = plot === plot1 ? conn1Id : conn2Id;
+ if (connId !== null) {
+ manager.disconnect(connId);
+ }
+
+ // Create new connection
+ const source = new SyntheticDataSource({
+ generator: generatorFunc(),
+ pointsPerLine: 100,
+ width: plot.width,
+ lineInterval: 100,
+ });
+
+ const newConnId = manager.connect(source, plot, { type: 'direct' });
+ plot.setTitle(title);
+
+ // Store connection ID
+ if (plot === plot1) {
+ conn1Id = newConnId;
+ } else {
+ conn2Id = newConnId;
+ }
+ };
+
+ // Initialize with default sources
+ switchSource(plot1, dataSources.sine, 'Plot 1 - Sine Wave');
+ switchSource(plot2, dataSources.complex, 'Plot 2 - Complex Pattern');
+
+ // Keyboard controls
+ window.addEventListener('keydown', (e) => {
+ switch (e.key) {
+ case '1':
+ switchSource(plot1, dataSources.sine, 'Plot 1 - Sine Wave');
+ break;
+ case '2':
+ switchSource(plot1, dataSources.complex, 'Plot 1 - Complex Pattern');
+ break;
+ case '3':
+ switchSource(plot1, dataSources.noise, 'Plot 1 - Perlin Noise');
+ break;
+ case '4':
+ switchSource(plot1, dataSources.sweep, 'Plot 1 - Frequency Sweep');
+ break;
+ case '5':
+ switchSource(plot1, dataSources.burst, 'Plot 1 - Burst Signal');
+ break;
+ case '6':
+ switchSource(plot2, dataSources.sine, 'Plot 2 - Sine Wave');
+ break;
+ case '7':
+ switchSource(plot2, dataSources.complex, 'Plot 2 - Complex Pattern');
+ break;
+ case '8':
+ switchSource(plot2, dataSources.noise, 'Plot 2 - Perlin Noise');
+ break;
+ case '9':
+ switchSource(plot2, dataSources.sweep, 'Plot 2 - Frequency Sweep');
+ break;
+ case '0':
+ switchSource(plot2, dataSources.burst, 'Plot 2 - Burst Signal');
+ break;
+ case 'g':
+ plot1.setGridVisible(!plot1.showGrid);
+ plot2.setGridVisible(!plot2.showGrid);
+ break;
+ case 'c':
+ plot1.clearData();
+ plot2.clearData();
+ break;
+ }
+ });
+
+ // Update loop
+ app.ticker.add(() => {
+ plot1.update();
+ plot2.update();
+ });
+
+ console.log('Controls:');
+ console.log(' 1-5: Change Plot 1 source');
+ console.log(' 6-0: Change Plot 2 source');
+ console.log(' G: Toggle grid');
+ console.log(' C: Clear data');
+
+ return { app, plot1, plot2, manager };
+}
+
+// ============================================================================
+// Quick Test: Run one of the examples
+// ============================================================================
+
+// Uncomment to run an example:
+// example1_SimpleSetup();
+// example2_QuickSetup();
+// example3_MultiplePlots();
+// example4_FunctionSource();
+// example5_SwappingSources();
+// example6_StreamingData();
+// example7_ConnectionManager();
+//example8_InteractiveDemo();