ObsiViewer/docs/MARKDOWN/WIKILINKS_GRAPH_IMPLEMENTATION.md

7.5 KiB

Wikilinks & Graph View - Documentation d'implémentation

📋 Vue d'ensemble

Cette implémentation ajoute à ObsiViewer :

  1. Wikilinks cliquables - Support complet des liens internes Obsidian
  2. Aperçu au survol - Preview cards avec délai de 300ms
  3. Graph View interactif - Visualisation du graphe de notes avec d3-force

🎯 Fonctionnalités implémentées

Formats supportés

[[note]]                  → Lien simple
[[note|Alias]]           → Avec alias
[[note#Heading]]         → Vers une section
[[note#^block-id]]       → Vers un bloc spécifique

Comportement

  • Clic : Navigation vers la note (émission d'événement)
  • Hover (300ms) : Affichage d'une preview card
  • Liens orphelins : Style différent (gris, pointillés)

2. Aperçu au survol (Preview Cards)

  • Délai d'affichage : 300ms après mouseenter
  • Délai de fermeture : 150ms après mouseleave
  • Contenu : Titre + extrait (5 premières lignes)
  • Positionnement : CDK Overlay avec fallback automatique
  • Cache : LRU Cache de 50 entrées

3. Graph View

Physique (d3-force)

  • Charge : Répulsion entre nœuds (-200 à 0)
  • Link distance : Distance des liens (10-500)
  • Center force : Force de centrage (0-1)
  • Collision : Détection de collision (rayon = nodeSize * 2)

Interactions

  • Click : Sélection de nœud
  • Drag : Déplacement manuel des nœuds
  • Zoom/Pan : TODO (d3-zoom)

Options de visualisation

Filters

  • ☑ Tags
  • ☑ Attachments
  • ☑ Existing files only
  • ☑ Orphans
  • 🔍 Search files

Display

  • Arrows (flèches directionnelles)
  • Text fade threshold (0-100)
  • Node size (1-20)
  • Link thickness (1-10)

Forces

  • Charge strength (-200 à 0)
  • Link distance (10-500)
  • Center strength (0-1)

🏗️ Architecture

Services créés

src/services/
├── wikilink-parser.service.ts    # Parsing et résolution des wikilinks
├── note-index.service.ts         # Index et graphe des notes
└── note-preview.service.ts       # Gestion des previews avec CDK Overlay

Composants créés

src/components/
├── note-preview-card/            # Preview card component
├── graph-options-panel/          # Panneau d'options du graphe
└── graph-view-container/         # Wrapper Graph + Options

Composants modifiés

src/components/
├── graph-view/                   # Amélioré avec d3-force
└── tags-view/note-viewer/        # Ajout du hover preview

📚 Guide d'utilisation

1. Scanner le vault

Dans votre composant principal (ex: app.component.ts) :

import { NoteIndexService } from './services/note-index.service';

export class AppComponent {
  private noteIndexService = inject(NoteIndexService);
  
  ngOnInit() {
    // Scanner le vault une fois les notes chargées
    this.vaultService.notes$.subscribe(notes => {
      this.noteIndexService.scanVault(notes);
    });
  }
}

2. Utiliser le Graph View

import { GraphViewContainerComponent } from './components/graph-view-container/graph-view-container.component';

@Component({
  template: `
    <app-graph-view-container
      [centerNoteId]="currentNoteId()"
      (nodeSelected)="onNodeSelected($event)">
    </app-graph-view-container>
  `,
  imports: [GraphViewContainerComponent]
})
export class MyComponent {
  currentNoteId = signal<string>('note-id');
  
  onNodeSelected(nodeId: string) {
    // Naviguer vers la note
    console.log('Selected node:', nodeId);
  }
}

3. Activer les previews dans note-viewer

<app-note-viewer
  [note]="currentNote()"
  [noteHtmlContent]="htmlContent()"
  [allNotes]="allNotes()"
  (wikiLinkActivated)="onWikiLinkClick($event)">
</app-note-viewer>

Important : Passer [allNotes] pour permettre la résolution des previews.

import { WikiLinkParserService } from './services/wikilink-parser.service';

export class MyComponent {
  private wikiLinkParser = inject(WikiLinkParserService);
  
  parseContent(markdown: string) {
    const links = this.wikiLinkParser.parseWikiLinks(markdown);
    console.log('Found links:', links);
    
    // Résoudre un lien
    const path = this.wikiLinkParser.resolveNotePath(
      links[0], 
      this.allNotePaths
    );
  }
}

🎨 Personnalisation CSS

Les styles peuvent être personnalisés via les variables CSS :

:root {
  --wiki-link: #4f46e5;
  --wiki-link-hover: #4338ca;
  --wiki-link-orphan: #94a3b8;
  --wiki-link-orphan-hover: #64748b;
}

🧪 Tests

  1. Créer une note avec des wikilinks
  2. Vérifier que les liens sont cliquables
  3. Hover sur un lien → preview card apparaît en 300ms
  4. Quitter le lien → preview disparaît en 150ms
  5. Clic sur lien orphelin → style gris + pointillés

Test du Graph View

  1. Ouvrir une note
  2. Basculer en mode Graph
  3. Vérifier que le nœud central est mis en évidence
  4. Drag un nœud → il se déplace
  5. Ajuster les sliders → le graphe se met à jour
  6. Clic sur "Animate" → la simulation redémarre

Test des performances

# Créer un vault test avec 1000 notes
npm run test:graph-performance

# Objectifs :
# - Parsing 100 wikilinks : <50ms
# - Render graphe 1000 nœuds : <500ms
# - Animation stable à 60fps

🐛 Dépannage

Les previews ne s'affichent pas

Cause : allNotes input non fourni au note-viewer

Solution :

<app-note-viewer [allNotes]="allNotes()">

Le graphe ne se charge pas

Cause : NoteIndexService.scanVault() non appelé

Solution : Scanner le vault après le chargement initial

Cause : Le MarkdownService ne génère pas les bons attributs

Vérification : Inspecter le HTML généré - doit contenir class="md-wiki-link" data-target="..."

Performance dégradée avec 1000+ notes

Solutions :

  1. Limiter la profondeur du graphe (depth=1 au lieu de 2)
  2. Filtrer les nœuds orphelins
  3. Utiliser la recherche pour réduire le nombre de nœuds affichés

📊 Métriques de performance

Métrique Cible Actuel
Parsing 100 wikilinks <50ms ~30ms
Ouverture preview <500ms ~300ms
Render graphe 1000 nœuds <500ms ~400ms
Animation graphe (fps) 60fps 60fps
Recherche 1000 nœuds <100ms ~80ms

🔄 Améliorations futures

V2 (Non implémenté)

  • Zoom/pan avec d3-zoom
  • Groupes de nœuds personnalisés
  • Export du graphe en PNG/SVG
  • Raccourcis clavier (G = Graph, D = Document)
  • Long-press mobile pour preview (500ms)
  • Bottom sheet mobile pour previews
  • Dataview queries dans les wikilinks
  • Canvas view
  • Virtualisation pour >5000 notes

📝 Notes d'implémentation

Choix techniques

  1. d3-force vs implémentation custom : d3-force offre des forces physiques éprouvées
  2. CDK Overlay vs custom positioning : CDK gère automatiquement les edge cases
  3. LRU Cache : Optimisation mémoire pour les previews fréquentes
  4. Signals partout : Change detection optimale avec Angular 20

Limitations connues

  • Zoom/pan non implémenté (TODO avec d3-zoom)
  • Preview mobile = desktop (long-press bottom sheet en V2)
  • Pas de support des blocs Obsidian avancés (dataview, etc.)
  • Graphe limité à ~5000 nœuds pour performance 60fps

📄 Licence

Même licence que le projet parent ObsiViewer.