Virtualization

The main job of the FlexGrid is to convert JavaScript data objects into DOM elements that the user can interact with. In many cases, the data consists of large arrays with many thousands of items. Creating DOM elements for each of these items would make for large and slow pages. Virtualization is the process of keeping track of which portions of the data are visible and rendering only those parts. This reduces the number of DOM elements in the document tree and improves performance dramatically. The FlexGrid exposes the visible part of the data through the viewRange property. Whenever the user resizes the screen or scrolls the grid, the viewRange is updated and the grid updates its child DOM elements.

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import { FlexGrid } from '@grapecity/wijmo.grid'; document.readyState === 'complete' ? init() : window.onload = init; function init() { // start with a small data set var data = getData(100); // initialize the grid var rowCount = document.getElementById('rowCount'); var cellCount = document.getElementById('cellCount'); var theGrid = new FlexGrid('#theGrid', { itemsSource: data, updatedView: function (s, e) { rowCount.textContent = s.rows.length; cellCount.textContent = s.hostElement.querySelectorAll('.wj-cell').length; }, scrollPositionChanged: function (s, e) { // if we're close to the bottom, add 20 items if (s.viewRange.bottomRow >= s.rows.length - 1) { addData(data, 20); s.collectionView.refresh(); } } }); // get an array with random data function getData(cnt, start) { var data = []; var countries = 'USA,Germany,UK,Japan,Italy,Greece'.split(','); if (!start) start = 0; for (var i = 0; i < cnt; i++) { data.push({ id: i + start, country: countries[i % countries.length], date: new Date(2014, i % 12, i % 28), amount: Math.random() * 10000, active: i % 4 === 0 }); } return data; } // add random data to an array function addData(data, cnt) { var more = getData(cnt, data.length); for (var i = 0; i < more.length; i++) { data.push(more[i]); } } } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Virtualization</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="theGrid"></div> <p> The grid now has <span id='rowCount'></span> rows and <span id='cellCount'></span> cell elements. </p> </div> </body> </html> .wj-flexgrid { height: 250px; margin: 6px 0px; } #rowCount, #cellCount { font-weight: bold; } body { margin-bottom: 24pt; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import { Component, enableProdMode, NgModule } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import * as wjcGrid from '@grapecity/wijmo.grid'; import { WjGridModule } from '@grapecity/wijmo.angular2.grid'; // @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { data: any[]; rowCount: string; cellCount: string; // DataSvc will be passed by derived classes constructor() { this.data = this._getData(100); } flexInitialized(flexgrid: wjcGrid.FlexGrid) { this.rowCount = flexgrid.rows.length.toString(); this.cellCount = flexgrid.hostElement.querySelectorAll('.wj-cell').length.toString(); flexgrid.updatedView.addHandler((s, e) => { this.rowCount = s.rows.length.toString(); this.cellCount = s.hostElement.querySelectorAll('.wj-cell').length.toString(); }); flexgrid.scrollPositionChanged.addHandler((s, e) => { // if we're close to the bottom, add 20 items if (s.viewRange.bottomRow >= s.rows.length - 1) { this._addData(this.data, 20); s.collectionView.refresh(); } }); } private _getData(cnt: number, start?: number) { let data = []; let countries = 'USA,Germany,UK,Japan,Italy,Greece'.split(','); if (start == null) { start = 0; } for (let i = 0; i < cnt; i++) { data.push({ id: i + start, country: countries[i % countries.length], date: new Date(2014, i % 12, i % 28), amount: Math.random() * 10000, active: i % 4 === 0 }); } return data; } // add random data to an array private _addData(data: any, cnt: number) { let more = this._getData(cnt, data.length); for (let i = 0; i < more.length; i++) { data.push(more[i]) } } } // @NgModule({ imports: [WjGridModule, BrowserModule], declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule { } // enableProdMode(); // Bootstrap application with hash style navigation and global services. platformBrowserDynamic().bootstrapModule(AppModule); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Arrays and CollectionViews Binding</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Polyfills --> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.min.js"></script> <!-- SystemJS --> <script src="node_modules/systemjs/dist/system.js"></script> <script src="systemjs.config.js"></script> <script> // workaround to load 'rxjs/operators' from the rxjs bundle System.import('rxjs').then(function (m) { System.set(SystemJS.resolveSync('rxjs/operators'), System.newModule(m.operators)); System.import('./src/app.component'); }); </script> </head> <body> <app-component></app-component> </body> </html> <div class="container-fluid"> <!-- the grid --> <wj-flex-grid #flex [(itemsSource)]="data" (initialized)="flexInitialized(flex)"> </wj-flex-grid> <p> The grid now has <span id="rowCount">{{rowCount}}</span> rows and <span id="cellCount">{{cellCount}}</span> cell elements. </p> </div> .wj-flexgrid { height: 250px; margin: 6px 0px; } #rowCount, #cellCount { font-weight: bold; } body { margin-bottom: 24pt; } <template> <div class="container-fluid"> <!-- the grid --> <wj-flex-grid :itemsSource="data" :initialized="flexInitialized"></wj-flex-grid> <p> The grid now has <span id="rowCount">{{rowCount}}</span> rows and <span id="cellCount">{{cellCount}}</span> cell elements. </p> </div> </template> <script> import "@grapecity/wijmo.styles/wijmo.css"; import "bootstrap.css"; import Vue from "vue"; import "@grapecity/wijmo.vue2.grid"; import * as wjcCore from "@grapecity/wijmo"; let App = Vue.extend({ name: "app", data: function() { return { data: this._getData(100), rowCount: "", cellCount: "" }; }, methods: { flexInitialized: function(flexgrid) { this.rowCount = flexgrid.rows.length.toString(); this.cellCount = flexgrid.hostElement .querySelectorAll(".wj-cell") .length.toString(); flexgrid.updatedView.addHandler((s, e) => { this.rowCount = s.rows.length.toString(); this.cellCount = s.hostElement .querySelectorAll(".wj-cell") .length.toString(); }); flexgrid.scrollPositionChanged.addHandler((s, e) => { // if we're close to the bottom, add 20 items if (s.viewRange.bottomRow >= s.rows.length - 1) { this._addData(this.data, 20); s.collectionView.refresh(); } }); }, _getData: function(cnt, start) { let data = []; let countries = "USA,Germany,UK,Japan,Italy,Greece".split(","); if (start == null) { start = 0; } for (let i = 0; i < cnt; i++) { data.push({ id: i + start, country: countries[i % countries.length], date: new Date(2014, i % 12, i % 28), amount: Math.random() * 10000, active: i % 4 === 0 }); } return data; }, // add random data to an array _addData: function(data, cnt) { let more = this._getData(cnt, data.length); for (let i = 0; i < more.length; i++) { data.push(more[i]); } } } }); new Vue({ render: h => h(App) }).$mount("#app"); </script> <style> .wj-flexgrid { height: 250px; margin: 6px 0px; } #rowCount, #cellCount { font-weight: bold; } body { margin-bottom: 24pt; } </style> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>AutoComplete</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.vue'); </script> </head> <body> <div id="app"> </div> </body> </html> import "bootstrap.css"; import "@grapecity/wijmo.styles/wijmo.css"; import "./app.css"; // import * as React from "react"; import * as ReactDOM from "react-dom"; import * as wjGrid from "@grapecity/wijmo.react.grid"; import * as wjcCore from "@grapecity/wijmo"; class App extends React.Component { constructor(props) { super(props); this.state = { data: this.getData(100), rowCount: "", cellCount: "" }; } render() { return (<div className="container-fluid"> <wjGrid.FlexGrid initialized={this.flexInitialized.bind(this)} itemsSource={this.state.data}/> <p> The grid now has <span id="rowCount">{this.state.rowCount}</span> {' '}rows and <span id="cellCount">{this.state.cellCount}</span> cell elements. </p> </div>); } flexInitialized(flexgrid) { this.setState({ rowCount: flexgrid.rows.length.toString(), cellCount: flexgrid.hostElement .querySelectorAll(".wj-cell") .length.toString() }); flexgrid.updatedView.addHandler((s, e) => { this.setState({ rowCount: s.rows.length.toString(), cellCount: s.hostElement.querySelectorAll(".wj-cell").length.toString() }); }); flexgrid.scrollPositionChanged.addHandler((s, e) => { // if we're close to the bottom, add 20 items if (s.viewRange.bottomRow >= s.rows.length - 1) { this.addData(this.state.data, 20); s.collectionView.refresh(); } }); } updateCurrentInfo() { this.setState({ selectedItem: wjcCore.format("Country: <b>{country}</b>, Sales: <b>{sales:c0}</b> Expenses: <b>{expenses:c0}</b>", this.flex.collectionView.currentItem) }); } addData(data, cnt) { let more = this.getData(cnt, data.length); for (let i = 0; i < more.length; i++) { data.push(more[i]); } } getData(cnt, start) { let data = []; let countries = "USA,Germany,UK,Japan,Italy,Greece".split(","); if (start == null) { start = 0; } for (let i = 0; i < cnt; i++) { data.push({ id: i + start, country: countries[i % countries.length], date: new Date(2014, i % 12, i % 28), amount: Math.random() * 10000, active: i % 4 === 0 }); } return data; } } ReactDOM.render(<App />, document.getElementById("app")); <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Virtualization</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 id="app"></div> </body> </html> .wj-flexgrid { height: 250px; margin: 6px 0px; } #rowCount, #cellCount { font-weight: bold; } body { margin-bottom: 24pt; }