# PivotGrid Customizations

Learn how to customize cells of Wijmo's OLAP PivotGrid in this tutorial

## Content

## Custom Cells

The **PivotGrid** extends the **FlexGrid** control, so you can customize the display of the grid cells using the **formatItem** event and modify the content of each cell with complete flexibility.

The **PivotGrid** below uses colors and icons similar to the ones in Microsoft Excel's icon sets to show how sales changed from quarter to quarter:

![pivot-grid-customize-cells](https://cdn.mescius.io/document-site-files/images/3c7113e2-10b3-45ed-8f3b-9fb1e0af2b74/pivot-grid-customize-cells.02456a.png)

```javascript
var pivotGrid = new wjOlap.PivotGrid('#pivotGrid', {
    isReadOnly: true,
    itemsSource: ngFmt,
    formatItem: formatItem // customize the grid cells
});

function formatItem(s, e) {

    // we are interested in the cells panel
    if (e.panel == s.cells) {

    // remove custom color by default
    var color = '';

    // format diff columns if custom formatting is on
    if (e.col % 2 == 1 && customCells.checked) {
        var value = s.getCellData(e.row, e.col),
        glyph = 'circle',
        span = ' <span style="font-size:120%" class="wj-glyph-{glyph}"></span>';
        color = '#d8b400';
        if (value != null) {
        if (value < 0) { // negative variation
            color = '#9f0000';
            glyph = 'down';
        } else if (value > 0.05) { // positive variation
            color = '#4c8f00';
            glyph = 'down';
        }
        e.cell.innerHTML += span.replace('{glyph}', glyph);
        }
    }

    // apply cell color
    e.cell.style.color = color;
    }
}
```

## Sparklines

You can use the **formatItem** event to add custom content such as sparklines and sparkbars to grid cells also.

This example adds two extra fields to a PivotEngine and uses the formatItem event to add sparklines and sparkbars to the extra fields.

To do this, the sample uses the engine's getDetail method to retrieve the detail records for each cell and uses that data to build svg elements displayed in each cell. The cell details are stored in the data item so they can be re-used when the grid scrolls.

![Pivot Grid Sparklines](https://cdn.mescius.io/document-site-files/images/3c7113e2-10b3-45ed-8f3b-9fb1e0af2b74/olap/pivot-grid-sparklines.png)

Refer to the Pivot Grid Sparklines demo for an example.

```javascript
var pivotGrid = new wjOlap.PivotGrid('#pivotGrid', {
  	isReadOnly: true,
    itemsSource: ng,
    formatItem: formatItem // customize the grid cells
});

// use formatItem to add sparklines and/or sparkbars
var maxSparkLength = 25;
function formatItem(s, e) {

  	// we want the cells panel
	if (e.panel == s.cells) {

			// we want the 'Sparklines' and 'Sparkbars' value fields
		var ng = s.engine,
      		field = ng.valueFields[e.col % ng.valueFields.length],
        	item = s.rows[e.row].dataItem,
        	binding = s.columns[e.col].binding,
        	spark = field.header == 'Sparklines' || field.header == 'Sparkbars';

		// add/remove spark class
    	wijmo.toggleClass(e.cell, 'spark', spark);

      	// add sparklines
      	if (spark) {

			// if we have the data, show it
			if (item.sparkData) {
				var data = item.sparkData,
					delta = data[data.length -1] - data[0];
					e.cell.innerHTML = field.header == 'Sparklines' ? getSparklines(item.sparkData) : getSparkbars(item.sparkData);
				wijmo.toggleClass(e.cell, 'spark-up', delta > 0);
				wijmo.toggleClass(e.cell, 'spark-down', delta < 0);
			}

        	// we dont have the data yet, so go get it
        	if (!item.sparkData) {
        		e.cell.innerHTML = '';
          		setTimeout(function() {
          			var detail = s.engine.getDetail(item, binding),
								len = detail.length;
					if (len > maxSparkLength) {
						detail = detail.slice(len - maxSparkLength);
					}
					item.sparkData = detail.map(function(dataItem) {
						return dataItem.sales;
					});
					s.invalidate(); // invalidate to show the sparlines
				});
        	}
      	}
    }
}

// generate sparklines as SVG
function getSparklines(data) {
	var svg = '<svg width="100%" height="100%">',
		min = Math.min.apply(Math, data),
		max = Math.max.apply(Math, data),
		x1 = 0,
		y1 = scaleY(data[0], min, max);
		for (var i = 1; i < data.length; i++) {
			var x2 = Math.round((i) / (data.length - 1) * 100),
				y2 = scaleY(data[i], min, max);
			svg += '<line x1=' + x1 + '% y1=' + y1 + '% x2=' + x2 + '% y2=' + y2 + '% />';
			x1 = x2;
			y1 = y2;
		}
		svg += '</svg>';
		return svg;
}
function getSparkbars(data) {
	var svg = '<svg width="100%" height="100%">',
        min = Math.min.apply(Math, data),
        max = Math.max.apply(Math, data),
    	base = Math.min(max, Math.max(min, 0)),
    	basey = scaleY(base, min, max),
    	w = Math.round(100 / data.length) - 2;
    for (var i = 0; i < data.length; i++) {
    	var x = i * Math.round(100 / data.length) + 1,
            y = scaleY(data[i], min, max);
        svg += '<rect x=' + x + '% width=' + w + '% y=' + Math.min(y, basey) + '% height=' + Math.abs(y - basey) + '% />';
	}
	svg += '<rect x=0% width=100% height=1 y=' + basey + '% opacity=.5 />';
	svg += '</svg>';
	return svg;
}
function scaleY(value, min, max) {
	return 100 - Math.round((value - min) / (max - min) * 100);
}
```

## HTML Content

Use the **PivotField**'s **isContentHtml** property to render fields that contain HTML instead of plain text.

For example, in the array below the "Buyer" and "Type" fields are bound to properties that contain HTML text:

```javascript
[
	{
		date: new Date(yr, 0, 1),
		buyer: '<span class="initial">M</span>om',
		type: '<span class="initial">F</span>uel',
		amount: 74
	},
	{
		date: new Date(yr, 0, 15),
		buyer: '<span class="initial">M</span>om',
		type: '<span class="initial">F</span>ood',
		amount: 235
	},
	{
		date: new Date(yr, 0, 17),
		buyer: '<span class="initial">D</span>ad',
		type: '<span class="initial">S</span>ports',
		amount: 20
	},
	{
		date: new Date(yr, 0, 21),
		buyer: '<span class="initial">K</span>elly',
		type: '<span class="initial">B</span>ooks',
		amount: 125
	},
	{
		date: new Date(yr, 1, 2),
		buyer: '<span class="initial">M</span>om',
		type: '<span class="initial">F</span>ood',
		amount: 235
	},
	{
	date: new Date(yr, 1, 20),
	buyer: '<span class="initial">K</span>elly',
	type: '<span class="initial">M</span>usic',
	amount: 20
	},
	{
	date: new Date(yr, 1, 25),
	buyer: '<span class="initial">K</span>elly',
	type: '<span class="initial">T</span>ickets',
	amount: 125
	},
];
```

To enable the content to render HTML, set **isContentHTML** to **true**.

```javascript
var ng = new wjOlap.PivotEngine({
    itemsSource: getData(), // raw data
    valueFields: ['Amount'], // summarize amounts
    rowFields: ['Buyer', 'Type'] // summarize amounts
});

ng.fields.getField('Buyer').isContentHtml = true;
ng.fields.getField('Type').isContentHtml = true;
```

##### Result

![isContentHTML](https://cdn.mescius.io/document-site-files/images/3c7113e2-10b3-45ed-8f3b-9fb1e0af2b74/olap/pivot-grid-is-content-html.png)