<template>
<div class="container-fluid">
<div class="row">
<!-- search box -->
<div class="toolbar-item col-sm-3 col-md-5">
<wj-flex-grid-search placeholder="Search" cssMatch="" :initialized="searchInitialized" />
</div>
<!-- data size -->
<div class="toolbar-item col-sm-3 col-md-3">
<div class="input-group">
<span class="input-group-addon">Items:</span>
<select class="form-control" v-model="itemsCount">
<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>
<!-- export to Excel -->
<div class="toolbar-item col-sm-3 col-md-2">
<excel-export-button :exportService="this.exportService" :getFlex="getFlex" />
</div>
<!-- export to PDF -->
<div class="toolbar-item col-sm-3 col-md-2">
<button class="btn btn-default btn-block" @click="exportToPdf">Export To PDF</button>
</div>
</div>
<!-- group panel -->
<wj-group-panel :placeholder="'Drag columns here to create groups'" :initialized="groupPanelInitialized" />
<!-- the grid -->
<wj-flex-grid :autoGenerateColumns="false" :allowAddNew="true" :allowDelete="true"
:allowPinning="'SingleColumn'" :newRowAtTop="true" :showMarquee="true" :selectionMode="'MultiRange'"
:validateEdits="false" :initialized="gridInitialized">
<wj-flex-grid-filter
:filterColumns="['id', 'date', 'time', 'countryId', 'productId', 'colorId', 'price', 'change', 'discount', 'rating', 'active']" />
<wj-flex-grid-column binding="id" header="ID" :width="70" :isReadOnly="true" />
<wj-flex-grid-column binding="date" header="Date" format="MMM d yyyy" :isRequired="false" :width="130"
:editor="editors.inputDate">
</wj-flex-grid-column>
<wj-flex-grid-column binding="countryId" header="Country" :dataMap="countryMap" :width="145">
<wj-flex-grid-cell-template cellType="Cell" v-slot="cell">
<span :class="'flag-icon flag-icon-' + getCountry(cell.item).flag"></span>
{{ getCountry(cell.item).name }}
</wj-flex-grid-cell-template>
</wj-flex-grid-column>
<wj-flex-grid-column binding="price" header="Price" format="c" :isRequired="false" :width="100" />
<wj-flex-grid-column binding="history" header="History" :width="180" align="center" :allowSorting="false"
:cellTemplate="historyCellTemplate">
</wj-flex-grid-column>
<wj-flex-grid-column binding="change" header="Change" align="right" :width="115">
<wj-flex-grid-cell-template cellType="Cell" v-slot="cell">
<span :class="getChangeCls(cell.item.change)">
{{ safeCurrency(cell.item.change) }}
</span>
</wj-flex-grid-cell-template>
</wj-flex-grid-column>
<wj-flex-grid-column binding="rating" header="Rating" :width="180" align="center" cssClass="cell-rating"
:cellTemplate="ratingCellTemplate">
</wj-flex-grid-column>
<wj-flex-grid-column binding="time" header="Time" format="HH:mm" :isRequired="false" :width="95"
:editor="editors.inputTime">
</wj-flex-grid-column>
<wj-flex-grid-column binding="colorId" header="Color" :dataMap="colorMap" :width="145">
<wj-flex-grid-cell-template cellType="Cell" v-slot="cell">
<span class="color-tile" :style="{ background: getColor(cell.item).value }"></span>
{{ getColor(cell.item).value }}
</wj-flex-grid-cell-template>
</wj-flex-grid-column>
<wj-flex-grid-column binding="productId" header="Product" :dataMap="productMap" :width="145" />
<wj-flex-grid-column binding="discount" header="Discount" format="p0" :width="130" />
<wj-flex-grid-column binding="active" header="Active" :width="100" />
</wj-flex-grid>
</div>
</template>
<script>
import '@mescius/wijmo.touch';
import { createApp } from "vue"
import { registerGrid } from '@mescius/wijmo.vue2.grid';
import { registerGridGrouppanel } from '@mescius/wijmo.vue2.grid.grouppanel';
import { registerGridFilter } from '@mescius/wijmo.vue2.grid.filter'
import { registerGridSearch } from "@mescius/wijmo.vue2.grid.search";
import { registerInput } from '@mescius/wijmo.vue2.input';
import * as wjCore from '@mescius/wijmo';
import { InputDate, InputTime } from "@mescius/wijmo.input";
import { DataMap } from '@mescius/wijmo.grid';
import { CellMaker, SparklineMarkers } from '@mescius/wijmo.grid.cellmaker';
import { Country, DataService, KeyValue } from "./data";
import { ExportService } from "./export";
import ExcelExportButton from "./export-btn.vue";
let App = {
name: "App",
components: {
ExcelExportButton
},
data: function () {
return {
itemsCount: 500,
// editors
editors: {
inputDate: new InputDate(document.createElement('div'), {
format: 'MM/dd/yyyy',
isRequired: false
}),
inputTime: new InputTime(document.createElement('div'), {
format: 'HH:mm',
isRequired: false
})
}
};
},
created: function () {
this.dataService = new DataService();
this.exportService = new ExportService();
this._lastId = this.itemsCount;
// initializes data maps
this._productMap = this._buildDataMap(this.dataService.getProducts());
this._countryMap = new DataMap(this.dataService.getCountries(), 'id', 'name');
this._colorMap = this._buildDataMap(this.dataService.getColors());
// 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'
});
},
beforeDestroy() {
this.exportService.cancelExcelExport();
},
methods: {
gridInitialized: function (ctl) {
this.flex = ctl;
this.flex.itemsSource = this._createItemsSource(this.itemsCount);
if (this.groupPanel) {
this.groupPanel.grid = this.flex;
}
if (this.search) {
this.search.grid = this.flex;
}
},
searchInitialized: function (ctl) {
this.search = ctl;
if (this.flex) {
this.search.grid = this.flex;
}
},
groupPanelInitialized: function (ctl) {
this.groupPanel = ctl;
if (this.flex) {
this.groupPanel.grid = this.flex;
}
},
exportToPdf: function () {
this.exportService.exportToPdf(this.flex, {
countryMap: this._countryMap,
colorMap: this._colorMap,
historyCellTemplate: this.historyCellTemplate
});
},
getCountry: function (item) {
const country = this._countryMap.getDataItem(item.countryId);
return country ? country : Country.NotFound;
},
getColor: function (item) {
const color = this._colorMap.getDataItem(item.colorId);
return color ? color : KeyValue.NotFound;
},
getChangeCls: function (value) {
if (wjCore.isNumber(value)) {
if (value > 0) {
return 'change-up';
}
if (value < 0) {
return 'change-down';
}
}
return '';
},
_createItemsSource(counter) {
const data = this.dataService.getData(counter);
const view = new wjCore.CollectionView(data, {
getError: (function (item, prop) {
const displayName = this.flex.columns.getColumn(prop).header;
return this.dataService.validate(item, prop, displayName);
}).bind(this)
});
view.collectionChanged.addHandler((function (s, e) {
// initializes new added item with a history data
if (e.action === wjCore.NotifyCollectionChangedAction.Add) {
e.item.history = this.dataService.getHistoryData();
e.item.id = this._lastId;
this._lastId++;
}
}).bind(this));
return view;
},
// build a data map from a string array using the indices as keys
_buildDataMap: function (items) {
const map = [];
for (let i = 0; i < items.length; i++) {
map.push({ key: i, value: items[i] });
}
return new DataMap(map, 'key', 'value');
},
getFlex: function () {
return this.flex;
},
safeCurrency: function (value) {
if (wjCore.isNumber(value)) {
return wjCore.Globalize.formatNumber(value, 'c');
}
if (!wjCore.isUndefined(value) && value !== null) {
return wjCore.changeType(value, wjCore.DataType.String);
}
return '';
}
},
computed: {
productMap: function () {
return this._productMap;
},
countryMap: function () {
return this._countryMap;
},
colorMap: function () {
return this._colorMap;
},
},
watch: {
itemsCount: function (itemsCount) {
this.flex.itemsSource.collectionChanged.removeAllHandlers();
this._lastId = itemsCount;
this.flex.itemsSource = this._createItemsSource(itemsCount);
},
},
};
const app = createApp(App);
// register all components and directives from Wijmo modules
registerGrid(app)
registerGridGrouppanel(app)
registerGridFilter(app)
registerInput(app)
registerGridSearch(app)
app.mount('#app');
</script>
<style>
@import "./node_modules/bootstrap/dist/css/bootstrap.css";
@import "./node_modules/@mescius/wijmo.styles/wijmo.css";
@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';
}
.change-down {
color: darkred;
}
.change-down:after {
content: '\25bc';
}
.cell-rating {
font-size: 12px;
}
.wj-flexgrid .wj-detail {
padding: 4px 16px;
}
.wj-detail h3 {
margin: 10px 0;
}
</style>
<!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="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.21.5/system.src.js" integrity="sha512-skZbMyvYdNoZfLmiGn5ii6KmklM82rYX2uWctBhzaXPxJgiv4XBwJnFGr5k8s+6tE1pcR1nuTKghozJHyzMcoA==" crossorigin="anonymous"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('./src/app.vue');
</script>
</head>
<body>
<div id="app">
</div>
</body>
</html>
import * as wjcCore from '@mescius/wijmo';
import {
RequiredValidator, MinNumberValidator, MinDateValidator,
MaxNumberValidator, MaxDateValidator
} from './validation';
//
export class KeyValue {
key;
value;
static NotFound = { key: -1, value: '' };
}
//
export class Country {
name;
id;
flag;
static NotFound = { id: -1, name: '', flag: '' };
}
//
export class DataService {
_products = ['Widget', 'Gadget', 'Doohickey'];
_colors = ['Black', 'White', 'Red', 'Green', 'Blue'];
_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'}
];
_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 '@mescius/wijmo';
import * as wjcGrid from '@mescius/wijmo.grid';
import * as wjcGridPdf from '@mescius/wijmo.grid.pdf';
import * as wjcGridXlsx from '@mescius/wijmo.grid.xlsx';
import * as wjcPdf from '@mescius/wijmo.pdf';
import * as wjcXlsx from '@mescius/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 {
static ZapfDingbatsSm = new wjcPdf.PdfFont('zapfdingbats', 8, 'normal', 'normal');
static ZapfDingbatsLg = new wjcPdf.PdfFont('zapfdingbats', 16, 'normal', 'normal');
}
//
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
);
}
cancelExcelExportAsync(doneCollback) {
wjcGridXlsx.FlexGridXlsxConverter.cancelAsync(doneCollback);
}
cancelExcelExport(ctx) {
wjcGridXlsx.FlexGridXlsxConverter.cancelAsync(() => {
console.log('Export to Excel canceled');
this._resetExcelContext(ctx);
});
}
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 '@mescius/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);
}
}
<template>
<button class="btn btn-default btn-block" :disabled="preparing" @click="exportToExcel">
<span v-if="!exporting">Export To Excel</span>
<span v-else>Cancel ({{ percent(progress) }} done)</span>
</button>
</template>
<script>
let ExcelExportBtn = {
name: 'ExcelExportBtn',
props: ['exportService', 'getFlex'],
data: function () {
return {
preparing: false,
exporting: false,
progress: 0,
};
},
methods: {
exportToExcel: function () {
const exportService = this.exportService;
const resetState = () => {
this.preparing = false;
this.exporting = false;
this.progress = 0;
};
if (!this.preparing && !this.exporting) {
this.preparing = true;
exportService.startExcelExport(this.getFlex(),
() => {
console.log('Export to Excel completed');
resetState();
},
err => {
console.error(`Export to Excel failed: ${err}`);
resetState();
},
prg => {
this.preparing = false;
this.exporting = true;
this.progress = prg;
}
);
console.log('Export to Excel started');
} else {
exportService.cancelExcelExportAsync(() => {
console.log('Export to Excel canceled');
resetState();
});
}
},
percent: function (value) {
return `${Math.ceil(value)}%`;
},
}
};
export default ExcelExportBtn;
</script>
(function (global) {
System.config({
transpiler: 'plugin-babel',
babelOptions: {
es2015: true
},
meta: {
'*.css': { loader: 'css' },
'*.vue': { loader: 'vue-loader' }
//'*.vue': { loader: 'systemjs-plugin-vue' }
},
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
'@mescius/wijmo': 'npm:@mescius/wijmo/index.js',
'@mescius/wijmo.input': 'npm:@mescius/wijmo.input/index.js',
'@mescius/wijmo.styles': 'npm:@mescius/wijmo.styles',
'@mescius/wijmo.cultures': 'npm:@mescius/wijmo.cultures',
'@mescius/wijmo.chart': 'npm:@mescius/wijmo.chart/index.js',
'@mescius/wijmo.chart.analytics': 'npm:@mescius/wijmo.chart.analytics/index.js',
'@mescius/wijmo.chart.animation': 'npm:@mescius/wijmo.chart.animation/index.js',
'@mescius/wijmo.chart.annotation': 'npm:@mescius/wijmo.chart.annotation/index.js',
'@mescius/wijmo.chart.finance': 'npm:@mescius/wijmo.chart.finance/index.js',
'@mescius/wijmo.chart.finance.analytics': 'npm:@mescius/wijmo.chart.finance.analytics/index.js',
'@mescius/wijmo.chart.hierarchical': 'npm:@mescius/wijmo.chart.hierarchical/index.js',
'@mescius/wijmo.chart.interaction': 'npm:@mescius/wijmo.chart.interaction/index.js',
'@mescius/wijmo.chart.radar': 'npm:@mescius/wijmo.chart.radar/index.js',
'@mescius/wijmo.chart.render': 'npm:@mescius/wijmo.chart.render/index.js',
'@mescius/wijmo.chart.webgl': 'npm:@mescius/wijmo.chart.webgl/index.js',
'@mescius/wijmo.chart.map': 'npm:@mescius/wijmo.chart.map/index.js',
'@mescius/wijmo.gauge': 'npm:@mescius/wijmo.gauge/index.js',
'@mescius/wijmo.grid': 'npm:@mescius/wijmo.grid/index.js',
'@mescius/wijmo.grid.detail': 'npm:@mescius/wijmo.grid.detail/index.js',
'@mescius/wijmo.grid.filter': 'npm:@mescius/wijmo.grid.filter/index.js',
'@mescius/wijmo.grid.search': 'npm:@mescius/wijmo.grid.search/index.js',
'@mescius/wijmo.grid.grouppanel': 'npm:@mescius/wijmo.grid.grouppanel/index.js',
'@mescius/wijmo.grid.multirow': 'npm:@mescius/wijmo.grid.multirow/index.js',
'@mescius/wijmo.grid.transposed': 'npm:@mescius/wijmo.grid.transposed/index.js',
'@mescius/wijmo.grid.transposedmultirow': 'npm:@mescius/wijmo.grid.transposedmultirow/index.js',
'@mescius/wijmo.grid.pdf': 'npm:@mescius/wijmo.grid.pdf/index.js',
'@mescius/wijmo.grid.sheet': 'npm:@mescius/wijmo.grid.sheet/index.js',
'@mescius/wijmo.grid.xlsx': 'npm:@mescius/wijmo.grid.xlsx/index.js',
'@mescius/wijmo.grid.selector': 'npm:@mescius/wijmo.grid.selector/index.js',
'@mescius/wijmo.grid.cellmaker': 'npm:@mescius/wijmo.grid.cellmaker/index.js',
'@mescius/wijmo.nav': 'npm:@mescius/wijmo.nav/index.js',
'@mescius/wijmo.odata': 'npm:@mescius/wijmo.odata/index.js',
'@mescius/wijmo.olap': 'npm:@mescius/wijmo.olap/index.js',
'@mescius/wijmo.rest': 'npm:@mescius/wijmo.rest/index.js',
'@mescius/wijmo.pdf': 'npm:@mescius/wijmo.pdf/index.js',
'@mescius/wijmo.pdf.security': 'npm:@mescius/wijmo.pdf.security/index.js',
'@mescius/wijmo.viewer': 'npm:@mescius/wijmo.viewer/index.js',
'@mescius/wijmo.xlsx': 'npm:@mescius/wijmo.xlsx/index.js',
'@mescius/wijmo.undo': 'npm:@mescius/wijmo.undo/index.js',
'@mescius/wijmo.interop.grid': 'npm:@mescius/wijmo.interop.grid/index.js',
'@mescius/wijmo.touch': 'npm:@mescius/wijmo.touch/index.js',
'@mescius/wijmo.cloud': 'npm:@mescius/wijmo.cloud/index.js',
'@mescius/wijmo.barcode': 'npm:@mescius/wijmo.barcode/index.js',
'@mescius/wijmo.barcode.common': 'npm:@mescius/wijmo.barcode.common/index.js',
'@mescius/wijmo.barcode.composite': 'npm:@mescius/wijmo.barcode.composite/index.js',
'@mescius/wijmo.barcode.specialized': 'npm:@mescius/wijmo.barcode.specialized/index.js',
"@mescius/wijmo.vue2.chart.analytics": "npm:@mescius/wijmo.vue2.chart.analytics/index.js",
"@mescius/wijmo.vue2.chart.animation": "npm:@mescius/wijmo.vue2.chart.animation/index.js",
"@mescius/wijmo.vue2.chart.annotation": "npm:@mescius/wijmo.vue2.chart.annotation/index.js",
"@mescius/wijmo.vue2.chart.finance.analytics": "npm:@mescius/wijmo.vue2.chart.finance.analytics/index.js",
"@mescius/wijmo.vue2.chart.finance": "npm:@mescius/wijmo.vue2.chart.finance/index.js",
"@mescius/wijmo.vue2.chart.hierarchical": "npm:@mescius/wijmo.vue2.chart.hierarchical/index.js",
"@mescius/wijmo.vue2.chart.interaction": "npm:@mescius/wijmo.vue2.chart.interaction/index.js",
"@mescius/wijmo.vue2.chart.radar": "npm:@mescius/wijmo.vue2.chart.radar/index.js",
'@mescius/wijmo.vue2.chart.map': 'npm:@mescius/wijmo.vue2.chart.map/index.js',
"@mescius/wijmo.vue2.chart": "npm:@mescius/wijmo.vue2.chart/index.js",
"@mescius/wijmo.vue2.core": "npm:@mescius/wijmo.vue2.core/index.js",
"@mescius/wijmo.vue2.gauge": "npm:@mescius/wijmo.vue2.gauge/index.js",
"@mescius/wijmo.vue2.grid.detail": "npm:@mescius/wijmo.vue2.grid.detail/index.js",
"@mescius/wijmo.vue2.grid.filter": "npm:@mescius/wijmo.vue2.grid.filter/index.js",
"@mescius/wijmo.vue2.grid.grouppanel": "npm:@mescius/wijmo.vue2.grid.grouppanel/index.js",
'@mescius/wijmo.vue2.grid.search': 'npm:@mescius/wijmo.vue2.grid.search/index.js',
"@mescius/wijmo.vue2.grid.multirow": "npm:@mescius/wijmo.vue2.grid.multirow/index.js",
"@mescius/wijmo.vue2.grid.sheet": "npm:@mescius/wijmo.vue2.grid.sheet/index.js",
'@mescius/wijmo.vue2.grid.transposed': 'npm:@mescius/wijmo.vue2.grid.transposed/index.js',
'@mescius/wijmo.vue2.grid.transposedmultirow': 'npm:@mescius/wijmo.vue2.grid.transposedmultirow/index.js',
"@mescius/wijmo.vue2.grid": "npm:@mescius/wijmo.vue2.grid/index.js",
"@mescius/wijmo.vue2.input": "npm:@mescius/wijmo.vue2.input/index.js",
"@mescius/wijmo.vue2.olap": "npm:@mescius/wijmo.vue2.olap/index.js",
"@mescius/wijmo.vue2.viewer": "npm:@mescius/wijmo.vue2.viewer/index.js",
"@mescius/wijmo.vue2.nav": "npm:@mescius/wijmo.vue2.nav/index.js",
"@mescius/wijmo.vue2.base": "npm:@mescius/wijmo.vue2.base/index.js",
'@mescius/wijmo.vue2.barcode.common': 'npm:@mescius/wijmo.vue2.barcode.common/index.js',
'@mescius/wijmo.vue2.barcode.composite': 'npm:@mescius/wijmo.vue2.barcode.composite/index.js',
'@mescius/wijmo.vue2.barcode.specialized': 'npm:@mescius/wijmo.vue2.barcode.specialized/index.js',
'bootstrap.css': 'npm:bootstrap/dist/css/bootstrap.min.css',
'jszip': 'npm:jszip/dist/jszip.js',
'css': 'npm:systemjs-plugin-css/css.js',
'vue': 'npm:vue/dist/vue.cjs.js',
'@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js',
'@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js',
'@vue/shared':'npm:@vue/shared/dist/shared.cjs.js',
'@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js',
'@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js',
'@vue/shared':'npm:@vue/shared/dist/shared.cjs.js',
'@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js',
'@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js',
'@vue/shared':'npm:@vue/shared/dist/shared.cjs.js',
'@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js',
'@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js',
'@vue/shared':'npm:@vue/shared/dist/shared.cjs.js',
'@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js',
'@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js',
'@vue/shared':'npm:@vue/shared/dist/shared.cjs.js',
'@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js',
'@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js',
'@vue/shared':'npm:@vue/shared/dist/shared.cjs.js',
'@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js',
'@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js',
'@vue/shared':'npm:@vue/shared/dist/shared.cjs.js',
'@vue/compiler-dom':'npm:@vue/compiler-dom/dist/compiler-dom.global.prod.js',
'@vue/runtime-dom':'npm:@vue/runtime-dom/dist/runtime-dom.global.prod.js',
'@vue/shared':'npm:@vue/shared/dist/shared.cjs.js',
'vue-loader': 'npm:systemjs-vue-browser/index.js',
//'systemjs-plugin-vue': 'npm:systemjs-plugin-vue/index.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: 'js'
},
rxjs: {
defaultExtension: 'js'
},
"node_modules": {
defaultExtension: 'js'
},
wijmo: {
defaultExtension: 'js',
}
}
});
})(this);