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.

Learn about OLAP | PivotEngine API Reference

import 'bootstrap.css'; import '@mescius/wijmo.styles/wijmo.css'; import './styles.css'; import '@mescius/wijmo.touch'; // support drag/drop on touch devices import * as wjOlap from '@mescius/wijmo.olap'; import * as wjCore from '@mescius/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: 'Quarter', format: '\"Q\"q yyyy' }, { binding: 'date', header: 'Month', format: 'MMMM' }, { binding: 'agent', header: 'Agent' }, { binding: 'region', header: 'Region' }, { binding: 'platform', header: 'Platform' }, { binding: 'product', header: 'Product' }, { binding: 'sales', header: 'Sales', format: 'c2' }, { binding: 'downloads', header: 'Downloads', format: 'n0' }, { binding: 'revenue', header: 'Revenue', format: 'c2' }, ], itemsSource: ds10, showRowTotals: 'Subtotals', rowFields: ['Quarter', 'Region'], columnFields: ['Platform', 'Product'], valueFields: ['Sales', 'Downloads', 'Revenue'], // // 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>MESCIUS Wijmo OLAP Pivot Engine Performance</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- SystemJS --> <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.21.5/system.src.js" integrity="sha512-skZbMyvYdNoZfLmiGn5ii6KmklM82rYX2uWctBhzaXPxJgiv4XBwJnFGr5k8s+6tE1pcR1nuTKghozJHyzMcoA==" crossorigin="anonymous"></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>
var products = [ { product: 'Wijmo', platform: 'Web' }, { product: 'ActiveReports', platform: 'Desktop' }, { product: 'ActiveReportsJS', platform: 'Web' }, { product: 'ComponentOne', platform: 'Desktop' }, { product: 'Spread', platform: 'Desktop' }, { product: 'SpreadJS', platform: 'Web' }, { product: 'GCDocs', platform: 'Desktop' } ]; var agents = [ { agent: 'Ashlyn Dunlop', region: 'East' }, { agent: 'Keith Vang', region: 'East' }, { agent: 'Bobbi Rodrigues', region: 'West' }, { agent: 'Charli Medina', region: 'West' }, { agent: 'Kaitlin Salt', region: 'West' }, ]; function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } export function addData(data, cnt) { var year = new Date().getFullYear(); for (var i = 0; i < cnt; i++) { let productIndex = randomInt(0, 6); let agentIndex = randomInt(0, 4); data.push({ orderId: randomInt(1, 10000), platform: products[productIndex].platform, product: products[productIndex].product, agent: agents[agentIndex].agent, region: agents[agentIndex].region, date: new Date(year - randomInt(0, 2), randomInt(0, 11), randomInt(0, 27)), sales: randomInt(1500, 3500), downloads: randomInt(10, 200), revenue: randomInt(500, 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', '@mescius/wijmo': 'npm:@mescius/wijmo/index.js', '@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js', '@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles', '@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures', '@mescius/wijmo.chart': 'npm:@mescius/wijmo.chart/index.js', '@mescius/wijmo.chart.analytics': 'npm:@mescius/wijmo.chart.analytics/index.js', '@mescius/wijmo.chart.animation': 'npm:@mescius/wijmo.chart.animation/index.js', '@mescius/wijmo.chart.annotation': 'npm:@mescius/wijmo.chart.annotation/index.js', '@mescius/wijmo.chart.finance': 'npm:@mescius/wijmo.chart.finance/index.js', '@mescius/wijmo.chart.finance.analytics': 'npm:@mescius/wijmo.chart.finance.analytics/index.js', '@mescius/wijmo.chart.hierarchical': 'npm:@mescius/wijmo.chart.hierarchical/index.js', '@mescius/wijmo.chart.interaction': 'npm:@mescius/wijmo.chart.interaction/index.js', '@mescius/wijmo.chart.radar': 'npm:@mescius/wijmo.chart.radar/index.js', '@mescius/wijmo.chart.render': 'npm:@mescius/wijmo.chart.render/index.js', '@mescius/wijmo.chart.webgl': 'npm:@mescius/wijmo.chart.webgl/index.js', '@mescius/wijmo.chart.map': 'npm:@mescius/wijmo.chart.map/index.js', '@mescius/wijmo.gauge': 'npm:@mescius/wijmo.gauge/index.js', '@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js', '@mescius/wijmo.grid.detail': 'npm:@mescius/wijmo.grid.detail/index.js', '@mescius/wijmo.grid.filter': 'npm:@mescius/wijmo.grid.filter/index.js', '@mescius/wijmo.grid.search': 'npm:@mescius/wijmo.grid.search/index.js', '@mescius/wijmo.grid.grouppanel': 'npm:@mescius/wijmo.grid.grouppanel/index.js', '@mescius/wijmo.grid.multirow': 'npm:@mescius/wijmo.grid.multirow/index.js', '@mescius/wijmo.grid.transposed': 'npm:@mescius/wijmo.grid.transposed/index.js', '@mescius/wijmo.grid.transposedmultirow': 'npm:@mescius/wijmo.grid.transposedmultirow/index.js', '@mescius/wijmo.grid.pdf': 'npm:@mescius/wijmo.grid.pdf/index.js', '@mescius/wijmo.grid.sheet': 'npm:@mescius/wijmo.grid.sheet/index.js', '@mescius/wijmo.grid.xlsx': 'npm:@mescius/wijmo.grid.xlsx/index.js', '@mescius/wijmo.grid.selector': 'npm:@mescius/wijmo.grid.selector/index.js', '@mescius/wijmo.grid.cellmaker': 'npm:@mescius/wijmo.grid.cellmaker/index.js', '@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js', '@mescius/wijmo.odata': 'npm:@mescius/wijmo.odata/index.js', '@mescius/wijmo.olap': 'npm:@mescius/wijmo.olap/index.js', '@mescius/wijmo.rest': 'npm:@mescius/wijmo.rest/index.js', '@mescius/wijmo.pdf': 'npm:@mescius/wijmo.pdf/index.js', '@mescius/wijmo.pdf.security': 'npm:@mescius/wijmo.pdf.security/index.js', '@mescius/wijmo.viewer': 'npm:@mescius/wijmo.viewer/index.js', '@mescius/wijmo.xlsx': 'npm:@mescius/wijmo.xlsx/index.js', '@mescius/wijmo.undo': 'npm:@mescius/wijmo.undo/index.js', '@mescius/wijmo.interop.grid': 'npm:@mescius/wijmo.interop.grid/index.js', '@mescius/wijmo.touch': 'npm:@mescius/wijmo.touch/index.js', '@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/index.js', '@mescius/wijmo.barcode': 'npm:@mescius/wijmo.barcode/index.js', '@mescius/wijmo.barcode.common': 'npm:@mescius/wijmo.barcode.common/index.js', '@mescius/wijmo.barcode.composite': 'npm:@mescius/wijmo.barcode.composite/index.js', '@mescius/wijmo.barcode.specialized': 'npm:@mescius/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);