|
|
import { useEffect, useRef } from 'react'; |
|
|
import * as d3 from 'd3'; |
|
|
import { getConfig } from '../config/mapConfig.js'; |
|
|
import { applyZoomTransform } from '../utils/mappingUtils.js'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function useZoom(svgRef, baseGlyphSize, enabled = true, darkMode = false) { |
|
|
console.log('useZoom: Hook appelé avec baseGlyphSize:', baseGlyphSize); |
|
|
const zoomRef = useRef(null); |
|
|
const baseGlyphSizeRef = useRef(baseGlyphSize); |
|
|
const isInitializedRef = useRef(false); |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
baseGlyphSizeRef.current = baseGlyphSize; |
|
|
}, [baseGlyphSize]); |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
if (!enabled) { |
|
|
console.log('useZoom: Hook désactivé, sortie'); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
if (isInitializedRef.current) { |
|
|
console.log('useZoom: Déjà initialisé, sortie'); |
|
|
return; |
|
|
} |
|
|
|
|
|
const initializeZoom = () => { |
|
|
if (!svgRef.current) { |
|
|
console.log('useZoom: svgRef.current is null, en attente...'); |
|
|
return; |
|
|
} |
|
|
|
|
|
const svg = d3.select(svgRef.current); |
|
|
console.log('useZoom: SVG sélectionné', svg.node()); |
|
|
|
|
|
|
|
|
let viewportGroup = svg.select('.viewport-group'); |
|
|
if (viewportGroup.empty()) { |
|
|
viewportGroup = svg.append('g').attr('class', 'viewport-group'); |
|
|
console.log('useZoom: Groupe viewport créé'); |
|
|
} else { |
|
|
console.log('useZoom: Groupe viewport existant trouvé'); |
|
|
} |
|
|
|
|
|
|
|
|
const zoom = d3.zoom() |
|
|
.scaleExtent(getConfig('zoom.scaleExtent', [0.3, 3.0])) |
|
|
.on('zoom', (event) => { |
|
|
console.log('useZoom: Événement de zoom déclenché', event.transform); |
|
|
|
|
|
|
|
|
viewportGroup.attr('transform', event.transform); |
|
|
|
|
|
|
|
|
const scale = event.transform.k; |
|
|
const fontSize = Math.max(8, 16 / scale); |
|
|
const strokeColor = darkMode ? '#000000' : '#ffffff'; |
|
|
|
|
|
viewportGroup.selectAll('.centroid-label') |
|
|
.attr('font-size', `${fontSize}px`) |
|
|
.attr('stroke-width', `${Math.max(1, 4 / scale)}px`) |
|
|
.attr('stroke', strokeColor); |
|
|
}) |
|
|
.on('start', () => { |
|
|
console.log('useZoom: Début de l\'interaction'); |
|
|
}) |
|
|
.on('end', () => { |
|
|
console.log('useZoom: Fin de l\'interaction'); |
|
|
}); |
|
|
|
|
|
|
|
|
svg.call(zoom); |
|
|
|
|
|
|
|
|
const initialScale = getConfig('zoom.initialScale', 0.8); |
|
|
const svgRect = svg.node().getBoundingClientRect(); |
|
|
const centerX = svgRect.width / 2; |
|
|
const centerY = svgRect.height / 2; |
|
|
|
|
|
|
|
|
const initialTransform = d3.zoomIdentity |
|
|
.translate(centerX * (1 - initialScale), centerY * (1 - initialScale)) |
|
|
.scale(initialScale); |
|
|
|
|
|
|
|
|
svg.call(zoom.transform, initialTransform); |
|
|
console.log('useZoom: Zoom initialisé avec échelle:', initialScale); |
|
|
|
|
|
|
|
|
zoomRef.current = zoom; |
|
|
isInitializedRef.current = true; |
|
|
}; |
|
|
|
|
|
|
|
|
initializeZoom(); |
|
|
|
|
|
|
|
|
if (!svgRef.current) { |
|
|
const timer = setTimeout(initializeZoom, 100); |
|
|
return () => clearTimeout(timer); |
|
|
} |
|
|
|
|
|
|
|
|
return () => { |
|
|
if (svgRef.current) { |
|
|
const svg = d3.select(svgRef.current); |
|
|
svg.on('.zoom', null); |
|
|
} |
|
|
|
|
|
zoomRef.current = null; |
|
|
isInitializedRef.current = false; |
|
|
}; |
|
|
}, [enabled]); |
|
|
|
|
|
const resetZoom = () => { |
|
|
if (zoomRef.current && svgRef.current && isInitializedRef.current) { |
|
|
const svg = d3.select(svgRef.current); |
|
|
const svgNode = svg.node(); |
|
|
const width = svgNode.clientWidth || window.innerWidth; |
|
|
const height = svgNode.clientHeight || window.innerHeight; |
|
|
|
|
|
const centerX = width / 2; |
|
|
const centerY = height / 2; |
|
|
const scale = getConfig('zoom.initialScale', 0.8); |
|
|
|
|
|
|
|
|
const translateX = centerX * (1 - scale); |
|
|
const translateY = centerY * (1 - scale); |
|
|
|
|
|
const resetTransform = d3.zoomIdentity |
|
|
.translate(translateX, translateY) |
|
|
.scale(scale); |
|
|
|
|
|
svg.transition().duration(getConfig('zoom.transitionDuration', 750)).call( |
|
|
zoomRef.current.transform, |
|
|
resetTransform |
|
|
); |
|
|
console.log('useZoom: Reset zoom appliqué'); |
|
|
} |
|
|
}; |
|
|
|
|
|
return { resetZoom }; |
|
|
} |
|
|
|