WINDOW
구문
인수
설명
window_function
(필수) window 함수입니다.
[partitionby_function]
(선택 사항) 행을 파티션으로 나눕니다.
[orderby_function]
(선택 사항) 각 파티션 내에서 행의 논리적 순서를 정의합니다.
[frame_function]
(선택 사항) 시작 및 끝 지점을 지정하여 현재 행에 대해 파티션 내 창에 행을 결합합니다.
사용법 참고 사항
WINDOW는 window 함수를 사용해서만 전달할 수 있으며 전체 행을 창으로 취급하고 PARTITIONBY, ORDERBY로 행의 시퀀스에 영향을 줍니다.
PARTITIONBY
구문
인수
설명
field_function
(필수) 분할되는 필드 이름 또는 수식
사용법 참고 사항
PARTITIONBY는 행을 파티션으로 나눕니다. window 함수는 각 파티션에 따로따로 적용되며 하나 이상의 매개 변수가 있어야 합니다. 예를 들면 다음과 같습니다.
ORDERBY
구문
인수
설명
field_function
(필수) 순서가 지정되는 필드 이름 또는 수식
인수
설명
field_function
(필수) 순서가 지정되는 필드 이름 또는 수식
사용법 참고 사항
ORDERBY는 각 파티션 내에서 행의 논리적 순서를 정의합니다. 지정된 창과 window 함수의 계산에 영향을 미치며 하나 이상의 매개 변수가 있어야 합니다. ORDERASC 및 ORDERDESC를 사용하여 정렬 순서를 오름차순이나 내림차순으로 나타냅니다. 기본 정렬 순서는 ORDERASC입니다. 예:
FRAMEROWS
구문
인수
설명
beginning_function
(필수) 현재 행을 기준으로 시작하는 행 수입니다.
[ending_function]
(선택 사항) 현재 행을 기준으로 끝나는 행 수입니다.
[exclude_mode]
(선택 사항) 다음 제외 모드를 지정합니다.0 - 기본값으로, 아무 행도 제외되지 않습니다.1 - 현재 행이 제외되며, FRAMEGROUPS 및 FRAMERANGE의 경우 현재 행의 다른 피어는 남아 있습니다.2 - 현재 행과 피어가 모두 제외됩니다.3 - 현재 행은 남아 있고 다른 피어는 제외됩니다.
사용법 참고 사항
FRAMEROWS는 현재 행 앞 또는 뒤에 오는 행 수를 음이 아닌 정수로 지정하여 창의 행 집합을 제한합니다. 첫 번째 매개 변수는 현재 행 앞의 행 수를 나타내며 -1, [@-n], [@+n] 또는 [@]를 사용할 수 있습니다. 두 번째 매개 변수는 현재 행 뒤의 행 수를 나타내며 -1, [@-n], [@+n] 또는 [@]를 사용할 수 있습니다. -1는 현재 파티션의 시작 또는 끝을 나타냅니다. [@-n] 또는 [@+n]은 현재 행 옆의 행 수를 나타내고, n에는 행 수를 나타내는 음이 아닌 정수를 사용할 수 있습니다. [@]는 현재 행을 나타냅니다. 예를 들면 다음과 같습니다.
FRAMERANGE
구문
인수
설명
beginning_function
(필수) 현재 행을 기준으로 시작하는 거리입니다.
[ending_function]
(선택 사항) 현재 행을 기준으로 끝나는 거리입니다.
[exclude_mode]
(선택 사항) 특정 행을 제외하기 위한 모드를 지정하며, FRAMEROWS와 동일합니다.
사용법 참고 사항
FRAMERANGE는 ORDERBY 열로 구성된 현재 행과 동일한 값을 같은 피어 행의 동일한 값의 거리로 음이 아닌 정수를 지정하여 기간의 범위를 제한합니다. 첫 번째 매개 변수는 현재 행의 연결된 행을 기준으로 시작하는 범위를 나타내며 -1, [@-/+n](순서가 내림차순인 경우 [@+/-n]) 또는 [@]를 사용할 수 있습니다. 두 번째 매개 변수는 현재 행의 연결된 행을 기준으로 끝나는 범위를 나타내며 -1, [@+/-n](순서가 내림차순인 경우 [@+/-n]) 또는 [@]를 사용할 수 있습니다. -1은 현재 파티션의 처음 또는 끝을 나타냅니다. n에는 거리를 나타내는 음이 아닌 정수를 사용할 수 있고, [@]는 현재 행과 같이 동일한 피어 행을 나타내고, 범위는 완전히 닫힌 구간입니다. 데이터 형식이 숫자인 첫 번째 열을 제공하기 위해 ORDERBY가 필요합니다. 정렬된 열이 두 개 이상인 경우 -1과 [@]만 사용할 수 있습니다. 예를 들면 다음과 같습니다.
FRAMEGROUPS
구문
인수
설명
beginning_function
(필수) 현재 그룹을 기준으로 시작하는 그룹 수입니다.
[ending_function]
(선택 사항) 현재 그룹을 기준으로 끝나는 그룹 수입니다.
[exclude_mode]
(선택 사항) 특정 행을 제외하기 위한 모드를 지정하며, FRAMEROWS와 동일합니다.
사용법 참고 사항
FRAMEGROUPS는 시작 및 끝 경계가 현재 그룹과 관련된 "그룹" 수에 따라 결정된다는 것을 의미합니다. "그룹"은 ORDERBY 창의 영향을 받는, 값이 동일한 모든 행의 집합입니다. 첫 번째 매개 변수는 현재 그룹을 기준으로 시작하는 그룹 수를 나타내며, -1, [@-n], [@+n] 또는 [@]를 사용할 수 있습니다. 두 번째 매개 변수는 현재 그룹을 기준으로 끝나는 그룹 수를 나타내며 -1, [@-n], [@+n] 또는 [@]를 사용할 수 있습니다. -1는 현재 파티션의 시작 또는 끝을 나타냅니다. [@-n] 또는 [@+n]은 현재 그룹 옆의 그룹 수를 나타내고, n에는 그룹 수를 나타내는 음이 아닌 정수를 사용할 수 있습니다. [@]는 현재 그룹을 나타냅니다. 예를 들면 다음과 같습니다.
창 연결
구문
사용법 참고 사항
창 연결은 PARTITYIONBY, ORDERBY 또는 창 프레임을 암시적으로 지정하여 창 하나를 먼저 정의한 후 새 창에서 재사용할 수 있는 간단한 방법입니다. 사전 정의된 창의 PARTITIONBY, ORDERBY, 창 프레임은 새 창의 식에 의해 재정의됩니다. WINDOWDEF를 사용하면 스키마의 기본 창을 정의할 수 있습니다.
/*REPLACE_MARKER*/
/*DO NOT DELETE THESE COMMENTS*/
window.onload = function () {
var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 0 });
initSpread(spread);
};
function initSpread(spread) {
spread.suspendPaint();
spread.clearSheets();
spread.options.autoFitType = GC.Spread.Sheets.AutoFitType.cellWithHeader;
spread.options.allowDynamicArray = true;
spread.options.highlightInvalidData = true;
spread.options.calcOnDemand = true;
discountAmount(spread);
revenueTrends(spread);
quantityRevenueTrends(spread);
monthlyRevenueTrends(spread);
spread.resumePaint();
}
function discountAmount(spread) {
//init a data manager
var dataManager = spread.dataManager();
var discountAmountTable = dataManager.addTable("discountAmountTable", {
remote: {
read: {
url: "$DEMOROOT$/spread/source/data/orderPriceQuantityData.csv"
}
},
schema: {
type: "csv",
columns: {
OrderDate: { dataType: "date" },
Quantity: { dataType: "number" },
Price: { dataType: "number" },
Amount: { dataType: 'formula', value: "=[@Price] * [@Quantity]" },
DiscountAmount: { dataType: 'formula', value: "=IF([@Quantity] > 30, [@Amount] * 0.8, [@Amount])" },
},
window: {
BeginCurrent: '=WINDOWDEF(PARTITIONBY([Category], [Product], YEAR([@OrderDate])), FRAMEROWS(-1,[@]))',
BeginEnd: '=WINDOWDEF(PARTITIONBY([Category], [Product], YEAR([@OrderDate])))',
}
}
});
//init a table sheet
var sheet = spread.addSheetTab(0, "Discount Amount", GC.Spread.Sheets.SheetType.tableSheet);
sheet.setDefaultRowHeight(40, GC.Spread.Sheets.SheetArea.colHeader);
sheet.options.allowAddNew = false; //hide new row
//bind a view to the table sheet
discountAmountTable.fetch().then(function () {
var discountHighlightRule = {
ruleType: "formulaRule",
formula: "[@Quantity]>30",
style: {
foreColor: "purple"
}
};
var myView = discountAmountTable.addView("myView", [
{ value: "Category", width: 90 },
{ value: "Product", width: 90 },
{ value: "=YEAR([@OrderDate])", caption: "Year", width: 80 },
{ value: "Amount", caption: "Amount", width: 100, conditionalFormats: [discountHighlightRule] },
// If the quantity exceeds 30, 20% off sales amount
{ value: "DiscountAmount", caption: "Discount Amount", conditionalFormats: [discountHighlightRule], width: 160 },
{ value: "Price", width: 70 },
{ value: "Quantity", width: 90, conditionalFormats: [discountHighlightRule] },
// The cumulative annual sales volume of each category and product
{ value: "=WINDOW(SUM([Quantity]), \"BeginCurrent\")", caption: 'Running Total Quantity', width: 190, style: { backColor: "#D9E1F2" } },
// The total annual sales volume of each category and product
{ value: "=WINDOW(SUM([Quantity]), \"BeginEnd\")", caption: 'Total Quantity', width: 140, style: { backColor: "#D9E1F2" } },
// The cumulative annual sales amount of each category and product, if the quantity exceeds 30, 20% off sales amount
{ value: "=WINDOW(SUM([DiscountAmount]), \"BeginCurrent\")", caption: 'Running Discount Total Amount', width: 240, style: { backColor: "#E2EFDA" } },
// The total annual sales amount of each category and product, if the quantity exceeds 30, 20% off sales amount
{ value: "=WINDOW(SUM([DiscountAmount]), \"BeginEnd\")", caption: 'Discount Total Amount', width: 190, style: { backColor: "#E2EFDA" } },
]);
spread.suspendPaint();
sheet.setDataView(myView);
spread.resumePaint();
});
}
function revenueTrends(spread) {
//init a data manager
var dataManager = spread.dataManager();
var revenueTrendsTable = dataManager.addTable("revenueTrendsTable", {
data: orderYearProductDataSource,
schema: {
type: "csv",
columns: {
Quantity: { dataType: "number" },
Amount: { dataType: "number" },
MovingAverageRevenue: { dataType: 'formula', value: '=WINDOW(AVERAGE([Amount]), "ProductYear")' },
},
window: {
ProductYear: '=WINDOWDEF(PARTITIONBY([Product]), ORDERBY([Year]), FRAMEROWS([@-2], [@]))'
}
}
});
//init a table sheet
var sheet = spread.addSheetTab(1, "Revenue Trends", GC.Spread.Sheets.SheetType.tableSheet);
sheet.setDefaultRowHeight(40, GC.Spread.Sheets.SheetArea.colHeader);
sheet.options.allowAddNew = false; //hide new row
//bind a view to the table sheet
revenueTrendsTable.fetch().then(function () {
var myView = revenueTrendsTable.addView("myView", [
{ value: "Year", width: 150 },
{ value: "Product", width: 105 },
{ value: "Amount", caption: "Revenue", width: 100, style: { formatter: "#,##0.00" } },
// Calculate the 3-year moving average of earned per product
// FRAMEROWS([@-2], [@]): the preceding two years and current
{ value: 'MovingAverageRevenue', caption: 'Moving Average Revenue', width: 200, style: { backColor: "#E2EFDA", formatter: "#,##0.00" } },
// To show a ratio of increase and decrease between the current and moving average amount
{ value: '=VARISPARKLINE(ROUND(([@Amount] - [@MovingAverageRevenue]) / [@Amount], 2),0,,,,0.2,TRUE)', caption: 'Revenue Trends %', width: 200, style: { backColor: "#E2EFDA" } },
]);
spread.suspendPaint();
sheet.setDataView(myView);
spread.resumePaint();
});
}
function quantityRevenueTrends(spread) {
//init a data manager
var dataManager = spread.dataManager();
var quantityRevenueTrendsTable = dataManager.addTable("quantityRevenueTrendsTable", {
remote: {
read: {
url: "$DEMOROOT$/spread/source/data/orderAmountData.csv"
}
},
schema: {
type: "csv",
columns: {
OrderDate: { dataType: "date" },
Amount: { dataType: "number" },
AverageRevenue: { dataType: 'formula', value: '=WINDOW(AVERAGE([Amount]), "ProductRangeAmount")' },
QuantityOfRevenue: { dataType: 'formula', value: '=WINDOW(COUNT([Amount]), "ProductRangeAmount")' },
},
window: {
ProductRangeAmount: '=WINDOWDEF(PARTITIONBY([Product]), ORDERBY([Amount]), FRAMERANGE([@-200], [@+200]))'
}
}
});
//init a table sheet
var sheet = spread.addSheetTab(2, "Quantity Of Revenue Trends", GC.Spread.Sheets.SheetType.tableSheet);
sheet.setDefaultRowHeight(40, GC.Spread.Sheets.SheetArea.colHeader);
sheet.options.allowAddNew = false; //hide new row
//bind a view to the table sheet
quantityRevenueTrendsTable.fetch().then(function () {
var myView = quantityRevenueTrendsTable.addView("myView", [
{ value: "Product", width: 150 },
{ value: "Amount", caption: "Revenue", width: 100, style: { formatter: "#,##0.00" } },
// The trend comparison of average selling prices and the quantity of the proximate orders
// When the price is within a certain range, there are more orders
// When the price is higher or lower, the order quantity decreases
// This situation of the quantity of the orders are close to the normal distribution
// The analytic function AVERAGE can obtain the average of proximate selling prices within each product
// FRAMERANGE([@-200], [@+200]): the amount range which minus or plus 200 against current amount will help to retrieve the orders as a window
{ value: "AverageRevenue", caption: 'Average Revenue', width: 150, style: { backColor: "#E2EFDA", formatter: "#,##0.00" } },
// Calculating the ratio of the average amount of the proximate orders against max amount in each product to show the bars
{ value: "=HBARSPARKLINE([@AverageRevenue] / WINDOW(MAX([Amount]), PARTITIONBY([Product])), \"#347B98\")", caption: 'Average Revenue Trends', width: 200, style: { backColor: "#E2EFDA" } },
// The analytic function COUNT can obtain the quantity of proximate selling prices within each product
// FRAMERANGE([@-200], [@+200]): the amount range which minus or plus 200 against current amount will help to retrieve the orders as a window
{ value: "QuantityOfRevenue", caption: 'Quantity Of Revenue', width: 180, style: { backColor: "#E2EFDA" } },
// Using LET to cached the ratio of the number of the proximate orders against the total number of the orders in each product to show the bars which indicates the trends through the ratio and colors
{ value: "=LET(ratio, [@QuantityOfRevenue] / WINDOW(COUNT([Amount]), PARTITIONBY([Product])),color,IF(ratio >= 0.32,\"green\", IF(ratio >= 0.2, \"#66B032\", IF(ratio >= 0.1, \"#B2D732\", \"red\"))), HBARSPARKLINE(ratio, color))", caption: 'Quantity Of Revenue Trends', width: 200, style: { backColor: "#E2EFDA" } },
]);
spread.suspendPaint();
sheet.setDataView(myView);
spread.resumePaint();
});
}
function monthlyRevenueTrends(spread) {
//init a data manager
var dataManager = spread.dataManager();
var monthlyRevenueTrendsTable = dataManager.addTable("monthlyRevenueTrendsTable", {
remote: {
read: {
url: "$DEMOROOT$/spread/source/data/orderAmountData.csv"
}
},
schema: {
type: "csv",
columns: {
OrderDate: { dataType: "date" },
Amount: { dataType: "number" },
MonthlyAverageRevenue: { dataType: 'formula', value: '=WINDOW(AVERAGE([Amount]), "ProductMonthly")' },
NearlyAverageRevenue: { dataType: 'formula', value: '=WINDOW(AVERAGE([Amount]), "ProductMonthly", FRAMEGROUPS([@-2], [@+2], 2))' },
},
window: {
ProductMonthly: '=WINDOWDEF(PARTITIONBY([Product]), ORDERBY(VALUE(DATEPART([@OrderDate], "M"))), FRAMEGROUPS([@], [@]))'
}
}
});
//init a table sheet
var sheet = spread.addSheetTab(3, "Monthly Revenue Trends", GC.Spread.Sheets.SheetType.tableSheet);
sheet.setDefaultRowHeight(40, GC.Spread.Sheets.SheetArea.colHeader);
sheet.options.allowAddNew = false; //hide new row
//bind a view to the table sheet
monthlyRevenueTrendsTable.fetch().then(function () {
var myView = monthlyRevenueTrendsTable.addView("myView", [
{ value: "Product", width: 150 },
{ value: '=VALUE(DATEPART([@OrderDate], "M"))', caption: 'Month', width: 150 },
{ value: "Amount", caption: "Revenue", width: 100, style: { formatter: "#,##0.00" } },
// Compare the monthly and nearly average of earned per product
// Current month average revenue
{ value: 'MonthlyAverageRevenue', caption: 'Monthly Average Revenue', width: 220, style: { backColor: "#E2EFDA", formatter: "#,##0.00" } },
// The nearly average revenue without the current month
// For FRAMEGROUPS, [@-2] indicates two months before current, [@+2] indicates two months after current, and the exclude mode is 2 that indicates the current row and the peers are all excluded.
{ value: 'NearlyAverageRevenue', caption: 'Nearly Average Revenue', width: 200, style: { backColor: "#E2EFDA", formatter: "#,##0.00" } },
// To show a ratio of increase and decrease between the current and nearly average amount
{ value: '=VARISPARKLINE(ROUND(([@MonthlyAverageRevenue] - [@NearlyAverageRevenue]) / [@MonthlyAverageRevenue], 2),0,,,,0.2,TRUE)', caption: 'Revenue Trends %', width: 200, style: { backColor: "#E2EFDA" } },
]);
spread.suspendPaint();
sheet.setDataView(myView);
spread.resumePaint();
});
}
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta charset="utf-8" />
<meta name="spreadjs culture" content="ko-kr"/>
<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">
<!-- Promise Polyfill for IE, https://www.npmjs.com/package/promise-polyfill -->
<script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"></script>
<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-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" type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/data/orderDataSource.js" type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/data/orderYearProductDataSource.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>
</html>
.sample-tutorial {
position: relative;
height: 100%;
overflow: hidden;
}
.sample-spreadsheets {
width: 100%;
height: 100%;
overflow: hidden;
float: left;
}
.options-container {
float: right;
width: 210px;
padding: 12px;
height: 100%;
box-sizing: border-box;
background: #fbfbfb;
overflow: auto;
}
.option-row {
font-size: 14px;
padding: 5px;
margin-top: 10px;
}
label {
display: block;
margin-bottom: 3px;
margin-top: 3px;
}
input {
padding: 4px 6px;
}
input[type=button] {
margin-top: 6px;
display: block;
width: 100%;
text-align: center;
}
input[type=text] {
width: 230px;
}
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: 0;
}