File size: 2,388 Bytes
eec7490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1d5cfba
 
 
 
 
eec7490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1d5cfba
eec7490
 
1d5cfba
eec7490
 
 
1d5cfba
eec7490
 
 
 
 
 
 
 
 
 
 
 
 
1d5cfba
 
eec7490
 
 
 
 
 
 
 
 
 
 
 
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
import { useEffect, type FC } from 'react'
import type OpenSeadragon from 'openseadragon'
import type { Region } from '../lib/api.ts'

const REGION_COLORS: Record<string, string> = {
  text_block: '#3b82f6',         // bleu
  miniature: '#f59e0b',          // or
  decorated_initial: '#10b981',  // vert
  margin: '#6b7280',             // gris
  rubric: '#ef4444',             // rouge
  other: '#8b5cf6',              // violet
}

interface Props {
  viewer: OpenSeadragon.Viewer | null
  regions: Region[]
  onRegionClick: (region: Region) => void
}

const RegionOverlay: FC<Props> = ({ viewer, regions, onRegionClick }) => {
  useEffect(() => {
    if (!viewer) return

    // AbortController pour nettoyer proprement tous les event listeners
    // lors du démontage ou du re-rendu (évite les fuites mémoire).
    const controller = new AbortController()
    const { signal } = controller

    const addOverlays = () => {
      viewer.clearOverlays()
      const item = viewer.world.getItemAt(0)
      if (!item) return

      for (const region of regions) {
        const [x, y, w, h] = region.bbox
        const color = REGION_COLORS[region.type] ?? REGION_COLORS['other']

        const el = document.createElement('div')
        el.style.border = `2px solid ${color}`
        el.style.boxSizing = 'border-box'
        el.style.cursor = 'pointer'
        el.title = `${region.type} · ${(region.confidence * 100).toFixed(0)} %`

        el.addEventListener('mouseenter', () => {
          el.style.backgroundColor = `${color}33`
        }, { signal })
        el.addEventListener('mouseleave', () => {
          el.style.backgroundColor = ''
        }, { signal })
        el.addEventListener('click', (e: MouseEvent) => {
          e.stopPropagation()
          onRegionClick(region)
        }, { signal })

        const rect = item.imageToViewportRectangle(x, y, w, h)
        viewer.addOverlay(el, rect)
      }
    }

    if (viewer.isOpen()) {
      addOverlays()
    } else {
      viewer.addOnceHandler('open', addOverlays)
    }

    return () => {
      // Supprime tous les event listeners d'un coup, puis les overlays
      controller.abort()
      try {
        viewer.clearOverlays()
      } catch {
        // viewer peut avoir été détruit lors du démontage
      }
    }
  }, [viewer, regions, onRegionClick])

  return null
}

export default RegionOverlay