Wijmo Olap 101

Introducing wijmo.olap

The wijmo.olap module contains controls that allow you to add Excel-like pivot table and pivot chart features to your applications. To use it, follow these steps:

  • Add references to the wijmo and wijmo.olap modules to the page.
  • Add a PivotPanel control to the page.
  • Add one or more PivotGrid and PivotChart controls to the page, and connect them to the PivotPanel by setting their itemsSource property to the PivotPanel control.
  • Set the PivotPanel's itemsSource property to an array containing the raw data you want to analyze.
  • Optionally add code to print, export, save and load views and view definitions.

That's all. The PivotPanel will show a list of the fields available, and users will be able to drag fields between summary areas to generate data summaries (AKA "views"). Users may also configure the fields by setting their headers, summary functions, filters, and formats.

Users may analyze the data and print the results, export the results to XLSX or PDF, and save view definitions that can be re-used later.

Here is a simple example:

Add a PivotPanel and a PivotGrid to the page

The PivotPanel control is similar to Excel's "field list" window that is associated with pivot tables and charts.

  • Add fields to the view by dragging or using the checkboxes.
  • Remove fields from the view by dragging them back to the top area or by using their context menu.
  • Configure fields using their context menu. You may modify their header, summary function, and format. Note that the format is used when grouping the data, so you can group data by day, month, quarter or year by changing the format of the date fields for example.

The PivotGrid control extends the FlexGrid to support pivoting features including custom cell merging, hierarchical row and column groups, and a custom context menu that allows users to configure the pivot fields and to drill-down into the data items that were used in the computation of specific summary cells.

<div class="mdl-grid" id="theView"> <div class="mdl-cell mdl-cell--4-col"> <wj-pivot-panel control="thePanel" items-source="rawData" initialized="initPanel(s,e)"> </wj-pivot-panel> </div> <div class="mdl-cell mdl-cell--8-col"> <wj-pivot-grid control="pivotGrid" items-source="thePanel"> </wj-pivot-grid> </div> </div>
// initialize the view definition $scope.initPanel = function (sender, e) { var ng = sender.engine; ng.rowFields.push('Product', 'Country'); ng.valueFields.push('Sales', 'Downloads'); ng.showRowTotals = wijmo.olap.ShowTotals.Subtotals; ng.showColTotals = wijmo.olap.ShowTotals.Subtotals; }

Use the viewDefinition property to save and restore view definitions. For example:

Or build a list of pre-defined views for the user to pick from. For example:

<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" ng-click="saveView()"> Save View </button> <button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" ng-click="loadView()"> Load View </button> <ul> <li ng-repeat="view in viewDefs"> <a href="#theView" index="$index" ng-click="loadView(view.def)"> {‌{ view.name }} </a> </li> </ul>
// save/restore view definitions $scope.saveView = function () { if ($scope.thePanel.isViewDefined) { localStorage.viewDefinition = $scope.thePanel.viewDefinition; } } $scope.loadView = function (def) { if (def) { // load pre-defined view (against specific dataset) $scope.rawData = $scope.dataSets[3].value; $scope.thePanel.viewDefinition = def; } else { // load view from localStorage (whatever the user saved) $scope.thePanel.viewDefinition = localStorage.viewDefinition; } }

Configure the PivotPanel properties

The PivotPanel control has properties that allow you to customize the view. Use the controls below to modify the value of some properties and see their effect:

Dataset
Row totals
Column totals
Show Zeros
Totals Before Data
<dl class="dl-horizontal"> <dt>Dataset</dt> <dd> <wj-combo-box items-source="dataSets" display-member-path="name" selected-value-path="value" selected-value="rawData"> </wj-combo-box> </dd> <dt>Row totals</dt> <dd> <wj-combo-box items-source="showTotals" display-member-path="name" selected-value-path="value" selected-value="thePanel.engine.showRowTotals"> </wj-combo-box> </dd> <dt>Column totals</dt> <dd> <wj-combo-box items-source="showTotals" display-member-path="name" selected-value-path="value" selected-value="thePanel.engine.showColumnTotals"> </wj-combo-box> </dd> <dt>Show Zeros</dt> <dd> <input ng-model="thePanel.engine.showZeros" type="checkbox" /> </dd> </dl>
// no code required!

Show the results in a PivotChart

The PivotChart control provides a graphical visualization of the results. It is similar to Excel's pivot charts, including support for multiple chart types and hierarchical axes.

To use the PivotChart control, connect it to a PivotPanel using the itemsSource property:

Please create a view in order to see the chart.

Chart Type
Show Legend
Show Title
<div ng-show="thePanel.isViewDefined"> <dl class="dl-horizontal"> <dt>Chart Type</dt> <dd> <wj-combo-box items-source="chartTypes" display-member-path="name" selected-value-path="value" selected-value="theChart.chartType"> </wj-combo-box> </dd> <dt>Show Legend</dt> <dd> <wj-combo-box items-source="legendVisibility" display-member-path="name" selected-value-path="value" selected-value="theChart.showLegend"> </wj-combo-box> </dd> <dt>Show Title</dt> <dd> <input type="checkbox" checked="checked" ng-model="theChart.showTitle"> </dd> </dl> <wj-pivot-chart control="theChart" show-legend="Auto" items-source="thePanel"> </wj-pivot-chart> </div> <div ng-hide="thePanel.isViewDefined"> <p> Please create a view in order to see the chart.</p> </div>
// no code required!

View and edit the source data

The pivot view is live. If you edit any of the {{ rawData.items.length | number }} items, the pivot view will be updated automatically. (This grid is read-only because it is bound to a read-only data source, but you can still apply filters to the raw data.)

<wj-flex-grid style="border:none" control="rawGrid" items-source="rawData" is-read-only="{‌{ rawData.tableName != null }}" show-selected-headers="All"> <wj-flex-grid-filter></wj-flex-grid-filter> </wj-flex-grid>
// no code required!

Export the results to Excel

The PivotGrid control extends the FlexGrid, so you can export it to any of the formats supported by the extension modules provided with the FlexGrid. The list of supported formats includes XLSX, CSV, and PDF.

For example, the button below creates an Excel file with two sheets: the current view and the raw data (if the data has 10,000 items or less):

<button class="mdl-button mdl-js-button mdl-button--raised mdl-button--colored mdl-js-ripple-effect" ng-click="export()"> Export to XLSX </button>
$scope.export = function () { var ng = $scope.thePanel.engine; // create book with current view var book = wijmo.grid.xlsx.FlexGridXlsxConverter.save($scope.pivotGrid, { includeColumnHeaders: true, includeRowHeaders: true }); book.sheets[0].name = 'Main View'; addTitleCell(book.sheets[0], getViewTitle(ng)); // add sheet with raw data if ($scope.rawGrid.rows.length <= 10000) { var raw = wijmo.grid.xlsx.FlexGridXlsxConverter.save($scope.rawGrid, { includeColumnHeaders: true, includeRowHeaders: false }); raw.sheets[0].name = 'Raw Data'; book.sheets.push(raw.sheets[0]); } // save the book book.save('wijmo.olap.xlsx'); }

Customize the PivotGrid cells

The PivotGrid control extends the FlexGrid, so you can customize the display of the grid cells using the formatItem event and modifying the content of each cell with complete flexibility.

For example, the PivotGrid below uses colors and icons similar to the ones in Excel's icon sets to show how sales changed from quarter to quarter:

<wj-pivot-grid items-source="ngFmt" format-item="formatItem(s,e)" style="border:none"> </wj-pivot-grid>
$scope.ngFmt = new wijmo.olap.PivotEngine({ autoGenerateFields: false, itemsSource: getSimpleDataSet(10000), showColumnTotals: wijmo.olap.ShowTotals.GrandTotals, showRowTotals: wijmo.olap.ShowTotals.None, fields: [ { binding: 'product', header: 'Product' }, { binding: 'date', header: 'Date', format: 'yyyy \"Q\"q' }, { binding: 'sales', header: 'Sales', format: 'n0' }, { binding: 'sales', header: 'Diff', format: 'p0', showAs: wijmo.olap.ShowAs.DiffRowPct } ] }); $scope.ngFmt.rowFields.push('Date'); $scope.ngFmt.columnFields.push('Product'); $scope.ngFmt.valueFields.push('Sales', 'Diff'); $scope.formatItem = function (s, e) { if (e.panel == s.cells && e.col % 2 == 1) { var value = s.getCellData(e.row, e.col), color = '#d8b400', glyph = 'circle'; if (value != null) { if (value < 0) { // negative variation color = '#9f0000'; glyph = 'down'; } else if (value > 0.05) { // positive variation color = '#4c8f00'; glyph = 'down'; } e.cell.style.color = color; e.cell.innerHTML += ' <span style="font-size:120%" class="wj-glyph-' + glyph + '"></span>'; } } }

Notice that in this example we only have one pre-defined view, and don't need a PivotPanel at all. Instead, the code creates a PivotEngine directly and uses that as the grid's itemsSource.