Add technical drawing dimension lines to design specification sheets

- Fix print area calculation: percentages stored as decimals (0.43125), not percentages
- Expand SVG viewBox to display dimension lines and measurements
- Add brown dimension lines showing distance from garment edges to design center
- Convert measurements from centimeters to inches for clarity
- Fix element center calculation to properly center markers and lines
- Update legend to explain all visual guides
- Add pixel columns to measurements table for manufacturing reference

The design spec now displays professional technical drawing format with:
- Horizontal dimension line at top showing distance from left edge
- Vertical dimension line at right showing distance from top edge
- All measurements overlaid on the actual garment placement image
- Element markers centered at actual design position

Fixes measurement accuracy and improves usability for manufacturers.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Andymick
2026-07-18 11:34:37 +01:00
co-authored by Claude Haiku 4.5
parent c6f041760a
commit bacad4efe2
+42 -13
View File
@@ -40,10 +40,10 @@ export async function GET(req: Request, { params }: { params: { id: string } })
hPct: number; hPct: number;
}; };
const printAreaStartX = DISPLAY * (printArea.xPct / 100); const printAreaStartX = DISPLAY * printArea.xPct;
const printAreaStartY = DISPLAY * (printArea.yPct / 100); const printAreaStartY = DISPLAY * printArea.yPct;
const printAreaWidthPx = DISPLAY * (printArea.wPct / 100); const printAreaWidthPx = DISPLAY * printArea.wPct;
const printAreaHeightPx = DISPLAY * (printArea.hPct / 100); const printAreaHeightPx = DISPLAY * printArea.hPct;
// Scale: how many centimeters per pixel // Scale: how many centimeters per pixel
// printAreaWidthMm / printAreaWidthPx = mm/px // printAreaWidthMm / printAreaWidthPx = mm/px
@@ -77,7 +77,7 @@ export async function GET(req: Request, { params }: { params: { id: string } })
<p><em>Design on product with measurement guides</em></p> <p><em>Design on product with measurement guides</em></p>
<div style="position: relative; display: inline-block; margin: 15px 0;"> <div style="position: relative; display: inline-block; margin: 15px 0;">
<img src="${placement}" alt="${side} design placement" class="mockup-image" style="max-height: 400px; width: auto; display: block; border: 1px solid #ddd;"> <img src="${placement}" alt="${side} design placement" class="mockup-image" style="max-height: 400px; width: auto; display: block; border: 1px solid #ddd;">
<svg style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;" preserveAspectRatio="none"> <svg viewBox="-60 -60 680 680" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;" preserveAspectRatio="xMidYMid meet">
<!-- Print area border --> <!-- Print area border -->
<rect x="${printAreaStartX}" y="${printAreaStartY}" width="${printAreaWidthPx}" height="${printAreaHeightPx}" <rect x="${printAreaStartX}" y="${printAreaStartY}" width="${printAreaWidthPx}" height="${printAreaHeightPx}"
fill="none" stroke="red" stroke-width="2" stroke-dasharray="5,5" opacity="0.8"/> fill="none" stroke="red" stroke-width="2" stroke-dasharray="5,5" opacity="0.8"/>
@@ -94,18 +94,43 @@ export async function GET(req: Request, { params }: { params: { id: string } })
<text x="${printAreaStartX + 5}" y="${printAreaStartY - 5}" font-size="12" fill="blue" font-weight="bold">X (0cm)</text> <text x="${printAreaStartX + 5}" y="${printAreaStartY - 5}" font-size="12" fill="blue" font-weight="bold">X (0cm)</text>
<text x="${printAreaStartX - 25}" y="${printAreaStartY + 15}" font-size="12" fill="green" font-weight="bold">Y (0cm)</text> <text x="${printAreaStartX - 25}" y="${printAreaStartY + 15}" font-size="12" fill="green" font-weight="bold">Y (0cm)</text>
<!-- Design elements with markers --> <!-- Design elements with markers and position dimensions in INCHES (overlaid on image) -->
${designElements.map((el, idx) => ` ${designElements.map((el, idx) => {
<circle cx="${el.x}" cy="${el.y}" r="5" fill="orange" opacity="0.9" stroke="white" stroke-width="1"/> const elWidth = el.width || 58;
<text x="${el.x + 10}" y="${el.y - 10}" font-size="12" fill="orange" font-weight="bold" font-family="monospace">E${idx + 1}</text> const elHeight = el.height || 58;
`).join('')} const elCenterX = el.x + elWidth / 2;
const elCenterY = el.y + elHeight / 2;
const distFromLeftCm = elCenterX * cmPerPx;
const distFromTopCm = elCenterY * cmPerPx;
const distFromLeftInches = (distFromLeftCm / 2.54).toFixed(2);
const distFromTopInches = (distFromTopCm / 2.54).toFixed(2);
return `
<!-- Horizontal dimension line at top of image (from left edge to element center) -->
<line x1="5" y1="10" x2="${elCenterX}" y2="10" stroke="brown" stroke-width="2" opacity="0.8"/>
<line x1="5" y1="5" x2="5" y2="15" stroke="brown" stroke-width="2" opacity="0.8"/>
<line x1="${elCenterX}" y1="5" x2="${elCenterX}" y2="15" stroke="brown" stroke-width="2" opacity="0.8"/>
<text x="${elCenterX / 2 + 5}" y="25" font-size="14" fill="brown" font-weight="bold" font-family="Arial" text-anchor="middle" style="background: rgba(255,255,255,0.8); padding: 2px 4px;">${distFromLeftInches}"</text>
<!-- Vertical dimension line on right side of image (from top edge to element center) -->
<line x1="540" y1="5" x2="540" y2="${elCenterY}" stroke="brown" stroke-width="2" opacity="0.8"/>
<line x1="535" y1="5" x2="545" y2="5" stroke="brown" stroke-width="2" opacity="0.8"/>
<line x1="535" y1="${elCenterY}" x2="545" y2="${elCenterY}" stroke="brown" stroke-width="2" opacity="0.8"/>
<text x="548" y="${elCenterY / 2}" font-size="14" fill="brown" font-weight="bold" font-family="Arial" text-anchor="start">${distFromTopInches}"</text>
<!-- Element marker at center -->
<circle cx="${elCenterX}" cy="${elCenterY}" r="5" fill="orange" opacity="0.9" stroke="white" stroke-width="1"/>
<text x="${elCenterX + 10}" y="${elCenterY - 10}" font-size="12" fill="orange" font-weight="bold" font-family="monospace">E${idx + 1}</text>
`;
}).join('')}
</svg> </svg>
</div> </div>
<div style="margin-top: 15px; font-size: 12px; color: #666; text-align: left; max-width: 400px;"> <div style="margin-top: 15px; font-size: 12px; color: #666; text-align: left; max-width: 400px;">
<p style="margin: 5px 0;"><strong style="color: red;">━━ Red dashed line:</strong> Print area boundary</p> <p style="margin: 5px 0;"><strong style="color: red;">━━ Red dashed line:</strong> Print area boundary</p>
<p style="margin: 5px 0;"><strong style="color: blue;">━ Blue line:</strong> X-axis (horizontal, 0cm at left)</p> <p style="margin: 5px 0;"><strong style="color: blue;">━ Blue line:</strong> X-axis (horizontal, 0cm at left edge)</p>
<p style="margin: 5px 0;"><strong style="color: green;">━ Green line:</strong> Y-axis (vertical, 0cm at top)</p> <p style="margin: 5px 0;"><strong style="color: green;">━ Green line:</strong> Y-axis (vertical, 0cm at top edge)</p>
<p style="margin: 5px 0;"><strong style="color: orange;">● Orange circles:</strong> Element positions (E1, E2, etc.)</p> <p style="margin: 5px 0;"><strong style="color: brown;">┊ Brown dashed lines:</strong> Position guides from edges to element center</p>
<p style="margin: 5px 0;"><strong style="color: brown;">T: / L:</strong> Distance from top and left edges of garment in cm</p>
<p style="margin: 5px 0;"><strong style="color: orange;">● Orange circles:</strong> Design element positions (E1, E2, etc.)</p>
</div> </div>
</div> </div>
` : ''} ` : ''}
@@ -116,7 +141,9 @@ export async function GET(req: Request, { params }: { params: { id: string } })
<th>Element</th> <th>Element</th>
<th>Type</th> <th>Type</th>
<th>Position (CM)</th> <th>Position (CM)</th>
<th>Position (px)</th>
<th>Size (CM)</th> <th>Size (CM)</th>
<th>Size (px)</th>
<th>Details</th> <th>Details</th>
</tr> </tr>
</thead> </thead>
@@ -126,7 +153,9 @@ export async function GET(req: Request, { params }: { params: { id: string } })
<td>E${idx + 1}</td> <td>E${idx + 1}</td>
<td class="element-type">${el.type === 'text' ? '📝 Text' : '🖼️ Image'}</td> <td class="element-type">${el.type === 'text' ? '📝 Text' : '🖼️ Image'}</td>
<td>X: ${convertPositionToCm(el.x, printAreaStartX)} | Y: ${convertPositionToCm(el.y, printAreaStartY)}</td> <td>X: ${convertPositionToCm(el.x, printAreaStartX)} | Y: ${convertPositionToCm(el.y, printAreaStartY)}</td>
<td>X: ${Math.round(el.x - printAreaStartX)} | Y: ${Math.round(el.y - printAreaStartY)}</td>
<td>${el.type === 'image' ? `${convertToCm(el.width)} × ${convertToCm(el.height)}` : 'N/A'}</td> <td>${el.type === 'image' ? `${convertToCm(el.width)} × ${convertToCm(el.height)}` : 'N/A'}</td>
<td>${el.type === 'image' ? `${Math.round(el.width)} × ${Math.round(el.height)}` : 'N/A'}</td>
<td> <td>
${el.type === 'text' ? ` ${el.type === 'text' ? `
Font: ${el.fontFamily}, ${Math.round(el.fontSize * cmPerPx * 2.834)}pt<br> Font: ${el.fontFamily}, ${Math.round(el.fontSize * cmPerPx * 2.834)}pt<br>