"use client"; import { useEffect, useRef, useState } from "react"; interface Point { norm_x: number; norm_y: number; } interface Impact { id: number; label: string; score: number; coords: Point; } interface PhotoOverlayProps { imageUrl: string; impacts: Impact[]; targetCorners: Point[]; isEditing?: boolean; onImpactsChange?: (impacts: Impact[]) => void; } export default function PhotoOverlay({ imageUrl, impacts, targetCorners, isEditing = false, onImpactsChange }: PhotoOverlayProps) { const containerRef = useRef(null); const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); const [dragIndex, setDragIndex] = useState(null); useEffect(() => { const updateDimensions = () => { if (containerRef.current) { setDimensions({ width: containerRef.current.offsetWidth, height: containerRef.current.offsetHeight, }); } }; updateDimensions(); window.addEventListener("resize", updateDimensions); return () => window.removeEventListener("resize", updateDimensions); }, []); const handleImageClick = (e: React.MouseEvent) => { if (!isEditing || !onImpactsChange || dragIndex !== null) return; const rect = containerRef.current?.getBoundingClientRect(); if (!rect) return; // Calculer les coordonnées normalisées const x = (e.clientX - rect.left) / dimensions.width; const y = (e.clientY - rect.top) / dimensions.height; // Créer un nouvel impact const newImpact: Impact = { id: impacts.length > 0 ? Math.max(...impacts.map(i => i.id)) + 1 : 1, label: "bullet_hole", score: 10, coords: { norm_x: x, norm_y: y } }; onImpactsChange([...impacts, newImpact]); }; const handleMouseMove = (e: React.MouseEvent) => { if (dragIndex === null || !onImpactsChange) return; const rect = containerRef.current?.getBoundingClientRect(); if (!rect) return; const x = (e.clientX - rect.left) / dimensions.width; const y = (e.clientY - rect.top) / dimensions.height; const newImpacts = [...impacts]; newImpacts[dragIndex] = { ...newImpacts[dragIndex], coords: { norm_x: x, norm_y: y } }; onImpactsChange(newImpacts); }; const deleteImpact = (e: React.MouseEvent, index: number) => { e.stopPropagation(); if (!isEditing || !onImpactsChange) return; const newImpacts = impacts.filter((_, i) => i !== index); onImpactsChange(newImpacts); }; return (
setDragIndex(null)} onMouseLeave={() => setDragIndex(null)} > {/* eslint-disable-next-line @next/next/no-img-element */} Target Analysis { const img = e.currentTarget; setDimensions({ width: img.clientWidth, height: img.clientHeight }); }} /> {dimensions.width > 0 && ( {/* Draw Target Box if corners exist */} {targetCorners && targetCorners.length === 4 && ( `${c.norm_x * dimensions.width},${c.norm_y * dimensions.height}`).join(' ')} fill="rgba(79, 70, 229, 0.15)" stroke="#6366f1" strokeWidth="2" strokeDasharray="4 2" /> )} {/* Draw Impacts */} {impacts.map((impact, index) => ( {/* Glow effect */} { if (!isEditing) return; e.stopPropagation(); setDragIndex(index); }} onContextMenu={(e) => deleteImpact(e, index)} /> {/* Main circle */} {/* Score text */} {impact.score} ))} )} {isEditing && (
MODE ÉDITION : CLIC POUR AJOUTER • DRAG POUR DÉPLACER • CLIC DROIT POUR SUPPRIMER
)}
); }