Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/__tests__/utils/generateStatsSvg.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ describe('generateStatsSvg 유틸리티 함수 테스트', () => {
// 사용자 데이터가 SVG에 포함되어 있는지 확인
expect(result).toContain('testuser');
expect(result).toContain('50');
expect(result).toContain('200/1000');
expect(result).toContain('200');
expect(result).toContain('1000');
expect(result).toContain('20.00%');
expect(result).toContain('5000');
});
Expand Down
42 changes: 26 additions & 16 deletions src/utils/generateCategorySvg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,31 @@ export function generateCategorySvg(stats: TCategoryStats, theme: Theme = 'light
const angleSize = percentage * 360;
const endAngle = currentAngle + angleSize;

// 원형 조각 경로
const startX = pieCenterX + radius * Math.cos((currentAngle - 90) * Math.PI / 180);
const startY = pieCenterY + radius * Math.sin((currentAngle - 90) * Math.PI / 180);
const endX = pieCenterX + radius * Math.cos((endAngle - 90) * Math.PI / 180);
const endY = pieCenterY + radius * Math.sin((endAngle - 90) * Math.PI / 180);
const largeArcFlag = angleSize > 180 ? 1 : 0;

const path = `
<path
d="M ${pieCenterX} ${pieCenterY} L ${startX} ${startY} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${endX} ${endY} Z"
fill="${category.color}"
stroke="${colors.background}"
stroke-width="1"
/>
`;
let path: string;

if (angleSize >= 359.99) {
// 100%인 경우 arc 대신 원을 그림 (SVG arc는 시작점==끝점이면 렌더링 안됨)
path = `
<circle cx="${pieCenterX}" cy="${pieCenterY}" r="${radius}" fill="${category.color}"
stroke="${colors.background}" stroke-width="1" />
`;
} else {
// 원형 조각 경로
const startX = pieCenterX + radius * Math.cos((currentAngle - 90) * Math.PI / 180);
const startY = pieCenterY + radius * Math.sin((currentAngle - 90) * Math.PI / 180);
const endX = pieCenterX + radius * Math.cos((endAngle - 90) * Math.PI / 180);
const endY = pieCenterY + radius * Math.sin((endAngle - 90) * Math.PI / 180);
const largeArcFlag = angleSize > 180 ? 1 : 0;

path = `
<path
d="M ${pieCenterX} ${pieCenterY} L ${startX} ${startY} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${endX} ${endY} Z"
fill="${category.color}"
stroke="${colors.background}"
stroke-width="1"
/>
`;
}

// 퍼센트 라벨
const midAngle = currentAngle + angleSize / 2;
Expand All @@ -97,7 +107,7 @@ export function generateCategorySvg(stats: TCategoryStats, theme: Theme = 'light
legends += `
<rect x="${legendStartX}" y="${legendY}" width="10" height="10" fill="${category.color}" rx="2" ry="2" />
<text x="${legendStartX + 16}" y="${legendY + 9}" class="legend-text">${capitalizedName}</text>
<text x="${legendStartX + 135}" y="${legendY + 9}" class="legend-value">${percentage}%</text>
<text x="${legendStartX + 125}" y="${legendY + 9}" class="legend-value">${percentage}%</text>
`;
});
}
Expand Down
8 changes: 7 additions & 1 deletion src/utils/generateStatsSvg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ const themes: Record<Theme, ThemeColors> = {
export function generateStatsSvg(stats: Tstats, theme: Theme = 'light'): string {
const colors = themes[theme];

const rankParts = stats.wargame_rank.split('/');
const rankDisplay = rankParts.length === 2
? `<tspan class="stat-value">${rankParts[0]}</tspan><tspan class="rank-total" dx="1">/</tspan><tspan class="rank-total" dx="1">${rankParts[1]}</tspan>`
: `<tspan class="stat-value">${stats.wargame_rank}</tspan>`;

return `
<svg xmlns="http://www.w3.org/2000/svg" width="390" height="190" viewBox="0 0 390 190" fill="none">
<style>
Expand All @@ -32,6 +37,7 @@ export function generateStatsSvg(stats: Tstats, theme: Theme = 'light'): string
.user-name { font: 700 28px 'JetBrains Mono', monospace; fill: ${colors.text}; }
.stat-label { font: 400 10px 'JetBrains Mono', monospace; fill: ${colors.subText}; }
.stat-value { font: 700 18px 'JetBrains Mono', monospace; fill: ${colors.text}; }
.rank-total { font: 700 12px 'JetBrains Mono', monospace; fill: ${colors.title}; }
.top-label { font: 500 12px 'JetBrains Mono', monospace; fill: ${colors.title}; }
.top-value { font: 700 20px 'JetBrains Mono', monospace; fill: ${colors.accent}; }
</style>
Expand Down Expand Up @@ -61,7 +67,7 @@ export function generateStatsSvg(stats: Tstats, theme: Theme = 'light'): string
<g transform="translate(137, 105)">
<rect x="0" y="0" width="115" height="70" fill="${colors.cardBackground}" rx="8" ry="8"/>
<text x="57.5" y="16" class="stat-label" text-anchor="middle">Rank</text>
<text x="57.5" y="48" class="stat-value" text-anchor="middle">${stats.wargame_rank}</text>
<text x="57.5" y="48" text-anchor="middle">${rankDisplay}</text>
</g>

<g transform="translate(259, 105)">
Expand Down
Loading