PivotGrid迷你版

您可以使用 formatItem 事件向网格单元格添加自定义内容,例如迷你图和火花条。

此示例向 PivotEngine 添加了两个额外字段,并使用 formatItem 事件向额外字段添加迷你图和sparkbars。

为此,示例使用引擎的 getDetail 方法检索每个单元格的详细记录,并使用该数据构建每个单元格中显示的svg元素。 单元格详细信息存储在数据项中,以便在网格滚动时可以重复使用它们。

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import * as wijmo from '@grapecity/wijmo'; import * as olap from '@grapecity/wijmo.olap'; import { getData } from './data'; // document.readyState === 'complete' ? init() : window.onload = init; // function init() { let a = scaleY(1, 0, 100); let b = scaleY(10, 0, 100); let c = scaleY(10, 0, 50); let d = scaleY(20, 0, 50); let e = scaleY(30, 0, 50); let f = scaleY(40, 0, 50); let g = scaleY(45, 0, 50); let h = scaleY(49, 0, 50); // create a PivotEngine with a custom view let ng = new olap.PivotEngine({ autoGenerateFields: false, itemsSource: getData(1000), showColumnTotals: 'Subtotals', showRowTotals: 'Subtotals', fields: [ { binding: 'product', header: 'Product', width: 100 }, { binding: 'date', header: 'Date', format: 'yyyy \"Q\"q', width: 100 }, { binding: 'sales', header: 'Sales', format: 'n0', width: 100 }, { binding: 'sales', header: 'Sparklines', width: 100 }, { binding: 'sales', header: 'Sparkbars', width: 100 } ], rowFields: ['Date'], columnFields: ['Product'], valueFields: ['Sales', 'Sparklines', 'Sparkbars'] }); // // show panel let pivotPanel = new olap.PivotPanel('#pivotPanel', { itemsSource: ng }); // // show summary let pivotGrid = new olap.PivotGrid('#pivotGrid', { isReadOnly: true, itemsSource: ng, formatItem: formatItem // customize the grid cells }); // // use formatItem to add sparklines and/or sparkbars let maxSparkLength = 25; function formatItem(s, e) { // we want the cells panel if (e.panel == s.cells) { // we want the 'Sparklines' and 'Sparkbars' value fields let ng = s.engine, field = ng.valueFields[e.col % ng.valueFields.length], item = s.rows[e.row].dataItem, binding = s.columns[e.col].binding, spark = field.header == 'Sparklines' || field.header == 'Sparkbars'; // // add/remove spark class wijmo.toggleClass(e.cell, 'spark', spark); // // add sparklines if (spark) { // if we have the data, show it if (item.sparkData) { let data = item.sparkData, delta = data[data.length - 1] - data[0]; // e.cell.innerHTML = field.header == 'Sparklines' ? getSparklines(item.sparkData) : getSparkbars(item.sparkData); wijmo.toggleClass(e.cell, 'spark-up', delta > 0); wijmo.toggleClass(e.cell, 'spark-down', delta < 0); } // // we dont have the data yet, so go get it if (!item.sparkData) { e.cell.innerHTML = ''; setTimeout(function () { let detail = s.engine.getDetail(item, binding), len = detail.length; // if (len > maxSparkLength) { detail = detail.slice(len - maxSparkLength); } // item.sparkData = detail.map(dataItem => dataItem.sales); // s.invalidate(); // invalidate to show the sparlines }); } } } } // // generate sparklines as SVG function getSparklines(data) { if (!data.length) { return ''; } // let svg = '<svg width="100%" height="100%">', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), x1 = 0, y1 = scaleY(data[0], min, max); // for (let i = 1; i < data.length; i++) { let x2 = Math.round((i) / (data.length - 1) * 100), y2 = scaleY(data[i], min, max); // svg += `<line x1="${x1}%" y1="${y1}%" x2="${x2}%" y2="${y2}%" />`; x1 = x2; y1 = y2; } // svg += '</svg>'; return svg; } // function getSparkbars(data) { if (!data.length) { return ''; } // let svg = '<svg width="100%" height="100%">', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), base = Math.min(max, Math.max(min, 0)), basey = scaleY(base, min, max), w = Math.round(100 / data.length) - 2; // for (let i = 0; i < data.length; i++) { let x = i * Math.round(100 / data.length) + 1, y = scaleY(data[i], min, max); svg += `<rect x="${x}%" width="${w}%" y="${Math.min(y, basey)}%" height="${Math.abs(y - basey)}%" />`; } // svg += `<rect x="0%" width="100%" height="1" y="${basey}%" opacity="0.5" />`; svg += '</svg>'; return svg; } // // min <= value <= max function scaleY(value, min, max) { if (min === max) { return 0; } // return 100 - Math.round((value - min) / (max - min) * 100); } } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Grapecity Wijmo OLAP Pivot Grid Sparkline</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 class="row"> <div class="col-xs-5"> <div id="pivotPanel"></div> </div> <div class="col-xs-7"> <div id="pivotGrid"></div> </div> </div> </div> </body> </html> // export function getData(cnt) { let year = new Date().getFullYear(), data = []; // for (let i = 0; i < cnt; i++) { data.push({ product: randomInt(0, 1) ? 'Wijmo' : 'Aoba', country: randomInt(0, 1) ? 'USA' : 'Japan', active: i % 2 == 0, date: new Date(year - randomInt(0, 2), randomInt(0, 11), randomInt(0, 27) + 1), sales: randomInt(10, 20), downloads: randomInt(10, 200) }); } // return data; } // function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } .wj-pivotgrid { max-height: 400px; box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); } .wj-pivotgrid .wj-cell.spark { padding: 8px; overflow: visible; } .wj-pivotgrid .wj-cell.spark svg { overflow: visible; stroke: currentColor; fill: currentColor; } .wj-pivotgrid .wj-cell.spark.spark-up svg { color: #009000; /* green for up */ } .wj-pivotgrid .wj-cell.spark.spark-down svg { color: #d00000; /* red for down */ } body { margin-bottom: 48pt; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import * as wjCore from '@grapecity/wijmo'; import * as wjOlap from '@grapecity/wijmo.olap'; import * as wjGrid from '@grapecity/wijmo.grid'; // import { Component, Inject, enableProdMode, NgModule, ViewChild } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import { WjOlapModule } from '@grapecity/wijmo.angular2.olap'; import { DataService, DataItem } from './app.data'; const maxSparkLength = 25; // @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { @ViewChild('grid') pivotGrid: wjOlap.PivotGrid; ng: wjOlap.PivotEngine; // constructor(@Inject(DataService) private dataService: DataService) { this.ng = new wjOlap.PivotEngine({ autoGenerateFields: false, itemsSource: dataService.getData(1000), showColumnTotals: 'Subtotals', showRowTotals: 'Subtotals', fields: [ { binding: 'product', header: 'Product', width: 100 }, { binding: 'date', header: 'Date', format: 'yyyy \"Q\"q', width: 100 }, { binding: 'sales', header: 'Sales', format: 'n0', width: 100 }, { binding: 'sales', header: 'Sparklines', width: 100 }, { binding: 'sales', header: 'Sparkbars', width: 100 } ], rowFields: ['Date'], columnFields: ['Product'], valueFields: ['Sales', 'Sparklines', 'Sparkbars'] }); } // formatItem(e: wjGrid.FormatItemEventArgs) { // we want the cells panel let g = this.pivotGrid; if (e.panel == this.pivotGrid.cells) { // we want the 'Sparklines' and 'Sparkbars' value fields let ng = g.engine, field = ng.valueFields[e.col % ng.valueFields.length], item = g.rows[e.row].dataItem, binding = g.columns[e.col].binding, spark = field.header == 'Sparklines' || field.header == 'Sparkbars'; // // add/remove spark class wjCore.toggleClass(e.cell, 'spark', spark); // // add sparklines if (spark) { // // if we have the data, show it if (item.sparkData) { let data = item.sparkData, delta = data[data.length - 1] - data[0]; // e.cell.innerHTML = field.header == 'Sparklines' ? this._getSparklines(item.sparkData) : this._getSparkbars(item.sparkData); wjCore.toggleClass(e.cell, 'spark-up', delta > 0); wjCore.toggleClass(e.cell, 'spark-down', delta < 0); } // // we dont have the data yet, so go get it if (!item.sparkData) { e.cell.innerHTML = ''; setTimeout(function () { let detail: DataItem[] = g.engine.getDetail(item, binding), len = detail.length; // if (len > maxSparkLength) { detail = detail.slice(len - maxSparkLength); } item.sparkData = detail.map(dataItem => dataItem.sales); g.invalidate(); // invalidate to show the sparlines }); } } } } // // generate sparklines as SVG private _getSparklines(data: number[]) { if (!data.length) { return ''; } // let svg = '<svg width="100%" height="100%">', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), x1 = 0, y1 = this._scaleY(data[0], min, max); // for (let i = 1; i < data.length; i++) { let x2 = Math.round((i) / (data.length - 1) * 100), y2 = this._scaleY(data[i], min, max); // svg += `<line x1="${x1}%" y1="${y1}%" x2="${x2}%" y2="${y2}%" />`; x1 = x2; y1 = y2; } // svg += '</svg>'; return svg; } // private _getSparkbars(data: number[]) { if (!data.length) { return ''; } // let svg = '<svg width="100%" height="100%">', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), base = Math.min(max, Math.max(min, 0)), basey = this._scaleY(base, min, max), w = Math.round(100 / data.length) - 2; // for (let i = 0; i < data.length; i++) { let x = i * Math.round(100 / data.length) + 1, y = this._scaleY(data[i], min, max); svg += `<rect x="${x}%" width="${w}%" y="${Math.min(y, basey)}%" height="${Math.abs(y - basey)}%" />`; } // svg += `<rect x="0%" width="100%" height="1" y="${basey}%" opacity="0.5" />`; svg += '</svg>'; return svg; } // private _scaleY(value: number, min: number, max: number) { if (min === max) { return 0; } // return 100 - Math.round((value - min) / (max - min) * 100); } } // @NgModule({ imports: [WjOlapModule, BrowserModule], declarations: [AppComponent], providers: [DataService], 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 OLAP Pivot Grid Sparkline</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"> <div class="row"> <div class="col-xs-5"> <wj-pivot-panel [itemsSource]="ng"></wj-pivot-panel> </div> <div class="col-xs-7"> <wj-pivot-grid #grid [itemsSource]="ng" [isReadOnly]=true (formatItem)="formatItem($event)"></wj-pivot-grid> </div> </div> </div> import { Injectable } from '@angular/core'; // export interface DataItem { product: string; country: string; active: boolean; date: Date; sales: number; downloads: number; } // function randomInt(min: number, max: number): number { return Math.floor(Math.random() * (max - min + 1) + min); } // @Injectable() export class DataService { getData(cnt: number): DataItem[] { let year = new Date().getFullYear(), data = []; // for (let i = 0; i < cnt; i++) { data.push({ product: randomInt(0, 1) ? 'Wijmo' : 'Aoba', country: randomInt(0, 1) ? 'USA' : 'Japan', active: i % 2 == 0, date: new Date(year - randomInt(0, 2), randomInt(0, 11), randomInt(0, 27) + 1), sales: randomInt(10, 20), downloads: randomInt(10, 200) }); } // return data; } } .wj-pivotgrid { max-height: 400px; box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); } .wj-pivotgrid .wj-cell.spark { padding: 8px; overflow: visible; } .wj-pivotgrid .wj-cell.spark svg { overflow: visible; stroke: currentColor; fill: currentColor; } .wj-pivotgrid .wj-cell.spark.spark-up svg { color: #009000; /* green for up */ } .wj-pivotgrid .wj-cell.spark.spark-down svg { color: #d00000; /* red for down */ } body { margin-bottom: 48pt; } <template> <div class="container-fluid"> <div class="row"> <div class="col-xs-5"> <wj-pivot-panel :itemsSource="ng"></wj-pivot-panel> </div> <div class="col-xs-7"> <wj-pivot-grid :itemsSource="ng" :isReadOnly=true :initialized="initializePivotGrid" :formatItem="formatItem"></wj-pivot-grid> </div> </div> </div> </template> <script> import '@grapecity/wijmo.styles/wijmo.css'; import 'bootstrap.css'; import Vue from 'vue'; import '@grapecity/wijmo.vue2.olap'; import * as wjcCore from '@grapecity/wijmo'; import * as wjcOlap from '@grapecity/wijmo.olap'; import { getData } from './data' const maxSparkLength = 25; let App = Vue.extend({ name: "app", data: function() { return { ng: new wjcOlap.PivotEngine({ autoGenerateFields: false, itemsSource: getData(1000), showColumnTotals: 'Subtotals', showRowTotals: 'Subtotals', fields: [ { binding: 'product', header: 'Product', width: 100 }, { binding: 'date', header: 'Date', format: 'yyyy \"Q\"q', width: 100 }, { binding: 'sales', header: 'Sales', format: 'n0', width: 100 }, { binding: 'sales', header: 'Sparklines', width: 100 }, { binding: 'sales', header: 'Sparkbars', width: 100 } ], rowFields: ['Date'], columnFields: ['Product'], valueFields: ['Sales', 'Sparklines', 'Sparkbars'] }) }; }, methods: { initializePivotGrid(pivotGrid) { this.pivotGrid = pivotGrid; }, formatItem(s, e) { // we want the cells panel let pivotGrid = this.pivotGrid; if (e.panel == this.pivotGrid.cells) { // we want the 'Sparklines' and 'Sparkbars' value fields let ng = pivotGrid.engine, field = ng.valueFields[e.col % ng.valueFields.length], item = pivotGrid.rows[e.row].dataItem, binding = pivotGrid.columns[e.col].binding, spark = field.header == 'Sparklines' || field.header == 'Sparkbars'; // // add/remove spark class wjcCore.toggleClass(e.cell, 'spark', spark); // add sparklines if (spark) { // if we have the data, show it if (item.sparkData) { let data = item.sparkData, delta = data[data.length - 1] - data[0]; // e.cell.innerHTML = field.header == 'Sparklines' ? this._getSparklines(item.sparkData) : this._getSparkbars(item.sparkData); wjcCore.toggleClass(e.cell, 'spark-up', delta > 0); wjcCore.toggleClass(e.cell, 'spark-down', delta < 0); } // we dont have the data yet, so go get it if (!item.sparkData) { e.cell.innerHTML = ''; setTimeout(() => { let detail = pivotGrid.engine.getDetail(item, binding), len = detail.length; if (len > maxSparkLength) { detail = detail.slice(len - maxSparkLength); } item.sparkData = detail.map(dataItem => dataItem.sales); pivotGrid.invalidate(); // invalidate to show the sparlines }); } } } }, // generate sparklines as SVG _getSparklines(data) { if (!data.length) { return ''; } // let svg = '<svg width="100%" height="100%">', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), x1 = 0, y1 = this._scaleY(data[0], min, max); // for (let i = 1; i < data.length; i++) { let x2 = Math.round((i) / (data.length - 1) * 100), y2 = this._scaleY(data[i], min, max); // svg += `<line x1="${x1}%" y1="${y1}%" x2="${x2}%" y2="${y2}%" />`; x1 = x2; y1 = y2; } // svg += '</svg>'; return svg; }, _getSparkbars(data) { if (!data.length) { return ''; } // let svg = '<svg width="100%" height="100%">', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), base = Math.min(max, Math.max(min, 0)), basey = this._scaleY(base, min, max), w = Math.round(100 / data.length) - 2; // for (let i = 0; i < data.length; i++) { let x = i * Math.round(100 / data.length) + 1, y = this._scaleY(data[i], min, max); svg += `<rect x="${x}%" width="${w}%" y="${Math.min(y, basey)}%" height="${Math.abs(y - basey)}%" />`; } // svg += `<rect x="0%" width="100%" height="1" y="${basey}%" opacity="0.5" />`; svg += '</svg>'; return svg; }, _scaleY(value, min, max) { if (min === max) { return 0; } // return 100 - Math.round((value - min) / (max - min) * 100); } } }); new Vue({ render: h => h(App) }).$mount("#app"); </script> <style> .wj-pivotgrid { max-height: 400px; box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); } .wj-pivotgrid .wj-cell.spark { padding: 8px; overflow: visible; } .wj-pivotgrid .wj-cell.spark svg { overflow: visible; stroke: currentColor; fill: currentColor; } .wj-pivotgrid .wj-cell.spark.spark-up svg { color: #009000; /* green for up */ } .wj-pivotgrid .wj-cell.spark.spark-down svg { color: #d00000; /* red for down */ } body { margin-bottom: 48pt; } </style> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>Grapecity Wijmo OLAP Pivot Grid Sparkline</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> export function getData(cnt) { let year = new Date().getFullYear(), data = []; // for (let i = 0; i < cnt; i++) { data.push({ product: randomInt(0, 1) ? 'Wijmo' : 'Aoba', country: randomInt(0, 1) ? 'USA' : 'Japan', active: i % 2 == 0, date: new Date(year - randomInt(0, 2), randomInt(0, 11), randomInt(0, 27) + 1), sales: randomInt(10, 20), downloads: randomInt(10, 200) }); } // return data; } // function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); } import './app.css'; import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; // import * as React from 'react'; import * as ReactDOM from 'react-dom'; // import * as Olap from '@grapecity/wijmo.react.olap'; import * as wjcCore from '@grapecity/wijmo'; import * as wjcOlap from '@grapecity/wijmo.olap'; import { getData } from './data'; const maxSparkLength = 25; class App extends React.Component { constructor(props) { super(props); this.state = { ng: new wjcOlap.PivotEngine({ autoGenerateFields: false, itemsSource: getData(1000), showColumnTotals: 'Subtotals', showRowTotals: 'Subtotals', fields: [ { binding: 'product', header: 'Product', width: 100 }, { binding: 'date', header: 'Date', format: 'yyyy \"Q\"q', width: 100 }, { binding: 'sales', header: 'Sales', format: 'n0', width: 100 }, { binding: 'sales', header: 'Sparklines', width: 100 }, { binding: 'sales', header: 'Sparkbars', width: 100 } ], rowFields: ['Date'], columnFields: ['Product'], valueFields: ['Sales', 'Sparklines', 'Sparkbars'] }) }; } render() { return (<div className="container-fluid"> <div className="row"> <div className="col-xs-5"> <Olap.PivotPanel itemsSource={this.state.ng}></Olap.PivotPanel> </div> <div className="col-xs-7"> <Olap.PivotGrid itemsSource={this.state.ng} isReadOnly={true} initialized={this.initializePivotGrid.bind(this)} formatItem={this.formatItem.bind(this)}></Olap.PivotGrid> </div> </div> </div>); } initializePivotGrid(sender) { this._grid = sender; } formatItem(s, e) { // we want the cells panel let g = this._grid; if (e.panel == this._grid.cells) { // we want the 'Sparklines' and 'Sparkbars' value fields let ng = g.engine, field = ng.valueFields[e.col % ng.valueFields.length], item = g.rows[e.row].dataItem, binding = g.columns[e.col].binding, spark = field.header == 'Sparklines' || field.header == 'Sparkbars'; // // add/remove spark class wjcCore.toggleClass(e.cell, 'spark', spark); // add sparklines if (spark) { // if we have the data, show it if (item.sparkData) { let data = item.sparkData, delta = data[data.length - 1] - data[0]; // e.cell.innerHTML = field.header == 'Sparklines' ? this._getSparklines(item.sparkData) : this._getSparkbars(item.sparkData); wjcCore.toggleClass(e.cell, 'spark-up', delta > 0); wjcCore.toggleClass(e.cell, 'spark-down', delta < 0); } // we dont have the data yet, so go get it if (!item.sparkData) { e.cell.innerHTML = ''; setTimeout(() => { let detail = g.engine.getDetail(item, binding), len = detail.length; if (len > maxSparkLength) { detail = detail.slice(len - maxSparkLength); } item.sparkData = detail.map(dataItem => dataItem.sales); g.invalidate(); // invalidate to show the sparlines }); } } } } // generate sparklines as SVG _getSparklines(data) { if (!data.length) { return ''; } // let svg = '<svg width="100%" height="100%">', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), x1 = 0, y1 = this._scaleY(data[0], min, max); // for (let i = 1; i < data.length; i++) { let x2 = Math.round((i) / (data.length - 1) * 100), y2 = this._scaleY(data[i], min, max); // svg += `<line x1="${x1}%" y1="${y1}%" x2="${x2}%" y2="${y2}%" />`; x1 = x2; y1 = y2; } // svg += '</svg>'; return svg; } _getSparkbars(data) { if (!data.length) { return ''; } // let svg = '<svg width="100%" height="100%">', min = Math.min.apply(Math, data), max = Math.max.apply(Math, data), base = Math.min(max, Math.max(min, 0)), basey = this._scaleY(base, min, max), w = Math.round(100 / data.length) - 2; // for (let i = 0; i < data.length; i++) { let x = i * Math.round(100 / data.length) + 1, y = this._scaleY(data[i], min, max); svg += `<rect x="${x}%" width="${w}%" y="${Math.min(y, basey)}%" height="${Math.abs(y - basey)}%" />`; } // svg += `<rect x="0%" width="100%" height="1" y="${basey}%" opacity="0.5" />`; svg += '</svg>'; return svg; } _scaleY(value, min, max) { if (min === max) { return 0; } // return 100 - Math.round((value - min) / (max - min) * 100); } } 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>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'); </script> </head> <body> <div id="app"></div> </body> </html> .wj-pivotgrid { max-height: 400px; box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); } .wj-pivotgrid .wj-cell.spark { padding: 8px; overflow: visible; } .wj-pivotgrid .wj-cell.spark svg { overflow: visible; stroke: currentColor; fill: currentColor; } .wj-pivotgrid .wj-cell.spark.spark-up svg { color: #009000; /* green for up */ } .wj-pivotgrid .wj-cell.spark.spark-down svg { color: #d00000; /* red for down */ } body { margin-bottom: 48pt; } // export function getData(cnt) { let year = new Date().getFullYear(), data = []; // for (let i = 0; i < cnt; i++) { data.push({ product: randomInt(0, 1) ? 'Wijmo' : 'Aoba', country: randomInt(0, 1) ? 'USA' : 'Japan', active: i % 2 == 0, date: new Date(year - randomInt(0, 2), randomInt(0, 11), randomInt(0, 27) + 1), sales: randomInt(10, 20), downloads: randomInt(10, 200) }); } // return data; } // function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1) + min); }