import 'bootstrap.css';
import '@grapecity/wijmo.styles/wijmo.css';
import './app.css';
//
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
//
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: color }}/>
{' '}{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('Export to Excel completed');
resetState();
}, err => {
console.error(`Export to Excel failed: ${err}`);
resetState();
}, prg => {
this.setState({
isExcelPreparing: false,
isExcelExporting: true,
excelProgress: prg,
});
});
console.log('Export to Excel started');
}
else {
exportService.cancelExcelExport(progress => {
console.log('Export to Excel canceled');
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: 'MM/dd/yyyy',
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="Search" cssMatch=""/>
</div>
<div className="toolbar-item col-sm-3 col-md-3">
<div className="input-group">
<span className="input-group-addon">Items:</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 ? `Cancel (${this.state.excelProgress}% done)` : 'Export To Excel'}
</button>
</div>
<div className="toolbar-item col-sm-3 col-md-2">
<button className="btn btn-default btn-block" onClick={this.exportToPdf}>Export To PDF</button>
</div>
</div>
<FlexGridGroupPanel grid={this.state.flex} placeholder={"Drag columns here to create groups"}/>
<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="Date" binding="date" format="MMM d yyyy" isRequired={false} width={130} editor={this._dateEditor}>
</FlexGridColumn>
<FlexGridColumn header="Country" binding="countryId" dataMap={this.countryMap} width={145}>
<FlexGridCellTemplate cellType="Cell" template={this.countryCellTemplate}/>
</FlexGridColumn>
<FlexGridColumn header="Price" binding="price" format="c" isRequired={false} width={100}/>
<FlexGridColumn header="History" binding="history" align="center" width={180} allowSorting={false} cellTemplate={this.historyCellTemplate}/>
<FlexGridColumn header="Change" binding="change" align="right" width={115}>
<FlexGridCellTemplate cellType="Cell" template={this.changeCellTemplate}/>
</FlexGridColumn>
<FlexGridColumn header="Rating" binding="rating" align="center" width={180} cssClass="cell-rating" cellTemplate={this.ratingCellTemplate}/>
<FlexGridColumn header="Time" binding="time" format="HH:mm" isRequired={false} width={95} editor={this._timeEditor}>
</FlexGridColumn>
<FlexGridColumn header="Color" binding="colorId" dataMap={this.colorMap} width={145}>
<FlexGridCellTemplate cellType="Cell" template={this.colorCellTemplate}/>
</FlexGridColumn>
<FlexGridColumn header="Product" binding="productId" dataMap={this.productMap} width={145}/>
<FlexGridColumn header="Discount" binding="discount" format="p0" width={130}/>
<FlexGridColumn header="Active" 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');
}
}
setTimeout(() => {
const container = document.getElementById('app');
if (container) {
const root = ReactDOM.createRoot(container);
root.render(<App dataService={new DataService()} exportService={new ExportService()}/>);
}
}, 100);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>MESCIUS 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 = ['Widget', 'Gadget', 'Doohickey'];
this._colors = ['Black', 'White', 'Red', 'Green', 'Blue'];
this._countries = [
{ id: 0, name: 'US', flag: 'us' },
{ id: 1, name: 'Germany', flag: 'de' },
{ id: 2, name: 'UK', flag: 'gb' },
{ id: 3, name: 'Japan', flag: 'jp' },
{ id: 4, name: 'Italy', flag: 'it' },
{ id: 5, name: 'Greece', 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} can't be less than {1} (${this._products[0]})`),
new MaxNumberValidator(this._products.length - 1, `{0} can't be greater than {1} (${this._products[this._products.length - 1]})`)
],
'countryId': [
new RequiredValidator(),
new MinNumberValidator(0, `{0} can't be less than {1} (${this._countries[0].name})`),
new MaxNumberValidator(this._countries.length - 1, `{0} can't be greater than {1} (${this._countries[this._countries.length - 1].name})`)
],
'colorId': [
new RequiredValidator(),
new MinNumberValidator(0, `{0} can't be less than {1} (${this._colors[0]})`),
new MaxNumberValidator(this._colors.length - 1, `{0} can't be greater than {1} (${this._colors[this._colors.length - 1]})`)
],
'price': [
new RequiredValidator(),
new MinNumberValidator(0, `Price can't be a negative value`)
]
};
}
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: "Across all our software products and services, our focus is on helping our customers achieve their goals. Our key principles – thoroughly understanding our customers' business objectives, maintaining a strong emphasis on quality, and adhering to the highest ethical standards – serve as the foundation for everything we do."
};
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');
//
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, {
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: {
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/${countryName.toLowerCase()}.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);
}
// 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(colorName), wjcCore.Color.fromString('gray'));
// draw color name
e.canvas.drawText(colorName, contentRect.left + imageWidth + 3, e.textTop);
}
// 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 + ' is required';
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} can\'t be less than {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} can\'t be greater than {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} can\'t be less than {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} can\'t be greater than {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} can\'t be less than {1}', format = 'MM/dd/yyyy') {
super(minValue, message, format);
}
_formatValue(value) {
return wjcCore.Globalize.formatDate(value, this.format);
}
}
export class MaxDateValidator extends MaxValueValidator {
constructor(maxValue, message = '{0} can\'t be greater than {1}', format = 'MM/dd/yyyy') {
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',
'react-dom/client': '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);