소개
SpreadJS 피벗 테이블은 항목 슬라이서와 시간 표시 막대 슬라이서, 이렇게 두 가지 유형을 지원합니다.
표 슬라이서와 마찬가지로, 피벗 슬라이서 역시 슬라이서 컬렉션을 통해 관리됩니다.
SpreadJS에서는 어떤 유형의 슬라이서가 추가될지 구분하기 위해 SlicerType을 정의했습니다.
피벗 슬라이서는 셰이프, 슬라이서, 피벗 추가 항목, 이렇게 3가지 플러그와 함께 작동하며,
슬라이서는 모든 필드(Calc 필드 제외)에 추가할 수 있습니다.
항목 슬라이서를 변경하는 것은 레이블 필터의 "textItems"를 의미하는 수동 필터를 사용하는 것과 같습니다.
시간 표시 막대 슬라이서만 날짜 유형 필드에 추가할 수 있습니다.
시간 표시 막대 슬라이서를 변경하는 것은 레이블 필터에서 "condition"을 의미하는 레이블 조건 필터를 사용하는 것과 같습니다.
예를 들어, 피벗 테이블 항목 슬라이서를 추가하려는 경우
"pt"라는 이름으로 피벗 테이블을 만들었다고 가정해 보겠습니다.
"name" 필드에 항목 슬라이서를 추가하려는 경우.
또한 피벗 테이블 "pt"에 "birthday"라는 날짜 필드가 있고
피벗 테이블 시간 표시 막대 슬라이서를 추가하고자 한다고 가정합니다.
다음과 같은 궁금증이 생길 수 있습니다.
항목 슬라이서와 시간 표시 막대 슬라이서를 동시에 날짜 필드에 추가할 수 있다는 점은 확실합니다.
그렇다면 두 슬라이서가 동시에 작동할 수 있을까요?
기본적으로 안 됩니다.
모두 labelFilter를 통해 작동하고 textItems를 설정하면 조건 필터가 손실됩니다.
이 문제는 피벗 테이블의 옵션인 allowMultipleFiltersPerField로 해결할 수 있습니다.
슬라이서에서 항목을 클릭하고 끌어 필터링해 보십시오.
항목 슬라이서를 사용하면 클릭하고 끌 때 Shift 및 Ctrl 키(Windows의 경우)/명령 키(Mac의 경우)를 눌러볼 수도 있습니다.
셰이프 기반
셰이프 기반 피벗 슬라이서.
예를 들어, 많은 셰이프 API를 사용하여 피벗 슬라이서를 제어할 수 있습니다.
피벗 테이블과 연결
피벗 슬라이서는 연결 관리, 피벗 테이블과의 연결 추가 또는 연결 해제 기능을 지원합니다.
피벗 테이블과의 연결이 해제되는 경우 슬라이서 필터 작업은 피벗 테이블에 영향을 미치지 않습니다.
피벗 테이블 필터 작업은 슬라이서에도 영향을 미치지 않습니다.
예를 들어, 이 기능을 통해 슬라이서를 사용하여 동일한 소스 피벗 테이블 여러 개를 관리할 수 있습니다.
"pt1" 및 "pt2"라는 피벗 테이블 두 개가 있고, 모두 "table1"이라는 테이블에서 만들어 데이터 소스와 필드가 동일하다고 가정해 보겠습니다.
좋습니다. 이제 slicer_name 컨트롤을 사용하여 피벗 테이블 두 개를 제어할 수 있습니다.
window.onload = function () {
var spread = new GC.Spread.Sheets.Workbook(_getElementById('ss'), { sheetCount: 2 });
initSpread(spread);
var pivotLayoutSheet = spread.getSheet(0);
initPivotTable(pivotLayoutSheet);
initSlicer(pivotLayoutSheet);
bindEvent(spread.getSheet(0));
};
function initSpread(spread) {
spread.suspendPaint();
let sheet = spread.getSheet(1);
sheet.name("DataSource");
sheet.setRowCount(650);
sheet.setColumnWidth(5, 120);
sheet.getCell(-1, 5).formatter("YYYY-mm-DD");
sheet.getRange(-1,4,0,1).formatter("$ #,##0");
sheet.setArray(0, 0, pivotSales);
let table = sheet.tables.add('tableSales', 0, 0, 637, 6);
table.style(GC.Spread.Sheets.Tables.TableThemes["none"]);
let sheet0 = spread.getSheet(0);
sheet0.name("PivotLayout");
sheet0.setValue(0, 0, "Pivot Table 1");
sheet0.setValue(0, 10, "Pivot Table 2");
spread.resumePaint();
}
function initPivotTable(sheet) {
var groupInfo = { originFieldName: "date", dateGroups: [{ by: GC.Pivot.DateGroupType.quarters }, {by: GC.Pivot.DateGroupType.years}, {by: GC.Pivot.DateGroupType.months}] };
var pt1 = sheet.pivotTables.add("pt1", "tableSales", 1, 0, GC.Spread.Pivot.PivotTableLayoutType.outline, GC.Spread.Pivot.PivotTableThemes.light8);
pt1.suspendLayout();
pt1.options.showRowHeader = true;
pt1.options.showColumnHeader = true;
pt1.options.subtotalsPosition = GC.Spread.Pivot.SubtotalsPosition.top;
pt1.layoutType(GC.Spread.Pivot.PivotTableLayoutType.compact);
pt1.add("region", "region", GC.Spread.Pivot.PivotTableFieldType.rowField);
pt1.add("country", "country", GC.Spread.Pivot.PivotTableFieldType.rowField);
pt1.add("city", "city", GC.Spread.Pivot.PivotTableFieldType.rowField);
pt1.add("amount", "amounts", GC.Spread.Pivot.PivotTableFieldType.valueField, GC.Pivot.SubtotalType.sum);
pt1.resumeLayout();
pt1.autoFitColumn();
var pt2 = sheet.pivotTables.add("pt2", "tableSales", 1, 10, GC.Spread.Pivot.PivotTableLayoutType.outline, GC.Spread.Pivot.PivotTableThemes.medium23);
pt2.suspendLayout();
pt2.options.showRowHeader = true;
pt2.options.showColumnHeader = true;
pt2.options.subtotalsPosition = GC.Spread.Pivot.SubtotalsPosition.top;
pt2.layoutType(GC.Spread.Pivot.PivotTableLayoutType.compact);
pt2.group(groupInfo);
pt2.add("연 (date)", "연 (date)", GC.Spread.Pivot.PivotTableFieldType.rowField);
pt2.add("분기 (date)", "분기 (date)", GC.Spread.Pivot.PivotTableFieldType.rowField);
pt2.add("연 (date)", "연 (date)", GC.Spread.Pivot.PivotTableFieldType.rowField);
pt2.add("amount", "Amounts", GC.Spread.Pivot.PivotTableFieldType.valueField, GC.Pivot.SubtotalType.sum);
pt2.resumeLayout();
pt2.autoFitColumn();
}
function initSlicer (sheet) {
sheet.suspendPaint();
var yearSlicer = sheet.slicers.add("Years", 'pt2', "date", GC.Spread.Sheets.Slicers.TimelineStyles.light5(), GC.Spread.Sheets.Slicers.SlicerType.pivotTimeline);
var monthSlicer = sheet.slicers.add("Months", 'pt2', "date", GC.Spread.Sheets.Slicers.TimelineStyles.light1(), GC.Spread.Sheets.Slicers.SlicerType.pivotTimeline);
this.setTimelineProp(yearSlicer, 967, 20, 310, 160, 1, "Years");
this.setTimelineProp(monthSlicer, 967, 160, 310, 160, 3, "Months");
var regionSlicer = sheet.slicers.add("region", 'pt1', "region", GC.Spread.Sheets.Slicers.SlicerStyles.dark1(), GC.Spread.Sheets.Slicers.SlicerType.pivotTable);
var countrySlicer = sheet.slicers.add("country", 'pt1', "country", GC.Spread.Sheets.Slicers.SlicerStyles.dark2(), GC.Spread.Sheets.Slicers.SlicerType.pivotTable);
var citySlicer = sheet.slicers.add("city", 'pt1', "city", GC.Spread.Sheets.Slicers.SlicerStyles.dark3(), GC.Spread.Sheets.Slicers.SlicerType.pivotTable);
this.setSlicerProp(regionSlicer, 285, 20, 140, 200, 1, true, true);
this.setSlicerProp(countrySlicer, 425, 20, 140, 200, 1, true, true);
this.setSlicerProp(citySlicer, 565, 20, 140, 200, 1, true, true);
sheet.resumePaint();
}
function setSlicerProp(slicer, x, y, width, height, columnCount, showHeader, showNoDataItemsInLast) {
slicer.position({x, y});
slicer.width(width);
slicer.height(height);
if (columnCount) {
slicer.columnCount(columnCount);
}
slicer.showHeader(!!showHeader);
slicer.showNoDataItemsInLast(!!showNoDataItemsInLast);
slicer.allowMove(false);
slicer.allowResize(false);
}
function setTimelineProp (timeline, x, y, width, height, level, caption) {
timeline.position({x, y});
timeline.width(width);
timeline.height(height);
timeline.level(level);
timeline.captionName(caption);
timeline.allowMove(false);
timeline.allowResize(false);
}
function bindEvent (sheet) {
var slicer;
sheet.bind(GC.Spread.Sheets.Events.SlicerChanged, function () {
var slicers = sheet.slicers.all();
for (var i = 0; i < slicers.length; i++) {
if (slicers[i].isSelected()) {
slicer = slicers[i];
updateSlicerInfo(slicer);
break;
}
}
});
['name', 'captionName'].forEach(prop => {
_getElementById(prop).addEventListener("change", function (e) {
var value = e.target.value;
if (value && slicer) {
slicer[prop](value);
}
});
});
['x', 'y', 'width', 'height'].forEach(prop => {
_getElementById(prop).addEventListener("change", function (e) {
var value = +e.target.value;
if (value && slicer) {
slicer[prop](value);
}
});
});
['pt1', 'pt2'].forEach(ptName => {
_getElementById(ptName).addEventListener("change", function (e) {
var checked = e.target.checked;
if (!_isNullOrUndefined(checked) && slicer) {
if (checked) {
slicer.connectPivotTable(ptName);
} else {
slicer.disconnectPivotTable(ptName);
}
}
});
});
}
function updateSlicerInfo (slicer) {
_getElementById("name").value = slicer.name();
_getElementById("captionName").value = slicer.captionName();
_getElementById("x").value = slicer.x();
_getElementById("y").value = slicer.y();
_getElementById("width").value = slicer.width();
_getElementById("height").value = slicer.height();
_getElementById("pt1").checked = slicer.isConnectedPivotTable('pt1');
_getElementById("pt2").checked = slicer.isConnectedPivotTable('pt2');
}
function _getElementById(id) {
return document.getElementById(id);
}
function _isNullOrUndefined(o) {
return o === null || o === undefined;
}
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta name="spreadjs culture" content="ko-kr"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<script src="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-shapes/dist/gc.spread.sheets.shapes.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-slicers/dist/gc.spread.sheets.slicers.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-pivot-addon/dist/gc.spread.pivot.pivottables.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/data/pivotSales.js" type="text/javascript"></script>
<script src="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-resources-ko/dist/gc.spread.sheets.resources.ko.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div class="sample-tutorial">
<div id="ss" class="sample-spreadsheets"></div>
<div class="options-container">
<div class="block slicer-infos">
<div>Current Selected Slicer Info:</div><br>
<div class="slicer-info">
<label class="info-label">Slicer Name:</label>
<input class="info-input" id="name"></input>
</div>
<div class="slicer-info">
<label class="info-label">Caption Name:</label>
<input class="info-input" id="captionName"></input>
</div>
<div class="slicer-info">
<label class="info-label">X:</label>
<input type="number" class="info-input" name="x" id="x", min="0", max="1000", step="1">
</div>
<div class="slicer-info">
<label class="info-label">Y:</label>
<input type="number" class="info-input" name="y" id="y", min="0", max="1000", step="1">
</div>
<div class="slicer-info">
<label class="info-label">Width:</label>
<input type="number" class="info-input" name="width" id="width", min="0", max="1000", step="1">
</div>
<div class="slicer-info">
<label class="info-label">Height:</label>
<input type="number" class="info-input" name="height" id="height", min="0", max="1000", step="1">
</div>
</div>
<div class="block">
<div>Slicer Connection</div><br/>
<div class="Connection">
<div class="slicer-info">
<input type="checkbox" id="pt1">
<label for="pt1">Connect Pivot Table 1</label>
</div>
<div class="slicer-info">
<input type="checkbox" id="pt2">
<label for="pt2">Connect Pivot Table 2</label>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
.sample-tutorial {
position: relative;
height: 100%;
overflow: hidden;
}
.sample-spreadsheets {
width: calc(100% - 330px);
height: 100%;
overflow: hidden;
float: left;
}
.options-container {
float: right;
width: 330px;
padding: 12px;
height: 100%;
box-sizing: border-box;
background: #fbfbfb;
overflow: auto;
}
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.slicer-info {
margin-top: 5px;
margin-bottom: 5px;
}
.block {
border: 1px solid gray;
padding-left: 5px;
padding-top: 10px;
padding-bottom: 10px;
margin-bottom: 1px;
}
.info-label {
width: 35%;
display: inline-block;
}
.info-input {
width: 58%;
display: inline-block;
}