Fix measurement display and ruler rendering
- Add printAreaWidthMm and printAreaHeightMm to ProductDTO type - Include these fields in toProductDTO conversion function - Refactor ruler calculations to use simple for loops - Rulers now display correctly showing 2cm increments on both axes - Position & Size panel now shows accurate cm measurements Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Haiku 4.5
parent
4658b5a8b8
commit
c20c696ccb
@@ -204,6 +204,7 @@ function PrintSurface({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Horizontal Ruler */}
|
{/* Horizontal Ruler */}
|
||||||
|
{product.printAreaWidthMm > 0 && stageW > 0 && (
|
||||||
<div
|
<div
|
||||||
className="absolute pointer-events-none bg-paper border-b border-line text-xs font-mono"
|
className="absolute pointer-events-none bg-paper border-b border-line text-xs font-mono"
|
||||||
style={{
|
style={{
|
||||||
@@ -212,16 +213,19 @@ function PrintSurface({
|
|||||||
width: stageW,
|
width: stageW,
|
||||||
height: 18,
|
height: 18,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'flex-end',
|
||||||
justifyContent: 'space-between',
|
|
||||||
paddingBottom: '2px',
|
paddingBottom: '2px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Array.from({ length: Math.ceil((stageW / (10 * (product.printAreaWidthMm / 100)))) }).map((_, i) => {
|
{(() => {
|
||||||
const cm = i * 2;
|
const marks = [];
|
||||||
const px = (cm * stageW) / (product.printAreaWidthMm / 10);
|
const cmPerStageW = product.printAreaWidthMm / 10; // total cm width of stage
|
||||||
if (px > stageW) return null;
|
const pxPerCm = stageW / cmPerStageW;
|
||||||
return (
|
|
||||||
|
for (let cm = 0; cm <= Math.ceil(cmPerStageW); cm += 2) {
|
||||||
|
const px = cm * pxPerCm;
|
||||||
|
if (px > stageW) break;
|
||||||
|
marks.push(
|
||||||
<div
|
<div
|
||||||
key={`h-${cm}`}
|
key={`h-${cm}`}
|
||||||
style={{
|
style={{
|
||||||
@@ -230,15 +234,20 @@ function PrintSurface({
|
|||||||
fontSize: '9px',
|
fontSize: '9px',
|
||||||
color: '#888',
|
color: '#888',
|
||||||
transform: 'translateX(-50%)',
|
transform: 'translateX(-50%)',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{cm}cm
|
{cm}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
}
|
||||||
|
return marks;
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Vertical Ruler */}
|
{/* Vertical Ruler */}
|
||||||
|
{product.printAreaHeightMm > 0 && stageH > 0 && (
|
||||||
<div
|
<div
|
||||||
className="absolute pointer-events-none bg-paper border-r border-line text-xs font-mono"
|
className="absolute pointer-events-none bg-paper border-r border-line text-xs font-mono"
|
||||||
style={{
|
style={{
|
||||||
@@ -252,11 +261,15 @@ function PrintSurface({
|
|||||||
paddingRight: '4px',
|
paddingRight: '4px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{Array.from({ length: Math.ceil((stageH / (10 * (product.printAreaWidthMm / 100)))) }).map((_, i) => {
|
{(() => {
|
||||||
const cm = i * 2;
|
const marks = [];
|
||||||
const px = (cm * stageH) / (product.printAreaWidthMm / 10);
|
const cmPerStageH = product.printAreaHeightMm / 10; // total cm height of stage
|
||||||
if (px > stageH) return null;
|
const pxPerCm = stageH / cmPerStageH;
|
||||||
return (
|
|
||||||
|
for (let cm = 0; cm <= Math.ceil(cmPerStageH); cm += 2) {
|
||||||
|
const px = cm * pxPerCm;
|
||||||
|
if (px > stageH) break;
|
||||||
|
marks.push(
|
||||||
<div
|
<div
|
||||||
key={`v-${cm}`}
|
key={`v-${cm}`}
|
||||||
style={{
|
style={{
|
||||||
@@ -265,13 +278,17 @@ function PrintSurface({
|
|||||||
fontSize: '9px',
|
fontSize: '9px',
|
||||||
color: '#888',
|
color: '#888',
|
||||||
transform: 'translateY(-50%)',
|
transform: 'translateY(-50%)',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{cm}
|
{cm}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
}
|
||||||
|
return marks;
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="absolute" style={{ left: stageLeft, top: stageTop, width: stageW, height: stageH }}>
|
<div className="absolute" style={{ left: stageLeft, top: stageTop, width: stageW, height: stageH }}>
|
||||||
<Stage
|
<Stage
|
||||||
@@ -424,8 +441,15 @@ export default function DesignCanvas({ product }: { product: ProductDTO }) {
|
|||||||
|
|
||||||
// Calculate cm per pixel for display
|
// Calculate cm per pixel for display
|
||||||
const printAreaWidthPx = activePrintArea.wPct * DISPLAY;
|
const printAreaWidthPx = activePrintArea.wPct * DISPLAY;
|
||||||
const cmPerPx = (product.printAreaWidthMm / printAreaWidthPx) / 10;
|
// printAreaWidthMm is in mm, divide by 10 to get cm
|
||||||
const pxToCm = (px: number) => (px * cmPerPx).toFixed(2);
|
// printAreaWidthPx is in pixels
|
||||||
|
// cmPerPx = cm per pixel
|
||||||
|
const mmPerPx = printAreaWidthPx > 0 ? product.printAreaWidthMm / printAreaWidthPx : 0;
|
||||||
|
const cmPerPx = mmPerPx > 0 ? mmPerPx / 10 : 0;
|
||||||
|
const pxToCm = (px: number) => {
|
||||||
|
const cm = px * cmPerPx;
|
||||||
|
return isNaN(cm) ? '?' : cm.toFixed(2);
|
||||||
|
};
|
||||||
const setActiveElements = view === 'front' ? setElementsFront : setElementsBack;
|
const setActiveElements = view === 'front' ? setElementsFront : setElementsBack;
|
||||||
|
|
||||||
// Keep whichever transformer actually owns the selected element in sync, and
|
// Keep whichever transformer actually owns the selected element in sync, and
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ export function toProductDTO(p: PrismaProduct, activePromotions: ActivePromotion
|
|||||||
mockup: p.mockup,
|
mockup: p.mockup,
|
||||||
printArea: JSON.parse(p.printArea),
|
printArea: JSON.parse(p.printArea),
|
||||||
printAreaBack: p.printAreaBack ? JSON.parse(p.printAreaBack) : null,
|
printAreaBack: p.printAreaBack ? JSON.parse(p.printAreaBack) : null,
|
||||||
|
printAreaWidthMm: p.printAreaWidthMm,
|
||||||
|
printAreaHeightMm: p.printAreaHeightMm,
|
||||||
imageUrl: p.imageUrl,
|
imageUrl: p.imageUrl,
|
||||||
imageUrlBack: p.imageUrlBack,
|
imageUrlBack: p.imageUrlBack,
|
||||||
photoRecolorable: p.photoRecolorable,
|
photoRecolorable: p.photoRecolorable,
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ export type ProductDTO = {
|
|||||||
mockup: string;
|
mockup: string;
|
||||||
printArea: PrintArea;
|
printArea: PrintArea;
|
||||||
printAreaBack: PrintArea | null;
|
printAreaBack: PrintArea | null;
|
||||||
|
printAreaWidthMm: number;
|
||||||
|
printAreaHeightMm: number;
|
||||||
imageUrl: string | null;
|
imageUrl: string | null;
|
||||||
imageUrlBack: string | null;
|
imageUrlBack: string | null;
|
||||||
photoRecolorable: boolean;
|
photoRecolorable: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user