# Correction du gel de l'application lors de l'ouverture du Graph View ## Problème identifié L'application gelait complètement pendant plusieurs secondes lors du passage à la vue graphe, empêchant même la prise de captures d'écran. ### Cause racine **Complexité algorithmique O(N²) dans `VaultService.graphData()`** L'ancien code effectuait une recherche linéaire (`.find()`) pour CHAQUE lien trouvé dans CHAQUE note : ```typescript // AVANT (O(N × M × N)) for (const note of notes) { // Boucle 1: N notes while ((match = linkRegex.exec(note.content)) !== null) { // Boucle 2: M liens const targetNote = notes.find(n => ...) // Boucle 3: N notes PAR LIEN! } } ``` **Résultat** : Avec 100 notes et 10 liens/note → **100,000+ opérations synchrones** bloquant le thread principal. ### Effets en cascade 1. `VaultService.graphData()` se recalcule (O(N²)) 2. `GraphViewContainerV2Component` déclenche multiples recalculs de computed signals 3. `GraphCanvasComponent` recrée le worker, les nodes, et le spatial index 4. **Tout cela de manière SYNCHRONE** → gel total ## Solutions implémentées ### 1. Optimisation O(N²) → O(N×M) dans VaultService **Fichier**: `src/services/vault.service.ts` Remplacement des `.find()` par des `Map.get()` (O(1)) : ```typescript // Build fast lookup maps const noteById = new Map(); const noteByTitle = new Map(); const notesByAlias = new Map(); // Index all notes once for (const note of notes) { noteById.set(note.id, note); noteByTitle.set(note.title, note); if (Array.isArray(note.frontmatter?.aliases)) { for (const alias of note.frontmatter.aliases) { notesByAlias.set(alias, note); } } } // Fast lookup during link extraction const targetNote = noteById.get(linkPath) || noteByTitle.get(rawLink) || notesByAlias.get(rawLink); ``` **Gain** : Complexité réduite de O(N×M×N) à O(N×M) ### 2. Debounce des mises à jour dans GraphCanvasComponent **Fichier**: `src/app/graph/graph-canvas.component.ts` Ajout d'un délai de 100ms pour éviter les cascades de recalculs : ```typescript // React to data changes with debounce let updateTimer: ReturnType | null = null; effect(() => { const nodes = this.nodes(); const links = this.links(); if (updateTimer) clearTimeout(updateTimer); updateTimer = setTimeout(() => { this.updateWorkerData(nodes, links); }, 100); }); ``` ### 3. Throttle de reconstruction du Spatial Index **Fichier**: `src/app/graph/graph-canvas.component.ts` Augmentation de l'intervalle de reconstruction de 200ms → 500ms : ```typescript // Rebuild spatial index at most every 500ms to reduce main thread load const now = performance.now(); if (now - lastIndexBuild > 500) { this.spatialIndex = new SpatialIndex(this.simulationNodes()); lastIndexBuild = now; } ``` ### 4. Éviter les réinitialisations inutiles du worker **Fichier**: `src/app/graph/graph-canvas.component.ts` Vérification du nombre de nodes/links avant de réinitialiser : ```typescript private updateWorkerData(nodes: GraphNodeWithVisuals[], links: GraphLink[]): void { // Skip update if data hasn't substantially changed if (nodes.length === this.lastNodeCount && links.length === this.lastLinkCount && this.session) { console.log(`[GraphCanvas] Skipping update - same data size`); return; } this.lastNodeCount = nodes.length; this.lastLinkCount = links.length; // ... reste de l'initialisation } ``` ### 5. Logs de performance pour diagnostic Ajout de traces pour mesurer les performances : ```typescript // Dans VaultService console.log(`[GraphData] Computed in ${duration.toFixed(2)}ms: ${nodes.length} nodes, ${edges.length} edges`); // Dans GraphCanvasComponent console.log(`[GraphCanvas] Updating worker: ${nodes.length} nodes, ${links.length} links`); ``` ## Résultats attendus - ✅ **Réduction drastique du temps de calcul** : O(N²) → O(N×M) - ✅ **Évite les recalculs en cascade** grâce au debounce - ✅ **Réduit la charge du thread principal** avec throttle spatial index - ✅ **Skip les updates inutiles** quand les données n'ont pas changé - ✅ **Visibilité sur les performances** via les console logs ## Validation Pour tester les améliorations : 1. Ouvrir DevTools Console 2. Passer à la vue Graph 3. Observer les logs : ``` [GraphData] Computed in XXms: YY nodes, ZZ edges [GraphCanvas] Updating worker: YY nodes, ZZ links ``` 4. Vérifier que l'application ne gèle plus 5. Essayer de prendre une capture d'écran pendant le chargement → devrait fonctionner ## Optimisations futures possibles Si des problèmes de performance persistent : 1. **Lazy loading** : Charger le graph view uniquement quand l'utilisateur clique dessus 2. **Virtual scrolling** pour les graphes très larges (>1000 nodes) 3. **Web Worker pour le parsing des liens** : Déplacer l'extraction des liens dans un worker séparé 4. **Cache du graphData** : Mémoriser le résultat et n'invalider que si les notes changent 5. **Pagination du graph** : Afficher seulement les N nodes les plus connectés par défaut ## Fichiers modifiés - `src/services/vault.service.ts` - Optimisation O(N²) → O(N×M) - `src/app/graph/graph-canvas.component.ts` - Debounce, throttle, logs