fix(vwb): image plein écran — calcul dimensions JS explicite (fix définitif)
Some checks failed
security-audit / Bandit (scan statique) (push) Successful in 12s
security-audit / pip-audit (CVE dépendances) (push) Successful in 11s
security-audit / Scan secrets (grep) (push) Successful in 9s
tests / Lint (ruff + black) (push) Successful in 14s
tests / Tests unitaires (sans GPU) (push) Failing after 14s
tests / Tests sécurité (critique) (push) Has been skipped
Some checks failed
security-audit / Bandit (scan statique) (push) Successful in 12s
security-audit / pip-audit (CVE dépendances) (push) Successful in 11s
security-audit / Scan secrets (grep) (push) Successful in 9s
tests / Lint (ruff + black) (push) Successful in 14s
tests / Tests unitaires (sans GPU) (push) Failing after 14s
tests / Tests sécurité (critique) (push) Has been skipped
Cause racine : max-width/max-height CSS ne font pas GRANDIR une image. Fix : calcul explicite width/height en JS via Math.min(ratio). min-height:0 sur le conteneur flex. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -412,6 +412,11 @@ function FullscreenSelector({
|
|||||||
// Scale de l'image affichee par rapport a l'image naturelle
|
// Scale de l'image affichee par rapport a l'image naturelle
|
||||||
const [imageScale, setImageScale] = useState({ x: 1, y: 1 });
|
const [imageScale, setImageScale] = useState({ x: 1, y: 1 });
|
||||||
|
|
||||||
|
// Dimensions explicites de l'image (calculees pour remplir le conteneur en contain)
|
||||||
|
// Resout le bug "timbre poste" : max-width/max-height seuls ne font PAS grandir
|
||||||
|
// une image plus petite que le conteneur. On calcule la taille explicitement.
|
||||||
|
const [imgDisplaySize, setImgDisplaySize] = useState<{ width: number; height: number } | null>(null);
|
||||||
|
|
||||||
// ── Detection automatique des elements UI ──
|
// ── Detection automatique des elements UI ──
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const runDetection = async () => {
|
const runDetection = async () => {
|
||||||
@@ -433,24 +438,46 @@ function FullscreenSelector({
|
|||||||
runDetection();
|
runDetection();
|
||||||
}, [capture.screenshot_base64]);
|
}, [capture.screenshot_base64]);
|
||||||
|
|
||||||
// ── Calcul de imageRect et imageScale ──
|
// ── Calcul des dimensions image + imageRect + imageScale ──
|
||||||
// Appele au chargement de l'image ET au redimensionnement de la fenetre.
|
// Appele au chargement de l'image ET au redimensionnement de la fenetre.
|
||||||
|
// Calcule la taille "contain" (remplir le conteneur en gardant le ratio)
|
||||||
|
// et l'applique comme width/height explicite sur l'img.
|
||||||
const recalcImageRect = useCallback(() => {
|
const recalcImageRect = useCallback(() => {
|
||||||
if (!imgRef.current || !contentRef.current) return;
|
if (!imgRef.current || !contentRef.current) return;
|
||||||
|
|
||||||
const containerRect = contentRef.current.getBoundingClientRect();
|
const containerRect = contentRef.current.getBoundingClientRect();
|
||||||
const imgBounds = imgRef.current.getBoundingClientRect();
|
const natW = imgRef.current.naturalWidth;
|
||||||
|
const natH = imgRef.current.naturalHeight;
|
||||||
|
|
||||||
setImageRect({
|
if (natW > 0 && natH > 0) {
|
||||||
left: imgBounds.left - containerRect.left,
|
// Calcul "contain" : ratio le plus contraignant
|
||||||
top: imgBounds.top - containerRect.top,
|
const scale = Math.min(
|
||||||
width: imgBounds.width,
|
containerRect.width / natW,
|
||||||
height: imgBounds.height,
|
containerRect.height / natH
|
||||||
});
|
);
|
||||||
|
const displayW = Math.round(natW * scale);
|
||||||
|
const displayH = Math.round(natH * scale);
|
||||||
|
setImgDisplaySize({ width: displayW, height: displayH });
|
||||||
|
}
|
||||||
|
|
||||||
setImageScale({
|
// Apres le render avec les nouvelles dimensions, recalculer imageRect
|
||||||
x: imgBounds.width / imgRef.current.naturalWidth,
|
// On utilise requestAnimationFrame pour lire le layout apres le paint
|
||||||
y: imgBounds.height / imgRef.current.naturalHeight,
|
requestAnimationFrame(() => {
|
||||||
|
if (!imgRef.current || !contentRef.current) return;
|
||||||
|
const cRect = contentRef.current.getBoundingClientRect();
|
||||||
|
const imgBounds = imgRef.current.getBoundingClientRect();
|
||||||
|
|
||||||
|
setImageRect({
|
||||||
|
left: imgBounds.left - cRect.left,
|
||||||
|
top: imgBounds.top - cRect.top,
|
||||||
|
width: imgBounds.width,
|
||||||
|
height: imgBounds.height,
|
||||||
|
});
|
||||||
|
|
||||||
|
setImageScale({
|
||||||
|
x: imgBounds.width / imgRef.current.naturalWidth,
|
||||||
|
y: imgBounds.height / imgRef.current.naturalHeight,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -601,7 +628,7 @@ function FullscreenSelector({
|
|||||||
<button onClick={onClose}>Fermer (Echap)</button>
|
<button onClick={onClose}>Fermer (Echap)</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Zone de contenu : flex center, l'image se dimensionne via max-width/max-height */}
|
{/* Zone de contenu : flex center, l'image se dimensionne via imgDisplaySize (contain calcule en JS) */}
|
||||||
<div
|
<div
|
||||||
className="fullscreen-content"
|
className="fullscreen-content"
|
||||||
ref={contentRef}
|
ref={contentRef}
|
||||||
@@ -615,7 +642,13 @@ function FullscreenSelector({
|
|||||||
alt="Capture plein ecran"
|
alt="Capture plein ecran"
|
||||||
draggable={false}
|
draggable={false}
|
||||||
onLoad={handleImageLoad}
|
onLoad={handleImageLoad}
|
||||||
style={{ maxWidth: '100%', maxHeight: 'calc(100vh - 70px)', objectFit: 'contain' }}
|
style={imgDisplaySize ? {
|
||||||
|
width: imgDisplaySize.width,
|
||||||
|
height: imgDisplaySize.height,
|
||||||
|
} : {
|
||||||
|
maxWidth: '100%',
|
||||||
|
maxHeight: '100%',
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Overlay : positionne exactement sur l'image via imageRect.
|
{/* Overlay : positionne exactement sur l'image via imageRect.
|
||||||
|
|||||||
@@ -1085,12 +1085,17 @@ body {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
/* min-height: 0 — indispensable pour que flex:1 fonctionne dans un
|
||||||
|
conteneur flex column. Sans ca, min-height:auto empeche le conteneur
|
||||||
|
de se dimensionner correctement et l'image reste minuscule. */
|
||||||
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fullscreen-content img {
|
.fullscreen-content img {
|
||||||
max-width: 100%;
|
/* Les dimensions width/height sont calculees en JS (contain manuel)
|
||||||
max-height: calc(100vh - 70px);
|
pour garantir que l'image remplit le conteneur quel que soit sa
|
||||||
object-fit: contain;
|
taille naturelle (y compris thumbnails 320x240 de la bibliotheque). */
|
||||||
|
display: block;
|
||||||
cursor: crosshair;
|
cursor: crosshair;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user