グリッド

FlexGridコントロールの基本機能を示します。グリッドをデータソースに連結して、下のメニューから、データ項目の数、選択モードデータマップ、書式設定などを選択できます。データ項目数がどれだけ多くてもグリッドの高速性や流動性が失われないことに注目してください。FlexGridは、行と列を自動的に仮想化することによってこのレベルのパフォーマンスを実現します。

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; import * as wjCore from '@grapecity/wijmo'; import * as wjInput from '@grapecity/wijmo.input'; import * as wjGrid from '@grapecity/wijmo.grid'; import { getData, getColors, getCountries, getProducts } from './data'; document.readyState === 'complete' ? init() : window.onload = init; function init() { // bind a grid to the data let theGrid = new wjGrid.FlexGrid('#theGrid', { autoGenerateColumns: false, columns: [ { binding: 'id', header: 'ID', width: 80 }, { binding: 'start', header: '開始' }, { binding: 'end', header: '終了' }, { binding: 'country', header: '国' }, { binding: 'product', header: '商品' }, { binding: 'color', header: '色' }, { binding: 'countryId', header: '国ID' }, { binding: 'productId', header: '商品ID' }, { binding: 'colorId', header: '色ID' }, { binding: 'amount', header: '金額' }, { binding: 'amount2', header: '金額2' }, { binding: 'discount', header: '値引', width: 80 }, { binding: 'active', header: '有効' }, ], }); theGrid.select(new wjGrid.CellRange(0, 0)); theGrid.selectionChanged.addHandler((s, e) => { document.querySelector('#cellRange').innerHTML = formatCellRange(e.range); }); let toFilter; document.querySelector('#filter').addEventListener('keyup', () => { if (toFilter) { clearTimeout(toFilter); } toFilter = setTimeout(function () { toFilter = null; if (theGrid) { let cv = theGrid.collectionView; if (cv) { if (cv.filter != filterFunction) { cv.filter = filterFunction; } else { cv.refresh(); } } } }, 500); }); document.querySelector('#first').addEventListener('click', () => { theGrid.collectionView.moveCurrentToFirst(); }); document.querySelector('#previous').addEventListener('click', () => { theGrid.collectionView.moveCurrentToPrevious(); }); document.querySelector('#next').addEventListener('click', () => { theGrid.collectionView.moveCurrentToNext(); }); document.querySelector('#last').addEventListener('click', () => { theGrid.collectionView.moveCurrentToLast(); }); // create item count menu let itemCountMenu = new wjInput.Menu('#itemCountMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.itemsSource = getData(s.selectedValue, currentItemChanged.bind(this)); if (dataMapsMenu) { updateDataMaps(dataMapsMenu.selectedValue); } if (formattingMenu) { updateFormatting(formattingMenu.selectedValue); } currentItemChanged(); } }, header: 'データ数', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: '5', value: 5 }, { header: '50', value: 50 }, { header: '500', value: 500 }, { header: '5,000', value: 5000 }, { header: '50,000', value: 50000 }, { header: '100,000', value: 100000 }, { header: '500,000', value: 500000 }, { header: '1,000,000', value: 1000000 } ] }); // initialize value itemCountMenu.selectedValue = 500; // create allow add new menu let allowAddNewMenu = new wjInput.Menu('#allowAddNewMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.allowAddNew = s.selectedValue; } }, header: '行の追加', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: '許可', value: true }, { header: '禁止', value: false } ] }); // initialize value allowAddNewMenu.selectedValue = false; // create selection mode menu let selectionModeMenu = new wjInput.Menu('#selectionModeMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.selectionMode = s.selectedValue; } }, header: '選択', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'なし', value: wjGrid.SelectionMode.None }, { header: 'セル', value: wjGrid.SelectionMode.Cell }, { header: 'セル範囲', value: wjGrid.SelectionMode.CellRange }, { header: '行', value: wjGrid.SelectionMode.Row }, { header: '行範囲', value: wjGrid.SelectionMode.RowRange }, { header: '行リスト', value: wjGrid.SelectionMode.ListBox } ] }); // initialize value selectionModeMenu.selectedValue = wjGrid.SelectionMode.CellRange; theGrid.selection = new wjGrid.CellRange(0, 0); // create header visibility menu let headersVisibilityMenu = new wjInput.Menu('#headersVisibilityMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.headersVisibility = s.selectedValue; } }, header: 'ヘッダー', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'なし', value: wjGrid.HeadersVisibility.None }, { header: '列', value: wjGrid.HeadersVisibility.Column }, { header: '行', value: wjGrid.HeadersVisibility.Row }, { header: 'すべて', value: wjGrid.HeadersVisibility.All } ] }); // initialize value headersVisibilityMenu.selectedValue = wjGrid.HeadersVisibility.All; // create show selected headers menu let showSelectedHeadersMenu = new wjInput.Menu('#showSelectedHeadersMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.showSelectedHeaders = s.selectedValue; } }, header: '選択されたヘッダー', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'なし', value: wjGrid.HeadersVisibility.None }, { header: '列', value: wjGrid.HeadersVisibility.Column }, { header: '行', value: wjGrid.HeadersVisibility.Row }, { header: 'すべて', value: wjGrid.HeadersVisibility.All } ] }); // initialize value showSelectedHeadersMenu.selectedValue = wjGrid.HeadersVisibility.None; // create Show Marquee menu let showMarqueeMenu = new wjInput.Menu('#showMarqueeMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); theGrid.showMarquee = s.selectedValue; } }, header: 'マーキー', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: '有効', value: true }, { header: '無効', value: false } ] }); // initialize value showMarqueeMenu.selectedValue = false; // create Data Maps menu let dataMapsMenu = new wjInput.Menu('#dataMapsMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); updateDataMaps(s.selectedValue); } }, header: 'データマップ', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: '有効', value: true }, { header: '無効', value: false } ] }); // initialize value dataMapsMenu.selectedValue = true; // create Formatting menu let formattingMenu = new wjInput.Menu('#formattingMenu', { // update header to show current selection selectedIndexChanged: function (s, e) { if (s.selectedIndex > -1) { formatMenuHeader(s); updateFormatting(s.selectedValue); } }, header: '書式設定', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: '有効', value: true }, { header: '無効', value: false } ] }); // initialize value formattingMenu.selectedValue = true; // Create Culture menu /*var cultureMenu = new wjInput.Menu('#cultureMenu', { header: 'Culture', displayMemberPath: 'header', selectedValuePath: 'value', itemsSource: [ { header: 'English', value: 'en' }, { header: 'Spanish', value: 'es' }, { header: 'Italian', value: 'it' }, { header: 'French', value: 'fr' }, { header: 'German', value: 'de' }, { header: 'Dutch', value: 'nl' }, { header: 'Japanese', value: 'ja' }, { header: 'Korean', value: 'ko' }, { header: 'Chinese', value: 'zh-HK' }, ], selectedIndexChanged: function(s, e) { if (s.selectedIndex > -1){ formatMenuHeader(s); loadCulture(s.selectedValue); } } }); cultureMenu.selectedValue = 'en';*/ document.querySelector('#toggleColumnVisibility').addEventListener('click', () => { let col = theGrid.columns[0]; col.visible = !col.visible; }); document.querySelector('#changeColumnSize').addEventListener('click', () => { let col = theGrid.columns[0]; col.visible = true; col.width = col.width < 0 ? 60 : -1; col = theGrid.rowHeaders.columns[0]; col.width = col.width < 0 ? 40 : -1; }); document.querySelector('#toggleRowVisibility').addEventListener('click', () => { let row = theGrid.rows[0]; row.visible = !row.visible; }); document.querySelector('#changeRowSize').addEventListener('click', () => { let row = theGrid.rows[0]; row.visible = true; row.height = row.height < 0 ? 80 : -1; row = theGrid.columnHeaders.rows[0]; row.height = row.height < 0 ? 80 : -1; }); document.querySelector('#changeDefaultRowSize').addEventListener('click', () => { theGrid.rows.defaultSize = theGrid.rows.defaultSize == 28 ? 65 : 28; }); document.querySelector('#changeScrollPosition').addEventListener('click', () => { if (theGrid.scrollPosition.y == 0) { var sz = theGrid.scrollSize; theGrid.scrollPosition = new wjCore.Point(-sz.width / 2, -sz.height / 2); } else { theGrid.scrollPosition = new wjCore.Point(0, 0); } }); function formatMenuHeader(menu) { let index = menu.header.indexOf(':'); if (index !== -1) { menu.header = menu.header.substring(0, menu.header.indexOf(':')) + wjCore.format(': <b>{header}</b>', menu.selectedItem); } else { menu.header = menu.header + wjCore.format(': <b>{header}</b>', menu.selectedItem); } } // apply/remove data maps function updateDataMaps(dataMaps) { if (theGrid) { var colCountry = theGrid.columns.getColumn('countryId'); var colProduct = theGrid.columns.getColumn('productId'); var colColor = theGrid.columns.getColumn('colorId'); if (colCountry && colProduct && colColor) { if (dataMaps) { colCountry.showDropDown = true; // show drop-down for countries colProduct.showDropDown = false; // don't show it for products colColor.showDropDown = false; // or colors (just to show how) colCountry.dataMap = buildDataMap(getCountries()); colProduct.dataMap = buildDataMap(getProducts()); colColor.dataMap = buildDataMap(getColors()); } else { colCountry.dataMap = null; colProduct.dataMap = null; colColor.dataMap = null; } } } } // build a data map from a string array using the indices as keys function buildDataMap(items) { var map = []; for (var i = 0; i < items.length; i++) { map.push({ key: i, value: items[i] }); } return new wjGrid.DataMap(map, 'key', 'value'); } // apply/remove column formatting function updateFormatting(fmt) { if (theGrid) { setColumnFormat('amount', fmt ? 'c' : null); setColumnFormat('amount2', fmt ? 'c' : null); setColumnFormat('discount', fmt ? 'p0' : null); setColumnFormat('start', fmt ? 't' : null); setColumnFormat('end', fmt ? 't' : null); } } function setColumnFormat(name, format) { var col = theGrid.columns.getColumn(name); if (col) { col.format = format; } } function formatCellRange(cellRange) { let rng; rng = '(' + cellRange.row + ';' + cellRange.col + ')'; if (!cellRange.isSingleCell) { rng += '-(' + cellRange.row2 + ';' + cellRange.col2 + ')'; } return rng; } function currentItemChanged() { let curr = wjCore.format('{current:n0} / {count:n0}', { current: theGrid.collectionView.currentPosition + 1, count: theGrid.collectionView.items.length }); document.querySelector('#inputCurrent').value = curr; if (theGrid.collectionView.currentPosition === 0) { document.querySelector('#first').setAttribute('disabled', 'true'); document.querySelector('#previous').setAttribute('disabled', 'true'); } else { document.querySelector('#first').removeAttribute('disabled'); document.querySelector('#previous').removeAttribute('disabled'); } if (theGrid.collectionView.currentPosition === theGrid.collectionView.items.length - 1) { document.querySelector('#last').setAttribute('disabled', 'true'); document.querySelector('#next').setAttribute('disabled', 'true'); } else { document.querySelector('#last').removeAttribute('disabled'); document.querySelector('#next').removeAttribute('disabled'); } } function filterFunction(item) { let f = document.querySelector('#filter').value; if (f && item) { // split string into terms to enable multi-field searches such as 'us gadget red' let terms = f.toUpperCase().split(' '); // look for any term in any string field for (let i = 0; i < terms.length; i++) { let termFound = false; for (let key in item) { let value = item[key]; if (wjCore.isString(value) && value.toUpperCase().indexOf(terms[i]) > -1) { termFound = true; break; } } // fail if any of the terms is not found if (!termFound) { return false; } } } // include item in view return true; } /*function loadCulture(culture) { // get culture url var url = 'https://cdn.grapecity.com/wijmo/5.latest/controls/cultures/wijmo.culture.' + culture + '.min.js'; // apply new culture to page var scripts = document.getElementsByTagName('script'), script; for (var i = 0; i < scripts.length; i++) { script = scripts[i]; if (script.src.indexOf('/cultures/wijmo.culture.') > -1) { script.parentElement.removeChild(script); break; } } script = document.createElement('script'); script.onload = updateControls(); script.src = url; document.head.appendChild(script); } function updateControls() { wjCore.Control.invalidateAll(); }*/ } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Overview</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> <!-- search box --> <div class="row"> <div class="col-md-6 col-xs-4"> <input id="filter" type="text" class="form-control app-pad" placeholder="フィルター" /> </div> <div class="col-md-6 col-xs-8"> <div class="pull-right wj-control wj-content wj-pager"> <div class="wj-input-group"> <span class="wj-input-group-btn"> <button id="first" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-left" style="margin-right:-4px"></span> <span class="wj-glyph-left"></span> </button> </span> <span class="wj-input-group-btn"> <button id="previous" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-left"></span> </button> </span> <input id="inputCurrent" type="text" class="wj-form-control" disabled> <span class="wj-input-group-btn"> <button id="next" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-right"></span> </button> </span> <span class="wj-input-group-btn"> <button id="last" class="wj-btn wj-btn-default" type="button"> <span class="wj-glyph-right"></span> <span class="wj-glyph-right" style="margin-left:-4px"></span> </button> </span> </div> </div> </div> </div> <!-- the grid --> <div id="theGrid"> </div> </div> <!-- commands --> <div class="well"> <div class="grid-sort-group"> <!-- current selection --> <p>選択されたセル: <b><span id="cellRange"></span></b></p> <!-- data size --> <div id="itemCountMenu"></div> <!-- allow add new --> <div id="allowAddNewMenu"></div> <!-- selection mode --> <div id="selectionModeMenu"></div> <!-- headers visibility --> <div id="headersVisibilityMenu"></div> <!-- highlight headers --> <div id="showSelectedHeadersMenu"></div> <!-- show marquee --> <div id="showMarqueeMenu"></div> <!-- data maps --> <div id="dataMapsMenu"></div> <!-- formatting --> <div id="formattingMenu"></div> <!-- culture --> <!-- <div id="cultureMenu"></div> --> <br /> <br /> <!-- testing the object model --> <button id="toggleColumnVisibility" class="btn btn-default"> 先頭列の表示を切り替え </button> <button id="changeColumnSize" class="btn btn-default"> 先頭列の幅を変更 </button> <button id="toggleRowVisibility" class="btn btn-default"> 先頭行の表示を切り替え </button> <button id="changeRowSize" class="btn btn-default"> 先頭行の高さを変更 </button> <button id="changeDefaultRowSize" class="btn btn-default"> 行の既定の高さを変更 </button> <button id="changeScrollPosition" class="btn btn-default"> スクロール位置を変更 </button> </div> </div> </div> </body> </html> import { CollectionView } from '@grapecity/wijmo'; let countries = ['アメリカ', 'ドイツ', 'イギリス', '日本', 'イタリア', 'ギリシャ']; let products = ['ウィジェット', 'ガジェット', 'ツール']; let colors = ['黒', '白', '赤', '緑', '青']; // generate some random data export function getData(count, currentChangedHdl) { let data = []; let dt = new Date(); // add count items for (let i = 0; i < count; i++) { // constants used to create data items let date = new Date(dt.getFullYear(), i % 12, 25, i % 24, i % 60, i % 60), countryId = Math.floor(Math.random() * countries.length), productId = Math.floor(Math.random() * products.length), colorId = Math.floor(Math.random() * colors.length); // create the item let item = { id: i, start: date, end: date, country: countries[countryId], product: products[productId], color: colors[colorId], countryId: countryId, productId: productId, colorId: colorId, amount: Math.random() * 10000 - 5000, amount2: Math.random() * 10000 - 5000, discount: Math.random() / 4, active: i % 4 == 0, }; // add an array (should not auto-bind) item.sales = []; for (var j = 0; j < 12; j++) { item.sales.push(50 + 20 * (Math.random() - .5) + j); } // add an object (should not auto-bind) item.someObject = { name: i, value: i }; // add the item to the list data.push(item); } // return a CollectionView so multiple controls bound to this source // will be updated automatically (TFS 145538) let cv = new CollectionView(data); if (currentChangedHdl) { cv.currentChanged.addHandler(currentChangedHdl); } return cv; } // get possible values for each field export function getCountries() { return countries; } export function getProducts() { return products; } export function getColors() { return colors; } .wj-flexgrid { height: 400px; margin: 6px 0; } .grid-sort-group .wj-menu, .grid-sort-group .btn { margin: 2px 4px 2px 0; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './styles.css'; // import { Component, Inject, enableProdMode, NgModule, ViewChild } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import * as wjcCore from '@grapecity/wijmo'; import * as wjcGrid from '@grapecity/wijmo.grid'; import { WjGridModule } from '@grapecity/wijmo.angular2.grid'; import { WjInputModule } from '@grapecity/wijmo.angular2.input'; import { AppPipesModule } from './app.pipe'; import { DataService } from './app.data'; // @Component({ selector: 'app-component', templateUrl: 'src/app.component.html' }) export class AppComponent { private _itemCount = 500; private _culture = 'ja'; private _dataMaps = true; private _formatting = true; private _filter = ''; private _toFilter: any; private _thisFilterFunction: wjcCore.IPredicate; private _groupBy = ''; private _pageSize = 0; protected dataSvc: DataService; data: any[]; // references FlexGrid named 'flex' in the view @ViewChild('flex') flex: wjcGrid.FlexGrid; // DataSvc will be passed by derived classes constructor( @Inject(DataService) dataSvc: DataService) { this.dataSvc = dataSvc; this._thisFilterFunction = this._filterFunction.bind(this); this.data = dataSvc.getData(this.itemCount); } get itemCount(): number { return this._itemCount; } set itemCount(value: number) { if (this._itemCount != value) { this._itemCount = value; this.data = this.dataSvc.getData(this.itemCount); this.groupBy = ''; } } get dataMaps(): boolean { return this._dataMaps; } set dataMaps(value: boolean) { if (this._dataMaps != value) { this._dataMaps = value; this._updateDataMaps(); } } get formatting(): boolean { return this._formatting; } set formatting(value: boolean) { if (this._formatting != value) { this._formatting = value; this._updateFormatting(); } } get culture(): string { return this._culture; } set culture(value: string) { if (this._culture != value) { this._culture = value; this._loadCultureInfo(); } } get filter(): string { return this._filter; } set filter(value: string) { if (this._filter != value) { this._filter = value; this._applyFilter(); } } get groupBy(): string { return this._groupBy; } set groupBy(value: string) { if (this._groupBy != value) { this._groupBy = value; this._applyGroupBy(); } } get pageSize(): number { return this._pageSize; } set pageSize(value: number) { if (this._pageSize != value) { this._pageSize = value; if (this.flex) { (<wjcCore.IPagedCollectionView>this.flex.collectionView).pageSize = value; } } } ngAfterViewInit() { if (this.flex) { this.updateDataMapSettings(); } } // update data maps, formatting, paging now and when the itemsSource changes itemsSourceChangedHandler() { var flex = this.flex; if (!flex) { return; } // update data maps and formatting this.updateDataMapSettings(); // set page size on the grid's internal collectionView if (flex.collectionView && this.pageSize) { (<wjcCore.IPagedCollectionView>flex.collectionView).pageSize = this.pageSize; } }; updateDataMapSettings() { this._updateDataMaps(); this._updateFormatting(); } toggleColumnVisibility() { var flex = this.flex; var col = flex.columns[0]; col.visible = !col.visible; }; changeColumnSize() { var flex = this.flex; var col = flex.columns[0]; col.visible = true; col.width = col.width < 0 ? 60 : -1; col = flex.rowHeaders.columns[0]; col.width = col.width < 0 ? 40 : -1; }; toggleRowVisibility() { var flex = this.flex; var row = flex.rows[0]; row.visible = !row.visible; }; changeRowSize() { var flex = this.flex; var row = flex.rows[0]; row.visible = true; row.height = row.height < 0 ? 80 : -1; row = flex.columnHeaders.rows[0]; row.height = row.height < 0 ? 80 : -1; }; changeDefaultRowSize() { var flex = this.flex; flex.rows.defaultSize = flex.rows.defaultSize == 28 ? 65 : 28; }; changeScrollPosition() { var flex = this.flex; if (flex.scrollPosition.y == 0) { var sz = flex.scrollSize; flex.scrollPosition = new wjcCore.Point(-sz.width / 2, -sz.height / 2); } else { flex.scrollPosition = new wjcCore.Point(0, 0); } }; // apply/remove data maps private _updateDataMaps() { var flex = this.flex; if (flex) { var colCountry = flex.columns.getColumn('countryId'); var colProduct = flex.columns.getColumn('productId'); var colColor = flex.columns.getColumn('colorId'); if (colCountry && colProduct && colColor) { if (this.dataMaps == true) { colCountry.showDropDown = true; // show drop-down for countries colProduct.showDropDown = false; // don't show it for products colColor.showDropDown = false; // or colors (just to show how) colCountry.dataMap = this._buildDataMap(this.dataSvc.getCountries()); colProduct.dataMap = this._buildDataMap(this.dataSvc.getProducts()); colColor.dataMap = this._buildDataMap(this.dataSvc.getColors()); } else { colCountry.dataMap = null; colProduct.dataMap = null; colColor.dataMap = null; } } } } // build a data map from a string array using the indices as keys private _buildDataMap(items: any[]): wjcGrid.DataMap { var map = []; for (var i = 0; i < items.length; i++) { map.push({ key: i, value: items[i] }); } return new wjcGrid.DataMap(map, 'key', 'value'); } // apply/remove column formatting private _updateFormatting() { var flex = this.flex; if (flex) { var fmt = this.formatting; this._setColumnFormat('amount', fmt ? 'c' : null); this._setColumnFormat('amount2', fmt ? 'c' : null); this._setColumnFormat('discount', fmt ? 'p0' : null); this._setColumnFormat('start', fmt ? 't' : null); this._setColumnFormat('end', fmt ? 't' : null); } } private _setColumnFormat(name: string, format: string) { var col = this.flex.columns.getColumn(name); if (col) { col.format = format; } } private _loadCultureInfo() { wjcCore.httpRequest('bin/Devel/sources/cultures/wijmo.culture.' + this.culture + '.js', { dataType: 'script', success: (xhr: XMLHttpRequest) => { eval(xhr.response); wjcCore.Control.invalidateAll(); } }); } // ICollectionView filter function private _filterFunction(item: any) { var f = this.filter; if (f && item) { // split string into terms to enable multi-field searches such as 'us gadget red' var terms = f.toUpperCase().split(' '); // look for any term in any string field for (var i = 0; i < terms.length; i++) { var termFound = false; for (var key in item) { var value = item[key]; if (wjcCore.isString(value) && value.toUpperCase().indexOf(terms[i]) > -1) { termFound = true; break; } } // fail if any of the terms is not found if (!termFound) { return false; } } } // include item in view return true; } // apply filter (applied on a 500 ms timeOut) protected _applyFilter() { if (this._toFilter) { clearTimeout(this._toFilter); } var self = this; this._toFilter = setTimeout(function () { self._toFilter = null; if (self.flex) { var cv = self.flex.collectionView; if (cv) { if (cv.filter != self._thisFilterFunction) { cv.filter = self._thisFilterFunction; } else { cv.refresh(); } } } }, 500); } private _applyGroupBy() { if (this.flex) { // get the collection view, start update var cv = this.flex.collectionView; cv.beginUpdate(); // clear existing groups cv.groupDescriptions.clear(); // add new groups var groupNames = this.groupBy.split('/'), groupDesc; for (var i = 0; i < groupNames.length; i++) { var propName = groupNames[i].toLowerCase(); if (propName == 'amount') { // group amounts in ranges // (could use the mapping function to group countries into continents, // names into initials, etc) groupDesc = new wjcCore.PropertyGroupDescription(propName, function (item:any, prop: string) { var value = item[prop]; if (value > 1000) return '多い'; if (value > 100) return '普通'; if (value > 0) return '少ない'; return 'マイナス'; }); cv.groupDescriptions.push(groupDesc); } else if (propName) { // group other properties by their specific values groupDesc = new wjcCore.PropertyGroupDescription(propName); cv.groupDescriptions.push(groupDesc); } } // done updating cv.endUpdate(); } } } // @NgModule({ imports: [WjInputModule, WjGridModule, AppPipesModule, BrowserModule, FormsModule], 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 FlexGrid Overview</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"> <!-- search box --> <div class="row"> <div class="col-md-6 col-xs-4"> <input type="text" class="form-control app-pad" placeholder="フィルター" [(ngModel)]="filter" /> </div> <div class="col-md-6 col-xs-8"> <wj-collection-view-navigator [cv]="flex.collectionView" class="pull-right"> </wj-collection-view-navigator> </div> </div> <!-- the grid --> <wj-flex-grid #flex class="grid" [allowResizing]="'Both'" [itemsSource]="data" [allowMerging]="'All'" [stickyHeaders]="true" (itemsSourceChanged)="itemsSourceChangedHandler()"> <wj-flex-grid-column binding="id" header="ID" [width]="80"></wj-flex-grid-column> <wj-flex-grid-column binding="start" header="開始"></wj-flex-grid-column> <wj-flex-grid-column binding="end" header="終了"></wj-flex-grid-column> <wj-flex-grid-column binding="country" header="国"></wj-flex-grid-column> <wj-flex-grid-column binding="product" header="商品"></wj-flex-grid-column> <wj-flex-grid-column binding="color" header="色"></wj-flex-grid-column> <wj-flex-grid-column binding="countryId" header="国ID"></wj-flex-grid-column> <wj-flex-grid-column binding="productId" header="商品ID"></wj-flex-grid-column> <wj-flex-grid-column binding="colorId" header="色ID"></wj-flex-grid-column> <wj-flex-grid-column binding="amount" header="金額"></wj-flex-grid-column> <wj-flex-grid-column binding="amount2" header="金額2"></wj-flex-grid-column> <wj-flex-grid-column binding="discount" header="値引" [width]="80"></wj-flex-grid-column> <wj-flex-grid-column binding="active" header="有効"></wj-flex-grid-column> </wj-flex-grid> <!-- commands --> <div class="well"> <div class="grid-sort-group"> <!-- current selection --> <p>選択されたセル: <b>{{flex.selection | cellRange}}</b></p> <!-- data size --> <wj-menu [(value)]="itemCount" [header]="'データ数'"> <wj-menu-item [value]="5">5</wj-menu-item> <wj-menu-item [value]="50">50</wj-menu-item> <wj-menu-item [value]="500">500</wj-menu-item> <wj-menu-item [value]="5000">5,000</wj-menu-item> <wj-menu-item [value]="50000">50,000</wj-menu-item> <wj-menu-item [value]="100000">100,000</wj-menu-item> <wj-menu-item [value]="500000">500,000</wj-menu-item> <wj-menu-item [value]="1000000">1,000,000</wj-menu-item> </wj-menu> <!-- allow add new --> <wj-menu [(value)]="flex.allowAddNew" [header]="'行の追加'"> <wj-menu-item [value]="true">許可</wj-menu-item> <wj-menu-item [value]="false">禁止</wj-menu-item> </wj-menu> <!-- selection mode --> <wj-menu [(value)]="flex.selectionMode" [header]="'選択'"> <wj-menu-item [value]="0">なし</wj-menu-item> <wj-menu-item [value]="1">セル</wj-menu-item> <wj-menu-item [value]="2">セル範囲</wj-menu-item> <wj-menu-item [value]="3">行</wj-menu-item> <wj-menu-item [value]="4">行範囲</wj-menu-item> <wj-menu-item [value]="5">行リスト</wj-menu-item> </wj-menu> <!-- headers visibility --> <wj-menu [(value)]="flex.headersVisibility" [header]="'ヘッダー'"> <wj-menu-item [value]="0">なし</wj-menu-item> <wj-menu-item [value]="1">列</wj-menu-item> <wj-menu-item [value]="2">行</wj-menu-item> <wj-menu-item [value]="3">すべて</wj-menu-item> </wj-menu> <!-- highlight headers --> <wj-menu [(value)]="flex.showSelectedHeaders" [header]="'選択されたヘッダー'"> <wj-menu-item [value]="0">なし</wj-menu-item> <wj-menu-item [value]="1">列</wj-menu-item> <wj-menu-item [value]="2">行</wj-menu-item> <wj-menu-item [value]="3">すべて</wj-menu-item> </wj-menu> <!-- show marquee --> <wj-menu [(value)]="flex.showMarquee" [header]="'マーキー'"> <wj-menu-item [value]="true">有効</wj-menu-item> <wj-menu-item [value]="false">無効</wj-menu-item> </wj-menu> <!-- data maps --> <wj-menu [(value)]="dataMaps" [header]="'データマップ'"> <wj-menu-item [value]="true">有効</wj-menu-item> <wj-menu-item [value]="false">無効</wj-menu-item> </wj-menu> <!-- formatting --> <wj-menu [(value)]="formatting" [header]="'書式設定'"> <wj-menu-item [value]="true">有効</wj-menu-item> <wj-menu-item [value]="false">無効</wj-menu-item> </wj-menu> <!-- culture --> <!-- <wj-menu [(value)]="culture" [header]="'Culture'"> <wj-menu-item [value]="'en'">English</wj-menu-item> <wj-menu-item [value]="'de'">German</wj-menu-item> <wj-menu-item [value]="'it'">Italian</wj-menu-item> <wj-menu-item [value]="'fr'">French</wj-menu-item> <wj-menu-item [value]="'pt'">Portuguese</wj-menu-item> <wj-menu-item [value]="'ru'">Russian</wj-menu-item> <wj-menu-item [value]="'ja'">Japanese</wj-menu-item> <wj-menu-item [value]="'ko'">Korean</wj-menu-item> </wj-menu> --> <br /> <br /> <!-- testing the object model --> <button class="btn btn-default" (click)="toggleColumnVisibility()"> 先頭列の表示を切り替え </button> <button class="btn btn-default" (click)="changeColumnSize()"> 先頭列の幅を変更 </button> <button class="btn btn-default" (click)="toggleRowVisibility()"> 先頭行の表示を切り替え </button> <button class="btn btn-default" (click)="changeRowSize()"> 先頭行の高さを変更 </button> <button class="btn btn-default" (click)="changeDefaultRowSize()"> 行の既定の高さを変更 </button> <button class="btn btn-default" (click)="changeScrollPosition()"> スクロール位置を変更 </button> </div> </div> </div> import { Injectable } from '@angular/core'; @Injectable() export class DataService { // data used to generate random items private _products = ['ウィジェット', 'ガジェット', 'ツール']; private _colors = ['黒', '白', '赤', '緑', '青']; private _someCountries = ['アメリカ', 'ドイツ', 'イギリス', '日本', 'イタリア', 'ギリシャ']; getCountries(): string[] { return this._someCountries; } getProducts(): string[] { return this._products; } getColors(): string[] { return this._colors; } // get matches for a search term getData(count: number): any[] { var data = []; var dt = new Date(); // add count items for (var i = 0; i < count; i++) { // constants used to create data items var date = new Date(dt.getFullYear(), i % 12, 25, i % 24, i % 60, i % 60), countryId = Math.floor(Math.random() * this._someCountries.length), productId = Math.floor(Math.random() * this._products.length), colorId = Math.floor(Math.random() * this._colors.length); // create the item var item = { id: i, start: date, end: new Date(date.getTime() + Math.random() * 30 * (24 * 60 * 60 * 1000)), country: this._someCountries[countryId], product: this._products[productId], color: this._colors[colorId], countryId: countryId, productId: productId, colorId: colorId, amount: Math.random() * 10000 - 5000, amount2: Math.random() * 10000 - 5000, discount: Math.random() / 4, active: i % 4 == 0 }; // add the item to the list data.push(item); } return data; } } .wj-flexgrid { height: 400px; margin: 6px 0; } .grid-sort-group .wj-menu, .grid-sort-group .btn { margin: 2px 2px 2px 0; } 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 wijmo from '@grapecity/wijmo'; import * as grid from '@grapecity/wijmo.grid'; // import * as wjInput from '@grapecity/wijmo.react.input'; import * as wjGrid from '@grapecity/wijmo.react.grid'; import { Navigator } from './navigator'; import { getData, getCountries, getProducts, getColors } from './data'; // var MenuType; (function (MenuType) { MenuType[MenuType["allowAdd"] = 1] = "allowAdd"; MenuType[MenuType["dataMaps"] = 7] = "dataMaps"; MenuType[MenuType["formatting"] = 8] = "formatting"; MenuType[MenuType["headersVisibility"] = 2] = "headersVisibility"; MenuType[MenuType["itemsCount"] = 3] = "itemsCount"; MenuType[MenuType["selectionMode"] = 4] = "selectionMode"; MenuType[MenuType["showMarquee"] = 5] = "showMarquee"; MenuType[MenuType["showSelectedHeaders"] = 6] = "showSelectedHeaders"; })(MenuType || (MenuType = {})); // class App extends React.Component { // constructor(props) { super(props); this._toFilter = null; this._itemsCount = 500; this.state = { allowAdd: false, dataMaps: true, filter: '', formatting: true, headersVisibility: 3, selectionMode: 2, showMarquee: false, showSelectedHeaders: 0, data: getData(this._itemsCount), selection: '' }; } render() { return <div className='container-fluid'> <div className='row'> <div className='col-md-6 col-xs-4'> <input type='text' className='form-control app-pad' placeholder='フィルター' value={this.filter} onChange={this._filterChanged.bind(this)}/> </div> <div className='col-md-6 col-xs-8'> <Navigator view={this.state.data}> </Navigator> </div> </div> <wjGrid.FlexGrid allowAddNew={this.allowAdd} allowMerging='All' allowResizing='Both' headersVisibility={this.headersVisibility} selectionMode={this.selectionMode} showMarquee={this.showMarquee} showSelectedHeaders={this.showSelectedHeaders} stickyHeaders={true} itemsSource={this.state.data} initialized={this._gridInitialized.bind(this)} itemsSourceChanged={this._gridItemsSourceChanged.bind(this)} selectionChanged={this._gridSelectionChanged.bind(this)}> <wjGrid.FlexGridColumn binding="id" header="ID" width={80}></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="start" header="開始"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="end" header="終了"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="country" header="国"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="product" header="商品"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="color" header="色"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="countryId" header="国ID"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="productId" header="商品ID"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="colorId" header="色ID"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="amount" header="金額"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="amount2" header="金額2"></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="discount" header="値引" width={80}></wjGrid.FlexGridColumn> <wjGrid.FlexGridColumn binding="active" header="有効"></wjGrid.FlexGridColumn> </wjGrid.FlexGrid> <div className='well'> <div className='grid-sort-group form-group row'> <p>選択されたセル: <b>{this.state.selection}</b></p> <wjInput.Menu header='データ数' value={this.itemsCount} itemClicked={this._menuChanged.bind(this, MenuType.itemsCount)}> <wjInput.MenuItem value={5}>5</wjInput.MenuItem> <wjInput.MenuItem value={50}>50</wjInput.MenuItem> <wjInput.MenuItem value={500}>500</wjInput.MenuItem> <wjInput.MenuItem value={5000}>5,000</wjInput.MenuItem> <wjInput.MenuItem value={50000}>50,000</wjInput.MenuItem> <wjInput.MenuItem value={100000}>100,000</wjInput.MenuItem> <wjInput.MenuItem value={500000}>500,000</wjInput.MenuItem> <wjInput.MenuItem value={1000000}>1,000,000</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='行の追加' value={this.allowAdd} itemClicked={this._menuChanged.bind(this, MenuType.allowAdd)}> <wjInput.MenuItem value={true}>許可</wjInput.MenuItem> <wjInput.MenuItem value={false}>禁止</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='選択' value={this.selectionMode} itemClicked={this._menuChanged.bind(this, MenuType.selectionMode)}> <wjInput.MenuItem value={0}>なし</wjInput.MenuItem> <wjInput.MenuItem value={1}>セル</wjInput.MenuItem> <wjInput.MenuItem value={2}>セル範囲</wjInput.MenuItem> <wjInput.MenuItem value={3}>行</wjInput.MenuItem> <wjInput.MenuItem value={4}>行範囲</wjInput.MenuItem> <wjInput.MenuItem value={5}>行リスト</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='ヘッダー' value={this.headersVisibility} itemClicked={this._menuChanged.bind(this, MenuType.headersVisibility)}> <wjInput.MenuItem value={0}>なし</wjInput.MenuItem> <wjInput.MenuItem value={1}>列</wjInput.MenuItem> <wjInput.MenuItem value={2}>行</wjInput.MenuItem> <wjInput.MenuItem value={3}>すべて</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='選択されたヘッダー' value={this.showSelectedHeaders} itemClicked={this._menuChanged.bind(this, MenuType.showSelectedHeaders)}> <wjInput.MenuItem value={0}>なし</wjInput.MenuItem> <wjInput.MenuItem value={1}>列</wjInput.MenuItem> <wjInput.MenuItem value={2}>行</wjInput.MenuItem> <wjInput.MenuItem value={3}>すべて</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='マーキー' value={this.showMarquee} itemClicked={this._menuChanged.bind(this, MenuType.showMarquee)}> <wjInput.MenuItem value={true}>有効</wjInput.MenuItem> <wjInput.MenuItem value={false}>無効</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='データマップ' value={this.dataMaps} itemClicked={this._menuChanged.bind(this, MenuType.dataMaps)}> <wjInput.MenuItem value={true}>有効</wjInput.MenuItem> <wjInput.MenuItem value={false}>無効</wjInput.MenuItem> </wjInput.Menu> <wjInput.Menu header='書式設定' value={this.formatting} itemClicked={this._menuChanged.bind(this, MenuType.formatting)}> <wjInput.MenuItem value={true}>有効</wjInput.MenuItem> <wjInput.MenuItem value={false}>無効</wjInput.MenuItem> </wjInput.Menu> <br /> <br /> <button className='btn btn-default' onClick={this._toggleColumnVisibility.bind(this)}> 先頭列の表示を切り替え </button> <button className='btn btn-default' onClick={this._changeColumnSize.bind(this)}> 先頭列の幅を変更 </button> <button className='btn btn-default' onClick={this._toggleRowVisibility.bind(this)}> 先頭行の表示を切り替え </button> <button className='btn btn-default' onClick={this._changeRowSize.bind(this)}> 先頭行の高さを変更 </button> <button className='btn btn-default' onClick={this._changeDefaultRowSize.bind(this)}> 行の既定の高さを変更 </button> <button className='btn btn-default' onClick={this._changeScrollPosition.bind(this)}> スクロール位置を変更 </button> </div> </div> </div>; } // get allowAdd() { return this.state.allowAdd; } set allowAdd(value) { if (this.state.allowAdd !== value) { this.setState({ allowAdd: value }); } } // get dataMaps() { return this.state.dataMaps; } set dataMaps(value) { if (this.state.dataMaps !== value) { this.setState({ dataMaps: value }); this._updateDataMaps(); } } // get formatting() { return this.state.formatting; } set formatting(value) { if (this.state.formatting !== value) { this.setState({ formatting: value }); this._updateFormatting(); } } // get filter() { return this.state.filter; } set filter(value) { if (this.filter !== value) { this.setState({ filter: value }); this._applyFilter(); } } // get headersVisibility() { return this.state.headersVisibility; } set headersVisibility(value) { if (this.state.headersVisibility !== value) { this.setState({ headersVisibility: value }); } } // get itemsCount() { return this._itemsCount; } set itemsCount(value) { if (this._itemsCount !== value) { this._itemsCount = value; this.setState({ data: getData(value) }); } } // get selectionMode() { return this.state.selectionMode; } set selectionMode(value) { if (this.state.selectionMode !== value) { this.setState({ selectionMode: value }); } } // get showMarquee() { return this.state.showMarquee; } set showMarquee(value) { if (this.state.showMarquee !== value) { this.setState({ showMarquee: value }); } } // get showSelectedHeaders() { return this.state.showSelectedHeaders; } set showSelectedHeaders(value) { if (this.state.showSelectedHeaders !== value) { this.setState({ showSelectedHeaders: value }); } } // componentDidMount() { this._updateDataMapSettings(); } // // apply filter (applied on a 500 ms timeOut) _applyFilter() { if (this._toFilter) { clearTimeout(this._toFilter); } // this._toFilter = setTimeout(() => { this._toFilter = null; if (this._grid) { let view = this._grid.collectionView; if (view) { if (!this.filter) { view.filter = null; } else { if (!view.filter) { view.filter = this._filterFunction.bind(this); } else { view.refresh(); } } } } }, 500); } // // ICollectionView filter function _filterFunction(item) { let f = this.filter; if (f && item) { // // split string into terms to enable multi-field searches such as 'us gadget red' let terms = f.toUpperCase().split(' '); // // look for any term in any string field for (let i = 0; i < terms.length; i++) { let termFound = false; for (let key in item) { let value = item[key]; if (wijmo.isString(value) && value.toUpperCase().indexOf(terms[i]) > -1) { termFound = true; break; } } // // fail if any of the terms is not found if (!termFound) { return false; } } } // // include item in view return true; } // _toggleColumnVisibility() { let col = this._grid.columns[0]; col.visible = !col.visible; } // _changeColumnSize() { let col = this._grid.columns[0]; col.visible = true; col.width = col.width < 0 ? 60 : -1; col = this._grid.rowHeaders.columns[0]; col.width = col.width < 0 ? 40 : -1; } // _toggleRowVisibility() { let row = this._grid.rows[0]; row.visible = !row.visible; } // _changeRowSize() { let row = this._grid.rows[0]; row.visible = true; row.height = row.height < 0 ? 80 : -1; row = this._grid.columnHeaders.rows[0]; row.height = row.height < 0 ? 80 : -1; } // _changeDefaultRowSize() { this._grid.rows.defaultSize = this._grid.rows.defaultSize == 28 ? 65 : 28; } // _changeScrollPosition() { let flex = this._grid; if (flex.scrollPosition.y == 0) { let sz = flex.scrollSize; flex.scrollPosition = new wijmo.Point(-sz.width / 2, -sz.height / 2); } else { flex.scrollPosition = new wijmo.Point(0, 0); } } // _gridInitialized(sender) { this._grid = sender; this.setState({ selection: this._cellRangeToString(sender.selection) }); } // _gridSelectionChanged(sender) { this.setState({ selection: this._cellRangeToString(sender.selection) }); } // _gridItemsSourceChanged(sender) { // update data maps and formatting this._updateDataMapSettings(); // // clear filter // this.filter = ''; } // _filterChanged(e) { this.filter = e.target.value; } // _menuChanged(type, menu) { if (menu.selectedIndex < 0) { return; } // switch (type) { case MenuType.itemsCount: this.itemsCount = menu.selectedValue; break; case MenuType.allowAdd: this.allowAdd = menu.selectedValue; break; case MenuType.dataMaps: this.dataMaps = menu.selectedValue; break; case MenuType.formatting: this.formatting = menu.selectedValue; break; case MenuType.headersVisibility: this.headersVisibility = menu.selectedValue; break; case MenuType.selectionMode: this.selectionMode = menu.selectedValue; break; case MenuType.showMarquee: this.showMarquee = menu.selectedValue; break; case MenuType.showSelectedHeaders: this.showSelectedHeaders = menu.selectedValue; break; } } // _getText(map, value) { return map.filter(val => val.value === value)[0].text; } // _cellRangeToString(value) { let rng = ''; // if (value instanceof grid.CellRange) { rng = `(${value.row};${value.col})`; if (!value.isSingleCell) { rng += `-(${value.row2};${value.col2})`; } } return rng; } // // apply/remove data maps _updateDataMaps() { if (!this._grid) { return; } // let country = this._grid.columns.getColumn('countryId'), product = this._grid.columns.getColumn('productId'), color = this._grid.columns.getColumn('colorId'); // if (country && product && color) { if (this.dataMaps == true) { country.showDropDown = true; // show drop-down for countries product.showDropDown = false; // don't show it for products color.showDropDown = false; // or colors (just to show how) country.dataMap = this._buildDataMap(getCountries()); product.dataMap = this._buildDataMap(getProducts()); color.dataMap = this._buildDataMap(getColors()); } else { country.dataMap = null; product.dataMap = null; color.dataMap = null; } } } // // build a data map from a string array using the indices as keys _buildDataMap(items) { let map = items.map((v, i) => ({ key: i, value: v })); return new grid.DataMap(map, 'key', 'value'); } // // apply/remove column formatting _updateFormatting() { if (!this._grid) { return; } // let fmt = this.formatting; this._setColumnFormat('amount', fmt ? 'c' : null); this._setColumnFormat('amount2', fmt ? 'c' : null); this._setColumnFormat('discount', fmt ? 'p0' : null); this._setColumnFormat('start', fmt ? 't' : null); this._setColumnFormat('end', fmt ? 't' : null); } // _setColumnFormat(name, format) { let col = this._grid.columns.getColumn(name); if (col) { col.format = format; } } // _updateDataMapSettings() { this._updateDataMaps(); this._updateFormatting(); } } // 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 Overview</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: 400px; margin: 6px 0; } .grid-sort-group .wj-menu, .grid-sort-group .btn { margin: 2px 2px 2px 0; } import { CollectionView } from '@grapecity/wijmo'; // let countries = ['アメリカ', 'ドイツ', 'イギリス', '日本', 'イタリア', 'ギリシャ']; let products = ['ウィジェット', 'ガジェット', 'ツール']; let colors = ['黒', '白', '赤', '緑', '青']; // // generate some random data export function getData(count, currentChangedHdl) { let data = []; let dt = new Date(); // // add count items for (let i = 0; i < count; i++) { // constants used to create data items let date = new Date(dt.getFullYear(), i % 12, 25, i % 24, i % 60, i % 60), countryId = Math.floor(Math.random() * countries.length), productId = Math.floor(Math.random() * products.length), colorId = Math.floor(Math.random() * colors.length); // // add the item to the list data.push({ id: i, start: date, end: date, country: countries[countryId], product: products[productId], color: colors[colorId], countryId: countryId, productId: productId, colorId: colorId, amount: Math.random() * 10000 - 5000, amount2: Math.random() * 10000 - 5000, discount: Math.random() / 4, active: i % 4 == 0 }); } // // return a CollectionView so multiple controls bound to this source // will be updated automatically (TFS 145538) let cv = new CollectionView(data); if (currentChangedHdl) { cv.currentChanged.addHandler(currentChangedHdl); } // return cv; } // // get possible values for each field export function getCountries() { return countries; } // export function getProducts() { return products; } // export function getColors() { return colors; } import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './app.css'; // import * as React from 'react'; // // CollectionView navigator component export class Navigator extends React.Component { // constructor(props) { super(props); this.BtnFirstStyle = { marginRight: '-4px' }; this.BtnLastStyle = { marginLeft: '-4px' }; } render() { return <div className='wj-control wj-content wj-pager pull-right'> <div className='wj-input-group'> <span className='wj-input-group-btn'> <button type='button' className='wj-btn wj-btn-default' onClick={this.moveCurrentToFirst.bind(this)} disabled={this.props.view.currentPosition <= 0}> <span className='wj-glyph-left' style={this.BtnFirstStyle}></span> <span className='wj-glyph-left'></span> </button> </span> <span className='wj-input-group-btn'> <button type='button' className='wj-btn wj-btn-default' onClick={this.moveCurrentToPrevious.bind(this)} disabled={this.props.view.currentPosition <= 0}> <span className='wj-glyph-left'></span> </button> </span> <input type='text' className='wj-form-control' value={this.props.view.currentPosition + 1 + ' / ' + this.props.view.itemCount} disabled/> <span className='wj-input-group-btn'> <button type='button' className='wj-btn wj-btn-default' onClick={this.moveCurrentToNext.bind(this)} disabled={this.props.view.currentPosition >= this.props.view.itemCount - 1}> <span className='wj-glyph-right'></span> </button> </span> <span className='wj-input-group-btn'> <button type='button' className='wj-btn wj-btn-default' onClick={this.moveCurrentToLast.bind(this)} disabled={this.props.view.currentPosition >= this.props.view.itemCount - 1}> <span className='wj-glyph-right'></span> <span className='wj-glyph-right' style={this.BtnLastStyle}></span> </button> </span> </div> </div>; } moveCurrentToFirst() { this.props.view.moveCurrentToFirst(); this.forceUpdate(); } // moveCurrentToPrevious() { this.props.view.moveCurrentToPrevious(); this.forceUpdate(); } // moveCurrentToNext() { this.props.view.moveCurrentToNext(); this.forceUpdate(); } // moveCurrentToLast() { this.props.view.moveCurrentToLast(); this.forceUpdate(); } } <template> <div class="container-fluid"> <!-- search box --> <div class="row"> <div class="col-md-6 col-xs-4"> <input type="text" class="form-control app-pad" placeholder="フィルター" v-model="filter" > </div> <div class="col-md-6 col-xs-8"> <wj-collection-view-navigator :cv="collectionView" class="pull-right"> </wj-collection-view-navigator> </div> </div> <!-- the grid --> <wj-flex-grid :itemsSource="collectionView" :initialized="initialized" class="grid" :allowResizing="'Both'" :allowMerging="'All'" :stickyHeaders="true" :allowAddNew="allowAddNew" :selectionMode="selectionMode" :headersVisibility="headersVisibility" :showSelectedHeaders="showSelectedHeaders" :showMarquee="showMarquee" > <wj-flex-grid-column binding="id" header="ID" :width=80></wj-flex-grid-column> <wj-flex-grid-column binding="start" header="開始"></wj-flex-grid-column> <wj-flex-grid-column binding="end" header="終了"></wj-flex-grid-column> <wj-flex-grid-column binding="country" header="国"></wj-flex-grid-column> <wj-flex-grid-column binding="product" header="商品"></wj-flex-grid-column> <wj-flex-grid-column binding="color" header="色"></wj-flex-grid-column> <wj-flex-grid-column binding="countryId" header="国ID"></wj-flex-grid-column> <wj-flex-grid-column binding="productId" header="商品ID"></wj-flex-grid-column> <wj-flex-grid-column binding="colorId" header="色ID"></wj-flex-grid-column> <wj-flex-grid-column binding="amount" header="金額"></wj-flex-grid-column> <wj-flex-grid-column binding="amount2" header="金額2"></wj-flex-grid-column> <wj-flex-grid-column binding="discount" header="値引" :width=80></wj-flex-grid-column> <wj-flex-grid-column binding="active" header="有効"></wj-flex-grid-column> </wj-flex-grid> <!-- commands --> <div class="well"> <div class="grid-sort-group"> <!-- current selection --> <p> 選択されたセル: <b>{{selection | cellRange}}</b> </p> <!-- data size --> <wj-menu :value="itemCount" :header="'データ数'" :itemClicked="itemClicked.bind(this,'itemCount')"> <wj-menu-item :value="5">5</wj-menu-item> <wj-menu-item :value="50">50</wj-menu-item> <wj-menu-item :value="500">500</wj-menu-item> <wj-menu-item :value="5000">5,000</wj-menu-item> <wj-menu-item :value="50000">50,000</wj-menu-item> <wj-menu-item :value="100000">100,000</wj-menu-item> <wj-menu-item :value="500000">500,000</wj-menu-item> <wj-menu-item :value="1000000">1,000,000</wj-menu-item> </wj-menu> <!-- allow add new --> <wj-menu :value="allowAddNew" :header="'行の追加'" :itemClicked="itemClicked.bind(this,'allowAddNew')"> <wj-menu-item :value="true">許可</wj-menu-item> <wj-menu-item :value="false">禁止</wj-menu-item> </wj-menu> <!-- selection mode --> <wj-menu :value="selectionMode" :header="'選択'" :itemClicked="itemClicked.bind(this,'selectionMode')"> <wj-menu-item :value="0">なし</wj-menu-item> <wj-menu-item :value="1">セル</wj-menu-item> <wj-menu-item :value="2">セル範囲</wj-menu-item> <wj-menu-item :value="3">行</wj-menu-item> <wj-menu-item :value="4">行範囲</wj-menu-item> <wj-menu-item :value="5">行リスト</wj-menu-item> </wj-menu> <!-- headers visibility --> <wj-menu :value="headersVisibility" :header="'ヘッダー'" :itemClicked="itemClicked.bind(this,'headersVisibility')"> <wj-menu-item :value="0">なし</wj-menu-item> <wj-menu-item :value="1">列</wj-menu-item> <wj-menu-item :value="2">行</wj-menu-item> <wj-menu-item :value="3">すべて</wj-menu-item> </wj-menu> <!-- highlight headers --> <wj-menu :value="showSelectedHeaders" :header="'選択されたヘッダー'" :itemClicked="itemClicked.bind(this,'showSelectedHeaders')"> <wj-menu-item :value="0">なし</wj-menu-item> <wj-menu-item :value="1">列</wj-menu-item> <wj-menu-item :value="2">行</wj-menu-item> <wj-menu-item :value="3">すべて</wj-menu-item> </wj-menu> <!-- show marquee --> <wj-menu :value="showMarquee" :header="'マーキー'" :itemClicked="itemClicked.bind(this,'showMarquee')"> <wj-menu-item :value="true">有効</wj-menu-item> <wj-menu-item :value="false">無効</wj-menu-item> </wj-menu> <!-- data maps --> <wj-menu :value="dataMaps" :header="'データマップ'" :itemClicked="itemClicked.bind(this,'dataMaps')"> <wj-menu-item :value="true">有効</wj-menu-item> <wj-menu-item :value="false">無効</wj-menu-item> </wj-menu> <!-- formatting --> <wj-menu :value="formatting" :header="'書式設定'" :itemClicked="itemClicked.bind(this,'formatting')"> <wj-menu-item :value="true">有効</wj-menu-item> <wj-menu-item :value="false">無効</wj-menu-item> </wj-menu> <br> <br> <!-- testing the object model --> <button class="btn btn-default" @click="toggleColumnVisibility()">先頭列の表示を切り替え</button> <button class="btn btn-default" @click="changeColumnSize()">先頭列の幅を変更</button> <button class="btn btn-default" @click="toggleRowVisibility()">先頭行の表示を切り替え</button> <button class="btn btn-default" @click="changeRowSize()">先頭行の高さを変更</button> <button class="btn btn-default" @click="changeDefaultRowSize()">行の既定の高さを変更</button> <button class="btn btn-default" @click="changeScrollPosition()">スクロール位置を変更</button> </div> </div> </div> </template> <script> import "@grapecity/wijmo.styles/wijmo.css"; import "bootstrap.css"; import * as wjcCore from "@grapecity/wijmo"; import * as wjcGrid from "@grapecity/wijmo.grid"; import Vue from "vue"; import { getCountries, getProducts, getColors, getData } from "./data"; import "@grapecity/wijmo.vue2.grid"; import "@grapecity/wijmo.vue2.input"; new Vue({ el: "#app", created: function() { this.dataArray = getData(this.itemCount); }, data: { dataMaps: true, formatting: true, filter: '', selection: null, allowAddNew: false, selectionMode: wjcGrid.SelectionMode.CellRange, headersVisibility: wjcGrid.HeadersVisibility.All, showSelectedHeaders: wjcGrid.HeadersVisibility.None, showMarquee: false, itemCount: 500, collectionView: new wjcCore.CollectionView(), dataArray: null }, watch: { dataMaps: function (newVal, oldVal) { console.log('dataMaps watcher'); this._updateDataMaps(); }, dataArray: function(newVal, oldVal) { console.log('dataArray watcher'); this.collectionView.sourceCollection = newVal; let flex = this.flex; // if it's the first assignment to dataArray if (oldVal == null && flex) { // make columns 25% wider (for readability and to show how) for (let i = 0; i < flex.columns.length; i++) { flex.columns[i].width = flex.columns[i].renderSize * 1.25; } } this.updateDataMapSettings(); }, itemCount: function(newVal) { console.log('itemCount watcher'); this.dataArray = getData(newVal); }, formatting: function() { this._updateFormatting(); }, filter: function() { this._applyFilter(); } }, methods: { initialized: function(flex) { this.flex = flex; this.selection = this.flex.selection; this.flex.selectionChanged.addHandler((s, e) => { this.selection = e.range; }); this.flex.select(new wjcGrid.CellRange(0, 0)); }, updateDataMapSettings: function() { this._updateDataMaps(); this._updateFormatting(); }, toggleColumnVisibility: function() { let flex = this.flex, col = flex.columns[0]; col.visible = !col.visible; }, changeColumnSize: function() { let flex = this.flex, col = flex.columns[0]; col.visible = true; col.width = col.width < 0 ? 60 : -1; col = flex.rowHeaders.columns[0]; col.width = col.width < 0 ? 40 : -1; }, toggleRowVisibility: function() { let flex = this.flex, row = flex.rows[0]; row.visible = !row.visible; }, changeRowSize: function() { let flex = this.flex, row = flex.rows[0]; row.visible = true; row.height = row.height == null ? 80 : null; row = flex.columnHeaders.rows[0]; row.height = row.height == null ? 80 : null; }, changeDefaultRowSize: function() { let flex = this.flex; flex.rows.defaultSize = flex.rows.defaultSize == 28 ? 65 : 28; }, changeScrollPosition: function() { let flex = this.flex; if (flex.scrollPosition.y == 0) { let sz = flex.scrollSize; flex.scrollPosition = new wjcCore.Point( -sz.width / 2, -sz.height / 2 ); } else { flex.scrollPosition = new wjcCore.Point(0, 0); } }, // apply/remove data maps _updateDataMaps: function() { let flex = this.flex; if (flex) { let colCountry = flex.columns.getColumn("countryId"), colProduct = flex.columns.getColumn("productId"), colColor = flex.columns.getColumn("colorId"); if (colCountry && colProduct && colColor) { if (this.dataMaps) { colCountry.showDropDown = true; // show drop-down for countries colProduct.showDropDown = false; // don't show it for products colColor.showDropDown = false; // or colors (just to show how) colCountry.dataMap = this._buildDataMap(getCountries()); colProduct.dataMap = this._buildDataMap(getProducts()); colColor.dataMap = this._buildDataMap(getColors()); } else { colCountry.dataMap = null; colProduct.dataMap = null; colColor.dataMap = null; } } } }, // build a data map from a string array using the indices as keys _buildDataMap: function(items) { let map = []; for (let i = 0; i < items.length; i++) { map.push({ key: i, value: items[i] }); } return new wjcGrid.DataMap(map, "key", "value"); }, // apply/remove column formatting _updateFormatting: function() { let flex = this.flex; if (flex) { let fmt = this.formatting; this._setColumnFormat("amount", fmt ? "c" : null); this._setColumnFormat("amount2", fmt ? "c" : null); this._setColumnFormat("discount", fmt ? "p0" : null); this._setColumnFormat("start", fmt ? "t" : null); this._setColumnFormat("end", fmt ? "t" : null); } }, _setColumnFormat: function(name, format) { let col = this.flex.columns.getColumn(name); if (col) { col.format = format; } }, // apply filter (applied on a 500 ms timeOut) _applyFilter: function() { if (this.filterTimeOut) { clearTimeout(this.filterTimeOut); } this.filterTimeOut = setTimeout(() => { this.filterTimeOut = null; if (this.collectionView) { let cv = this.collectionView; if (cv) { if (cv.filter != this.filterFunction) { cv.filter = this.filterFunction; } else { cv.refresh(); } } } }, 500); }, itemClicked: function(prop, s, e) { if (s.selectedIndex > -1) { this[prop] = s.selectedValue; } }, filterFunction: function(item) { let f = this.filter; if (f && item) { // split string into terms to enable multi-field searches such as 'us gadget red' let terms = f.toUpperCase().split(" "); // look for any term in any string field for (let i = 0; i < terms.length; i++) { let termFound = false; for (let key in item) { let value = item[key]; if ( wjcCore.isString(value) && value.toUpperCase().indexOf(terms[i]) > -1 ) { termFound = true; break; } } // fail if any of the terms is not found if (!termFound) { return false; } } } // include item in view return true; } }, filters: { // formats grid selection range to display its value to a user cellRange: function (value) { let rng = ""; if (value instanceof wjcGrid.CellRange) { rng = "(" + value.row + ";" + value.col + ")"; if (!value.isSingleCell) { rng += "-(" + value.row2 + ";" + value.col2 + ")"; } } return rng; } }, }); </script> <style> .wj-flexgrid { height: 400px; margin: 6px 0; } .grid-sort-group .wj-menu, .grid-sort-group .btn { margin: 2px 2px 2px 0; } </style> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>GrapeCity Wijmo FlexGrid Overview</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> var _products = ['ウィジェット', 'ガジェット', 'ツール']; var _colors = ['黒', '白', '赤', '緑', '青']; var _someCountries = ['アメリカ', 'ドイツ', 'イギリス', '日本', 'イタリア', 'ギリシャ']; export function getCountries() { return _someCountries; } export function getProducts() { return _products; } export function getColors() { return _colors; } // get matches for a search term export function getData(count) { var data = []; var dt = new Date(); // add count items for (var i = 0; i < count; i++) { // constants used to create data items var date = new Date(dt.getFullYear(), i % 12, 25, i % 24, i % 60, i % 60), countryId = Math.floor(Math.random() * _someCountries.length), productId = Math.floor(Math.random() * _products.length), colorId = Math.floor(Math.random() * _colors.length); // create the item var item = { id: i, start: date, end: new Date(date.getTime() + Math.random() * 30 * (24 * 60 * 60 * 1000)), country: _someCountries[countryId], product: _products[productId], color: _colors[colorId], countryId: countryId, productId: productId, colorId: colorId, amount: Math.random() * 10000 - 5000, amount2: Math.random() * 10000 - 5000, discount: Math.random() / 4, active: i % 4 == 0 }; // add the item to the list data.push(item); } return data; }