Goal Seek

Goal Seek is a What-If Analysis tool that finds the input value needed to achieve a specific target result in a formula. It's useful for scenarios where you know the desired outcome but need to determine the input value required to achieve it.

Goal Seek is a powerful What-If Analysis tool that helps you find the input value needed to achieve a specific goal in a formula. This demo demonstrates how to use the GC.Spread.Sheets.CalcEngine.goalSeek API to find the value needed to reach your target. Example Scenarios This demo includes two practical examples: Example 1: Revenue Calculation Unit Price (B3): Starting at $100 Units Sold (B4): 50 units Total Revenue (B5): =B3*B4 (calculates to $5,000) If you want to achieve a revenue of $10,000, Goal Seek can automatically determine what Unit Price or Units Sold value is needed. Example 2: Loan Payment Calculation Loan Amount (B9): $10,000 Term in Months (B10): 18 months Interest Rate (B11): 5.00% (initial value) Monthly Payment (B12): =-PMT(B11/12,B10,B9) If you want a monthly payment of $600, Goal Seek can find the required interest rate (approximately 10%). API Method Signature Parameters Name Type Description changingSheet GC.Spread.Sheets.Worksheet Worksheet that contains the cell to be adjusted. changingRow number Zero-based row index of the cell to be adjusted. changingColumn number Zero-based column index of the cell to be adjusted. formulaSheet GC.Spread.Sheets.Worksheet Worksheet that contains the formula cell. formulaRow number Zero-based row index of the formula cell. formulaColumn number Zero-based column index of the formula cell. desiredResult number Target value that the formula cell should achieve. options IGoalSeekOptions (optional) Optional settings that control the goal seek iteration behavior and accuracy. options.maximumIterations number (optional) Maximum number of iterations. Default: 200. options.tolerance number (optional) Maximum acceptable difference between the formula result and the desired result. Default: 0.001. options.callback (info: IGoalSeekStepInfo) => boolean | void | Promise<boolean | void> (optional) A callback invoked after each iteration. Receives the current trial solution and returns true to stop goal seek early or false/void to continue. When the callback returns a Promise, goal seek waits for that promise to settle before proceeding to the next iteration. The callback can be declared as an async function to perform asynchronous operations such as pausing for visualization. Return Value boolean: For synchronous calls (no incremental calculation and no asynchronous callback), indicates whether a solution was found. Promise<boolean>: For incremental-calculation scenarios or when options.callback is provided, returns a promise that resolves to true if a solution is found, or false otherwise. Sample Notes After calling this API, the changing cell is updated to the found value. If no solution is found, the original value of that cell is restored. If a callback is provided, it is called after each iteration with the current step information. If it returns true (or resolves to true), goalSeek stops early and treats the current value as the final result.
window.onload = function () { var spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 1 }); initSpread(spread); }; function initSpread(spread) { var sheet = spread.getSheet(0); // Set up sample data sheet.setValue(0, 0, 'Goal Seek Example'); sheet.getRange(0, 0, 1, 2).font('bold 14px Arial'); sheet.setValue(2, 0, 'Unit Price:'); sheet.setValue(2, 1, 100); sheet.setFormatter(2, 1, '$#,##0.00'); sheet.setValue(3, 0, 'Units Sold:'); sheet.setValue(3, 1, 50); sheet.setValue(4, 0, 'Total Revenue:'); sheet.setFormula(4, 1, '=B3*B4'); sheet.setFormatter(4, 1, '$#,##0.00'); sheet.getCell(4, 1).backColor('#e3f2fd'); sheet.setColumnWidth(0, 120); sheet.setColumnWidth(1, 100); // Add PMT example sheet.setValue(6, 0, 'Loan Payment Example (PMT)'); sheet.getRange(6, 0, 1, 2).font('bold 14px Arial'); sheet.setValue(8, 0, 'Loan Amount:'); sheet.setValue(8, 1, 10000); sheet.setFormatter(8, 1, '$#,##0.00'); sheet.setValue(9, 0, 'Term (Months):'); sheet.setValue(9, 1, 18); sheet.setValue(10, 0, 'Interest Rate:'); sheet.setValue(10, 1, 0.05); sheet.setFormatter(10, 1, '0.00%'); sheet.setValue(11, 0, 'Monthly Payment:'); sheet.setFormula(11, 1, '=-PMT(B11/12,B10,B9)'); sheet.setFormatter(11, 1, '$#,##0.00'); sheet.getCell(11, 1).backColor('#fff3cd'); // Add instructions sheet.setValue(13, 0, 'Instructions:'); sheet.getCell(13, 0).font('bold 12px Arial'); sheet.setValue(14, 0, '1. Example 1: Use B5 as formula cell to find revenue target'); sheet.setValue(15, 0, '2. Example 2: Use B12 as formula cell with target 600'); sheet.setValue(16, 0, ' and B11 as variable to find required interest rate'); sheet.setValue(17, 0, '3. Enter your values and click "Run Goal Seek"'); // Goal Seek implementation document.getElementById("runGoalSeek").addEventListener('click', function() { var formulaCellRef = document.getElementById("formulaCell").value; var targetValue = parseFloat(document.getElementById("targetValue").value); var variableCellRef = document.getElementById("variableCell").value; var maximumIterations = parseInt(document.getElementById("maximumIterations").value) || 100; var tolerance = parseFloat(document.getElementById("tolerance").value) || 0.001; var resultDiv = document.getElementById("result"); try { var formulaCell = parseCellReference(sheet, formulaCellRef); var variableCell = parseCellReference(sheet, variableCellRef); var seekResult = GC.Spread.Sheets.CalcEngine.goalSeek( variableCell.sheet, variableCell.row, variableCell.col, formulaCell.sheet, formulaCell.row, formulaCell.col, targetValue, { maximumIterations: maximumIterations, tolerance: tolerance }); if (seekResult) { resultDiv.innerHTML = '<div class="success">Goal Seek succeeded!<br/>Found value: ' + formulaCell.sheet.getValue(formulaCell.row, formulaCell.col).toFixed(2) + '</div>'; } else { resultDiv.innerHTML = '<div class="error">Goal Seek could not find a solution.<br/>Try a different target value.</div>'; } } catch (e) { resultDiv.innerHTML = '<div class="error">Error: ' + e.message + '</div>'; } }); } function parseCellReference(sheet, address) { var ranges = GC.Spread.Sheets.CalcEngine.formulaToRanges(sheet, address, 0, 0); if (ranges && ranges.length === 1 && ranges[0].ranges.length === 1 && ranges[0].ranges[0].rowCount === 1 && ranges[0].ranges[0].colCount === 1) { return { sheet: sheet.getParent().getSheetFromName(ranges[0].sheetName), row: ranges[0].ranges[0].row, col: ranges[0].ranges[0].col }; } else { throw new Error('Invalid cell reference: ' + address); } }
<!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"> <label>Set Formula Cell:</label> <input type="text" id="formulaCell" value="B5" placeholder="e.g., B5" /> </div> <div class="option-row"> <label>Target Value:</label> <input type="number" id="targetValue" value="10000" placeholder="e.g., 10000" /> </div> <div class="option-row"> <label>Variable Cell:</label> <input type="text" id="variableCell" value="B3" placeholder="e.g., B3" /> </div> <div class="option-row"> <label>Maximum Iterations:</label> <input type="number" id="maximumIterations" value="100" placeholder="Default: 100" /> </div> <div class="option-row"> <label>Tolerance:</label> <input type="number" id="tolerance" value="0.001" step="0.0001" placeholder="Default: 0.001" /> </div> <div class="option-row"> <input type="button" value="Run Goal Seek" id="runGoalSeek" /> </div> <div class="option-row"> <label>Result:</label> <div id="result" class="result-container"></div> </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; overflow: auto; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; } .option-row { margin-bottom: 12px; } .option-row label { display: block; margin-bottom: 4px; font-weight: bold; font-size: 12px; } input[type=text], input[type=number] { width: 100%; padding: 6px; border: 1px solid #ccc; border-radius: 3px; box-sizing: border-box; } input[type=button] { width: 100%; padding: 8px 6px; margin-bottom: 6px; background: #007acc; color: white; border: none; border-radius: 3px; cursor: pointer; font-weight: bold; } input[type=button]:hover { background: #005a9e; } .result-container { padding: 8px; border-radius: 3px; min-height: 40px; } .success { background: #d4edda; color: #155724; padding: 8px; border-radius: 3px; } .error { background: #f8d7da; color: #721c24; padding: 8px; border-radius: 3px; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }