Fix design spec measurements and add visual X/Y axis guides
- Fixed conversion formula for accurate CM measurements - Add red dashed border around print area - Add blue X-axis line (horizontal, 0cm at left) - Add green Y-axis line (vertical, 0cm at top) - Add orange circles marking design element positions - Add reference legend explaining all visual guides - Element labels changed from E1, E2 for clarity
This commit is contained in:
@@ -42,10 +42,95 @@ export async function GET(req: Request, { params }: { params: { id: string } })
|
|||||||
|
|
||||||
const printAreaWidthPx = DISPLAY * (printArea.wPct / 100);
|
const printAreaWidthPx = DISPLAY * (printArea.wPct / 100);
|
||||||
const printAreaHeightPx = DISPLAY * (printArea.hPct / 100);
|
const printAreaHeightPx = DISPLAY * (printArea.hPct / 100);
|
||||||
|
|
||||||
|
// Scale: how many pixels per millimeter
|
||||||
const pxPerMm = printAreaWidthPx / printAreaWidthMm;
|
const pxPerMm = printAreaWidthPx / printAreaWidthMm;
|
||||||
|
|
||||||
// Convert pixel positions to CM
|
// Convert pixel measurements to CM (divide by pxPerMm to get mm, then divide by 10 for cm)
|
||||||
const convertToCm = (px: number) => (px / pxPerMm / 10).toFixed(1);
|
const convertToCm = (px: number) => {
|
||||||
|
const mm = px / pxPerMm;
|
||||||
|
return (mm / 10).toFixed(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
const printAreaStartX = DISPLAY * (printArea.xPct / 100);
|
||||||
|
const printAreaStartY = DISPLAY * (printArea.yPct / 100);
|
||||||
|
|
||||||
|
const generateDesignSection = (designElements: any[], side: 'Front' | 'Back', placement: string | null, designPreview: string | null) => {
|
||||||
|
if (!designElements || designElements.length === 0) return '';
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="spec-section">
|
||||||
|
<h2>${side} Design</h2>
|
||||||
|
|
||||||
|
<div class="print-area-info">
|
||||||
|
<strong>Printable Area:</strong> ${printAreaWidthMm}mm × ${printAreaHeightMm}mm (${convertToCm(printAreaWidthPx)} cm × ${convertToCm(printAreaHeightPx)} cm)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
${placement ? `
|
||||||
|
<div class="mockup-container">
|
||||||
|
<p><em>Design on product (reference only) — with measurement guides</em></p>
|
||||||
|
<div style="position: relative; display: inline-block; max-width: 100%; max-height: 400px;">
|
||||||
|
<img src="${placement}" alt="${side} design placement" class="mockup-image" style="max-height: 400px; width: auto; display: block;">
|
||||||
|
<svg style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none;" viewBox="0 0 ${DISPLAY} ${DISPLAY}">
|
||||||
|
<!-- Print area border -->
|
||||||
|
<rect x="${printAreaStartX}" y="${printAreaStartY}" width="${printAreaWidthPx}" height="${printAreaHeightPx}" fill="none" stroke="#ff0000" stroke-width="2" stroke-dasharray="5,5" opacity="0.7"/>
|
||||||
|
|
||||||
|
<!-- X-axis line -->
|
||||||
|
<line x1="${printAreaStartX}" y1="${printAreaStartY}" x2="${printAreaStartX + printAreaWidthPx}" y2="${printAreaStartY}" stroke="#0066ff" stroke-width="1" opacity="0.5"/>
|
||||||
|
|
||||||
|
<!-- Y-axis line -->
|
||||||
|
<line x1="${printAreaStartX}" y1="${printAreaStartY}" x2="${printAreaStartX}" y2="${printAreaStartY + printAreaHeightPx}" stroke="#00cc00" stroke-width="1" opacity="0.5"/>
|
||||||
|
|
||||||
|
<!-- Design elements with coordinate markers -->
|
||||||
|
${designElements.map((el, idx) => `
|
||||||
|
<circle cx="${el.x}" cy="${el.y}" r="4" fill="#ff6600" opacity="0.9"/>
|
||||||
|
<text x="${el.x + 8}" y="${el.y - 8}" font-size="11" fill="#ff6600" font-weight="bold" font-family="monospace">E${idx + 1}</text>
|
||||||
|
`).join('')}
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top: 15px; font-size: 12px; color: #666; text-align: left;">
|
||||||
|
<p style="margin: 5px 0;"><strong style="color: #ff0000;">━━ Red dashed:</strong> Print area boundary</p>
|
||||||
|
<p style="margin: 5px 0;"><strong style="color: #0066ff;">━ Blue:</strong> X-axis (0cm at left)</p>
|
||||||
|
<p style="margin: 5px 0;"><strong style="color: #00cc00;">━ Green:</strong> Y-axis (0cm at top)</p>
|
||||||
|
<p style="margin: 5px 0;"><strong style="color: #ff6600;">● Orange circles:</strong> Element positions with labels (E1, E2, etc.)</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
|
<table class="measurements-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Element</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Position (CM)</th>
|
||||||
|
<th>Size (CM)</th>
|
||||||
|
<th>Details</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
${designElements.map((el, idx) => `
|
||||||
|
<tr>
|
||||||
|
<td>E${idx + 1}</td>
|
||||||
|
<td class="element-type">${el.type === 'text' ? '📝 Text' : '🖼️ Image'}</td>
|
||||||
|
<td>X: ${convertToCm(el.x)} | Y: ${convertToCm(el.y)}</td>
|
||||||
|
<td>${el.type === 'image' ? `${convertToCm(el.width)} × ${convertToCm(el.height)}` : 'N/A'}</td>
|
||||||
|
<td>
|
||||||
|
${el.type === 'text' ? `
|
||||||
|
Font: ${el.fontFamily}, ${Math.round(el.fontSize / pxPerMm * 10 / 10)}pt<br>
|
||||||
|
Color: ${el.fill}<br>
|
||||||
|
Text: "${el.text}"<br>
|
||||||
|
Rotation: ${Math.round(el.rotation)}°
|
||||||
|
` : `
|
||||||
|
Rotation: ${Math.round(el.rotation)}°
|
||||||
|
`}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`).join('')}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
const html = `
|
const html = `
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@@ -134,109 +219,15 @@ export async function GET(req: Request, { params }: { params: { id: string } })
|
|||||||
<p><strong>Order Date:</strong> ${new Date(order.createdAt).toLocaleDateString()}</p>
|
<p><strong>Order Date:</strong> ${new Date(order.createdAt).toLocaleDateString()}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
${design.front && design.front.length > 0 ? `
|
${generateDesignSection(design.front, 'Front', item.placementPreviewUrl, item.designPreviewUrl)}
|
||||||
<div class="spec-section">
|
${generateDesignSection(design.back, 'Back', item.placementPreviewUrlBack, item.designPreviewUrlBack)}
|
||||||
<h2>Front Design</h2>
|
|
||||||
|
|
||||||
<div class="print-area-info">
|
|
||||||
<strong>Printable Area:</strong> ${printAreaWidthMm}mm × ${printAreaHeightMm}mm (${convertToCm(printAreaWidthPx)} cm × ${convertToCm(printAreaHeightPx)} cm)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
${item.placementPreviewUrl ? `
|
|
||||||
<div class="mockup-container">
|
|
||||||
<p><em>Design on product (reference only)</em></p>
|
|
||||||
<img src="${item.placementPreviewUrl}" alt="Front design placement" class="mockup-image" style="max-height: 400px;">
|
|
||||||
</div>
|
|
||||||
` : ''}
|
|
||||||
|
|
||||||
<table class="measurements-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Element</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Position (CM)</th>
|
|
||||||
<th>Size (CM)</th>
|
|
||||||
<th>Details</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
${(design.front as any[]).map((el, idx) => `
|
|
||||||
<tr>
|
|
||||||
<td>${idx + 1}</td>
|
|
||||||
<td class="element-type">${el.type === 'text' ? '📝 Text' : '🖼️ Image'}</td>
|
|
||||||
<td>X: ${convertToCm(el.x)} | Y: ${convertToCm(el.y)}</td>
|
|
||||||
<td>${el.type === 'image' ? `${convertToCm(el.width)} × ${convertToCm(el.height)}` : 'N/A'}</td>
|
|
||||||
<td>
|
|
||||||
${el.type === 'text' ? `
|
|
||||||
Font: ${el.fontFamily}, ${Math.round(el.fontSize / pxPerMm * 10 / 10)}pt<br>
|
|
||||||
Color: ${el.fill}<br>
|
|
||||||
Text: "${el.text}"<br>
|
|
||||||
Rotation: ${Math.round(el.rotation)}°
|
|
||||||
` : `
|
|
||||||
Rotation: ${Math.round(el.rotation)}°
|
|
||||||
`}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
`).join('')}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
` : ''}
|
|
||||||
|
|
||||||
${design.back && design.back.length > 0 ? `
|
|
||||||
<div class="spec-section">
|
|
||||||
<h2>Back Design</h2>
|
|
||||||
|
|
||||||
<div class="print-area-info">
|
|
||||||
<strong>Printable Area:</strong> ${printAreaWidthMm}mm × ${printAreaHeightMm}mm (${convertToCm(printAreaWidthPx)} cm × ${convertToCm(printAreaHeightPx)} cm)
|
|
||||||
</div>
|
|
||||||
|
|
||||||
${item.placementPreviewUrlBack ? `
|
|
||||||
<div class="mockup-container">
|
|
||||||
<p><em>Design on product (reference only)</em></p>
|
|
||||||
<img src="${item.placementPreviewUrlBack}" alt="Back design placement" class="mockup-image" style="max-height: 400px;">
|
|
||||||
</div>
|
|
||||||
` : ''}
|
|
||||||
|
|
||||||
<table class="measurements-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Element</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Position (CM)</th>
|
|
||||||
<th>Size (CM)</th>
|
|
||||||
<th>Details</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
${(design.back as any[]).map((el, idx) => `
|
|
||||||
<tr>
|
|
||||||
<td>${idx + 1}</td>
|
|
||||||
<td class="element-type">${el.type === 'text' ? '📝 Text' : '🖼️ Image'}</td>
|
|
||||||
<td>X: ${convertToCm(el.x)} | Y: ${convertToCm(el.y)}</td>
|
|
||||||
<td>${el.type === 'image' ? `${convertToCm(el.width)} × ${convertToCm(el.height)}` : 'N/A'}</td>
|
|
||||||
<td>
|
|
||||||
${el.type === 'text' ? `
|
|
||||||
Font: ${el.fontFamily}, ${Math.round(el.fontSize / pxPerMm * 10 / 10)}pt<br>
|
|
||||||
Color: ${el.fill}<br>
|
|
||||||
Text: "${el.text}"<br>
|
|
||||||
Rotation: ${Math.round(el.rotation)}°
|
|
||||||
` : `
|
|
||||||
Rotation: ${Math.round(el.rotation)}°
|
|
||||||
`}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
`).join('')}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
` : ''}
|
|
||||||
|
|
||||||
<div class="spec-section" style="margin-top: 40px; padding-top: 20px; border-top: 1px solid #ccc; font-size: 12px; color: #666;">
|
<div class="spec-section" style="margin-top: 40px; padding-top: 20px; border-top: 1px solid #ccc; font-size: 12px; color: #666;">
|
||||||
<p><strong>Notes:</strong></p>
|
<p><strong>Notes:</strong></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>All measurements are in centimeters (CM)</li>
|
<li>All measurements are in centimeters (CM)</li>
|
||||||
<li>Coordinates are measured from top-left of the printable area</li>
|
<li>Coordinates are measured from top-left of the printable area (0,0)</li>
|
||||||
|
<li>X-axis runs left-to-right | Y-axis runs top-to-bottom</li>
|
||||||
<li>Print the design files separately for production</li>
|
<li>Print the design files separately for production</li>
|
||||||
<li>This specification sheet is for reference and planning only</li>
|
<li>This specification sheet is for reference and planning only</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
Reference in New Issue
Block a user