File size: 2,278 Bytes
b3f0c1a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
 * Hook pour calculer UMAP en direct via Web Worker
 */

import { useState, useCallback, useEffect, useRef } from 'react';

/**
 * Hook pour gérer le calcul UMAP en direct
 */
export function useLiveUMAP() {
  const [isCalculating, setIsCalculating] = useState(false);
  const [progress, setProgress] = useState(null);
  const [error, setError] = useState(null);
  const [result, setResult] = useState(null);

  const workerRef = useRef(null);
  const resolveRef = useRef(null);
  const rejectRef = useRef(null);

  // Initialiser le worker
  useEffect(() => {
    // Création du worker
    // Note: CRA v5 gère automatiquement l'import avec cette syntaxe
    const worker = new Worker(new URL('../workers/umap.worker.js', import.meta.url));

    worker.onmessage = (e) => {
      const { type, payload } = e.data;

      if (type === 'PROGRESS') {
        setProgress(payload);
      } else if (type === 'RESULT') {
        setResult(payload);
        setIsCalculating(false);
        if (resolveRef.current) {
          resolveRef.current(payload);
          resolveRef.current = null;
        }
      } else if (type === 'ERROR') {
        setError(payload);
        setIsCalculating(false);
        if (rejectRef.current) {
          rejectRef.current(new Error(payload));
          rejectRef.current = null;
        }
      }
    };

    workerRef.current = worker;

    return () => {
      worker.terminate();
    };
  }, []);

  /**
   * Calcule UMAP avec les paramètres donnés
   */
  const calculate = useCallback((config) => {
    return new Promise((resolve, reject) => {
      if (!workerRef.current) {
        reject(new Error('Worker non initialisé'));
        return;
      }

      setIsCalculating(true);
      setError(null);
      setProgress({ stage: 'starting', progress: 0 });

      resolveRef.current = resolve;
      rejectRef.current = reject;

      workerRef.current.postMessage({
        type: 'CALCULATE',
        payload: config
      });
    });
  }, []);

  /**
   * Réinitialise l'état
   */
  const reset = useCallback(() => {
    setResult(null);
    setError(null);
    setProgress(null);
    setIsCalculating(false);
  }, []);

  return {
    calculate,
    reset,
    isCalculating,
    progress,
    error,
    result
  };
}