Calculation Service

SpreadJS gives you the ability to suspend the evaluation of formulas and switch the calculation mode to manual using the calculate API.

Description
app.js
index.html
styles.css
Copy to CodeMine

Suspend Calculation Service

Users can suspend the calculation service for a better experience when calling API in batches. For example:

spread.suspendPaint();
spread.suspendCalcService();
sheet.setFormula(0, 1, "SUM(A:A)");
for (var i = 0; i < 100; i++) {
    sheet.setValue(i, 0, i); // if not suspended, each setValue will calculate the B1 formula.
}
spread.resumeCalcService();
spread.resumePaint();

Calculation Options

SpreadJS supports a CalculationMode which can be set to manual or automatic.

Automatic Calculation (default) Calculate all dirty cells every time the relevant data is changed, like when something has been entered or copy-pasted in a cell.

Manual Calculation Only evaluate a formula when that formula is entered or updated, and keep its dependencies dirty. When cutting/copying-pasting, this mode will set the formula and the cell value, but won’t recalculate any formulas.

Calculate API

You can force calculation by calling the calculate API.
The Calculate function will rebuild, mark dirty, broadcast dirty and calculate the dirty cells.

  • First rebuild and mark cells in the formula reference as dirty using the calculation type. The list of `GC.Spread.Sheets.CalculationType` is as follows:
    • all - The default calculation type that mark cells in the range as dirty for calculation.
    • rebuild - Rebuild all the formula models in the range and then mark them as dirty for calculation.
    • minimal - Keep the current cell calculation dirty status.
    • regular - Mark the volatile and circular reference cells as dirty for calculation.
  • Broadcasting dirty cells will recursively set the dependents of dirty cells to dirty in the workbook.
  • The last step is calculate. In automatic mode, all the dirty cells will be calculated. In manual mode, only the cells in the formula reference are calculated, other cells will keep their dirty state.

For example:

 spread.sheets[0].setFormula(0,0,"RAND()");
 spread.sheets[0].setFormula(1,0,"=Sheet2!A1");
 spread.sheets[1].setFormula(0,0,"RAND()");
 spread.sheets[1].setFormula(1,0,"=Sheet1!A1");
 spread.calculate(GC.Spread.Sheets.CalculationType.all, "Sheet1"); // The Sheet1!A1 will generate a new random number, but Sheet2!A1 keeps th old value.  Sheet2!A2 keeps the old value when it's in manual calculation mode.
 spread.calculate(); // All the cells are recalculated.
Suspend Calculation Service Users can suspend the calculation service for a better experience when calling API in batches. For example: Calculation Options SpreadJS supports a CalculationMode which can be set to manual or automatic. Automatic Calculation (default) Calculate all dirty cells every time the relevant data is changed, like when something has been entered or copy-pasted in a cell. Manual Calculation Only evaluate a formula when that formula is entered or updated, and keep its dependencies dirty. When cutting/copying-pasting, this mode will set the formula and the cell value, but won’t recalculate any formulas. Calculate API You can force calculation by calling the calculate API. The Calculate function will rebuild, mark dirty, broadcast dirty and calculate the dirty cells. First rebuild and mark cells in the formula reference as dirty using the calculation type. The list of `GC.Spread.Sheets.CalculationType` is as follows: all - The default calculation type that mark cells in the range as dirty for calculation. rebuild - Rebuild all the formula models in the range and then mark them as dirty for calculation. minimal - Keep the current cell calculation dirty status. regular - Mark the volatile and circular reference cells as dirty for calculation. Broadcasting dirty cells will recursively set the dependents of dirty cells to dirty in the workbook. The last step is calculate. In automatic mode, all the dirty cells will be calculated. In manual mode, only the cells in the formula reference are calculated, other cells will keep their dirty state. For example:
window.onload = function () { var spread = new GC.Spread.Sheets.Workbook(_getElementById("ss")); initSpread(spread); }; function initSpread(spread) { var sheet = spread.getActiveSheet(); spread.setSheetCount(2); var sheet2 = spread.sheets[1]; spread.suspendPaint(); spread.suspendCalcService(); spread.options.iterativeCalculationMaximumIterations = 1; spread.options.iterativeCalculationMaximumChange = 10; sheet.setValue(0,0,"Tick:"); sheet.setFormula(0,1,"=REFRESH(B1+1,2,80)"); sheet.setValue(2,0,"Value:"); sheet.setFormula(2,1,"=IFERROR(CHOOSE(MOD(B1,16),5,-5,20,-2),0)+RAND()"); sheet.setValue(0,4,"Values:"); sheet.getRange(1,4,60,1).formula("=IF(MOD($B$1,60)=(ROW()-2),$B$3,E2)", true); sheet2.setValue(0,6,"Values:"); sheet2.getRange(1,6,60,1).formula("=OFFSET(Sheet1!$E$2,MOD(Sheet1!$B$1-1+ROW(),60),0)", true); sheet.setValue(1,6,'Value Sparkline:'); sheet.addSpan(2,6,6,6); sheet.setFormula(2,6,'=LINESPARKLINE(E2:E61,0,,,)'); sheet.setValue(10,6,'Sheet2 reorder values:'); sheet.addSpan(11,6,6,6); sheet.setFormula(11,6,'=LINESPARKLINE(Sheet2!G2:G61,0,,,)'); spread.resumeCalcService(); spread.resumePaint(); bindEvent(spread); } function bindEvent (spread) { _getElementById("enableCalcService").addEventListener('change', function () { if (this.checked) { spread.resumeCalcService(); } else { spread.suspendCalcService(); } }); _getElementById("calculationMode").addEventListener('change', function () { console.log(JSON.stringify(this.value)); if (this.value === "0") { spread.options.calculationMode = GC.Spread.Sheets.CalculationMode.auto; spread.calculate(false); } else { spread.options.calculationMode = GC.Spread.Sheets.CalculationMode.manual; } }); _getElementById("calculateSpread").addEventListener('click', function () { let type = _getElementById("calculationType").value; spread.calculate(GC.Spread.Sheets.CalculationType[type]); }); _getElementById("calculateSheet").addEventListener('click', function () { let type = _getElementById("calculationType").value; spread.calculate(GC.Spread.Sheets.CalculationType[type], spread.getActiveSheet().name()); }); _getElementById("calculateRange").addEventListener('click', function () { let type = _getElementById("calculationType").value; let sheet = spread.getActiveSheet(); let range = sheet.getSelections()[0]; spread.calculate(GC.Spread.Sheets.CalculationType[type], sheet.name()+"!"+GC.Spread.Sheets.CalcEngine.rangeToFormula(range)); }); } function _getElementById(id) { return document.getElementById(id); }
<!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/purejs/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script> <script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> <link rel="stylesheet" type="text/css" href="styles.css"> </head> <body> <div class="sample-tutorial"> <div id="ss" class="sample-spreadsheets"></div> <div class="options-container"> <div class="option-row"> <input style="width: 20px;float: left;" type="checkbox" id="enableCalcService" checked="checked"/> <label for="enableCalcService">enable Calculation Service</label> </div> <div class="option-row"> <p>Change the Calculation Mode and input formulas to see the calculation behavior. </p> <label for="calculationMode">Calculation Mode</label> <select id="calculationMode"> <option value="0">Automatic</option> <option value="1">Manual</option> </select> </div> <div class="option-row"> <p>Check the different calculate scopes with different calculation types in different calculation modes. </p> <label for="calculationType">Calculation Type</label> <select id="calculationType"> <option value="all">All</option> <option value="rebuild">Rebuild</option> <option value="minimal">Minimal</option> <option value="regular">Regular</option> </select> <button id="calculateSpread">Calculate Spread</button> <br /> <button id="calculateSheet">Calculate Sheet</button> <br /> <button id="calculateRange">Calculate Selection</button> </div> </div> </div></body> </html>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 280px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 280px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding: 5px; margin-top: 10px; } input { margin-bottom: 5px; padding: 2px 4px; width: 100%; box-sizing: border-box; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }