fix: Zellen an Box-Zone clampen im Overlay-Modus (keine Ueberlappung)
Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 29s
CI / test-go-edu-search (push) Successful in 30s
CI / test-python-klausur (push) Failing after 2m15s
CI / test-python-agent-core (push) Successful in 17s
CI / test-nodejs-website (push) Successful in 23s

Zellen oberhalb der Box werden in der Hoehe begrenzt, Zellen unterhalb
werden nach unten verschoben. Sub-Session-Zellen bleiben unveraendert.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-03-10 22:52:08 +01:00
parent 618c82ef42
commit f468c30112

View File

@@ -476,6 +476,47 @@ export function StepReconstruction({ sessionId, onNext }: StepReconstructionProp
)
}
// Box zones in percent for clamping cell positions in overlay mode
const boxZonesPct = useMemo(() =>
parentZones
.filter(z => z.zone_type === 'box' && z.box)
.map(z => {
const imgH = imageNaturalSize?.h || 1
return {
topPct: (z.box!.y / imgH) * 100,
bottomPct: ((z.box!.y + z.box!.height) / imgH) * 100,
}
}),
[parentZones, imageNaturalSize]
)
// Clamp cell positions so they don't overlap with box zones
const adjustCellForBoxZones = (
bboxPct: { x: number; y: number; w: number; h: number },
cellId: string,
): { x: number; y: number; w: number; h: number } => {
// Sub-session cells (inside box) → no adjustment
if (cellId.startsWith('sub_')) return bboxPct
if (boxZonesPct.length === 0) return bboxPct
const cellTop = bboxPct.y
const cellBottom = bboxPct.y + bboxPct.h
const cellCenter = cellTop + bboxPct.h / 2
for (const { topPct, bottomPct } of boxZonesPct) {
// Cell ABOVE box: clamp height so bottom doesn't exceed box top
if (cellCenter < topPct && cellBottom > topPct) {
return { ...bboxPct, h: topPct - cellTop }
}
// Cell BELOW box: push top down to box bottom
if (cellCenter > bottomPct && cellTop < bottomPct) {
const newY = bottomPct
return { ...bboxPct, y: newY, h: cellBottom - newY }
}
}
return bboxPct
}
// Overlay rendering helper
const renderOverlayMode = () => {
const imgW = imageNaturalSize?.w || 1
@@ -562,7 +603,8 @@ export function StepReconstruction({ sessionId, onNext }: StepReconstructionProp
const displayText = getDisplayText(cell)
const edited = isEdited(cell)
const wordPos = cellWordPositions.get(cell.cellId)
const cellHeightPx = containerH * (cell.bboxPct.h / 100)
const adjBbox = adjustCellForBoxZones(cell.bboxPct, cell.cellId)
const cellHeightPx = containerH * (adjBbox.h / 100)
// Pixel-analysed: render word-groups at detected positions as inputs
if (wordPos && wordPos.length > 0) {
@@ -579,9 +621,9 @@ export function StepReconstruction({ sessionId, onNext }: StepReconstructionProp
className="absolute leading-none pointer-events-none select-none"
style={{
left: `${wp.xPct}%`,
top: `${cell.bboxPct.y}%`,
top: `${adjBbox.y}%`,
width: `${wp.wPct}%`,
height: `${cell.bboxPct.h}%`,
height: `${adjBbox.h}%`,
fontSize: `${fs}px`,
fontWeight: globalBold ? 'bold' : (cell.colType === 'column_en' ? 'bold' : 'normal'),
fontFamily: "'Liberation Sans', Arial, sans-serif",
@@ -601,9 +643,9 @@ export function StepReconstruction({ sessionId, onNext }: StepReconstructionProp
return (
<div key={`${cell.cellId}_wp_${i}`} className="absolute group" style={{
left: `${wp.xPct}%`,
top: `${cell.bboxPct.y}%`,
top: `${adjBbox.y}%`,
width: `${wp.wPct}%`,
height: `${cell.bboxPct.h}%`,
height: `${adjBbox.h}%`,
}}>
<input
id={`cell-${cell.cellId}`}
@@ -644,10 +686,10 @@ export function StepReconstruction({ sessionId, onNext }: StepReconstructionProp
const fontSize = Math.max(6, cellHeightPx * fontScale)
return (
<div key={cell.cellId} className="absolute group" style={{
left: `${cell.bboxPct.x}%`,
top: `${cell.bboxPct.y}%`,
width: `${cell.bboxPct.w}%`,
height: `${cell.bboxPct.h}%`,
left: `${adjBbox.x}%`,
top: `${adjBbox.y}%`,
width: `${adjBbox.w}%`,
height: `${adjBbox.h}%`,
}}>
<input
id={`cell-${cell.cellId}`}