PivotEngine Performance

The PivotEngine can summarize large data sets, either on the client or on the server. Either way, data summaries are generated asynchronously, so the UI remains responsive while the data is being summarized.

This example demonstrates performance by showing the time it takes to summarize client-side data sets of different sizes.

If your data sets are really large (millions of records), you should consider using server-side OLAP providers like SSAS cubes or ComponentOne Data Services. The PivotEngine can connect to either.

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import '@grapecity/wijmo.touch'; // support drag/drop on touch devices import * as wjOlap from '@grapecity/wijmo.olap'; import * as wjCore from '@grapecity/wijmo'; import { addData } from './data'; // document.readyState === 'complete' ? init() : window.onload = init; // function init() { // // initialize data sets var ds10 = addData([], 10e3), ds100 = [], ds500 = [], result = document.getElementById('result'), start = 0; // // initialize pivot engine var ng = new wjOlap.PivotEngine({ autoGenerateFields: false, fields: [ { binding: 'date', header: 'Date', format: 'yyyy' }, { binding: 'buyer', header: 'Person' }, { binding: 'type', header: 'Category' }, { binding: 'amount', header: 'Amount', format: 'c0', aggregate: 'Sum' } ], itemsSource: ds10, showRowTotals: 'Subtotals', valueFields: ['Amount'], rowFields: ['Person', 'Category'], // // benchmark updatingView: function () { if (start == 0) { start = Date.now(); } }, updatedView: function (s) { var fmt = 'Summarized <b>{cnt:n0}</b> items in <b>{tm:n0}</b>ms'; result.innerHTML = wjCore.format(fmt, { cnt: s.itemsSource.length, tm: Date.now() - start }); start = 0; } }); // // show summary var pivotGrid = new wjOlap.PivotGrid('#pivotGrid', { itemsSource: ng }); // // handle click events to apply different data sources document.getElementById('buttons').addEventListener('click', function (e) { switch (e.target.id) { case '10k': ng.itemsSource = ds10; break; case '100k': ng.itemsSource = ds100; break; case '500k': ng.itemsSource = ds500; break; } }); // // create large data asynchronously createDataAsync(100e3, function (result) { ds100 = result; enableButton('100k'); }); createDataAsync(500e3, function (result) { ds500 = result; enableButton('500k'); }); function enableButton(id) { document.getElementById(id).disabled = false; } // // create data asynchronously function createDataAsync(cnt, callback) { var data = []; addDataAsync(data, cnt, function () { callback(data); }); } function addDataAsync(data, cnt, callback) { setTimeout(function () { addData(data, Math.min(cnt - data.length, 1000)); if (data.length == cnt) { callback(data); } else { addDataAsync(data, cnt, callback); } }); } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Grapecity Wijmo OLAP Pivot Engine Performance</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('./src/app'); </script> </head> <body> <div class="container-fluid"> <div id="buttons"> <button id="10k" class="btn btn-primary"> 10k items </button> <button id="100k" class="btn btn-primary" disabled> 100k items </button> <button id="500k" class="btn btn-primary" disabled> 500k items </button> </div> <p id="result"> </p> <div class="output"> <div id="pivotGrid"></div> </div> </div> </body> </html>
import { DateTime } from '@grapecity/wijmo'; function randomItem(arr) { return arr[Math.floor(Math.random() * arr.length)]; } export function addData(data, cnt) { var today = new Date(), buyers = 'Mom,Dad,Kelly,Sheldon'.split(','), types = 'Food,Clothes,Fuel,Books,Sports,Music'.split(','); for (var i = 0; i < cnt; i++) { data.push({ date: DateTime.addYears(today, -Math.random() * 3), buyer: randomItem(buyers), type: randomItem(types), amount: 20 + Math.random() * 1000 }); } return data; }
#buttons { display: flex; margin-bottom: 6px; } #buttons .btn { margin: 6px; white-space: normal; } .output { display: flex; justify-content: center; margin: 6px; } .wj-pivotgrid { width: auto; max-height: 300px; } body { margin-bottom: 36pt; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { 'jszip': 'npm:jszip/dist/jszip.js', '@grapecity/wijmo': 'npm:@grapecity/wijmo/index.js', '@grapecity/wijmo.input': 'npm:@grapecity/wijmo.input/index.js', '@grapecity/wijmo.styles': 'npm:@grapecity/wijmo.styles', '@grapecity/wijmo.cultures': 'npm:@grapecity/wijmo.cultures', '@grapecity/wijmo.chart': 'npm:@grapecity/wijmo.chart/index.js', '@grapecity/wijmo.chart.analytics': 'npm:@grapecity/wijmo.chart.analytics/index.js', '@grapecity/wijmo.chart.animation': 'npm:@grapecity/wijmo.chart.animation/index.js', '@grapecity/wijmo.chart.annotation': 'npm:@grapecity/wijmo.chart.annotation/index.js', '@grapecity/wijmo.chart.finance': 'npm:@grapecity/wijmo.chart.finance/index.js', '@grapecity/wijmo.chart.finance.analytics': 'npm:@grapecity/wijmo.chart.finance.analytics/index.js', '@grapecity/wijmo.chart.hierarchical': 'npm:@grapecity/wijmo.chart.hierarchical/index.js', '@grapecity/wijmo.chart.interaction': 'npm:@grapecity/wijmo.chart.interaction/index.js', '@grapecity/wijmo.chart.radar': 'npm:@grapecity/wijmo.chart.radar/index.js', '@grapecity/wijmo.chart.render': 'npm:@grapecity/wijmo.chart.render/index.js', '@grapecity/wijmo.chart.webgl': 'npm:@grapecity/wijmo.chart.webgl/index.js', '@grapecity/wijmo.gauge': 'npm:@grapecity/wijmo.gauge/index.js', '@grapecity/wijmo.grid': 'npm:@grapecity/wijmo.grid/index.js', '@grapecity/wijmo.grid.detail': 'npm:@grapecity/wijmo.grid.detail/index.js', '@grapecity/wijmo.grid.filter': 'npm:@grapecity/wijmo.grid.filter/index.js', '@grapecity/wijmo.grid.search': 'npm:@grapecity/wijmo.grid.search/index.js', '@grapecity/wijmo.grid.grouppanel': 'npm:@grapecity/wijmo.grid.grouppanel/index.js', '@grapecity/wijmo.grid.multirow': 'npm:@grapecity/wijmo.grid.multirow/index.js', '@grapecity/wijmo.grid.transposed': 'npm:@grapecity/wijmo.grid.transposed/index.js', '@grapecity/wijmo.grid.transposedmultirow': 'npm:@grapecity/wijmo.grid.transposedmultirow/index.js', '@grapecity/wijmo.grid.pdf': 'npm:@grapecity/wijmo.grid.pdf/index.js', '@grapecity/wijmo.grid.sheet': 'npm:@grapecity/wijmo.grid.sheet/index.js', '@grapecity/wijmo.grid.xlsx': 'npm:@grapecity/wijmo.grid.xlsx/index.js', '@grapecity/wijmo.grid.selector': 'npm:@grapecity/wijmo.grid.selector/index.js', '@grapecity/wijmo.grid.cellmaker': 'npm:@grapecity/wijmo.grid.cellmaker/index.js', '@grapecity/wijmo.nav': 'npm:@grapecity/wijmo.nav/index.js', '@grapecity/wijmo.odata': 'npm:@grapecity/wijmo.odata/index.js', '@grapecity/wijmo.olap': 'npm:@grapecity/wijmo.olap/index.js', '@grapecity/wijmo.pdf': 'npm:@grapecity/wijmo.pdf/index.js', '@grapecity/wijmo.pdf.security': 'npm:@grapecity/wijmo.pdf.security/index.js', '@grapecity/wijmo.viewer': 'npm:@grapecity/wijmo.viewer/index.js', '@grapecity/wijmo.xlsx': 'npm:@grapecity/wijmo.xlsx/index.js', '@grapecity/wijmo.undo': 'npm:@grapecity/wijmo.undo/index.js', '@grapecity/wijmo.interop.grid': 'npm:@grapecity/wijmo.interop.grid/index.js', '@grapecity/wijmo.touch': 'npm:@grapecity/wijmo.touch/index.js', '@grapecity/wijmo.cloud': 'npm:@grapecity/wijmo.cloud/index.js', '@grapecity/wijmo.barcode': 'npm:@grapecity/wijmo.barcode/index.js', '@grapecity/wijmo.barcode.common': 'npm:@grapecity/wijmo.barcode.common/index.js', '@grapecity/wijmo.barcode.composite': 'npm:@grapecity/wijmo.barcode.composite/index.js', '@grapecity/wijmo.barcode.specialized': 'npm:@grapecity/wijmo.barcode.specialized/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'js' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);