Appearance
DailyAndHourlyChart
개요
DailyAndHourlyChart
는 서비스 메트릭 데이터를 일간 및 시간별로 시각화하는 차트 컴포넌트입니다. 메트릭 선택, 탭 전환, 데이터 선택 등의 인터랙티브 기능을 제공하여 시계열 데이터 분석을 지원합니다.
주요 기능
- 일간/시간별 메트릭 데이터 시각화
- 메트릭 타입 선택 (서비스 개수, 응답시간 등)
- 차트 타입 전환 (Bar, Column)
- 날짜 및 시간 선택 기능
- v-model을 통한 양방향 데이터 바인딩
- 커스텀 툴팁 포맷터 지원
Props 인터페이스
typescript
interface DailyAndHourlyChartProps {
width: number; // 차트 너비
height: number; // 차트 높이
tabItems: TabItem[]; // 차트 타입 탭 항목
metricItems: MetricItem[]; // 메트릭 선택 항목
items: ChartItem[]; // 차트 데이터
hourlyItemMap: Record<number, ChartItem[]>; // 시간별 데이터 맵
nameWidth?: number; // 이름 영역 너비 (기본값: 32)
tooltipFormatter?: (item: ChartItem, type: ChartType) => string; // 툴팁 포맷터
}
interface TabItem {
text: string; // 탭 표시 텍스트
value: ChartType; // 차트 타입 값
}
interface MetricItem {
text: string; // 메트릭 표시 텍스트
value: string; // 메트릭 값 (형식: "daily:MxDef" 또는 "hourly:MxDef")
}
interface ChartItem {
time: number; // 시간 (timestamp)
name: string; // 표시명
value: number; // 값
}
type ChartType = 'bar' | 'column';
v-model Props
typescript
// 양방향 바인딩 지원 props
selectedMetric: string; // 선택된 메트릭 (기본값: "daily:service_count")
selectedDate: number; // 선택된 날짜 (기본값: -1)
selectedHour: number; // 선택된 시간 (기본값: -1)
selectedTab: ChartType; // 선택된 차트 타입 (기본값: "bar")
이벤트
typescript
interface DailyAndHourlyChartEmits {
(e: 'tab', item: ChartType): void;
(e: 'select', time: number, hour: number, duplicate: boolean): void;
(e: 'metric', metric: MxDef, interval: number): void;
(e: 'update:selectedMetric', selectedMetric: string): void;
(e: 'update:selectedDate', selectedDate: number): void;
(e: 'update:selectedHour', selectedHour: number): void;
(e: 'update:selectedTab', selectedTab: ChartType): void;
}
- tab: 차트 타입 탭 변경 시 발생
- select: 차트 데이터 선택 시 발생
- metric: 메트릭 변경 시 발생
- update:* : v-model 업데이트 이벤트
기본 사용법
vue
<template>
<daily-and-hourly-chart
:width="800"
:height="400"
:tab-items="tabItems"
:metric-items="metricItems"
:items="chartData"
:hourly-item-map="hourlyDataMap"
v-model:selected-metric="selectedMetric"
v-model:selected-date="selectedDate"
v-model:selected-hour="selectedHour"
@tab="onTabChange"
@select="onDataSelect"
@metric="onMetricChange"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { DailyAndHourlyChart } from '@jennifersoft/apm-components';
import { MxDef } from '@jennifersoft/apm-apis';
import type {
ChartItem,
ChartType,
TabItem,
MetricItem,
} from '@jennifersoft/apm-components';
// 탭 항목 정의
const tabItems: TabItem[] = [
{ text: '막대형', value: 'bar' },
{ text: '세로막대형', value: 'column' },
];
// 메트릭 항목 정의
const metricItems: MetricItem[] = [
{ text: '일간 서비스 개수', value: `daily:${MxDef.service_count}` },
{
text: '일간 평균 응답시간',
value: `daily:${MxDef.service_responseTime}`,
},
{ text: '시간별 서비스 개수', value: `hourly:${MxDef.service_count}` },
];
// 상태 관리
const selectedMetric = ref<string>(`daily:${MxDef.service_count}`);
const selectedDate = ref<number>(-1);
const selectedHour = ref<number>(-1);
// 차트 데이터
const chartData: ChartItem[] = [
{ time: 1640995200000, name: '01/01', value: 1250 },
{ time: 1641081600000, name: '01/02', value: 980 },
{ time: 1641168000000, name: '01/03', value: 1450 },
];
// 시간별 데이터 맵
const hourlyDataMap: Record<number, ChartItem[]> = {
1640995200000: [
{ time: 1640995200000, name: '00:00', value: 45 },
{ time: 1640998800000, name: '01:00', value: 52 },
// ... 24시간 데이터
],
};
// 이벤트 핸들러
const onTabChange = (tab: ChartType) => {
console.log('차트 타입 변경:', tab);
};
const onDataSelect = (time: number, hour: number, duplicate: boolean) => {
console.log('데이터 선택:', { time, hour, duplicate });
};
const onMetricChange = (metric: MxDef, interval: number) => {
console.log('메트릭 변경:', { metric, interval });
// API 호출하여 새 데이터 로드
};
</script>
인터랙티브 데모
현재 상태
선택된 메트릭:daily:301
선택된 날짜:없음
선택된 시간:없음
차트 타입:bar
데이터 구조
ChartItem
typescript
interface ChartItem {
time: number; // 시간 (Unix timestamp)
name: string; // 표시명 (예: "01/01", "14:00")
value: number; // 메트릭 값
}
MetricItem & TabItem
typescript
interface MetricItem {
text: string; // 사용자에게 표시될 텍스트
value: string; // 메트릭 식별자 (형식: "daily:MxDef" 또는 "hourly:MxDef")
}
interface TabItem {
text: string; // 탭 텍스트
value: ChartType; // 차트 타입 ('bar' | 'column')
}
고급 사용법
커스텀 툴팁 포맷터
vue
<template>
<daily-and-hourly-chart
v-bind="chartProps"
:tooltip-formatter="customTooltipFormatter"
/>
</template>
<script setup lang="ts">
const customTooltipFormatter = (item: ChartItem, type: ChartType): string => {
const dateFormat = type === 'bar' ? 'YYYY/MM/DD' : 'HH:mm';
const formattedDate = dayjs(item.time).format(dateFormat);
return `${formattedDate}: ${item.value.toLocaleString()}건`;
};
</script>
동적 데이터 로딩
vue
<script setup lang="ts">
import { ref, watch } from 'vue';
const selectedMetric = ref<string>(`daily:${MxDef.service_count}`);
const chartData = ref<ChartItem[]>([]);
const hourlyDataMap = ref<Record<number, ChartItem[]>>({});
const onMetricChange = async (metric: MxDef, interval: number) => {
// API 호출하여 새 데이터 로드
const data = await fetchChartData(metric, interval);
chartData.value = data.daily;
hourlyDataMap.value = data.hourly;
};
// 메트릭 변경 감지하여 자동 데이터 로드
watch(selectedMetric, async (newMetric) => {
const [type, metricId] = newMetric.split(':');
const interval = type === 'daily' ? 86400000 : 3600000;
await onMetricChange(parseInt(metricId), interval);
});
</script>
반응형 차트 크기
vue
<template>
<div ref="containerRef" class="chart-container">
<daily-and-hourly-chart
:width="containerWidth"
:height="containerHeight"
v-bind="chartProps"
/>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { useResizeObserver } from '@vueuse/core';
const containerRef = ref<HTMLElement>();
const containerWidth = ref<number>(800);
const containerHeight = ref<number>(400);
useResizeObserver(containerRef, (entries) => {
const entry = entries[0];
containerWidth.value = entry.contentRect.width;
containerHeight.value = Math.max(300, entry.contentRect.height);
});
</script>
의존성
@jennifersoft/apm-components
@jennifersoft/apm-apis
@jennifersoft/vue-components-v2
@vueuse/core
(유틸리티 함수 사용 시)