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:
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user