| 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 }; |
| } |
|
|