Skip to content

Commit d3215f5

Browse files
wontoryclaude
andcommitted
fix(orbit): ensure SVG width accommodates long text
Add character width calculation to dynamically expand SVG width when text exceeds the orbit-based dimensions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent bd576cd commit d3215f5

3 files changed

Lines changed: 89 additions & 1 deletion

File tree

packages/orbit/src/constants.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,60 @@ const COLORS = {
2828

2929
const FONT_FAMILY = `"Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif`
3030

31-
export { SVG_CONFIG, COLORS, FONT_FAMILY }
31+
const DEFAULT_CHAR_WIDTH = 6.7
32+
const CJK_CHAR_WIDTH = 10
33+
34+
const CHAR_WIDTHS: Record<string, number> = {
35+
' ': 2.8,
36+
f: 3.4,
37+
i: 2.8,
38+
j: 2.8,
39+
l: 2.8,
40+
r: 3.8,
41+
t: 3.8,
42+
'!': 2.8,
43+
'.': 2.8,
44+
',': 2.8,
45+
':': 2.8,
46+
';': 2.8,
47+
'|': 2.8,
48+
"'": 2.8,
49+
'-': 3.8,
50+
m: 10,
51+
w: 8.5,
52+
M: 8.5,
53+
W: 10,
54+
A: 7.2,
55+
B: 7.2,
56+
C: 7.2,
57+
D: 7.6,
58+
E: 6.3,
59+
F: 5.8,
60+
G: 7.6,
61+
H: 7.6,
62+
I: 2.8,
63+
J: 4.5,
64+
K: 7.2,
65+
L: 5.8,
66+
N: 7.6,
67+
O: 8,
68+
P: 6.7,
69+
Q: 8,
70+
R: 7.2,
71+
S: 6.7,
72+
T: 6.3,
73+
U: 7.6,
74+
V: 7.2,
75+
X: 6.7,
76+
Y: 6.3,
77+
Z: 6.7,
78+
}
79+
80+
export {
81+
SVG_CONFIG,
82+
COLORS,
83+
FONT_FAMILY,
84+
DEFAULT_CHAR_WIDTH,
85+
CJK_CHAR_WIDTH,
86+
CHAR_WIDTHS,
87+
}

packages/orbit/src/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
calculateOrbitRadius,
1212
calculateOuterOrbitIconSize,
1313
calculateSvgDimensions,
14+
calculateTextWidth,
1415
escapeXml,
1516
} from '#utils'
1617

@@ -208,6 +209,12 @@ export const generateOrbitSvg = (text: string, icons: SimpleIcon[]): string => {
208209
)
209210
const padding = calculateDynamicPadding(outerOrbitIconSize)
210211
const svgDimensions = calculateSvgDimensions(largestOrbitRadius, padding)
212+
const textWidth = calculateTextWidth(text, SVG_CONFIG.fontSize)
213+
const textPadding = 40
214+
const minWidth = textWidth + textPadding * 2
215+
if (svgDimensions.width < minWidth) {
216+
svgDimensions.width = minWidth
217+
}
211218
const center = calculateCenter(svgDimensions.width, svgDimensions.height)
212219

213220
const orbitConfig: OrbitConfig = {

packages/orbit/src/utils.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { CHAR_WIDTHS, CJK_CHAR_WIDTH, DEFAULT_CHAR_WIDTH } from '#constants'
12
import type { Point, SvgDimensions } from '#types'
23

34
const calculateLargestOrbitRadius = (
@@ -61,6 +62,29 @@ const calculateIconSizeMultiplier = (
6162
orbitIndex: number,
6263
): number => baseMultiplier + incrementFactor * (orbitIndex + 1) ** 1.1
6364

65+
const isCjk = (char: string): boolean => {
66+
const code = char.charCodeAt(0)
67+
return (
68+
(code >= 0x4e00 && code <= 0x9fff) ||
69+
(code >= 0x3400 && code <= 0x4dbf) ||
70+
(code >= 0xac00 && code <= 0xd7af) ||
71+
(code >= 0x3040 && code <= 0x30ff)
72+
)
73+
}
74+
75+
const calculateTextWidth = (text: string, fontSize: number): number => {
76+
const scale = fontSize / 12
77+
let width = 0
78+
for (const char of text) {
79+
if (isCjk(char)) {
80+
width += CJK_CHAR_WIDTH
81+
} else {
82+
width += CHAR_WIDTHS[char] ?? DEFAULT_CHAR_WIDTH
83+
}
84+
}
85+
return Math.ceil(width * scale)
86+
}
87+
6488
const escapeXml = (text: string): string => {
6589
return text
6690
.replace(/&/g, '&amp;')
@@ -79,5 +103,6 @@ export {
79103
calculateOrbitRadius,
80104
calculateAnimationDuration,
81105
calculateIconSizeMultiplier,
106+
calculateTextWidth,
82107
escapeXml,
83108
}

0 commit comments

Comments
 (0)