|
| 1 | +import { wrapText } from '../utils'; |
| 2 | + |
| 3 | +export const blueprint = (ctx, width, height, scale, data) => { |
| 4 | + const { repoOwner, repoName, description, stars, supportUrl } = data; |
| 5 | + // Improved Blueprint CAD Style |
| 6 | + const blueBg = '#004ecb'; // Deeper, more authentic blueprint blue |
| 7 | + ctx.fillStyle = blueBg; |
| 8 | + ctx.fillRect(0, 0, width, height); |
| 9 | + |
| 10 | + const padding = 60 * scale; |
| 11 | + |
| 12 | + // Grid (Subtle) |
| 13 | + ctx.strokeStyle = 'rgba(255, 255, 255, 0.15)'; |
| 14 | + ctx.lineWidth = 1 * scale; |
| 15 | + const gridSize = 40 * scale; |
| 16 | + |
| 17 | + ctx.beginPath(); |
| 18 | + for (let x = 0; x < width; x += gridSize) ctx.rect(x, 0, 1, height); |
| 19 | + for (let y = 0; y < height; y += gridSize) ctx.rect(0, y, width, 1); |
| 20 | + ctx.stroke(); |
| 21 | + |
| 22 | + // Major Grid Lines |
| 23 | + ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)'; |
| 24 | + ctx.lineWidth = 2 * scale; |
| 25 | + ctx.beginPath(); |
| 26 | + for (let x = 0; x < width; x += gridSize * 4) ctx.rect(x, 0, 1, height); |
| 27 | + for (let y = 0; y < height; y += gridSize * 4) ctx.rect(0, y, width, 1); |
| 28 | + ctx.stroke(); |
| 29 | + |
| 30 | + // Main Frame |
| 31 | + ctx.strokeStyle = 'white'; |
| 32 | + ctx.lineWidth = 6 * scale; |
| 33 | + ctx.strokeRect(padding, padding, width - (padding * 2), height - (padding * 2)); |
| 34 | + |
| 35 | + // Title Block (Bottom Left) |
| 36 | + const blockW = 500 * scale; |
| 37 | + const blockH = 180 * scale; |
| 38 | + const blockX = padding; // Move to left |
| 39 | + const blockY = height - padding - blockH; |
| 40 | + |
| 41 | + ctx.lineWidth = 3 * scale; |
| 42 | + ctx.fillStyle = 'white'; |
| 43 | + ctx.strokeRect(blockX, blockY, blockW, blockH); |
| 44 | + |
| 45 | + // Internal lines of Title Block |
| 46 | + const rowH = blockH / 4; |
| 47 | + ctx.beginPath(); |
| 48 | + for(let i=1; i<4; i++) { |
| 49 | + ctx.moveTo(blockX, blockY + (i*rowH)); |
| 50 | + ctx.lineTo(blockX + blockW, blockY + (i*rowH)); |
| 51 | + } |
| 52 | + ctx.moveTo(blockX + (blockW * 0.3), blockY); |
| 53 | + ctx.lineTo(blockX + (blockW * 0.3), blockY + blockH); |
| 54 | + ctx.stroke(); |
| 55 | + |
| 56 | + // Text in Block |
| 57 | + ctx.font = `bold ${14 * scale}px "Courier New", monospace`; |
| 58 | + ctx.textAlign = 'left'; |
| 59 | + ctx.textBaseline = 'middle'; |
| 60 | + |
| 61 | + const labels = ['PROJECT', 'AUTHOR', 'URL', 'STARS']; |
| 62 | + const values = [repoName.substring(0, 20).toUpperCase(), repoOwner.toUpperCase(), (supportUrl || '').toUpperCase(), stars || '0']; |
| 63 | + |
| 64 | + labels.forEach((label, i) => { |
| 65 | + ctx.fillText(label, blockX + 10 * scale, blockY + (i * rowH) + (rowH/2)); |
| 66 | + ctx.fillText(values[i], blockX + (blockW * 0.3) + 10 * scale, blockY + (i * rowH) + (rowH/2)); |
| 67 | + }); |
| 68 | + |
| 69 | + // Main Drawing Area Content |
| 70 | + ctx.textAlign = 'center'; |
| 71 | + ctx.textBaseline = 'middle'; |
| 72 | + |
| 73 | + // Center Lines |
| 74 | + ctx.setLineDash([20 * scale, 10 * scale, 5 * scale, 10 * scale]); |
| 75 | + ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)'; |
| 76 | + ctx.lineWidth = 1 * scale; |
| 77 | + ctx.beginPath(); |
| 78 | + ctx.moveTo(width/2, padding); ctx.lineTo(width/2, height - padding); // Vert |
| 79 | + ctx.moveTo(padding, height/2); ctx.lineTo(width - padding, height/2); // Horiz |
| 80 | + ctx.stroke(); |
| 81 | + ctx.setLineDash([]); |
| 82 | + |
| 83 | + // Project Name (Main) - Moved Up |
| 84 | + ctx.font = `bold ${100 * scale}px "Courier New", monospace`; |
| 85 | + ctx.fillStyle = 'white'; |
| 86 | + ctx.fillText(repoName.toUpperCase(), width/2, height/2 - 80 * scale); |
| 87 | + |
| 88 | + // Measurement Lines |
| 89 | + const textW = ctx.measureText(repoName.toUpperCase()).width; |
| 90 | + const lineY = height/2; // adjusted |
| 91 | + |
| 92 | + ctx.beginPath(); |
| 93 | + ctx.moveTo(width/2 - textW/2, lineY); |
| 94 | + ctx.lineTo(width/2 + textW/2, lineY); |
| 95 | + ctx.strokeStyle = 'white'; |
| 96 | + ctx.lineWidth = 2 * scale; |
| 97 | + ctx.stroke(); |
| 98 | + |
| 99 | + // Arrows |
| 100 | + ctx.beginPath(); |
| 101 | + ctx.moveTo(width/2 - textW/2 + 20*scale, lineY - 10*scale); ctx.lineTo(width/2 - textW/2, lineY); ctx.lineTo(width/2 - textW/2 + 20*scale, lineY + 10*scale); |
| 102 | + ctx.moveTo(width/2 + textW/2 - 20*scale, lineY - 10*scale); ctx.lineTo(width/2 + textW/2, lineY); ctx.lineTo(width/2 + textW/2 - 20*scale, lineY + 10*scale); |
| 103 | + ctx.fill(); |
| 104 | + |
| 105 | + // Description - Bottom Right |
| 106 | + ctx.textAlign = 'left'; |
| 107 | + ctx.textBaseline = 'top'; |
| 108 | + ctx.font = `${24 * scale}px "Courier New", monospace`; |
| 109 | + ctx.fillStyle = 'rgba(255, 255, 255, 0.9)'; |
| 110 | + |
| 111 | + const descX = width/2 + 40 * scale; |
| 112 | + const descY = height/2 + 40 * scale; |
| 113 | + const descW = width/2 - padding - 80 * scale; |
| 114 | + |
| 115 | + // Label for description |
| 116 | + ctx.fillText("NOTES:", descX, descY); |
| 117 | + |
| 118 | + // Wrap text below "NOTES:" |
| 119 | + wrapText(ctx, description.toUpperCase(), descX, descY + 40 * scale, descW, 35 * scale); |
| 120 | +}; |
0 commit comments