2025-03-14T13:00:37
This commit is contained in:
205
doc/svg/12_SVG를 활용한 대시보드 UI.md
Normal file
205
doc/svg/12_SVG를 활용한 대시보드 UI.md
Normal file
@@ -0,0 +1,205 @@
|
||||
### SVG를 활용한 대시보드 UI 구현
|
||||
|
||||
SVG(Scalable Vector Graphics)는 대시보드 UI를 구현하는 데 매우 적합한 기술입니다. 확장 가능한 벡터 그래픽 특성 덕분에 다양한 화면 크기와 해상도에서 선명함을 유지하며, 동적 데이터 시각화와 인터랙티브 요소를 구현하기에 유연합니다. 아래에서는 SVG를 활용한 대시보드 UI의 설계 접근법, 주요 구성 요소, 그리고 구현 예시를 설명합니다.
|
||||
|
||||
---
|
||||
|
||||
### SVG 기반 대시보드 UI의 장점
|
||||
|
||||
1. **해상도 독립성**: 데스크톱, 모바일 등 모든 디바이스에서 품질 유지.
|
||||
2. **동적 업데이트**: JavaScript로 실시간 데이터 반영 가능.
|
||||
3. **스타일링 유연성**: CSS로 색상, 크기, 애니메이션 조정.
|
||||
4. **인터랙티브성**: 클릭, 호버, 드래그 등 이벤트 처리 용이.
|
||||
5. **작은 파일 크기**: 이미지 기반 UI보다 효율적.
|
||||
|
||||
---
|
||||
|
||||
### 대시보드 UI 설계 접근법
|
||||
|
||||
대시보드는 데이터 시각화(차트, 그래프), 상태 표시(아이콘, 게이지), 사용자 인터랙션(버튼, 필터) 등으로 구성됩니다. SVG를 활용한 설계 단계는 다음과 같습니다.
|
||||
|
||||
1. **레이아웃 정의**: SVG 캔버스의 크기와 `viewBox`로 기본 구조 설정.
|
||||
2. **컴포넌트 분리**: 차트, 아이콘, 버튼 등을 모듈화.
|
||||
3. **데이터 매핑**: 데이터 소스를 SVG 요소로 변환.
|
||||
4. **인터랙션 추가**: 이벤트 리스너로 사용자 입력 처리.
|
||||
5. **애니메이션 적용**: 데이터 변화나 사용자 행동에 반응하는 효과 추가.
|
||||
|
||||
---
|
||||
|
||||
### 주요 구성 요소와 SVG 활용법
|
||||
|
||||
#### 1. 차트 (예: 막대그래프)
|
||||
데이터를 시각화하는 핵심 요소로, `<rect>`나 `<path>`로 표현.
|
||||
```xml
|
||||
<svg id="barChart" width="400" height="200" viewBox="0 0 400 200">
|
||||
<g id="bars"></g>
|
||||
</svg>
|
||||
<script>
|
||||
const data = [50, 100, 75, 120];
|
||||
const barsGroup = document.getElementById("bars");
|
||||
const maxHeight = 200;
|
||||
|
||||
data.forEach((value, i) => {
|
||||
const bar = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
||||
bar.setAttribute("x", i * 100);
|
||||
bar.setAttribute("y", maxHeight - value);
|
||||
bar.setAttribute("width", "80");
|
||||
bar.setAttribute("height", value);
|
||||
bar.setAttribute("fill", "steelblue");
|
||||
barsGroup.appendChild(bar);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
#### 2. 원형 게이지 (예: 진행률 표시)
|
||||
`<circle>`과 `stroke-dasharray`로 진행률을 시각화.
|
||||
```xml
|
||||
<svg width="100" height="100">
|
||||
<circle cx="50" cy="50" r="40" fill="none" stroke="lightgray" stroke-width="10"/>
|
||||
<circle id="progress" cx="50" cy="50" r="40" fill="none" stroke="green" stroke-width="10"
|
||||
stroke-dasharray="251.2" stroke-dashoffset="251.2"/>
|
||||
</svg>
|
||||
<script>
|
||||
const progress = document.getElementById("progress");
|
||||
const updateProgress = (percent) => {
|
||||
const circumference = 2 * Math.PI * 40; // 원 둘레
|
||||
const offset = circumference * (1 - percent / 100);
|
||||
progress.setAttribute("stroke-dashoffset", offset);
|
||||
};
|
||||
updateProgress(75); // 75% 진행률
|
||||
</script>
|
||||
```
|
||||
|
||||
#### 3. 아이콘 시스템
|
||||
`<symbol>`과 `<use>`로 상태 아이콘 제공.
|
||||
```xml
|
||||
<svg style="display: none;">
|
||||
<symbol id="icon-alert" viewBox="0 0 24 24">
|
||||
<path d="M12 2L2 22h20L12 2zm0 5v8m0 4h.01" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
<svg class="icon" width="24" height="24"><use href="#icon-alert"/></svg>
|
||||
```
|
||||
|
||||
#### 4. 버튼 및 인터랙티브 요소
|
||||
`<rect>`와 `<text>`로 버튼을 만들고 이벤트 추가.
|
||||
```xml
|
||||
<svg width="100" height="40">
|
||||
<rect x="0" y="0" width="100" height="40" rx="5" fill="blue"/>
|
||||
<text x="50" y="25" fill="white" text-anchor="middle" font-size="16">Click</text>
|
||||
</svg>
|
||||
<script>
|
||||
const button = document.querySelector("svg");
|
||||
button.addEventListener("click", () => alert("Button clicked!"));
|
||||
button.addEventListener("mouseover", () => button.querySelector("rect").setAttribute("fill", "darkblue"));
|
||||
button.addEventListener("mouseout", () => button.querySelector("rect").setAttribute("fill", "blue"));
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 예시: 간단한 대시보드 UI
|
||||
|
||||
#### HTML과 SVG 구조
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.dashboard { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
|
||||
.icon { width: 24px; height: 24px; }
|
||||
.chart, .gauge, .status { border: 1px solid #ccc; padding: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="dashboard">
|
||||
<!-- 막대그래프 -->
|
||||
<div class="chart">
|
||||
<svg id="barChart" width="400" height="200" viewBox="0 0 400 200">
|
||||
<g id="bars"></g>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 진행률 게이지 -->
|
||||
<div class="gauge">
|
||||
<svg width="100" height="100">
|
||||
<circle cx="50" cy="50" r="40" fill="none" stroke="lightgray" stroke-width="10"/>
|
||||
<circle id="progress" cx="50" cy="50" r="40" fill="none" stroke="green" stroke-width="10"
|
||||
stroke-dasharray="251.2" stroke-dashoffset="251.2"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- 상태 아이콘 -->
|
||||
<div class="status">
|
||||
<svg class="icon"><use href="#icon-alert"/></svg>
|
||||
<span>Warning</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 아이콘 정의 -->
|
||||
<svg style="display: none;">
|
||||
<symbol id="icon-alert" viewBox="0 0 24 24">
|
||||
<path d="M12 2L2 22h20L12 2zm0 5v8m0 4h.01" fill="none" stroke="currentColor" stroke-width="2"/>
|
||||
</symbol>
|
||||
</svg>
|
||||
|
||||
<script>
|
||||
// 막대그래프 데이터
|
||||
const data = [50, 100, 75, 120];
|
||||
const barsGroup = document.getElementById("bars");
|
||||
data.forEach((value, i) => {
|
||||
const bar = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
||||
bar.setAttribute("x", i * 100);
|
||||
bar.setAttribute("y", 200 - value);
|
||||
bar.setAttribute("width", "80");
|
||||
bar.setAttribute("height", value);
|
||||
bar.setAttribute("fill", "steelblue");
|
||||
barsGroup.appendChild(bar);
|
||||
});
|
||||
|
||||
// 진행률 업데이트
|
||||
const progress = document.getElementById("progress");
|
||||
const updateProgress = (percent) => {
|
||||
const circumference = 2 * Math.PI * 40;
|
||||
progress.setAttribute("stroke-dashoffset", circumference * (1 - percent / 100));
|
||||
};
|
||||
updateProgress(75);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### 설명
|
||||
- **막대그래프**: 데이터 배열을 기반으로 동적 생성.
|
||||
- **진행률 게이지**: 원형 진행률을 실시간으로 업데이트 가능.
|
||||
- **상태 아이콘**: 재사용 가능한 아이콘 시스템 통합.
|
||||
- **CSS Grid**: 대시보드 레이아웃을 구조화.
|
||||
|
||||
---
|
||||
|
||||
### 실무에서의 고급 기법
|
||||
|
||||
1. **데이터 연동**: API에서 가져온 JSON 데이터를 SVG로 렌더링.
|
||||
```javascript
|
||||
fetch("data.json")
|
||||
.then(response => response.json())
|
||||
.then(data => renderChart(data));
|
||||
```
|
||||
|
||||
2. **애니메이션**: 데이터 변화 시 부드러운 전환 추가.
|
||||
```javascript
|
||||
gsap.to("#progress", { duration: 1, attr: { "stroke-dashoffset": newOffset } });
|
||||
```
|
||||
|
||||
3. **드래그&드롭**: 차트 요소를 재배치 가능하도록 구현.
|
||||
- 앞서 설명한 `pointer-events` 활용.
|
||||
|
||||
4. **반응형 설계**: `viewBox`와 CSS 미디어 쿼리로 다양한 화면 크기에 대응.
|
||||
|
||||
5. **라이브러리 활용**: D3.js로 복잡한 차트(예: 선그래프, 파이차트)를 쉽게 구현.
|
||||
|
||||
---
|
||||
|
||||
### 결론
|
||||
|
||||
SVG를 활용한 대시보드 UI는 차트, 게이지, 아이콘 등 다양한 요소를 조합해 데이터 중심의 인터랙티브 인터페이스를 제공합니다. `<rect>`, `<circle>`, `<path>`로 시각적 요소를 그리고, JavaScript로 동적 업데이트와 이벤트를 처리하며, CSS로 스타일링과 레이아웃을 관리합니다. 실무에서는 데이터 연동과 애니메이션을 추가해 사용자 경험을 강화하고, 최적화와 반응형 설계를 통해 성능과 접근성을 확보해야 합니다. 위 예시를 기반으로 프로젝트 요구사항에 맞게 확장하면 강력한 대시보드 UI를 구축할 수 있습니다.
|
||||
Reference in New Issue
Block a user