グリッド (React)

FlexGridは、高速で柔軟なJavaScriptデータグリッドコントロールです。コアグリッドモジュールには、最も一般的な機能がすべて含まれています。また、さらにグリッドをカスタマイズするための拡張機能と柔軟なAPIも含まれています。

このサンプルでは、FlexGridソートグループ化検索フィルターデータマップセルテンプレートスパークラインカスタムエディタExcelエクスポートPDFエクスポート検証詳細行などの多くの機能を紹介しています。

データ項目の数を変更してみて、非常に大規模なデータセットであってもグリッドが高速のままであることを確認してください。FlexGridは、行と列を自動的に仮想化することにより、このレベルのパフォーマンスを実現します。

このサンプルはReactを使用しています。

import 'bootstrap.css'; import '@grapecity/wijmo.styles/wijmo.css'; import './app.css'; // import * as React from 'react'; import * as ReactDOM from 'react-dom'; // import '@grapecity/wijmo.touch'; import * as wjCore from '@grapecity/wijmo'; import { InputDate, InputTime } from '@grapecity/wijmo.input'; import { CellMaker, SparklineMarkers } from '@grapecity/wijmo.grid.cellmaker'; import { DataMap } from '@grapecity/wijmo.grid'; import { FlexGrid, FlexGridColumn, FlexGridCellTemplate } from '@grapecity/wijmo.react.grid'; import { FlexGridFilter } from '@grapecity/wijmo.react.grid.filter'; import { FlexGridSearch } from '@grapecity/wijmo.react.grid.search'; import { GroupPanel as FlexGridGroupPanel } from '@grapecity/wijmo.react.grid.grouppanel'; import { DataService, Country, KeyValue } from './data'; import { ExportService } from './export'; // class App extends React.Component { // constructor(props) { super(props); // this.countryCellTemplate = (ctx) => { const country = this._countryMap.getDataItem(ctx.item.countryId) || Country.NotFound; return (<React.Fragment> <span className={`flag-icon flag-icon-${country.flag}`}/> {' '}{country.name}{' '} </React.Fragment>); }; // this.colorCellTemplate = (ctx) => { const color = (this._colorMap.getDataItem(ctx.item.colorId) || KeyValue.NotFound).value; return (<React.Fragment> <span className="color-tile" style={{ background: ['Black', 'White', 'Red', 'Green', 'Blue'][ctx.item.colorId] }}/> {' '}{color}{' '} </React.Fragment>); }; // this.changeCellTemplate = (ctx) => { const change = ctx.item.change; let cssClass = ''; let displayValue = ''; if (wjCore.isNumber(change)) { if (change > 0) { cssClass = 'change-up'; } else if (change < 0) { cssClass = 'change-down'; } displayValue = wjCore.Globalize.formatNumber(change, 'c'); } else if (!wjCore.isUndefined(change) && change !== null) { displayValue = wjCore.changeType(change, wjCore.DataType.String); } return (<span className={cssClass}> {displayValue} </span>); }; // this.gridInitialized = (ctl) => { this.setState({ flex: ctl }, () => { this.state.flex.itemsSource = this._createItemsSource(this.state.itemsCount); }); }; // this.itemsCountChanged = (e) => { this.setState({ itemsCount: parseInt(e.target.value), }, () => { this.state.flex.itemsSource.collectionChanged.removeAllHandlers(); this._lastId = this.state.itemsCount; this.state.flex.itemsSource = this._createItemsSource(this.state.itemsCount); }); }; // this.exportToExcel = () => { const exportService = this.props.exportService; const { isExcelPreparing: preparing, isExcelExporting: exporting } = this.state; const resetState = () => this.setState({ isExcelPreparing: false, isExcelExporting: false, excelProgress: 0, }); if (!preparing && !exporting) { this.setState({ isExcelPreparing: true }); exportService.startExcelExport(this.state.flex, () => { console.log('Excelエクスポートが完了しました'); resetState(); }, err => { console.error(`Excelエクスポートが失敗しました: ${err}`); resetState(); }, prg => { this.setState({ isExcelPreparing: false, isExcelExporting: true, excelProgress: prg, }); }); console.log('Excelエクスポートが開始されました'); } else { exportService.cancelExcelExport(progress => { console.log('Excelエクスポートがキャンセルされました'); resetState(); }); } }; // this.exportToPdf = () => { this.props.exportService.exportToPdf(this.state.flex, { countryMap: this._countryMap, colorMap: this._colorMap, historyCellTemplate: this._historyCellTemplate }); }; this.state = { itemsCount: 500, flex: null, isExcelPreparing: false, isExcelExporting: false, excelProgress: 0, }; this.theGrid = React.createRef(); this.theSearch = React.createRef(); this._lastId = this.state.itemsCount; // initializes data maps const dataService = props.dataService; this._productMap = this._buildDataMap(dataService.getProducts()); this._countryMap = new DataMap(dataService.getCountries(), 'id', 'name'); this._colorMap = this._buildDataMap(dataService.getColors()); // initialize editors this._dateEditor = new InputDate(document.createElement('div'), { format: 'd', isRequired: false }); this._timeEditor = new InputTime(document.createElement('div'), { format: 'HH:mm', isRequired: false }); // initializes cell templates this._historyCellTemplate = CellMaker.makeSparkline({ markers: SparklineMarkers.High | SparklineMarkers.Low, maxPoints: 25, label: 'price history', }); this._ratingCellTemplate = CellMaker.makeRating({ range: [1, 5], label: 'rating' }); } // componentDidMount() { // connect search box and grid let theGrid = this.theGrid.current.control; let theSearch = this.theSearch.current.control; theSearch.grid = theGrid; } // componentWillUnmount() { this.props.exportService.cancelExcelExport(); } // render() { return (<div className="container-fluid"> <div className="row"> <div className="toolbar-item col-sm-3 col-md-5"> <FlexGridSearch ref={this.theSearch} placeholder="フィルター" cssMatch=""/> </div> <div className="toolbar-item col-sm-3 col-md-3"> <div className="input-group"> <span className="input-group-addon">データ数:</span> <select className="form-control" value={this.state.itemsCount} onChange={this.itemsCountChanged}> <option value="5">5</option> <option value="50">50</option> <option value="500">500</option> <option value="5000">5,000</option> <option value="50000">50,000</option> <option value="100000">100,000</option> </select> </div> </div> <div className="toolbar-item col-sm-3 col-md-2"> <button className="btn btn-default btn-block" disabled={this.state.isExcelPreparing} onClick={this.exportToExcel}> {this.state.isExcelExporting ? `キャンセル (${this.state.excelProgress}% 完了)` : 'Excelにエクスポート'} </button> </div> <div className="toolbar-item col-sm-3 col-md-2"> <button className="btn btn-default btn-block" onClick={this.exportToPdf}>PDFにエクスポート</button> </div> </div> <FlexGridGroupPanel grid={this.state.flex} placeholder={"ここに列をドラッグするとグループを作成します"}/> <FlexGrid ref={this.theGrid} autoGenerateColumns={false} allowAddNew allowDelete allowPinning="SingleColumn" newRowAtTop showMarquee selectionMode="MultiRange" validateEdits={false} initialized={this.gridInitialized}> <FlexGridFilter /> <FlexGridColumn header="ID" binding="id" width={70} isReadOnly={true}/> <FlexGridColumn header="日付" binding="date" format="d" isRequired={false} width={130} editor={this._dateEditor}> </FlexGridColumn> <FlexGridColumn header="国" binding="countryId" dataMap={this.countryMap} width={145}> <FlexGridCellTemplate cellType="Cell" template={this.countryCellTemplate}/> </FlexGridColumn> <FlexGridColumn header="金額" binding="price" format="c" isRequired={false} width={100}/> <FlexGridColumn header="履歴" binding="history" align="center" width={180} allowSorting={false} cellTemplate={this.historyCellTemplate}/> <FlexGridColumn header="変化量" binding="change" align="right" width={115}> <FlexGridCellTemplate cellType="Cell" template={this.changeCellTemplate}/> </FlexGridColumn> <FlexGridColumn header="レーティング" binding="rating" align="center" width={180} cssClass="cell-rating" cellTemplate={this.ratingCellTemplate}/> <FlexGridColumn header="時刻" binding="time" format="HH:mm" isRequired={false} width={95} editor={this._timeEditor}> </FlexGridColumn> <FlexGridColumn header="色" binding="colorId" dataMap={this.colorMap} width={145}> <FlexGridCellTemplate cellType="Cell" template={this.colorCellTemplate}/> </FlexGridColumn> <FlexGridColumn header="商品" binding="productId" dataMap={this.productMap} width={145}/> <FlexGridColumn header="値引" binding="discount" format="p0" width={130}/> <FlexGridColumn header="有効" binding="active" width={100}/> </FlexGrid> </div>); } // // get productMap() { return this._productMap; } // get countryMap() { return this._countryMap; } // get colorMap() { return this._colorMap; } // get historyCellTemplate() { return this._historyCellTemplate; } // get ratingCellTemplate() { return this._ratingCellTemplate; } // _createItemsSource(counter) { const data = this.props.dataService.getData(counter); const view = new wjCore.CollectionView(data, { getError: (item, prop) => { const displayName = this.state.flex.columns.getColumn(prop).header; return this.props.dataService.validate(item, prop, displayName); } }); view.collectionChanged.addHandler((s, e) => { // initializes new added item with a history data if (e.action === wjCore.NotifyCollectionChangedAction.Add) { e.item.history = this.props.dataService.getHistoryData(); e.item.id = this._lastId; this._lastId++; } }); return view; } // build a data map from a string array using the indices as keys _buildDataMap(items) { const map = []; for (let i = 0; i < items.length; i++) { map.push({ key: i, value: items[i] }); } return new DataMap(map, 'key', 'value'); } } ReactDOM.render(<App dataService={new DataService()} exportService={new ExportService()}/>, 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>
@import url('https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/3.1.0/css/flag-icon.css'); body { font-size: 1.5em; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI Light", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; } .toolbar-item { margin-bottom: 6px; } .wj-flexgridsearch { width: 100%; } .wj-flexgrid { height: 330px; } .wj-flexgrid .wj-cell { padding: 7px; border: none; } .wj-cell.wj-state-invalid:not(.wj-header)::after { top: -14px; border: 14px solid transparent; border-right-color: red; } .flag-icon { box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.4); } .color-tile { display: inline-block; position: relative; width: 1em; height: 1em; border-radius: 50%; box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.4); vertical-align: middle; } .change-up { color: darkgreen; } .change-up:after { content: '\25b2'; margin-left: 0.5em; } .change-down { color: darkred; } .change-down:after { content: '\25bc'; margin-left: 0.5em; } .cell-rating { font-size: 12px; } .wj-flexgrid .wj-detail { padding: 4px 16px; } .wj-detail h3 { margin: 10px 0; }
import * as wjcCore from '@grapecity/wijmo'; import { RequiredValidator, MinNumberValidator, MinDateValidator, MaxNumberValidator, MaxDateValidator } from './validation'; // export class KeyValue { } KeyValue.NotFound = { key: -1, value: '' }; // export class Country { } Country.NotFound = { id: -1, name: '', flag: '' }; // export class DataService { constructor() { this._products = ['ウィジェット', 'ガジェット', 'ツール']; this._colors = ['黒', '白', '赤', '緑', '青']; this._countries = [ { id: 0, name: 'アメリカ', flag: 'us' }, { id: 1, name: 'ドイツ', flag: 'de' }, { id: 2, name: 'イギリス', flag: 'gb' }, { id: 3, name: '日本', flag: 'jp' }, { id: 4, name: 'イタリア', flag: 'it' }, { id: 5, name: 'ギリシャ', flag: 'gr' } ]; this._validationConfig = { 'date': [ new RequiredValidator(), new MinDateValidator(new Date('2000-01-01T00:00:00')), new MaxDateValidator(new Date('2100-01-01T00:00:00')) ], 'time': [ new RequiredValidator(), new MinDateValidator(new Date('2000-01-01T00:00:00')), new MaxDateValidator(new Date('2100-01-01T00:00:00')) ], 'productId': [ new RequiredValidator(), new MinNumberValidator(0, `{0}は{1}(${this._products[0]})より小さくすることはできません`), new MaxNumberValidator(this._products.length - 1, `{0}は{1}(${this._products[this._products.length - 1]})より大きくすることはできません`) ], 'countryId': [ new RequiredValidator(), new MinNumberValidator(0, `{0}は{1}(${this._countries[0].name})より小さくすることはできません`), new MaxNumberValidator(this._countries.length - 1, `{0}は{1}(${this._countries[this._countries.length - 1].name})より大きくすることはできません`) ], 'colorId': [ new RequiredValidator(), new MinNumberValidator(0, `{0}は{1}(${this._colors[0]})より小さくすることはできません`), new MaxNumberValidator(this._colors.length - 1, `{0}は{1}(${this._colors[this._colors.length - 1]})より大きくすることはできません`) ], 'price': [ new RequiredValidator(), new MinNumberValidator(0, `金額を負の値にすることはできません`) ] }; } getCountries() { return this._countries; } getProducts() { return this._products; } getColors() { return this._colors; } getHistoryData() { return this._getRandomArray(25, 100); } getData(count) { const data = []; const dt = new Date(); const year = dt.getFullYear(); const itemsCount = Math.max(count, 5); // add items for (let i = 0; i < itemsCount; i++) { const item = this._getItem(i, year); data.push(item); } // set invalid data to demonstrate errors visualization data[1].price = -2000; data[2].date = new Date('1970-01-01T00:00:00'); data[4].time = undefined; data[4].price = -1000; return data; } validate(item, prop, displayName) { const validators = this._validationConfig[prop]; if (wjcCore.isUndefined(validators)) { return ''; } const value = item[prop]; for (let i = 0; i < validators.length; i++) { const validationError = validators[i].validate(displayName, value); if (!wjcCore.isNullOrWhiteSpace(validationError)) { return validationError; } } } _getItem(i, year) { const date = new Date(year, i % 12, 25, i % 24, i % 60, i % 60); const countryIndex = this._getRandomIndex(this._countries); const productIndex = this._getRandomIndex(this._products); const colorIndex = this._getRandomIndex(this._colors); const item = { id: i, date: date, time: new Date(date.getTime() + Math.random() * 30 * (24 * 60 * 60 * 1000)), countryId: this._countries[countryIndex].id, productId: productIndex, colorId: colorIndex, price: wjcCore.toFixed(Math.random() * 10000 + 5000, 2, true), change: wjcCore.toFixed(Math.random() * 1000 - 500, 2, true), history: this.getHistoryData(), discount: wjcCore.toFixed(Math.random() / 4, 2, true), rating: this._getRating(), active: i % 4 == 0, size: Math.floor(100 + Math.random() * 900), weight: Math.floor(100 + Math.random() * 900), quantity: Math.floor(Math.random() * 10), description: "すべてのソフトウェア製品とサービスにおいて、お客様の目標達成を支援することに重点を置いています。お客様のビジネス目標を完全に理解し、品質に重点を置き、最高の倫理基準を遵守するという私たちの主要な原則は、私たちが行うすべての基礎となります。" }; return item; } _getRating() { return Math.ceil(Math.random() * 5); } _getRandomIndex(arr) { return Math.floor(Math.random() * arr.length); } _getRandomArray(len, maxValue) { const arr = []; for (let i = 0; i < len; i++) { arr.push(Math.floor(Math.random() * maxValue)); } return arr; } }
import * as wjcCore from '@grapecity/wijmo'; import * as wjcGrid from '@grapecity/wijmo.grid'; import * as wjcGridPdf from '@grapecity/wijmo.grid.pdf'; import * as wjcGridXlsx from '@grapecity/wijmo.grid.xlsx'; import * as wjcPdf from '@grapecity/wijmo.pdf'; import * as wjcXlsx from '@grapecity/wijmo.xlsx'; import { KeyValue, Country } from './data'; // const ExcelExportDocName = 'FlexGrid.xlsx'; const PdfExportDocName = 'FlexGrid.pdf'; const FakeColumn = new wjcGrid.Column(); const FakeRow = new wjcGrid.Row(); // class Fonts { } Fonts.ZapfDingbatsSm = new wjcPdf.PdfFont('zapfdingbats', 8, 'normal', 'normal'); Fonts.ZapfDingbatsLg = new wjcPdf.PdfFont('zapfdingbats', 16, 'normal', 'normal'); Fonts.Ipaexg = new wjcPdf.PdfFont('ipaexg'); // export class IExcelExportContext { } // export class ExportService { startExcelExport(flex, successCallback, errorCallback, progressCallback) { wjcGridXlsx.FlexGridXlsxConverter.saveAsync(flex, { includeColumnHeaders: true, includeStyles: false, formatItem: this._formatExcelItem.bind(this) }, ExcelExportDocName, successCallback, errorCallback, progressCallback, true); } cancelExcelExport(doneCollback) { wjcGridXlsx.FlexGridXlsxConverter.cancelAsync(doneCollback); } exportToPdf(flex, options) { wjcGridPdf.FlexGridPdfConverter.export(flex, PdfExportDocName, { embeddedFonts: [{ source: 'https://demo.grapecity.com/wijmo/sample/fonts/ipaexg.ttf', name: 'ipaexg' }], maxPages: 100, exportMode: wjcGridPdf.ExportMode.All, scaleMode: wjcGridPdf.ScaleMode.ActualSize, documentOptions: { pageSettings: { layout: wjcPdf.PdfPageOrientation.Landscape }, header: { declarative: { text: '\t&[Page] / &[Pages]' } }, footer: { declarative: { text: '\t&[Page] / &[Pages]' } } }, styles: { cellStyle: { font: { family: 'ipaexg' }, backgroundColor: '#ffffff', borderColor: '#c6c6c6' }, altCellStyle: { backgroundColor: '#f9f9f9' }, groupCellStyle: { backgroundColor: '#dddddd' }, headerCellStyle: { backgroundColor: '#eaeaea' }, // Highlight Invalid Cells errorCellStyle: { backgroundColor: 'rgba(255, 0, 0, 0.3)' } }, customCellContent: false, formatItem: (e) => this._formatPdfItem(e, options) }); } _formatExcelItem(e) { const panel = e.panel; if (panel.cellType !== wjcGrid.CellType.Cell) { return; } // highlight invalid cells if (panel.grid._getError(panel, e.row, e.col)) { const fill = new wjcXlsx.WorkbookFill(); fill.color = '#ff0000'; e.xlsxCell.style.fill = fill; } } _resetExcelContext(ctx) { ctx.exporting = false; ctx.progress = 0; ctx.preparing = false; } _formatPdfItem(e, options) { const panel = e.panel; if (panel.cellType !== wjcGrid.CellType.Cell) { return; } switch (panel.columns[e.col].binding) { case 'countryId': this._formatPdfCountryCell(e, options.countryMap); break; case 'colorId': this._formatPdfColorCell(e, options.colorMap); break; case 'change': this._formatPdfChangeCell(e); break; case 'history': /*** Version #1: get grid cell produced before by a cell template ***/ // const cell = e.getFormattedCell(); // this._formatPdfHistoryCell(e, cell); /*** Version #2: create fake cell from a cell template ***/ const history = e.panel.getCellData(e.row, e.col, false); const cell = this._createCellFromCellTemplate(options.historyCellTemplate, history); this._formatPdfHistoryCell(e, cell); break; case 'rating': this._formatPdfRatingCell(e); break; } } _formatPdfCountryCell(e, countryMap) { e.drawBackground(e.style.backgroundColor); // check whether country exists const countryName = e.data; if (this._isCountryExist(countryName, countryMap)) { // bound rectangle of cell's content area const contentRect = e.contentRect; // draw flag image const image = e.canvas.openImage(`resources/${['us', 'germany', 'uk', 'japan', 'italy', 'greece'][countryMap.getKeyValue(countryName)]}.png`); const imageTop = contentRect.top + (contentRect.height - image.height) / 2; e.canvas.drawImage(image, contentRect.left, imageTop); // draw country name e.canvas.drawText(countryName, contentRect.left + image.width + 3, e.textTop, { font: Fonts.Ipaexg }); } // cancel standard cell content drawing e.cancel = true; } _formatPdfColorCell(e, colorMap) { e.drawBackground(e.style.backgroundColor); // check whether color exists const colorName = e.data; if (this._isColorExist(colorName, colorMap)) { // bound rectangle of cell's content area const contentRect = e.contentRect; // draw color indicator const imageHeight = Math.min(10, contentRect.height); const imageWidth = 1.33 * imageHeight; const imageTop = contentRect.top + (contentRect.height - imageHeight) / 2; e.canvas.paths .rect(contentRect.left, imageTop, imageWidth, imageHeight) .fillAndStroke(wjcCore.Color.fromString(['Black', 'White', 'Red', 'Green', 'Blue'][colorMap.getKeyValue(colorName)]), wjcCore.Color.fromString('gray')); // draw color name e.canvas.drawText(colorName, contentRect.left + imageWidth + 3, e.textTop, { font: Fonts.Ipaexg }); } // cancel standard cell content drawing e.cancel = true; } _formatPdfChangeCell(e) { e.drawBackground(e.style.backgroundColor); // get change value and text const cellData = e.panel.getCellData(e.row, e.col, false); let change = 0; let changeText = ''; if (wjcCore.isNumber(cellData)) { change = cellData; changeText = wjcCore.Globalize.formatNumber(change, 'c'); } else if (!wjcCore.isUndefined(cellData) && cellData !== null) { changeText = wjcCore.changeType(cellData, wjcCore.DataType.String); } // determine whether change is positive or negative let changeIndicator = ''; let changeColor = e.style.color; if (change > 0) { changeIndicator = '\x73'; // ▲ changeColor = 'darkgreen'; } else if (change < 0) { changeIndicator = '\x74'; // ▼ changeColor = 'darkred'; } // draw change indicator let indent = 10; e.canvas.drawText(changeIndicator, e.contentRect.right - indent, e.contentRect.top + indent, { brush: changeColor, font: Fonts.ZapfDingbatsSm }); // draw change text indent += 3; e.canvas.drawText(changeText, e.contentRect.left, e.textTop, { brush: changeColor, align: wjcPdf.PdfTextHorizontalAlign.Right, width: e.contentRect.width - indent }); // cancel standard cell content drawing e.cancel = true; } _formatPdfHistoryCell(e, cell) { e.drawBackground(e.style.backgroundColor); // draw history svg const svgUrl = this._getHistorySvgDataUrlFromCell(cell, e.clientRect.width, e.clientRect.height); if (svgUrl) { let cr = e.contentRect; e.canvas.drawSvg(svgUrl, cr.left + 2, cr.top + 2, { width: cr.width - 4, height: cr.height - 4 }); } // cancel standard cell content drawing e.cancel = true; } _getHistorySvgDataUrlFromCell(cell, width, height) { let dataUrl = null; // extract SVG from provided cell const svg = cell.getElementsByTagName('svg')[0]; if (svg) { const clone = svg.cloneNode(true); clone.setAttribute('version', '1.1'); clone.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/2000/svg'); clone.style.overflow = 'visible'; clone.style.stroke = '#376092'; clone.style.fill = '#376092'; const s = document.createElement('style'); s.setAttribute('type', 'text/css'); s.innerHTML = `<![CDATA[ line { stroke-width: 2; } circle { stroke-width: 0; stroke-opacity: 0; } .wj-marker { fill: #d00000; opacity: 1; } ]]>`; const defs = document.createElement('defs'); defs.appendChild(s); clone.insertBefore(defs, clone.firstChild); const outer = document.createElement('div'); outer.appendChild(clone); dataUrl = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(outer.innerHTML))); } return dataUrl; } _formatPdfRatingCell(e) { e.drawBackground(e.style.backgroundColor); // check whether rating is defined let rating = wjcCore.changeType(e.data, wjcCore.DataType.Number); if (wjcCore.isInt(rating)) { const ratingIndicator = '\x48'; // ★ const ratingNormalColor = wjcCore.Color.fromRgba(255, 165, 0, 1); // orange const ratingLightColor = wjcCore.Color.fromRgba(255, 165, 0, 0.2); // draw rating indicators const indent = 16; const count = 5; const width = count * indent; const y = e.clientRect.top + indent; let x = e.contentRect.left + (e.contentRect.width - width) / 2; rating = wjcCore.clamp(rating, 1, count); for (let i = 0; i < count; i++) { e.canvas.drawText(ratingIndicator, x, y, { brush: (i < rating) ? ratingNormalColor : ratingLightColor, font: Fonts.ZapfDingbatsLg, height: e.clientRect.height }); x += indent; } } // cancel standard cell content drawing e.cancel = true; } _isCountryExist(countryName, countryMap) { const countryId = countryMap.getKeyValue(countryName); if (wjcCore.isUndefined(countryId) || countryId === null) { return false; } if (countryId === Country.NotFound.id) { return false; } return true; } _isColorExist(colorName, colorMap) { const colorId = colorMap.getKeyValue(colorName); if (wjcCore.isUndefined(colorId) || colorId === null) { return false; } if (colorId === KeyValue.NotFound.key) { return false; } return true; } _createCellFromCellTemplate(cellTemplate, data) { const cell = document.createElement('div'); cellTemplate({ col: FakeColumn, row: FakeRow, value: data, item: null, text: null }, cell); return cell; } }
import * as wjcCore from '@grapecity/wijmo'; export class RequiredValidator { validate(name, value) { const message = name + 'は入力必須です'; if (wjcCore.isUndefined(value)) { return message; } const str = wjcCore.changeType(value, wjcCore.DataType.String); if (wjcCore.isNullOrWhiteSpace(str)) { return message; } return ''; } } export class MinValueValidator { constructor(minValue, message = '{0}は{1}より小さくすることはできません', format = null) { this.minValue = minValue; this.message = message; this.format = format; } validate(name, value) { if (value < this.minValue) { return wjcCore.format(this.message, { 0: name, 1: this._formatValue(this.minValue) }); } return ''; } } export class MaxValueValidator { constructor(maxValue, message = '{0}は{1}より大きくすることはできません', format = null) { this.maxValue = maxValue; this.message = message; this.format = format; } validate(name, value) { if (value > this.maxValue) { return wjcCore.format(this.message, { 0: name, 1: this._formatValue(this.maxValue) }); } return ''; } } export class MinNumberValidator extends MinValueValidator { constructor(minValue, message = '{0}は{1}より小さくすることはできません', format = 'n') { super(minValue, message, format); } _formatValue(value) { return wjcCore.Globalize.formatNumber(value, this.format); } } export class MaxNumberValidator extends MaxValueValidator { constructor(maxValue, message = '{0}は{1}より大きくすることはできません', format = 'n') { super(maxValue, message, format); } _formatValue(value) { return wjcCore.Globalize.formatNumber(value, this.format); } } export class MinDateValidator extends MinValueValidator { constructor(minValue, message = '{0}は{1}より小さくすることはできません', format = 'd') { super(minValue, message, format); } _formatValue(value) { return wjcCore.Globalize.formatDate(value, this.format); } } export class MaxDateValidator extends MaxValueValidator { constructor(maxValue, message = '{0}は{1}より大きくすることはできません', format = 'd') { super(maxValue, message, format); } _formatValue(value) { return wjcCore.Globalize.formatDate(value, this.format); } }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true, react: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { 'jszip': 'npm:jszip/dist/jszip.js', '@grapecity/wijmo': 'npm:@grapecity/wijmo/index.js', '@grapecity/wijmo.input': 'npm:@grapecity/wijmo.input/index.js', '@grapecity/wijmo.styles': 'npm:@grapecity/wijmo.styles', '@grapecity/wijmo.cultures': 'npm:@grapecity/wijmo.cultures', '@grapecity/wijmo.chart': 'npm:@grapecity/wijmo.chart/index.js', '@grapecity/wijmo.chart.analytics': 'npm:@grapecity/wijmo.chart.analytics/index.js', '@grapecity/wijmo.chart.animation': 'npm:@grapecity/wijmo.chart.animation/index.js', '@grapecity/wijmo.chart.annotation': 'npm:@grapecity/wijmo.chart.annotation/index.js', '@grapecity/wijmo.chart.finance': 'npm:@grapecity/wijmo.chart.finance/index.js', '@grapecity/wijmo.chart.finance.analytics': 'npm:@grapecity/wijmo.chart.finance.analytics/index.js', '@grapecity/wijmo.chart.hierarchical': 'npm:@grapecity/wijmo.chart.hierarchical/index.js', '@grapecity/wijmo.chart.interaction': 'npm:@grapecity/wijmo.chart.interaction/index.js', '@grapecity/wijmo.chart.radar': 'npm:@grapecity/wijmo.chart.radar/index.js', '@grapecity/wijmo.chart.render': 'npm:@grapecity/wijmo.chart.render/index.js', '@grapecity/wijmo.chart.webgl': 'npm:@grapecity/wijmo.chart.webgl/index.js', '@grapecity/wijmo.chart.map': 'npm:@grapecity/wijmo.chart.map/index.js', '@grapecity/wijmo.gauge': 'npm:@grapecity/wijmo.gauge/index.js', '@grapecity/wijmo.grid': 'npm:@grapecity/wijmo.grid/index.js', '@grapecity/wijmo.grid.detail': 'npm:@grapecity/wijmo.grid.detail/index.js', '@grapecity/wijmo.grid.filter': 'npm:@grapecity/wijmo.grid.filter/index.js', '@grapecity/wijmo.grid.search': 'npm:@grapecity/wijmo.grid.search/index.js', '@grapecity/wijmo.grid.grouppanel': 'npm:@grapecity/wijmo.grid.grouppanel/index.js', '@grapecity/wijmo.grid.multirow': 'npm:@grapecity/wijmo.grid.multirow/index.js', '@grapecity/wijmo.grid.transposed': 'npm:@grapecity/wijmo.grid.transposed/index.js', '@grapecity/wijmo.grid.transposedmultirow': 'npm:@grapecity/wijmo.grid.transposedmultirow/index.js', '@grapecity/wijmo.grid.pdf': 'npm:@grapecity/wijmo.grid.pdf/index.js', '@grapecity/wijmo.grid.sheet': 'npm:@grapecity/wijmo.grid.sheet/index.js', '@grapecity/wijmo.grid.xlsx': 'npm:@grapecity/wijmo.grid.xlsx/index.js', '@grapecity/wijmo.grid.selector': 'npm:@grapecity/wijmo.grid.selector/index.js', '@grapecity/wijmo.grid.cellmaker': 'npm:@grapecity/wijmo.grid.cellmaker/index.js', '@grapecity/wijmo.grid.immutable': 'npm:@grapecity/wijmo.grid.immutable/index.js', '@grapecity/wijmo.touch': 'npm:@grapecity/wijmo.touch/index.js', '@grapecity/wijmo.cloud': 'npm:@grapecity/wijmo.cloud/index.js', '@grapecity/wijmo.nav': 'npm:@grapecity/wijmo.nav/index.js', '@grapecity/wijmo.odata': 'npm:@grapecity/wijmo.odata/index.js', '@grapecity/wijmo.olap': 'npm:@grapecity/wijmo.olap/index.js', '@grapecity/wijmo.rest': 'npm:@grapecity/wijmo.rest/index.js', '@grapecity/wijmo.pdf': 'npm:@grapecity/wijmo.pdf/index.js', '@grapecity/wijmo.pdf.security': 'npm:@grapecity/wijmo.pdf.security/index.js', '@grapecity/wijmo.viewer': 'npm:@grapecity/wijmo.viewer/index.js', '@grapecity/wijmo.xlsx': 'npm:@grapecity/wijmo.xlsx/index.js', '@grapecity/wijmo.undo': 'npm:@grapecity/wijmo.undo/index.js', '@grapecity/wijmo.interop.grid': 'npm:@grapecity/wijmo.interop.grid/index.js', '@grapecity/wijmo.barcode': 'npm:@grapecity/wijmo.barcode/index.js', '@grapecity/wijmo.barcode.common': 'npm:@grapecity/wijmo.barcode.common/index.js', '@grapecity/wijmo.barcode.composite': 'npm:@grapecity/wijmo.barcode.composite/index.js', '@grapecity/wijmo.barcode.specialized': 'npm:@grapecity/wijmo.barcode.specialized/index.js', "@grapecity/wijmo.react.chart.analytics": "npm:@grapecity/wijmo.react.chart.analytics/index.js", "@grapecity/wijmo.react.chart.animation": "npm:@grapecity/wijmo.react.chart.animation/index.js", "@grapecity/wijmo.react.chart.annotation": "npm:@grapecity/wijmo.react.chart.annotation/index.js", "@grapecity/wijmo.react.chart.finance.analytics": "npm:@grapecity/wijmo.react.chart.finance.analytics/index.js", "@grapecity/wijmo.react.chart.finance": "npm:@grapecity/wijmo.react.chart.finance/index.js", "@grapecity/wijmo.react.chart.hierarchical": "npm:@grapecity/wijmo.react.chart.hierarchical/index.js", "@grapecity/wijmo.react.chart.interaction": "npm:@grapecity/wijmo.react.chart.interaction/index.js", "@grapecity/wijmo.react.chart.radar": "npm:@grapecity/wijmo.react.chart.radar/index.js", "@grapecity/wijmo.react.chart": "npm:@grapecity/wijmo.react.chart/index.js", "@grapecity/wijmo.react.core": "npm:@grapecity/wijmo.react.core/index.js", '@grapecity/wijmo.react.chart.map': 'npm:@grapecity/wijmo.react.chart.map/index.js', "@grapecity/wijmo.react.gauge": "npm:@grapecity/wijmo.react.gauge/index.js", "@grapecity/wijmo.react.grid.detail": "npm:@grapecity/wijmo.react.grid.detail/index.js", "@grapecity/wijmo.react.grid.filter": "npm:@grapecity/wijmo.react.grid.filter/index.js", "@grapecity/wijmo.react.grid.grouppanel": "npm:@grapecity/wijmo.react.grid.grouppanel/index.js", '@grapecity/wijmo.react.grid.search': 'npm:@grapecity/wijmo.react.grid.search/index.js', "@grapecity/wijmo.react.grid.multirow": "npm:@grapecity/wijmo.react.grid.multirow/index.js", "@grapecity/wijmo.react.grid.sheet": "npm:@grapecity/wijmo.react.grid.sheet/index.js", '@grapecity/wijmo.react.grid.transposed': 'npm:@grapecity/wijmo.react.grid.transposed/index.js', '@grapecity/wijmo.react.grid.transposedmultirow': 'npm:@grapecity/wijmo.react.grid.transposedmultirow/index.js', '@grapecity/wijmo.react.grid.immutable': 'npm:@grapecity/wijmo.react.grid.immutable/index.js', "@grapecity/wijmo.react.grid": "npm:@grapecity/wijmo.react.grid/index.js", "@grapecity/wijmo.react.input": "npm:@grapecity/wijmo.react.input/index.js", "@grapecity/wijmo.react.olap": "npm:@grapecity/wijmo.react.olap/index.js", "@grapecity/wijmo.react.viewer": "npm:@grapecity/wijmo.react.viewer/index.js", "@grapecity/wijmo.react.nav": "npm:@grapecity/wijmo.react.nav/index.js", "@grapecity/wijmo.react.base": "npm:@grapecity/wijmo.react.base/index.js", '@grapecity/wijmo.react.barcode.common': 'npm:@grapecity/wijmo.react.barcode.common/index.js', '@grapecity/wijmo.react.barcode.composite': 'npm:@grapecity/wijmo.react.barcode.composite/index.js', '@grapecity/wijmo.react.barcode.specialized': 'npm:@grapecity/wijmo.react.barcode.specialized/index.js', 'jszip': 'npm:jszip/dist/jszip.js', 'react': 'npm:react/umd/react.production.min.js', 'react-dom': 'npm:react-dom/umd/react-dom.production.min.js', 'redux': 'npm:redux/dist/redux.min.js', 'react-redux': 'npm:react-redux/dist/react-redux.min.js', 'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'jsx' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);