UNPKG

@ichigo_san/graphing

Version:

A lightweight UML-style diagram editor built with React Flow and Tailwind CSS

546 lines (505 loc) โ€ข 17.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _EdgeWorkerService = _interopRequireDefault(require("./EdgeWorkerService")); var _LayoutAwareRoutingService = _interopRequireDefault(require("./LayoutAwareRoutingService")); var _EdgePerformanceMonitor = _interopRequireDefault(require("./EdgePerformanceMonitor")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } /** * EnhancedEdgeManager - Central manager for Draw.io-style orthogonal edge functionality * Coordinates between Web Worker service, layout-aware routing, and performance monitoring */ class EnhancedEdgeManager { constructor() { this.isInitialized = false; this.edgeRegistry = new Map(); this.activeEdges = new Set(); this.processingQueue = new Map(); this.config = { enablePerformanceMonitoring: true, enableLayoutAwareRouting: true, enableBatchProcessing: true, debounceTime: 100, maxConcurrentProcessing: 5, virtualBendsEnabled: true, intersectionDetectionEnabled: true }; this.statistics = { totalProcessed: 0, averageProcessingTime: 0, cacheHitRate: 0, optimizationsSuggested: 0, optimizationsApplied: 0 }; this.eventCallbacks = new Map(); } /** * Initialize the enhanced edge manager */ async initialize(config = {}) { if (this.isInitialized) return; // Merge configuration this.config = { ...this.config, ...config }; try { // Initialize services try { await _EdgeWorkerService.default.initWorker(); console.log('โœ… EnhancedEdgeManager: Web Worker initialized successfully'); } catch (error) { console.warn('โš ๏ธ EnhancedEdgeManager: Web Worker failed to initialize, using fallback processing:', error.message); } // Start performance monitoring if enabled if (this.config.enablePerformanceMonitoring) { _EdgePerformanceMonitor.default.startMonitoring(); // Setup performance alert handler _EdgePerformanceMonitor.default.onAlert(alert => { this.handlePerformanceAlert(alert); }); } // Setup layout constraints for layout-aware routing if (this.config.enableLayoutAwareRouting) { this.setupLayoutConstraints(); } this.isInitialized = true; console.log('๐Ÿš€ EnhancedEdgeManager: Initialized successfully'); // Emit initialization event this.emit('initialized', { config: this.config }); } catch (error) { console.error('โŒ EnhancedEdgeManager: Initialization failed:', error); throw error; } } /** * Register an edge for enhanced processing */ registerEdge(edgeId, edgeData, nodes) { const registration = { id: edgeId, data: edgeData, nodes: nodes, lastProcessed: 0, processingCount: 0, averageProcessingTime: 0, optimizedWaypoints: null, virtualBends: null, intersections: null, status: 'registered' }; this.edgeRegistry.set(edgeId, registration); this.activeEdges.add(edgeId); console.log(`๐Ÿ“ EnhancedEdgeManager: Registered edge ${edgeId}`); this.emit('edge_registered', { edgeId, registration }); } /** * Unregister an edge */ unregisterEdge(edgeId) { if (this.edgeRegistry.has(edgeId)) { this.edgeRegistry.delete(edgeId); this.activeEdges.delete(edgeId); // Cancel any pending processing if (this.processingQueue.has(edgeId)) { this.processingQueue.delete(edgeId); } console.log(`๐Ÿ“ EnhancedEdgeManager: Unregistered edge ${edgeId}`); this.emit('edge_unregistered', { edgeId }); } } /** * Process an edge with full Draw.io-style functionality */ async processEdge(edgeId, operation = 'full', options = {}) { if (!this.isInitialized) { await this.initialize(); } const registration = this.edgeRegistry.get(edgeId); if (!registration) { throw new Error(`Edge ${edgeId} not registered`); } const startTime = performance.now(); registration.status = 'processing'; try { let result = {}; // Record processing start if (this.config.enablePerformanceMonitoring) { _EdgePerformanceMonitor.default.recordProcessingTime(edgeId, 0, `${operation}_start`); } switch (operation) { case 'full': result = await this.processFullEnhancement(registration, options); break; case 'optimize': result = await this.processOptimization(registration, options); break; case 'virtual_bends': result = await this.processVirtualBends(registration, options); break; case 'intersections': result = await this.processIntersections(registration, options); break; case 'layout_aware': result = await this.processLayoutAwareRouting(registration, options); break; default: throw new Error(`Unknown operation: ${operation}`); } // Update registration with results this.updateRegistrationWithResults(registration, result); // Record processing completion const processingTime = performance.now() - startTime; registration.processingCount++; registration.averageProcessingTime = (registration.averageProcessingTime * (registration.processingCount - 1) + processingTime) / registration.processingCount; registration.lastProcessed = performance.now(); registration.status = 'completed'; if (this.config.enablePerformanceMonitoring) { _EdgePerformanceMonitor.default.recordProcessingTime(edgeId, processingTime, operation); } this.statistics.totalProcessed++; this.statistics.averageProcessingTime = (this.statistics.averageProcessingTime * (this.statistics.totalProcessed - 1) + processingTime) / this.statistics.totalProcessed; console.log(`โœ… EnhancedEdgeManager: Processed edge ${edgeId} (${operation}) in ${processingTime.toFixed(2)}ms`); this.emit('edge_processed', { edgeId, operation, result, processingTime }); return result; } catch (error) { registration.status = 'error'; console.error(`โŒ EnhancedEdgeManager: Failed to process edge ${edgeId}:`, error); this.emit('edge_processing_error', { edgeId, operation, error }); throw error; } } /** * Process full enhancement (all features) */ async processFullEnhancement(registration, options) { const { layoutType = 'default' } = options; // Run all processing operations in parallel for maximum performance const [optimizedWaypoints, virtualBends, intersections, layoutAwarePath] = await Promise.all([_EdgeWorkerService.default.optimizeWaypoints(registration.data, registration.nodes), this.config.virtualBendsEnabled ? _EdgeWorkerService.default.calculateVirtualBends(registration.data, registration.nodes) : [], this.config.intersectionDetectionEnabled ? _EdgeWorkerService.default.detectIntersections(registration.data, registration.nodes) : [], this.config.enableLayoutAwareRouting ? _LayoutAwareRoutingService.default.calculateLayoutAwarePath(registration.data, registration.nodes, layoutType) : null]); return { optimizedWaypoints, virtualBends, intersections, layoutAwarePath, layoutType }; } /** * Process optimization only */ async processOptimization(registration, options) { const optimizedWaypoints = await _EdgeWorkerService.default.optimizeWaypoints(registration.data, registration.nodes); return { optimizedWaypoints }; } /** * Process virtual bends calculation */ async processVirtualBends(registration, options) { if (!this.config.virtualBendsEnabled) { return { virtualBends: [] }; } const virtualBends = await _EdgeWorkerService.default.calculateVirtualBends(registration.data, registration.nodes); return { virtualBends }; } /** * Process intersection detection */ async processIntersections(registration, options) { if (!this.config.intersectionDetectionEnabled) { return { intersections: [] }; } const intersections = await _EdgeWorkerService.default.detectIntersections(registration.data, registration.nodes); return { intersections }; } /** * Process layout-aware routing */ async processLayoutAwareRouting(registration, options) { if (!this.config.enableLayoutAwareRouting) { return { layoutAwarePath: null }; } const { layoutType = 'default' } = options; const layoutAwarePath = await _LayoutAwareRoutingService.default.calculateLayoutAwarePath(registration.data, registration.nodes, layoutType); return { layoutAwarePath, layoutType }; } /** * Batch process multiple edges */ async batchProcessEdges(edgeIds, operation = 'full', options = {}) { if (!this.config.enableBatchProcessing) { // Process individually if batch processing is disabled const results = new Map(); for (const edgeId of edgeIds) { results.set(edgeId, await this.processEdge(edgeId, operation, options)); } return results; } const startTime = performance.now(); const results = new Map(); const validRegistrations = []; // Collect valid registrations for (const edgeId of edgeIds) { const registration = this.edgeRegistry.get(edgeId); if (registration) { validRegistrations.push({ edgeId, registration }); } } if (validRegistrations.length === 0) { return results; } try { // Prepare batch data const edges = validRegistrations.map(({ registration }) => registration.data); const allNodes = validRegistrations[0].registration.nodes; // Assume same nodes for batch // Process batch using Web Worker const batchResult = await _EdgeWorkerService.default.processBatch(edges, allNodes); // Distribute results back to individual edges batchResult.forEach((result, index) => { const { edgeId, registration } = validRegistrations[index]; this.updateRegistrationWithResults(registration, result); results.set(edgeId, result); }); const processingTime = performance.now() - startTime; console.log(`โœ… EnhancedEdgeManager: Batch processed ${edgeIds.length} edges in ${processingTime.toFixed(2)}ms`); this.emit('batch_processed', { edgeIds, operation, results, processingTime }); return results; } catch (error) { console.error('โŒ EnhancedEdgeManager: Batch processing failed:', error); this.emit('batch_processing_error', { edgeIds, operation, error }); throw error; } } /** * Update registration with processing results */ updateRegistrationWithResults(registration, result) { if (result.optimizedWaypoints) { registration.optimizedWaypoints = result.optimizedWaypoints; } if (result.virtualBends) { registration.virtualBends = result.virtualBends; } if (result.intersections) { registration.intersections = result.intersections; } if (result.layoutAwarePath) { registration.layoutAwarePath = result.layoutAwarePath; } } /** * Handle performance alerts */ handlePerformanceAlert(alert) { console.warn('โš ๏ธ EnhancedEdgeManager: Performance alert:', alert); // Get optimization recommendations const recommendations = _EdgePerformanceMonitor.default.getOptimizationRecommendations(); if (recommendations.length > 0) { this.statistics.optimizationsSuggested += recommendations.length; // Auto-apply safe optimizations this.applyOptimizations(recommendations.filter(r => r.priority === 'high')); this.emit('performance_alert', { alert, recommendations }); } } /** * Apply optimization recommendations */ applyOptimizations(recommendations) { recommendations.forEach(recommendation => { try { switch (recommendation.action) { case 'clear_cache': _EdgeWorkerService.default.clearCache(); _LayoutAwareRoutingService.default.clearCaches(); console.log('๐Ÿงน EnhancedEdgeManager: Cleared caches for performance'); break; case 'enable_batching': this.config.enableBatchProcessing = true; console.log('๐Ÿ“ฆ EnhancedEdgeManager: Enabled batch processing'); break; case 'reduce_batch_size': // Reduce batch size to lower memory usage if (_EdgeWorkerService.default.batchSize) { _EdgeWorkerService.default.batchSize = Math.max(_EdgeWorkerService.default.batchSize / 2, 5); console.log(`๐Ÿ“ฆ EnhancedEdgeManager: Reduced batch size to ${_EdgeWorkerService.default.batchSize}`); } break; case 'debounce_increase': this.config.debounceTime = Math.min(this.config.debounceTime * 1.5, 500); console.log(`โฐ EnhancedEdgeManager: Increased debounce to ${this.config.debounceTime}ms`); break; case 'optimize_rendering': // Reduce visual effects for better performance this.config.virtualBendsEnabled = false; this.config.intersectionDetectionEnabled = false; console.log('๐ŸŽจ EnhancedEdgeManager: Optimized rendering by disabling visual effects'); break; default: console.warn(`โ“ EnhancedEdgeManager: Unknown optimization action: ${recommendation.action}`); } this.statistics.optimizationsApplied++; } catch (error) { console.error('โŒ EnhancedEdgeManager: Failed to apply optimization:', error); } }); } /** * Setup layout constraints */ setupLayoutConstraints() { // These are already set up in LayoutAwareRoutingService, but can be customized here console.log('๐Ÿ“ EnhancedEdgeManager: Layout-aware routing configured'); } /** * Get comprehensive statistics */ getStatistics() { const performanceReport = this.config.enablePerformanceMonitoring ? _EdgePerformanceMonitor.default.generateReport() : null; const routingStats = this.config.enableLayoutAwareRouting ? _LayoutAwareRoutingService.default.getRoutingStatistics() : null; return { manager: { ...this.statistics, totalRegisteredEdges: this.edgeRegistry.size, activeEdges: this.activeEdges.size, pendingProcessing: this.processingQueue.size, config: this.config }, performance: performanceReport, routing: routingStats, worker: { initialized: _EdgeWorkerService.default.isInitialized // Add worker-specific stats here } }; } /** * Get edge information */ getEdgeInfo(edgeId) { return this.edgeRegistry.get(edgeId) || null; } /** * Get all registered edges */ getAllEdges() { return Array.from(this.edgeRegistry.values()); } /** * Event system */ on(event, callback) { if (!this.eventCallbacks.has(event)) { this.eventCallbacks.set(event, new Set()); } this.eventCallbacks.get(event).add(callback); return () => { var _this$eventCallbacks$; (_this$eventCallbacks$ = this.eventCallbacks.get(event)) === null || _this$eventCallbacks$ === void 0 || _this$eventCallbacks$.delete(callback); }; } emit(event, data) { const callbacks = this.eventCallbacks.get(event); if (callbacks) { callbacks.forEach(callback => { try { callback(data); } catch (error) { console.error(`โŒ EnhancedEdgeManager: Event callback error for ${event}:`, error); } }); } } /** * Update configuration */ updateConfig(newConfig) { this.config = { ...this.config, ...newConfig }; console.log('โš™๏ธ EnhancedEdgeManager: Configuration updated'); this.emit('config_updated', { config: this.config }); } /** * Cleanup and destroy */ destroy() { console.log('๐Ÿงน EnhancedEdgeManager: Cleaning up...'); // Stop performance monitoring if (this.config.enablePerformanceMonitoring) { _EdgePerformanceMonitor.default.stopMonitoring(); } // Clear all data this.edgeRegistry.clear(); this.activeEdges.clear(); this.processingQueue.clear(); this.eventCallbacks.clear(); // Destroy services _EdgeWorkerService.default.destroy(); _EdgePerformanceMonitor.default.destroy(); _LayoutAwareRoutingService.default.clearCaches(); this.isInitialized = false; this.emit('destroyed'); } } // Create singleton instance const enhancedEdgeManager = new EnhancedEdgeManager(); var _default = exports.default = enhancedEdgeManager;