Pivot Conditional Rules

You can apply, get, and remove conditional formatting rules in a pivot area. The conditional rules work as expected irrespective of the changes to PivotTable layout.

The following demo applies different color formatting depending on the cell values, with green being the lowest and red the highest.

PivotTable offers the ability to set conditional rules to specific dimensions. No matter how the PivotTable layout changes, the conditional rules are only applied the specified dimensions. Add a conditionalRule with the setConditionalRule API Get a conditionalRule with the getConditionalRulee API Remove a conditionalRule with the removeConditionalRule API
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import './styles.css'; import { AppFunc } from './app-func'; import { App } from './app-class'; // 1. Functional Component sample ReactDOM.render(<AppFunc />, document.getElementById('app')); // 2. Class Component sample // ReactDOM.render(<App />, document.getElementById('app'));
import * as React from 'react'; import GC from '@mescius/spread-sheets'; import "@mescius/spread-sheets-shapes"; import "@mescius/spread-sheets-pivot-addon"; import { SpreadSheets } from '@mescius/spread-sheets-react'; import './styles.css'; const useState = React.useState; let currentIndex = 0; const scaleRule = new GC.Spread.Sheets.ConditionalFormatting.ScaleRule(11, 1, 0, "#82bc00", 0, 40000, "#f7ea00", 2, 100000, "#e45d5d"); export function AppFunc() { const [spread, setSpread] = useState(null); const [pivotTable, setPivotTable] = useState(null); const names = ['Alan', "Bob", "John", "Serena", "Tess"]; const namesCount = names.length; const getCurrentPivotAreas = (isPrev) => { if (isPrev) { if (currentIndex === 0) { currentIndex = namesCount * 10; } currentIndex--; } else { currentIndex++; } return [ { dataOnly: true, references: [{ fieldName: "Salesperson", items: [names[currentIndex % namesCount]] }, { fieldName: "Cars" }] } ]; } const switchRegionUp = () => { spread.suspendPaint(); pivotTable.removeConditionalRule(scaleRule); pivotTable.addConditionalRule(getCurrentPivotAreas(true), scaleRule); spread.resumePaint(); } const switchRegionDown = () => { spread.suspendPaint(); pivotTable.removeConditionalRule(scaleRule); pivotTable.addConditionalRule(getCurrentPivotAreas(), scaleRule); spread.resumePaint(); } const switchLayoutType = (e) => { if (spread) { let type = parseInt(e.target.value, 10); pivotTable.layoutType(type); pivotTable.autoFitColumn(); } } const initSpread = (spread) => { setSpread(spread); spread.suspendPaint(); spread.setSheetCount(2); let sheet1 = spread.getSheet(0); let sheet2 = spread.getSheet(1); let tableName = getDataSource(sheet2, pivotSales); let pivotTable = initPivotTable(sheet1, tableName); setPivotTable(pivotTable); spread.resumePaint(); } const getDataSource = (sheet, tableSource) => { sheet.name("DataSource"); sheet.setRowCount(117); sheet.setColumnWidth(0, 120); sheet.getCell(-1, 0).formatter("YYYY-mm-DD"); sheet.getRange(-1, 4, 0, 2).formatter("$ #,##0"); let table = sheet.tables.add('table', 0, 0, 117, 6); for (let i = 2; i <= 117; i++) { sheet.setFormula(i - 1, 5, '=D' + i + '*E' + i) } table.style(GC.Spread.Sheets.Tables.TableThemes["none"]); sheet.setArray(0, 0, tableSource); return table.name(); } const initPivotTable = (sheet, tableName) => { sheet.name("PivotTable"); sheet.setRowCount(1000); let pivotTableOptions = { bandRows: true, bandColumns: true }; let pivotTable = sheet.pivotTables.add("PivotTable", tableName, 1, 1, GC.Spread.Pivot.PivotTableLayoutType.outline, GC.Spread.Pivot.PivotTableThemes.light8, pivotTableOptions); pivotTable.suspendLayout(); pivotTable.add("salesperson", "Salesperson", GC.Spread.Pivot.PivotTableFieldType.rowField); pivotTable.add("car", "Cars", GC.Spread.Pivot.PivotTableFieldType.rowField); let groupInfo = { originFieldName: "date", dateGroups: [{ by: GC.Pivot.DateGroupType.quarters }] }; pivotTable.group(groupInfo); pivotTable.add("Quarters (date)", "Quarters (date)", GC.Spread.Pivot.PivotTableFieldType.columnField); pivotTable.add("total", "Totals", GC.Spread.Pivot.PivotTableFieldType.valueField, GC.Pivot.SubtotalType.sum); let pivotArea = { dataOnly: true, references: [{ fieldName: "Salesperson", items: ["Alan"] }, { fieldName: "Cars" }] }; pivotTable.addConditionalRule([pivotArea], scaleRule); let style = new GC.Spread.Sheets.Style(); style.formatter = "$ #,##0"; pivotTable.setStyle({ dataOnly: true }, style); pivotTable.resumeLayout(); pivotTable.autoFitColumn(); return pivotTable; } return ( <div class="sample-tutorial"> <div class="sample-spreadsheets"> <SpreadSheets workbookInitialized={spread => initSpread(spread)}> </SpreadSheets> </div> <div id="container" class="options-container"> <div class="option-row"> <label><b>Settings:</b> </label> </div> <hr /> <div class="option-row"> <label>Click the <b>MoveNext</b> or <b>MovePrev</b> buttons to apply the conditional rule to the Salesperson above or below the currently highlighted dimension. </label> </div> <input type="button" value="MovePrev" className="set-option" id="switch-region-up" onClick={switchRegionUp} /> <br /> <input type="button" value="MoveNext" className="set-option" id="switch-region-down" onClick={switchRegionDown} /> <br /> <hr /> <div class="option-row"> <label>Change the dropdown menu below to see how changing pivot table layout affects the conditional rules. </label> </div> <br /> <div class="option-row"> <select id="layoutType" onChange={(e) => { switchLayoutType(e) }}> <option value="0">Compact Form</option> <option value="1" selected>Outline Form</option> <option value="2">Tabular Form</option> </select> </div> </div> </div> ); }
import * as React from 'react'; import GC from '@mescius/spread-sheets'; import "@mescius/spread-sheets-shapes"; import "@mescius/spread-sheets-pivot-addon"; import { SpreadSheets } from '@mescius/spread-sheets-react'; import './styles.css'; const Component = React.Component; export class App extends Component { constructor(props) { super(props); this.scaleRule = new GC.Spread.Sheets.ConditionalFormatting.ScaleRule(11, 1, 0, "#82bc00", 0, 40000, "#f7ea00", 2, 100000, "#e45d5d"); this.names = ['Alan', "Bob", "John", "Serena", "Tess"]; this.namesCount = this.names.length; this.currentIndex = 0; this.switchRegionUp = this.switchRegionUp.bind(this); this.switchRegionDown = this.switchRegionDown.bind(this); } getCurrentPivotAreas() { return [ { dataOnly: true, references: [{ fieldName: "Salesperson", items: [this.names[this.currentIndex % this.namesCount]] }, { fieldName: "Cars" }] } ]; } getNextPivotAreas() { this.currentIndex++; return this.getCurrentPivotAreas(); } getPreviousPivotAreas() { if (this.currentIndex === 0) { this.currentIndex = this.namesCount * 10; } this.currentIndex--; return this.getCurrentPivotAreas(); } switchRegionUp() { let pivotTable = this.pivotTable; this.spread.suspendPaint(); pivotTable.removeConditionalRule(this.scaleRule); pivotTable.addConditionalRule(this.getPreviousPivotAreas(), this.scaleRule); this.spread.resumePaint(); } switchRegionDown() { let pivotTable = this.pivotTable; this.spread.suspendPaint(); pivotTable.removeConditionalRule(this.scaleRule); pivotTable.addConditionalRule(this.getNextPivotAreas(), this.scaleRule); this.spread.resumePaint(); } switchLayoutType(e) { let spread = this.spread; if (spread) { let type = parseInt(e.target.value, 10); this.pivotTable.layoutType(type); this.pivotTable.autoFitColumn(); } } render() { return ( <div class="sample-tutorial"> <div class="sample-spreadsheets"> <SpreadSheets workbookInitialized={spread => this.initSpread(spread)}> </SpreadSheets> </div> <div id="container" class="options-container"> <div class="option-row"> <label><b>Settings:</b> </label> </div> <hr /> <div class="option-row"> <label>Click the <b>MoveNext</b> or <b>MovePrev</b> buttons to apply the conditional rule to the Salesperson above or below the currently highlighted dimension. </label> </div> <input type="button" value="MovePrev" className="set-option" id="switch-region-up" onClick={this.switchRegionUp} /> <br /> <input type="button" value="MoveNext" className="set-option" id="switch-region-down" onClick={this.switchRegionDown} /> <br /> <hr /> <div class="option-row"> <label>Change the dropdown menu below to see how changing pivot table layout affects the conditional rules. </label> </div> <br /> <div class="option-row"> <select id="layoutType" onChange={(e) => { this.switchLayoutType(e) }}> <option value="0">Compact Form</option> <option value="1" selected>Outline Form</option> <option value="2">Tabular Form</option> </select> </div> </div> </div> ); } initSpread(spread) { this.spread = spread; spread.suspendPaint(); spread.setSheetCount(2); let sheet1 = spread.getSheet(0); let sheet2 = spread.getSheet(1); let tableName = this.getDataSource(sheet2, pivotSales); let pivotTable = this.initPivotTable(sheet1, tableName); this.pivotTable = pivotTable; spread.resumePaint(); } getDataSource(sheet, tableSource) { sheet.name("DataSource"); sheet.setRowCount(117); sheet.setColumnWidth(0, 120); sheet.getCell(-1, 0).formatter("YYYY-mm-DD"); sheet.getRange(-1, 4, 0, 2).formatter("$ #,##0"); let table = sheet.tables.add('table', 0, 0, 117, 6); for (let i = 2; i <= 117; i++) { sheet.setFormula(i - 1, 5, '=D' + i + '*E' + i) } table.style(GC.Spread.Sheets.Tables.TableThemes["none"]); sheet.setArray(0, 0, tableSource); return table.name(); } initPivotTable(sheet, tableName) { sheet.name("PivotTable"); sheet.setRowCount(1000); let pivotTableOptions = { bandRows: true, bandColumns: true }; let pivotTable = sheet.pivotTables.add("PivotTable", tableName, 1, 1, GC.Spread.Pivot.PivotTableLayoutType.outline, GC.Spread.Pivot.PivotTableThemes.light8, pivotTableOptions); pivotTable.suspendLayout(); pivotTable.add("salesperson", "Salesperson", GC.Spread.Pivot.PivotTableFieldType.rowField); pivotTable.add("car", "Cars", GC.Spread.Pivot.PivotTableFieldType.rowField); let groupInfo = { originFieldName: "date", dateGroups: [{ by: GC.Pivot.DateGroupType.quarters }] }; pivotTable.group(groupInfo); pivotTable.add("Quarters (date)", "Quarters (date)", GC.Spread.Pivot.PivotTableFieldType.columnField); pivotTable.add("total", "Totals", GC.Spread.Pivot.PivotTableFieldType.valueField, GC.Pivot.SubtotalType.sum); let pivotArea = { dataOnly: true, references: [{ fieldName: "Salesperson", items: ["Alan"] }, { fieldName: "Cars" }] }; pivotTable.addConditionalRule([pivotArea], this.scaleRule); let style = new GC.Spread.Sheets.Style(); style.formatter = "$ #,##0"; pivotTable.setStyle({ dataOnly: true }, style); pivotTable.resumeLayout(); pivotTable.autoFitColumn(); return pivotTable; } }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/react/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/spread/source/data/pivot-data.js" type="text/javascript"></script> <!-- SystemJS --> <script src="$DEMOROOT$/en/react/node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('$DEMOROOT$/en/lib/react/license.js').then(function () { System.import('./src/app'); }); </script> </head> <body> <div id="app" style="height: 100%;"></div> </body> </html>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 300px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 300px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; } .set-option { display: block; margin-top: 20px; width: 250px; } #reportFilterFieldsPerColumn { width: 28px; } .select-option-class{ display: block; margin-top: 20px; margin-bottom: 10px } .select-option-select{ width: 250px; display: block; margin-bottom: 20px; } .option-item{ height: 20px; margin-bottom: 10px; }
(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: { '@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-shapes': 'npm:@mescius/spread-sheets-shapes/index.js', '@mescius/spread-sheets-pivot-addon': 'npm:@mescius/spread-sheets-pivot-addon/index.js', '@mescius/spread-sheets-react': 'npm:@mescius/spread-sheets-react/index.js', '@grapecity/jsob-test-dependency-package/react-components': 'npm:@grapecity/jsob-test-dependency-package/react-components/index.js', 'react': 'npm:react/umd/react.production.min.js', 'react-dom': 'npm:react-dom/umd/react-dom.production.min.js', '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);