Featuring Design System

Shape Primitives

SVG 도형 원시 컴포넌트 — activeShape, activeBar, dot, shape 등의 커스텀 렌더러로 사용.

개요

차트 시리즈의 activeShape, activeBar, dot, activeDot, shape 같은 slot을 함수((props) => ReactElement)로 전달할 때 사용하는 원시 컴포넌트입니다. fill/stroke $토큰 해석을 지원합니다.

컴포넌트fillstroketypo주 용도
SectorOO-Pie activeShape, RadialBar activeShape
RectangleOO-Bar activeBar
ChartDotOO-Line/Area dot / activeDot
CrossOO-Scatter shape, ChartTooltip cursor
TrapezoidOO-Funnel activeShape
PolygonOO-Radar 커스텀 shape
SymbolsOO-Scatter 마커 (circle, cross, diamond 등)
Curve-O-SVG path 곡선
TextO-OSVG 텍스트 (ChartTypo 토큰 지원)

Usage

Pie + Sector activeShape

activeShape에 함수를 전달해 호버 시 Sector의 outerRadius를 확장합니다.

() => {
const data = [
  { name: '인스타그램', value: 420 },
  { name: '유튜브', value: 310 },
  { name: '틱톡', value: 230 },
  { name: '블로그', value: 140 },
];
const fills = ['$primary-50', '$teal-50', '$lightBlue-40', '$gray-50'];
return (
  <ResponsiveContainer width="100%" height={280}>
    <PieChart>
      <Pie
        data={data}
        dataKey="value"
        nameKey="name"
        cx="50%"
        cy="50%"
        outerRadius={100}
        activeShape={(props) => (
          <Sector
            {...props}
            stroke="$primary-60"
            strokeWidth={2}
            outerRadius={props.outerRadius + 8}
          />
        )}
      >
        {data.map((_, i) => (
          <Cell key={i} fill={resolveToken(fills[i])} />
        ))}
      </Pie>
      <ChartTooltip />
    </PieChart>
  </ResponsiveContainer>
);
}

Bar + Rectangle activeBar

activeBar로 호버 상태 막대를 Rectangle 원시로 그립니다.

() => {
const data = [
  { name: '1월', value: 4200 },
  { name: '2월', value: 3800 },
  { name: '3월', value: 5200 },
  { name: '4월', value: 4780 },
  { name: '5월', value: 3890 },
];
return (
  <ResponsiveContainer width="100%" height={280}>
    <BarChart data={data}>
      <CartesianGrid />
      <XAxis dataKey="name" />
      <YAxis />
      <Bar
        dataKey="value"
        fill="$primary-50"
        activeBar={(props) => (
          <Rectangle
            {...props}
            fill="$primary-30"
            stroke="$primary-60"
            strokeWidth={2}
          />
        )}
      />
      <ChartTooltip />
    </BarChart>
  </ResponsiveContainer>
);
}

Line + ChartDot customDot

dotactiveDot에 함수를 전달해 데이터 포인트를 커스텀 렌더합니다.

() => {
const data = [
  { date: '04/01', views: 4200 },
  { date: '04/02', views: 3800 },
  { date: '04/03', views: 5100 },
  { date: '04/04', views: 4780 },
  { date: '04/05', views: 3890 },
  { date: '04/06', views: 6200 },
];
return (
  <ResponsiveContainer width="100%" height={280}>
    <LineChart data={data}>
      <CartesianGrid />
      <XAxis dataKey="date" />
      <YAxis />
      <Line
        type="monotone"
        dataKey="views"
        stroke="$primary-50"
        strokeWidth={2}
        dot={(props) => (
          <ChartDot key={props.key} cx={props.cx} cy={props.cy} r={4} fill="$primary-50" stroke="$background-1" strokeWidth={2} />
        )}
        activeDot={(props) => (
          <ChartDot key={props.key} cx={props.cx} cy={props.cy} r={6} fill="$primary-30" stroke="$background-1" strokeWidth={2} />
        )}
      />
      <ChartTooltip />
    </LineChart>
  </ResponsiveContainer>
);
}

Scatter + Cross shape

Scatter.shape에 함수를 전달하면 포인트마다 Cross 원시를 그립니다.

() => {
const data = [
  { x: 100, y: 200 },
  { x: 120, y: 100 },
  { x: 170, y: 300 },
  { x: 140, y: 250 },
  { x: 150, y: 400 },
  { x: 110, y: 280 },
];
return (
  <ResponsiveContainer width="100%" height={280}>
    <ScatterChart margin={{ top: 20, right: 20, bottom: 20, left: 20 }}>
      <CartesianGrid />
      <XAxis dataKey="x" name="X" />
      <YAxis dataKey="y" name="Y" />
      <Scatter
        name="데이터"
        data={data}
        fill="$primary-50"
        shape={(props) => (
          <Cross
            x={props.cx}
            y={props.cy}
            top={props.cy - 8}
            left={props.cx - 8}
            width={16}
            height={16}
            fill="$teal-50"
            stroke="$teal-50"
          />
        )}
      />
      <ChartTooltip />
    </ScatterChart>
  </ResponsiveContainer>
);
}

Funnel + Trapezoid activeShape

Funnel 단계의 호버 상태를 Trapezoid 원시로 덮어씁니다.

() => {
const data = [
  { name: '도달', value: 1000000 },
  { name: '참여', value: 250000 },
  { name: '클릭', value: 50000 },
  { name: '전환', value: 12000 },
];
const fills = ['$primary-50', '$primary-40', '$primary-30', '$primary-20'];
return (
  <ResponsiveContainer width="100%" height={280}>
    <FunnelChart>
      <Funnel
        dataKey="value"
        data={data}
        activeShape={(props) => (
          <Trapezoid
            {...props}
            stroke="$primary-60"
            strokeWidth={2}
          />
        )}
      >
        {data.map((_, i) => <Cell key={i} fill={resolveToken(fills[i])} />)}
      </Funnel>
      <ChartTooltip />
    </FunnelChart>
  </ResponsiveContainer>
);
}

Text — SVG 텍스트 with typo 토큰

독립 SVG 안에 텍스트를 배치할 때 typo 토큰을 사용하면 fontSize, fontWeight, fontFamily가 자동 적용됩니다.

() => (
<svg width={300} height={80}>
  <Text x={20} y={30} fill="$text-1" typo="$heading-5">제목</Text>
  <Text x={20} y={55} fill="$text-3" typo="$caption-1">보조 설명</Text>
</svg>
)

Props

모든 shape primitive는 recharts의 동일 이름 컴포넌트를 래핑합니다. 여기에 명시되지 않은 props는 해당 recharts API를 참고하세요.

공통 Shape Props

모두 SVG 속성을 그대로 받으며, fill/stroke 입력에 $토큰을 사용할 수 있습니다. 단 Curvefill 토큰을 해석하지 않고, Textstroke 토큰을 해석하지 않습니다 (위 표 참고).

Prop

Type

Sector

extends recharts Sector

Prop

Type

Rectangle

extends recharts Rectangle

Prop

Type

Dot

extends recharts Dot

Prop

Type

Cross

extends recharts Cross

Prop

Type

Trapezoid

extends recharts Trapezoid

Prop

Type

Polygon

extends recharts Polygon

Prop

Type

Symbols

extends recharts Symbols

Prop

Type

Curve

extends recharts Curve

Prop

Type

Text

extends recharts Text

Prop

Type