PivotGrid (피벗 그리드)
Va.PivotGrid — 크로스탭 집계 그리드 컴포넌트
평평한 원본 데이터를 축(row/column/value)으로 교차 집계하여 표 형태로 표시하는 피벗 그리드 컴포넌트입니다. Excel 피벗 테이블과 유사한 구조로, 행 축·열 축·값 축을 컬럼에 지정하기만 하면 프레임워크가 자동으로 컬럼을 확장하고 집계값을 계산합니다. Va.Grid를 상속받아 가상 스크롤, 정렬, 고정 컬럼, 다단 헤더, 다중 선택 등 그리드의 모든 기능을 그대로 계승합니다.
클래스 정보
- Va.PivotGrid extends Va.Grid
- tagName: 'pivotGrid'
- isContainer: false
- 파일: va_pivotgrid.js
기본 사용법
{
ref: 'refPivotGrid',
tagName: 'pivotGrid',
style: { flex: 1, width: '100%' },
columns: [
{ key: 'itemId', title: '품목코드', position: 'left', width: 200, fixed: true },
{ key: 'itemName', title: '품명', position: 'left', width: 100, fixed: true },
{ key: 'year', title: '연도', position: 'top', width: 100, pivotSummaryType: 'sum' },
{ key: 'quater', title: '분기', position: 'top', width: 100 },
{ key: 'amt', title: '금액', position: 'value', width: 100, pivotSummaryType: 'sum' }
]
}
데이터 세팅 (mounted 후):
this.getRef('refPivotGrid').setData([
{ itemId: 'A001', itemName: '노트북', year: 2023, quater: 1, amt: 1500 },
{ itemId: 'A001', itemName: '노트북', year: 2023, quater: 2, amt: 2200 },
{ itemId: 'A001', itemName: '노트북', year: 2024, quater: 1, amt: 1800 },
{ itemId: 'B001', itemName: '마우스', year: 2023, quater: 1, amt: 300 },
{ itemId: 'B001', itemName: '마우스', year: 2024, quater: 1, amt: 450 }
]);
원본은 평평한 배열을 넘기면, 피벗 그리드가 내부에서 자동으로 교차 집계된 컬럼과 셀 값을 만들어냅니다.
피벗 축의 개념 (position)
PivotGrid의 핵심은 컬럼마다 position을 지정하는 것입니다. 3가지 축 중 하나로 분류됩니다.
position의미배치 위치
| 'left' | 행 축 (row group) — 세로로 그룹화할 기준 | 좌측 고정 영역 |
| 'top' | 열 축 (column group) — 가로로 확장할 기준 | 상단 헤더가 값별로 확장됨 |
| 'value' | 값 축 (measure) — 집계 대상 | 교차 셀에 집계값 표시 |
| (미지정) | 표시 안 함 | 원본에는 있지만 피벗에 미사용 |
예시 흐름 — 위 데이터를 위 설정으로 렌더링하면:
- 왼쪽: itemId, itemName 열이 세로로 그룹화됨
- 상단 헤더: year × quater 조합으로 컬럼이 자동 생성 (예: 2023-1분기, 2023-2분기, 2024-1분기 ...)
- 교차 셀: 각 조합별 amt 합계
핸들러는 반드시 문자열 참조 (JSON 원칙)
VanillaFront는 화면 정의를 JSON으로 유지하는 철학입니다. 모든 이벤트/렌더 핸들러는 문자열로 View 메서드 이름을 지정합니다.
{ onRowClick: 'onRowClick', onRender: 'onValueRender' }
인라인 function 사용 금지 — JSON 직렬화/에디터/저장 불가.
컬럼 정의 (columns)
각 컬럼 객체의 속성:
속성타입설명
| key | String | 데이터 필드명 (필수) |
| title | String | 헤더 텍스트 (필수) |
| position | String | 피벗 축 지정 — 'left', 'top', 'value' (핵심) |
| width | Number | 고정 폭 (px) |
| align | String | 'left', 'center', 'right' |
| type | String | 'number', 'date' 등 (value 컬럼일 때 셀 포맷팅) |
| decimalPoint | Number | 소수점 자릿수 (value 컬럼) |
| pivotSummaryType | String | 집계 방식 — 'sum', 'avg', 'min', 'max' (value 및 top 축) |
| pivotGroupSummary | Boolean | 행 그룹별 소계 행 표시 (left 축에 지정) |
| fixed | Boolean | 좌측 고정 (좌측 축은 대개 fixed 권장) |
주요 PivotGrid 속성
속성타입기본값설명
| columns | Array | — | 컬럼 정의 (필수, position 지정) |
| data | Array | [] | 평평한 원본 데이터 (자동 피벗 변환) |
| fakeData | Array | — | 에디터 미리보기용 샘플 데이터 |
| size | String | 'medium' | xsmall, small, medium, large, xlarge |
| clickToSelect | Boolean | true | 클릭 시 자동 선택 |
| selectType | String | 'singleSelect' | 'singleSelect', 'multiSelect' |
| stripe | Boolean | — | 홀짝 행 배경 구분 |
| enableCopy | Boolean | false | Ctrl+C 셀 복사 |
집계 방식 — pivotSummaryType
position: 'value' 컬럼에 지정하면 교차 셀의 계산 방식이 결정됩니다.
값의미
| 'sum' | 합계 |
| 'avg' | 평균 |
| 'min' | 최솟값 |
| 'max' | 최댓값 |
position: 'top' 컬럼에도 지정할 수 있으며, 이 경우 해당 축 헤더 옆에 소계 컬럼이 자동 추가됩니다 (예: 2023 합계, 2024 합계).
value 컬럼이 1개일 때 vs 여러 개일 때
이 차이가 PivotGrid를 이해하는 핵심입니다.
value 컬럼이 1개
columns: [
{ key: 'itemId', position: 'left', title: '품목코드', width: 200, fixed: true },
{ key: 'itemName', position: 'left', title: '품명', width: 100, fixed: true },
{ key: 'year', position: 'top', title: '연도', width: 100, pivotSummaryType: 'sum' },
{ key: 'quater', position: 'top', title: '분기', width: 100 },
{ key: 'amt', position: 'value', title: '금액', width: 100, pivotSummaryType: 'sum' }
]
→ 새로운 값 컬럼을 만들지 않고 top 축을 따라 확장됩니다. 헤더는 2023 1분기, 2023 2분기, 2024 1분기 식으로 나뉘고 각 셀엔 amt 합계.
value 컬럼이 여러 개
columns: [
{ key: 'itemId', position: 'left', title: '품목코드', width: 200, fixed: true },
{ key: 'quater', position: 'left', title: '분기', width: 100, fixed: true },
{ key: 'year', position: 'top', title: '연도', width: 100, pivotSummaryType: 'sum' },
{ key: 'amt', position: 'value', title: '금액1', width: 100, type: 'number', align: 'right', pivotSummaryType: 'avg' },
{ key: 'amt2', position: 'value', title: '금액2', width: 100, type: 'number', align: 'right', pivotSummaryType: 'avg' }
]
→ top 축 아래에 value 컬럼들이 추가로 계층됨. 헤더는 2023 > (금액1, 금액2), 2024 > (금액1, 금액2) 식의 다단 구조로 확장.
좌측 그룹 소계 — pivotGroupSummary
position: 'left' 컬럼에 pivotGroupSummary: true를 지정하면 그 그룹별로 소계 행이 자동 생성됩니다.
{
key: 'itemName',
title: '품명',
position: 'left',
pivotGroupSummary: true, // itemName별 소계 행 자동 추가
width: 100
}
각 소계 행의 계산은 대응하는 value 컬럼의 pivotSummaryType을 따릅니다.
표시하지 않는 원본 컬럼
position을 지정하지 않으면 그 컬럼은 원본에는 존재하지만 피벗 결과에 표시되지 않습니다. 나중에 활용 가능성이 있는 필드를 원본에 유지하되 UI에는 감출 때 사용합니다.
{
key: 'itemGroupId',
title: '품목그룹',
width: 200
// position 미지정 → 피벗에 미표시
}
종합 예시 — 다중 value 축 + 소계
config() {
return {
tagName: 'page',
tags: [{
tagName: 'panel',
style: { flex: 1 },
tags: [{
ref: 'refPivotGrid',
tagName: 'pivotGrid',
style: { flex: 1, width: '100%' },
selectType: 'singleSelect',
stripe: true,
enableCopy: true,
columns: [
// 좌측 그룹 축
{ key: 'itemId', title: '품목코드', position: 'left', width: 150, fixed: true, align: 'center' },
{ key: 'itemName', title: '품명', position: 'left', width: 120, fixed: true,
pivotGroupSummary: true },
{ key: 'quater', title: '분기', position: 'left', width: 80, fixed: true, align: 'center' },
// 상단 열 축
{ key: 'year', title: '연도', position: 'top', width: 120, pivotSummaryType: 'sum' },
// 값 축 (2개 → top 아래에 다단 확장됨)
{ key: 'amt', title: '금액', position: 'value', width: 120, type: 'number',
align: 'right', pivotSummaryType: 'sum', decimalPoint: 0 },
{ key: 'qty', title: '수량', position: 'value', width: 100, type: 'number',
align: 'right', pivotSummaryType: 'avg', decimalPoint: 2 }
]
}]
}]
};
}
mounted() {
ItemService.getPivotList(this, {}, (view, ok, res) => {
if (ok) view.getRef('refPivotGrid').setData(res.data.list);
});
}
주의사항
- 컬럼마다 position 지정 필수 — 'left', 'top', 'value' 중 하나. 미지정 컬럼은 표시 안 됨
- 좌측 축('left')은 대부분 fixed: true 권장 — 가로 스크롤 시 기준 축 유지
- 원본 데이터는 평평한 배열로 전달 — 사전 집계 불필요, PivotGrid가 내부에서 처리
- value 컬럼 개수에 따라 헤더 구조가 달라짐 — 1개면 top 축만 확장, 2개 이상이면 다단 확장
- pivotSummaryType은 value 및 top 축에 각각 지정 가능 — top에 지정하면 해당 축 소계 컬럼 추가
- pivotGroupSummary는 left 축에만 지정 — 좌측 그룹별 소계 행 생성
- 핸들러는 문자열 참조만 — 인라인 function은 JSON 원칙 위반
- 최상위에 명시적 크기 필요 — style: { flex: 1, minHeight: '...' } 없으면 안 그려짐
- 데이터 재로드는 setData(list) 전체 교체 — 부분 갱신은 재계산 원칙상 미권장
대안 비교
상황추천
| 크로스탭 집계 (매출×연도, 지역×제품 등) | Va.PivotGrid |
| 일반 목록/편집 | Va.Grid |
| 계층 트리 데이터 | Va.TreeGrid |
| 컬럼 자체를 동적 생성 (피벗은 아님) | Va.DynamicGrid |
| 정적 격자 레이아웃 | Va.GridDiv |
참고
- API 문서 페이지: https://vanillafront.com/docs.html?theme=light#main#apipivotgrid
- 연관: Va.Grid (부모 클래스), Va.DynamicGrid (동적 컬럼)