fix: improve debug panel layout and log display

- Clear logs between rotation updates (no more expanding text)
- Increase canvas size from 600x450 to 900x600 for better visibility
- Reorganize layout: left controls, right canvas + single-line log
- Make crop box much larger and easier to see
This commit is contained in:
2026-04-22 11:20:43 +03:00
parent 36e721e742
commit 82948ada92

View File

@@ -25,10 +25,11 @@ export function DebugRotationPanel({
}: DebugRotationPanelProps) { }: DebugRotationPanelProps) {
const [rotation, setRotation] = useState(originalRotation); const [rotation, setRotation] = useState(originalRotation);
const canvasRef = useRef<HTMLCanvasElement>(null); const canvasRef = useRef<HTMLCanvasElement>(null);
const [logs, setLogs] = useState<string[]>([]); const [log, setLog] = useState('');
const imageRef = useRef<HTMLImageElement | null>(null); const imageRef = useRef<HTMLImageElement | null>(null);
const [imageLoaded, setImageLoaded] = useState(false); const [imageLoaded, setImageLoaded] = useState(false);
const [scaledDimensions, setScaledDimensions] = useState({ width: 0, height: 0, scale: 1 }); const [scaledDimensions, setScaledDimensions] = useState({ width: 0, height: 0, scale: 1 });
const containerRef = useRef<HTMLDivElement>(null);
// Use original photo path if available, otherwise fall back to processed image URL // Use original photo path if available, otherwise fall back to processed image URL
const displayImageUrl = originalPhotoPath ? originalPhotoPath : imageUrl; const displayImageUrl = originalPhotoPath ? originalPhotoPath : imageUrl;
@@ -44,8 +45,8 @@ export function DebugRotationPanel({
{ label: '±180°', value: 180 }, { label: '±180°', value: 180 },
]; ];
const addLog = (message: string) => { const updateLog = (message: string) => {
setLogs((prev) => [...prev, `[${new Date().toLocaleTimeString()}] ${message}`]); setLog(message);
}; };
useEffect(() => { useEffect(() => {
@@ -54,18 +55,17 @@ export function DebugRotationPanel({
img.onload = () => { img.onload = () => {
imageRef.current = img; imageRef.current = img;
setImageLoaded(true); setImageLoaded(true);
addLog(`📸 Image loaded: ${img.width}×${img.height}px`);
// Calculate scaled dimensions to fit canvas // Calculate scaled dimensions to fit available space (much larger)
const maxWidth = 600; const maxWidth = 900;
const maxHeight = 500; const maxHeight = 600;
const scale = Math.min(maxWidth / img.width, maxHeight / img.height); const scale = Math.min(maxWidth / img.width, maxHeight / img.height);
const scaledW = img.width * scale; const scaledW = img.width * scale;
const scaledH = img.height * scale; const scaledH = img.height * scale;
setScaledDimensions({ width: scaledW, height: scaledH, scale }); setScaledDimensions({ width: scaledW, height: scaledH, scale });
addLog(`📐 Scaled to fit: ${scaledW.toFixed(0)}×${scaledH.toFixed(0)}px (scale ${scale.toFixed(2)}x)`); updateLog(`📸 ${img.width}×${img.height}px → scaled ${scaledW.toFixed(0)}×${scaledH.toFixed(0)}px (${scale.toFixed(2)}x)`);
}; };
img.onerror = () => addLog('❌ Failed to load image'); img.onerror = () => updateLog('❌ Failed to load image');
img.src = displayImageUrl; img.src = displayImageUrl;
}, [displayImageUrl]); }, [displayImageUrl]);
@@ -83,13 +83,10 @@ export function DebugRotationPanel({
canvas.width = scaledDimensions.width; canvas.width = scaledDimensions.width;
canvas.height = scaledDimensions.height; canvas.height = scaledDimensions.height;
addLog(`\n🎨 --- Drawing Preview ---`);
addLog(`Rotation: ${rotation}°`);
// Draw scaled image // Draw scaled image
ctx.drawImage(img, 0, 0, canvas.width, canvas.height); ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// Draw crop bounding box on the ORIGINAL image // Calculate crop box in scaled coordinates
const cropX = originalCropBounds.x * scale; const cropX = originalCropBounds.x * scale;
const cropY = originalCropBounds.y * scale; const cropY = originalCropBounds.y * scale;
const cropW = originalCropBounds.width * scale; const cropW = originalCropBounds.width * scale;
@@ -126,35 +123,32 @@ export function DebugRotationPanel({
ctx.restore(); ctx.restore();
// Logs // Update log with current state
addLog(`Crop area: (${originalCropBounds.x}, ${originalCropBounds.y}) ${originalCropBounds.width}×${originalCropBounds.height}px`); const logText = `Rotation: ${rotation}° | Crop: (${cropX.toFixed(0)}, ${cropY.toFixed(0)}) ${cropW.toFixed(0)}×${cropH.toFixed(0)}px`;
addLog(`Scaled crop: (${cropX.toFixed(0)}, ${cropY.toFixed(0)}) ${cropW.toFixed(0)}×${cropH.toFixed(0)}px`); updateLog(logText);
if (Math.abs(rotation) > 0.5) {
addLog(`✅ Rotation overlay shown in ORANGE`);
}
}, [imageLoaded, rotation, originalCropBounds, scaledDimensions]); }, [imageLoaded, rotation, originalCropBounds, scaledDimensions]);
return ( return (
<div className="fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-2"> <div className="fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4">
<div className="bg-slate-900 border border-slate-700 rounded-lg shadow-2xl max-w-5xl w-full max-h-[95vh] overflow-y-auto"> <div className="bg-slate-900 border border-slate-700 rounded-lg shadow-2xl max-w-6xl w-full max-h-[95vh] overflow-hidden flex flex-col">
{/* Header */} {/* Header */}
<div className="p-2 border-b border-slate-700 flex items-center justify-between bg-slate-800 sticky top-0"> <div className="p-3 border-b border-slate-700 flex items-center justify-between bg-slate-800 flex-shrink-0">
<h2 className="text-base font-bold text-white">🔧 Debug Rotation & Crop</h2> <h2 className="text-lg font-normal text-white">Debug Rotation & Crop</h2>
<button <button
onClick={onClose} onClick={onClose}
className="p-1 hover:bg-slate-700 rounded text-gray-400 hover:text-white transition" className="p-2 hover:bg-slate-700 rounded text-gray-400 hover:text-white transition"
> >
<X size={18} /> <X size={20} />
</button> </button>
</div> </div>
<div className="grid grid-cols-2 gap-2 p-3 auto-rows-max"> <div className="flex gap-4 p-4 flex-1 overflow-hidden">
{/* Left: Controls */} {/* Left: Controls */}
<div className="space-y-2 bg-slate-800 p-2 rounded"> <div className="w-48 bg-slate-800 p-3 rounded space-y-4 flex-shrink-0 overflow-y-auto">
{/* Rotation Slider */} {/* Rotation Slider */}
<div> <div>
<label className="block text-sm font-semibold text-white mb-2"> <label className="block text-sm font-normal text-white mb-2">
Rotation: <span className="text-yellow-400 font-bold">{rotation}°</span> Rotation: <span className="text-yellow-400">{rotation}°</span>
</label> </label>
<input <input
type="range" type="range"
@@ -168,13 +162,13 @@ export function DebugRotationPanel({
{/* Quick Presets */} {/* Quick Presets */}
<div> <div>
<label className="block text-sm font-semibold text-white mb-2">Quick Angles</label> <label className="block text-sm font-normal text-white mb-2">Quick Angles</label>
<div className="grid grid-cols-4 gap-1"> <div className="grid grid-cols-2 gap-1">
{commonAngles.map((angle) => ( {commonAngles.map((angle) => (
<button <button
key={angle.value} key={angle.value}
onClick={() => setRotation(angle.value)} onClick={() => setRotation(angle.value)}
className={`py-1 px-2 rounded text-xs font-semibold transition ${ className={`py-1 px-2 rounded text-xs font-normal transition ${
rotation === angle.value rotation === angle.value
? 'bg-yellow-600 text-white' ? 'bg-yellow-600 text-white'
: 'bg-slate-700 text-gray-300 hover:bg-slate-600' : 'bg-slate-700 text-gray-300 hover:bg-slate-600'
@@ -188,16 +182,14 @@ export function DebugRotationPanel({
{/* Original Values */} {/* Original Values */}
{originalRotation !== undefined && ( {originalRotation !== undefined && (
<div className="bg-slate-700 p-3 rounded text-xs"> <div className="bg-slate-700 p-3 rounded text-xs space-y-1">
<h3 className="font-semibold text-white mb-2">Original Values</h3> <h3 className="font-normal text-white">Original AI Values</h3>
<div className="text-gray-300 space-y-1 font-mono"> <div className="text-gray-300 font-mono text-xs">
<div>Rotation: {originalRotation}°</div> <div>Rotation: {originalRotation}°</div>
{originalCropBounds && ( {originalCropBounds && (
<> <>
<div>Crop X: {originalCropBounds.x}</div> <div>Crop ({originalCropBounds.x}, {originalCropBounds.y})</div>
<div>Crop Y: {originalCropBounds.y}</div> <div>Size {originalCropBounds.width}×{originalCropBounds.height}</div>
<div>Width: {originalCropBounds.width}</div>
<div>Height: {originalCropBounds.height}</div>
</> </>
)} )}
{imageProcessing?.confidence && ( {imageProcessing?.confidence && (
@@ -208,30 +200,23 @@ export function DebugRotationPanel({
)} )}
</div> </div>
{/* Center: Canvas Preview + Right: Logs */} {/* Right: Canvas + Log */}
<div className="col-span-2 flex gap-2"> <div className="flex-1 flex flex-col gap-3 min-w-0 overflow-hidden">
{/* Canvas */} {/* Canvas - takes most space */}
<div className="flex-1 flex flex-col bg-slate-800 p-2 rounded"> <div className="flex-1 flex flex-col bg-slate-800 p-3 rounded border border-slate-700 overflow-hidden">
<h3 className="text-xs font-semibold text-white mb-1">Image Preview</h3> <h3 className="text-xs font-normal text-white mb-2">Preview (Green = Crop, Orange = Rotation)</h3>
<div className="border border-slate-600 rounded flex items-center justify-center bg-black/50 flex-1 min-h-72"> <div className="flex-1 flex items-center justify-center bg-black/70 rounded border border-slate-600 overflow-auto">
<canvas <canvas
ref={canvasRef} ref={canvasRef}
className="max-w-full max-h-full rounded" className="rounded"
/> />
</div> </div>
<div className="text-xs text-gray-400 mt-1 text-center">
<span>🟢 Crop </span>
<span>🟠 Rotate</span>
</div>
</div> </div>
{/* Logs */} {/* Log - single line */}
<div className="w-64 bg-slate-800 p-2 rounded flex flex-col"> <div className="bg-slate-800 p-2 rounded border border-slate-700 flex-shrink-0">
<h3 className="text-xs font-semibold text-white mb-1">Logs</h3> <div className="bg-black text-green-400 p-2 rounded font-mono text-xs">
<div className="bg-black text-green-400 p-2 rounded font-mono text-xs flex-1 overflow-y-auto border border-slate-700"> {log}
{logs.map((log, i) => (
<div key={i} className="whitespace-pre-wrap">{log}</div>
))}
</div> </div>
</div> </div>
</div> </div>