d1615a9e01
Reported: dragging toward an image edge (e.g. to reveal a cropped-off head) stopped short of what the reference preview showed was possible — the two panels visibly disagreed. Root cause: transform-origin was set to match the pan position (X%,Y%) instead of staying at the CSS default (50% 50%, the box's own center). CSS object-position places the *unzoomed* crop; transform:scale then magnifies around transform-origin. Tying that origin to X/Y meant zoom dragged its own anchor point toward whichever edge you'd panned to, instead of always magnifying what's actually centered in the frame — harmless near the middle (why initial testing looked fine) but increasingly wrong the closer you drag to an edge, exactly where you'd need to go to reach a cropped head. A second, smaller error was in how the reference-rectangle preview converted focal position to natural-image coordinates (didn't account for the zoom-independent anchor point). Fixed both the crop editor's own math and includes/photo.php's photo_crop_style() (used for every final render — cards, previews) to drop the origin back to the CSS default and use the correct geometry. clampFocal() also simplifies to a plain [0,100] clamp — under real object-position semantics that's always a valid, fully-covered crop at any zoom >= 1, no image-dimension-dependent math needed. Verified in a standalone test harness: dragging now reaches all the way to an image's edges, zoom stays synced between the editor's live frame and its reference-rectangle preview, and the applied result matches the editor's preview exactly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
31 lines
1.3 KiB
PHP
31 lines
1.3 KiB
PHP
<?php
|
|
/**
|
|
* includes/photo.php — shared helper for the photo reposition/zoom feature.
|
|
*/
|
|
|
|
/**
|
|
* Build the inline style="" value that applies a session/novena_group row's
|
|
* stored crop (photo_focal_x/photo_focal_y/photo_zoom) to an <img> using
|
|
* object-fit: cover. Falls back to 50/50/1 (dead center, no zoom — today's
|
|
* default behavior) when the row predates this feature or the values are
|
|
* otherwise missing, so old photos render exactly as they always have.
|
|
*/
|
|
function photo_crop_style(array $row): string {
|
|
$x = isset($row['photo_focal_x']) && $row['photo_focal_x'] !== null ? (float)$row['photo_focal_x'] : 50.0;
|
|
$y = isset($row['photo_focal_y']) && $row['photo_focal_y'] !== null ? (float)$row['photo_focal_y'] : 50.0;
|
|
$zoom = isset($row['photo_zoom']) && $row['photo_zoom'] !== null ? (float)$row['photo_zoom'] : 1.0;
|
|
|
|
$x = max(0, min(100, $x));
|
|
$y = max(0, min(100, $y));
|
|
$zoom = max(1, min(3, $zoom));
|
|
|
|
// transform-origin is deliberately left at its CSS default (50% 50% —
|
|
// the box's own center), not tied to $x/$y: object-position places the
|
|
// unzoomed crop, and the scale transform then magnifies around whatever
|
|
// is currently centered, matching the crop editor exactly.
|
|
return sprintf(
|
|
'object-position:%.2f%% %.2f%%;transform:scale(%.3f);',
|
|
$x, $y, $zoom
|
|
);
|
|
}
|