[]
        
(Showing Draft Content)

ワークシート外での数式計算

SpreadJS には強力な計算エンジンが搭載されており、ワークシートのセル以外でも数式の評価や計算を行うことができます。GC.Spread.Sheets.CalcEngine モジュールには、ワークシートに直接数式を設定せずに、数式の解析・評価・変換を行うためのユーティリティメソッドがいくつか用意されています。

機能説明の例として、以下のような売上データを含むテーブル(「Table1」)を使用して説明します。

image

evaluateFormula: 指定した数式文字列を評価し、結果を返します。

利用シーン:

  • ワークシートのレンダリングやユーザー操作に依存せず、コード内で動的に数式の結果を計算する必要がある場合(例えば、バックエンドでデータを処理する時や数式ロジックを一括検証する時)に使用します。

  • 配列数式の複数の出力を保持したい場合は、preserveArrayResult: true を指定して、完全な配列を取得してください。

  • コード内でR1C1形式の数式を生成または解析する必要がある場合に使用します。

メソッド: evaluateFormula(context, formula, baseRow?, baseColumn?, useR1C1?, preserveArrayResult?)

パラメーター:

  • context(Object) – 評価コンテキスト(通常はアクティブなシートオブジェクト)。

  • formula(string) – 評価する数式文字列。

  • baseRow(number, optional) – 相対参照の基準となる行インデックス。

  • baseColumn(number, optional) – 相対参照の基準となる列インデックス。

  • useR1C1(boolean, optional) – R1C1参照形式を使用するかどうか(デフォルト:false)。

  • preserveArrayResult(boolean, optional) – trueの場合は配列結果を返し、falseの場合は単一の値を返します。

例 1: 計算結果を直接取得します。

var sheet = spread.getActiveSheet();
GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, '=SUM(Table1[[#Data],[Units]])')
//結果: 84878

例 2: baseRow と baseColumn を使った相対参照の利用。

var sheet = spread.getActiveSheet();
GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, '=Table1[@[Sales Rep]]',2,0);
//結果: Tom
GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, '=Table1[@[Sales Rep]]',5,0);
//結果: Sal
GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, '=Table1[@[Sales Rep]]',12,0);
//結果: Amy

例 3: baseRow と baseColumn を使ってR1C1形式を利用する。

var sheet = spread.getActiveSheet();
GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, '=R[3]C[3]',0,0,true);
//結果: Grape
GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, '=R[3]C[3]',2,1,true);
//結果: 5323

例 4: preserveArrayResult を使って配列の結果を取得する。

var sheet = spread.getActiveSheet();
spread.options.allowDynamicArray = true; 
GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, '=UNIQUE(Table1[[#Data],[Product]])')
//結果: Apple
GC.Spread.Sheets.CalcEngine.evaluateFormula(sheet, '=UNIQUE(Table1[[#Data],[Product]])',null,null,null,true)
//結果: [['Apple'],['Grape'],['Pear'],['Banana']]

evaluateFormulaAsync: 指定された数式文字列を評価し、その結果を Promise として返します。

AsyncFunctionEvaluateMode.onInterval または REFRESH 関数には対応していません。

使用例:

  • 非同期タスクを実行するカスタム関数を使用する場合。

  • 非同期でデータを返す API またはデータソースと統合する場合。

  • ユーザーインターフェースをフリーズさせたくない長時間実行の計算を行う場合。

メソッド:

evaluateFormulaAsync(context: Object, formula: string, baseRow?: number, baseColumn?: number)

パラメーター:

  • context: 評価コンテキストを表すオブジェクト。ほとんどの場合、アクティブなシートオブジェクト(GC.Spread.Sheets.Worksheet)を渡します。

  • formula: 評価する数式を含む string

A1 参照形式のみをサポートします。

  • baseRow(オプション): 数式の基準行インデックスを表す数値。セルコンテキスト外で数式を評価する場合、相対参照に使用します。

  • baseColumn(オプション): 数式の基準列インデックスを表す数値。セルコンテキスト外で数式を評価する場合、相対参照に使用します。

戻り値:

数式評価の結果を解決する Promise を返します。

複数回 context.setAsyncResult が呼び出された場合、Promise は最初の1回のみ解決されます。

例:

setTimeout を使用して遅延をシミュレートする簡単な非同期カスタム関数 ASUM(Asynchronous Sum)を定義します。

// 非同期関数 ASUM を定義
var asyncSum = function () {};
asyncSum.prototype = new GC.Spread.CalcEngine.Functions.AsyncFunction("ASUM", 1, 255);
// 計算が保留中の間に表示するデフォルト値
asyncSum.prototype.defaultValue = function () {
    return "Loading...";
};
// 非同期評価のロジック
asyncSum.prototype.evaluateAsync = function (context) {
    // setTimeout を用いてサーバー側評価の 2 秒遅延を擬似的に再現
    var args = arguments;
    setTimeout(function () {
        var result = 0;
        // 引数はインデックス 1 から始まる(インデックス 0 は context)
        for (var i = 1; i < args.length; i++) {
            result += args[i];
        }
        // 提供された context を使用して最終結果を設定
        context.setAsyncResult(result * 2); // 例:合計を 2 倍にする
    }, 2000); // 2 秒の遅延をシミュレート
};
// カスタム関数をグローバルに登録
GC.Spread.CalcEngine.Functions.defineGlobalCustomFunction("ASUM", new asyncSum());
  1. 非同期関数での基本使用法:

GC.Spread.Sheets.CalcEngine.evaluateFormulaAsync(sheet, "ASUM(2, 2)", 0, 0)
    .then(result => {
        console.log("ASUM(2, 2) result:", result); // Expected output after ~2s: ASUM(2, 2) result: 8
    })
    .catch(error => {
        console.error("Evaluation error:", error);
    });
//結果:Promise{8}
  1. 並列非同期関数:

GC.Spread.Sheets.CalcEngine.evaluateFormulaAsync(sheet, "ASUM(2, 2) + ASUM(2, 2)", 0, 0)
    .then(result => {
        console.log("ASUM(2, 2) + ASUM(2, 2) result:", result); // Expected output after ~2s: ASUM(2, 2) + ASUM(2, 2) result: 16
    })
    .catch(error => {
        console.error("Evaluation error:", error);
    });
//結果:Promise{16}
  1. 直列(ネスト)非同期関数:

GC.Spread.Sheets.CalcEngine.evaluateFormulaAsync(sheet, "ASUM(ASUM(2, 2), 2)", 0, 0)
    .then(result => {
        console.log("ASUM(ASUM(2, 2), 2) result:", result); // Expected output after ~4s (approx 2s for inner + 2s for outer): ASUM(ASUM(2, 2), 2) result: 20 (ASUM(8, 2) -> (8+2)*2 = 20)
    })
    .catch(error => {
        console.error("Evaluation error:", error);
    });
//結果:Promise{20}
  1. 結果が配列の場合:

GC.Spread.Sheets.CalcEngine.evaluateFormulaAsync(sheet, "VSTACK(ASUM(2, 2), ASUM(2))", 0, 0)
    .then(result => {
        console.log("VSTACK result:", result); // Expected output after ~2s: VSTACK result: [[8],[4]] (ASUM(2,2)->8, ASUM(2)->4)
    })
    .catch(error => {
        console.error("Evaluation error:", error);
    });
//結果:Promise{[[8],[4]]}
  1. 通常(同期)数式の評価:

GC.Spread.Sheets.CalcEngine.evaluateFormulaAsync(sheet, "1 + 23", 0, 0)
    .then(result => {
        console.log("Regular formula result:", result); // Expected output: Regular formula result: 24
    })
    .catch(error => {
        console.error("Evaluation error:", error);
    });
//結果:Promise{24}
  1. セル/範囲参照の評価:

// 前提: セル A1 に値 10、A2:A3 に値 20、30 が入力されているものとする
// (これらの例を実行するには、sheet オブジェクト内に該当セルの値を設定する必要がある場合があります)
// セル参照
GC.Spread.Sheets.CalcEngine.evaluateFormulaAsync(sheet, "A1", 0, 0)
    .then(result => {
        console.log("A1 result:", result); // 期待値: A1 の値(例: 10)
    })
    .catch(error => {
        console.error("評価エラー:", error);
    });
// 結果: Promise{null}
// 範囲参照
GC.Spread.Sheets.CalcEngine.evaluateFormulaAsync(sheet, "A1:A3", 0, 0)
    .then(result => {
        console.log("A1:A3 result:", result); // 期待値: [[A1の値],[A2の値],[A3の値]](例: [[10],[20],[30]])
    })
    .catch(error => {
        console.error("評価エラー:", error);
    });
// 結果: Promise{[[null],[null],[null],[null],[null]]}

expressionToFormula: 式を元の数式文字列に変換する。

利用シーン:

  • 複雑な数式を動的に構築する(文字列の連結によるリスクを避けるため)。多くの場合、formulaToExpression と一緒に使われる。

  • カスタム名の式を解析し、対応する数式を生成する。

メソッド: expressionToFormula(context, expression, baseRow?, baseColumn?, useR1C1?)

パラメーター:

  • context(Object) – 評価コンテキスト(通常はアクティブなシートオブジェクト)。

  • expression(GC.Spread.CalcEngine.Expression) – 変換する式ツリー。

  • baseRow(number, optional) – 相対参照の基準となる行インデックス。

  • baseColumn(number, optional) – 相対参照の基準となる列インデックス。

  • useR1C1(boolean, optional) – R1C1参照形式を使うかどうか(デフォルト:false)。

例: 名前付き式を数式文字列に変換する。

var sheet = spread.getActiveSheet();
sheet.addCustomName('averageUnits', '=AVERAGE(Table1[[#Data],[Units]])');
var cname = sheet.getCustomName("averageUnits");
var expr = cname.getExpression();
GC.Spread.Sheets.CalcEngine.expressionToFormula(sheet,expr);
//結果: AVERAGE(Table1[[#Data],[Units]])

formulaToExpression: 数式文字列を式に解析する。

利用シーン:

  • 既存の数式をプログラムで解析し、特定のパラメータやロジックを変更した上で、再度数式を生成する必要がある場合。

  • 数式内で参照されているセル、関数、依存関係を確認し、データフローの分析や監査を行う場合。

  • R1C1形式とA1形式を変換する際、まず数式を式ツリーに解析し、その後再構築する必要がある場合。

  • 数式の検証に文字列を使用するのは避ける。Expressions を使うことで、より詳細な分析が可能になる。

メソッド: formulaToExpression(context, formula, baseRow?, baseColumn?, useR1C1?)

パラメーター:

  • context(Object) – 評価コンテキスト(通常はアクティブなシートオブジェクト)。

  • formula(string) – 評価する数式文字列。

  • baseRow(number, optional) – 相対参照の基準となる行インデックス。

  • baseColumn(number, optional) – 相対参照の基準となる列インデックス。

  • useR1C1(boolean, optional) – R1C1参照形式を使用するかどうか(デフォルト:false)。

例: 数式を式オブジェクトに変換する。

var sheet = spread.getActiveSheet();
var expr = GC.Spread.Sheets.CalcEngine.formulaToExpression(sheet, '=CONCAT(Table1[@Region],Table1[@[Sales Rep]],Table1[@Product])',4,0)
//結果:
//expr.functionName は CONCAT
//expr.arguments.length は 3

formulaToRanges: 数式文字列を参照されているセル範囲の配列に変換する。

利用シーン:

  • 数式で参照されているすべてのセル範囲を素早く取得し、データ依存関係グラフの作成や影響範囲の分析を行うために利用できる。

  • 数式が参照しているセルをすべて UI 上でハイライト表示し、ユーザーが数式のロジックを直感的に理解できるようサポートする。

  • 数式の論理構造ではなく、物理的な位置情報(行や列のインデックス)を扱う必要がある場合、この方法は formulaToExpression よりも直接的かつ効率的である。

メソッド: formulaToRanges(sheet, formula, baseRow?, baseCol?)

パラメーター:

  • sheet(GC.Spread.Sheets.Worksheet) – 基本となるワークシート。

  • formula(string) – 解析対象の数式。

  • baseRow(number, optional) – 相対参照の場合の基準行インデックス。

  • baseColumn(number, optional) – 相対参照の場合の基準列インデックス。

例: 数式内で参照されているすべての範囲を取得する。

var sheet = spread.getActiveSheet();
var result = GC.Spread.Sheets.CalcEngine.formulaToRanges(sheet, '=SUM(A1,A2,A5:C8)');
//結果:
//result.sheetName は Sheet1
//result.ranges:[
//  Range {row: 0, rowCount: 1, col: 0, colCount: 1}
//  Range {row: 1, rowCount: 1, col: 0, colCount: 1}
//  Range {row: 4, rowCount: 4, col: 0, colCount: 3}
//  Range {row: 2, rowCount: 16, col: 4, colCount: 1}
//]

rangesToFormula: 範囲の配列を数式文字列に変換する。

利用シーン:

  • 実行時のデータ(ユーザーの選択やデータ量に応じて範囲を自動調整する場合など)に基づいて、範囲参照の数式を動的に構築する必要があるとき。

  • ワークシート参照をコードで扱う際に、複雑な参照文字列を手動で連結するのを避けたいとき。

  • 相対参照と絶対参照を柔軟に切り替える必要があるとき。

メソッド: rangesToFormula(ranges, baseRow?, baseCol?, rangeReferenceRelative?, useR1C1?)

パラメーター:

  • ranges(GC.Spread.Sheets.Range[]) – 変換する範囲。

  • baseRow(number, optional) – 相対参照の場合の基準行インデックス。

  • baseColumn(number, optional) – 相対参照の場合の基準列インデックス。

  • rangeReferenceRelative(RangeReferenceRelative, optional) – 参照の相対性(絶対/相対)を指定。

  • useR1C1(boolean, optional) – R1C1 スタイルを使用するかどうか。

例: 範囲の配列を対応する数式に変換する。

var ranges = [
    new GC.Spread.Sheets.Range(0,0,1,1),
    new GC.Spread.Sheets.Range(3,3,5,5),
];
GC.Spread.Sheets.CalcEngine.rangesToFormula(ranges,0,0,GC.Spread.Sheets.CalcEngine.RangeReferenceRelative.allRelative);
//結果: 'A1, D4:H8'
GC.Spread.Sheets.CalcEngine.rangesToFormula(ranges,0,0,GC.Spread.Sheets.CalcEngine.RangeReferenceRelative.allAbsolute);
//結果: '$A$1, $D$4:$H$8'
GC.Spread.Sheets.CalcEngine.rangesToFormula(ranges,0,0,GC.Spread.Sheets.CalcEngine.RangeReferenceRelative.colRelative);
//結果: 'A$1, D$4:H$8'
GC.Spread.Sheets.CalcEngine.rangesToFormula(ranges,0,0,GC.Spread.Sheets.CalcEngine.RangeReferenceRelative.allRelative, true);
//結果: 'RC, R[3]C[3]:R[7]C[7]'