데이터 차트는 계층형 카테고리를 지원하며, 이를 통해 직교 좌표계 차트에서 다중 수준 카테고리 축을 사용할 수 있습니다. category 인코딩의 child 속성을 사용하여 중첩 카테고리를 정의합니다.
지원되는 차트 유형에는 세로 막대형, 범위 세로 막대형, 누적 세로 막대형, 100% 기준 누적 세로 막대형, 가로 막대형, 범위 가로 막대형, 누적 가로 막대형, 100% 기준 누적 가로 막대형, 영역형, 범위 영역형, 누적 영역형, 100% 기준 누적 영역형, 꺾은선형, 주식형, OHLC가 포함됩니다. 이 샘플의 각 시트는 이러한 차트 유형 중 하나를 계층형 카테고리 축과 함께 보여 줍니다.
참고: 계층형 카테고리는 축 기반(직교 좌표계) 차트 유형에만 적용됩니다. 원형, 도넛, 선버스트, 트리맵, 깔때기형, 폭포형 같은 비축 차트는 이 기능을 지원하지 않습니다.
window.onload = async () => {
const { spread, designer } = createSpreadAndDesigner();
await initDataManager(spread);
const DataChartType = GC.Spread.Sheets.DataCharts.DataChartType;
const Aggregate = GC.Spread.Sheets.DataCharts.Aggregate;
const chartConfigs = [
{ name: 'Column', type: DataChartType.column, table: 'Sales', encoding: 'single' },
{ name: 'Range Column', type: DataChartType.rangeColumn, table: 'Sales', encoding: 'range' },
{ name: 'Stacked Column', type: DataChartType.stackedColumn, table: 'Sales', encoding: 'stacked' },
{ name: 'Percent Stacked Column', type: DataChartType.percentStackedColumn, table: 'Sales', encoding: 'stacked' },
{ name: 'Bar', type: DataChartType.bar, table: 'Sales', encoding: 'single' },
{ name: 'Range Bar', type: DataChartType.rangeBar, table: 'Sales', encoding: 'range' },
{ name: 'Stacked Bar', type: DataChartType.stackedBar, table: 'Sales', encoding: 'stacked' },
{ name: 'Percent Stacked Bar', type: DataChartType.percentStackedBar, table: 'Sales', encoding: 'stacked' },
{ name: 'Area', type: DataChartType.area, table: 'Sales', encoding: 'single' },
{ name: 'Range Area', type: DataChartType.rangeArea, table: 'Sales', encoding: 'range' },
{ name: 'Stacked Area', type: DataChartType.stackedArea, table: 'Sales', encoding: 'stacked' },
{ name: 'Percent Stacked Area', type: DataChartType.percentStackedArea, table: 'Sales', encoding: 'stacked' },
{ name: 'Line', type: DataChartType.line, table: 'Sales', encoding: 'single' },
{ name: 'Candlestick', type: DataChartType.candlestick, table: 'Stock', encoding: 'ohlc' },
{ name: 'OHLC', type: DataChartType.ohlc, table: 'Stock', encoding: 'ohlc' },
];
spread.setSheetCount(chartConfigs.length);
for (let i = 0; i < chartConfigs.length; i++) {
const cfg = chartConfigs[i];
const sheet = spread.getSheet(i);
sheet.name(cfg.name);
addChartToSheet(sheet, cfg, Aggregate);
}
spread.setActiveSheetIndex(0);
spread.getActiveSheet().dataCharts.all()[0].isSelected(true);
if (designer) {
designer.refresh();
}
}
function addChartToSheet(sheet, cfg, Aggregate) {
const dataChart = sheet.dataCharts.add(cfg.name, 20, 20, 450, 300, cfg.type);
let encodings;
const hierarchicalCategory = {
field: 'Region',
child: { field: 'Salesman' }
};
const ohlcHierarchicalCategory = {
field: 'month',
child: { field: 'day' }
};
switch (cfg.encoding) {
case 'single':
encodings = {
values: [{ field: 'Sales', aggregate: Aggregate.sum }],
category: hierarchicalCategory,
};
break;
case 'range':
encodings = {
values: [{
vectors: {
upper: { field: 'Sales' },
lower: { field: 'Return' },
},
aggregate: Aggregate.sum,
}],
category: hierarchicalCategory,
};
break;
case 'stacked':
encodings = {
values: [{ field: 'Sales', aggregate: Aggregate.sum }],
category: hierarchicalCategory,
color: { field: 'Product' },
};
break;
case 'ohlc':
encodings = {
values: [{
vectors: {
open: { field: 'open' },
high: { field: 'high' },
low: { field: 'low' },
close: { field: 'close' },
},
}],
category: ohlcHierarchicalCategory,
};
break;
}
dataChart.setChartConfig({
tableName: cfg.table,
plots: [{
type: cfg.type,
encodings: encodings,
}],
config: {
header: {
title: cfg.name + ' - Hierarchical Category',
padding: { left: 10, right: 10, top: 10, bottom: 10 },
textStyle: {
fontSize: 16,
alignment: GC.Spread.Sheets.DataCharts.HAlign.left,
},
},
},
});
}
function createSpreadAndDesigner() {
const demoHost = document.getElementById('demo-host');
if (window !== top) {
const spread = new GC.Spread.Sheets.Workbook('spread-host', { sheetCount: 1 });
new GC.Spread.Sheets.DataCharts.DataChartConfigPanel('panel-host', spread);
return {
spread
}
} else {
const designer = new GC.Spread.Sheets.Designer.Designer(demoHost, undefined, undefined, { sheetCount: 1 });
return {
designer,
spread: designer.getWorkbook(),
}
}
}
async function initDataManager(spread) {
const dataManager = spread.dataManager();
await dataManager.addTable('Sales', {
data: [
{ Region: 'East', Salesman: 'Alice', Product: 'Laptop', Sales: 450, Return: 120 },
{ Region: 'East', Salesman: 'Alice', Product: 'Phone', Sales: 320, Return: 85 },
{ Region: 'East', Salesman: 'Bob', Product: 'Laptop', Sales: 380, Return: 95 },
{ Region: 'East', Salesman: 'Bob', Product: 'Phone', Sales: 290, Return: 70 },
{ Region: 'East', Salesman: 'Carol', Product: 'Laptop', Sales: 410, Return: 110 },
{ Region: 'East', Salesman: 'Carol', Product: 'Phone', Sales: 350, Return: 90 },
{ Region: 'West', Salesman: 'Dave', Product: 'Laptop', Sales: 520, Return: 140 },
{ Region: 'West', Salesman: 'Dave', Product: 'Phone', Sales: 280, Return: 65 },
{ Region: 'West', Salesman: 'Eve', Product: 'Laptop', Sales: 470, Return: 130 },
{ Region: 'West', Salesman: 'Eve', Product: 'Phone', Sales: 310, Return: 80 },
{ Region: 'West', Salesman: 'Frank', Product: 'Laptop', Sales: 390, Return: 100 },
{ Region: 'West', Salesman: 'Frank', Product: 'Phone', Sales: 260, Return: 60 },
{ Region: 'North', Salesman: 'Grace', Product: 'Laptop', Sales: 340, Return: 90 },
{ Region: 'North', Salesman: 'Grace', Product: 'Phone', Sales: 270, Return: 75 },
{ Region: 'North', Salesman: 'Hank', Product: 'Laptop', Sales: 430, Return: 115 },
{ Region: 'North', Salesman: 'Hank', Product: 'Phone', Sales: 300, Return: 80 },
{ Region: 'South', Salesman: 'Ivy', Product: 'Laptop', Sales: 480, Return: 125 },
{ Region: 'South', Salesman: 'Ivy', Product: 'Phone', Sales: 330, Return: 85 },
{ Region: 'South', Salesman: 'Jack', Product: 'Laptop', Sales: 360, Return: 95 },
{ Region: 'South', Salesman: 'Jack', Product: 'Phone', Sales: 250, Return: 55 },
],
}).fetch();
await dataManager.addTable('Stock', {
data: [
{ month: 'Jan', day: 'Jan-01', open: 150.00, high: 155.20, low: 148.50, close: 153.80 },
{ month: 'Jan', day: 'Jan-02', open: 153.80, high: 157.40, low: 152.10, close: 156.90 },
{ month: 'Jan', day: 'Jan-03', open: 156.90, high: 158.60, low: 154.30, close: 155.20 },
{ month: 'Jan', day: 'Jan-04', open: 155.20, high: 159.80, low: 154.00, close: 158.50 },
{ month: 'Jan', day: 'Jan-05', open: 158.50, high: 162.30, low: 157.20, close: 161.00 },
{ month: 'Feb', day: 'Feb-01', open: 161.00, high: 163.50, low: 159.80, close: 162.40 },
{ month: 'Feb', day: 'Feb-02', open: 162.40, high: 165.70, low: 161.30, close: 164.80 },
{ month: 'Feb', day: 'Feb-03', open: 164.80, high: 166.20, low: 162.50, close: 163.10 },
{ month: 'Feb', day: 'Feb-04', open: 163.10, high: 167.90, low: 162.00, close: 167.30 },
{ month: 'Feb', day: 'Feb-05', open: 167.30, high: 170.10, low: 166.50, close: 169.20 },
{ month: 'Mar', day: 'Mar-01', open: 169.20, high: 172.40, low: 168.00, close: 171.50 },
{ month: 'Mar', day: 'Mar-02', open: 171.50, high: 173.80, low: 169.60, close: 170.30 },
{ month: 'Mar', day: 'Mar-03', open: 170.30, high: 174.50, low: 169.10, close: 173.90 },
{ month: 'Mar', day: 'Mar-04', open: 173.90, high: 176.20, low: 172.30, close: 175.60 },
{ month: 'Mar', day: 'Mar-05', open: 175.60, high: 178.00, low: 174.20, close: 176.80 },
],
}).fetch();
}
<!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">
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-designer/styles/gc.spread.sheets.designer.light.min.css">
<link rel="stylesheet" type="text/css" href="styles.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-print/dist/gc.spread.sheets.print.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-datacharts-addon/dist/gc.spread.sheets.datacharts.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-tablesheet/dist/gc.spread.sheets.tablesheet.min.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"></script>
<script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script>
<script>
const designerDependencyScripts = [
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-charts/dist/gc.spread.sheets.charts.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-barcode/dist/gc.spread.sheets.barcode.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-pdf/dist/gc.spread.sheets.pdf.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-pivot-addon/dist/gc.spread.pivot.pivottables.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-slicers/dist/gc.spread.sheets.slicers.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-reportsheet-addon/dist/gc.spread.report.reportsheet.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-ganttsheet/dist/gc.spread.sheets.ganttsheet.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-formula-panel/dist/gc.spread.sheets.formulapanel.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-io/dist/gc.spread.sheets.io.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-designer-resources-ko/dist/gc.spread.sheets.designer.resource.ko.min.js',
'$DEMOROOT$/ko/purejs/node_modules/@mescius/spread-sheets-designer/dist/gc.spread.sheets.designer.all.min.js',
'$DEMOROOT$/spread/source/js/designer/license.js',
]
function appendScriptNode (src) {
const script = document.createElement('script');
script.src = src;
script.async = false;
script.type = 'text/javascript';
document.head.appendChild(script);
}
if (top === window) { // not in iframe
designerDependencyScripts.forEach(appendScriptNode);
}
</script>
<script src="app.js" type="text/javascript"></script>
</head>
<body>
<div class="sample-tutorial">
<div id="demo-host">
<div id="spread-host"></div>
<div id="panel-host"></div>
</div>
</div>
</body>
</html>
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.sample-tutorial {
position: relative;
height: 100%;
overflow: hidden;
}
#demo-host {
width: 100%;
height: 100%;
overflow: hidden;
float: left;
}
#spread-host {
position: absolute;
top: 0;
left: 0;
width: calc(100% - 380px);
height: 100%;
}
#panel-host {
position: absolute;
top: 0;
right: 0;
width: 380px;
height: 100%;
}