/** * 图形符号配对专用的图形定义 * 所有图形保持大小一致 */ export interface ShapeSymbolShape { id: string; name: string; } export const SHAPE_SYMBOL_SHAPES: ShapeSymbolShape[] = [ { id: 'circle', name: '圆形' }, { id: 'square', name: '正方形' }, { id: 'triangle', name: '三角形' }, { id: 'diamond', name: '菱形' }, { id: 'trapezoid', name: '梯形' }, { id: 'ellipse', name: '椭圆' }, { id: 'star', name: '五角星' }, { id: 'pentagon', name: '五边形' }, { id: 'heart', name: '心形' }, ]; /** * 绘制图形(无边框,仅填充) * 所有图形保持相同的大小 */ export function drawShapeSymbolShape( ctx: RenderingContext, shapeId: string, x: number, y: number, size: number, fillColor: string, ): void { ctx.save(); ctx.translate(x, y); const radius = size / 2; ctx.fillStyle = fillColor; switch (shapeId) { case 'circle': ctx.beginPath(); ctx.arc(0, 0, radius, 0, Math.PI * 2); ctx.fill(); break; case 'square': ctx.fillRect(-radius, -radius, size, size); break; case 'triangle': ctx.beginPath(); ctx.moveTo(0, -radius); ctx.lineTo(-radius, radius); ctx.lineTo(radius, radius); ctx.closePath(); ctx.fill(); break; case 'diamond': ctx.beginPath(); ctx.moveTo(0, -radius); ctx.lineTo(radius, 0); ctx.lineTo(0, radius); ctx.lineTo(-radius, 0); ctx.closePath(); ctx.fill(); break; case 'trapezoid': ctx.beginPath(); const topWidth = radius * 0.6; ctx.moveTo(-topWidth, -radius * 0.7); ctx.lineTo(topWidth, -radius * 0.7); ctx.lineTo(radius, radius * 0.7); ctx.lineTo(-radius, radius * 0.7); ctx.closePath(); ctx.fill(); break; case 'ellipse': ctx.beginPath(); ctx.ellipse(0, 0, radius * 0.8, radius * 0.6, 0, 0, Math.PI * 2); ctx.fill(); break; case 'star': // 五角星 ctx.beginPath(); for (let i = 0; i < 5; i++) { const angle1 = (i * 2 * Math.PI) / 5 - Math.PI / 2; const angle2 = ((i + 0.5) * 2 * Math.PI) / 5 - Math.PI / 2; const r1 = radius; const r2 = radius * 0.4; const x1 = Math.cos(angle1) * r1; const y1 = Math.sin(angle1) * r1; const x2 = Math.cos(angle2) * r2; const y2 = Math.sin(angle2) * r2; if (i === 0) { ctx.moveTo(x1, y1); } else { ctx.lineTo(x1, y1); } ctx.lineTo(x2, y2); } ctx.closePath(); ctx.fill(); break; case 'pentagon': ctx.beginPath(); for (let i = 0; i < 5; i++) { const angle = (i * 2 * Math.PI) / 5 - Math.PI / 2; const px = Math.cos(angle) * radius; const py = Math.sin(angle) * radius; if (i === 0) ctx.moveTo(px, py); else ctx.lineTo(px, py); } ctx.closePath(); ctx.fill(); break; case 'heart': // 爱心路径(参考 shapes.ts 中的 SVG 路径) // SVG路径:M50,35 C35,20 20,35 25,50 C30,65 50,80 50,80 C50,80 70,65 75,50 C80,35 65,20 50,35Z // SVG中心为(50,50),高度约为60(从y=20到y=80) // 使用scale=60使心形高度约为size,与其他图形保持一致 const scale = 60; function tx(px: number) { return ((px - 50) / scale) * size; } function ty(py: number) { return ((py - 50) / scale) * size; } ctx.beginPath(); ctx.moveTo(tx(50), ty(35)); ctx.bezierCurveTo(tx(35), ty(20), tx(20), ty(35), tx(25), ty(50)); ctx.bezierCurveTo(tx(30), ty(65), tx(50), ty(80), tx(50), ty(80)); ctx.bezierCurveTo(tx(50), ty(80), tx(70), ty(65), tx(75), ty(50)); ctx.bezierCurveTo(tx(80), ty(35), tx(65), ty(20), tx(50), ty(35)); ctx.closePath(); ctx.fill(); break; default: // 默认绘制圆形 ctx.beginPath(); ctx.arc(0, 0, radius, 0, Math.PI * 2); ctx.fill(); } ctx.restore(); }