Power BI ビジュアルの選択によってビジュアルに対話機能を追加する

Power BI には、視覚化と対話する方法として、選択とフィルター処理の 2 つが用意されています。 次の例は、1 つの視覚化から項目を選択し、レポート内の他の視覚化に新しい選択状態について通知する方法を示しています。

インターフェイスは Selection オブジェクトに対応しています。

export interface ISelectionId {
    equals(other: ISelectionId): boolean;
    includes(other: ISelectionId, ignoreHighlight?: boolean): boolean;
    getKey(): string;
    getSelector(): Selector;
    getSelectorsByColumn(): SelectorsByColumn;
    hasIdentity(): boolean;
}

選択マネージャーを使用してデータ ポイントを選択する

視覚化のホスト オブジェクトには、選択マネージャーのインスタンスを作成するためのメソッドが用意されています。 選択マネージャーには、次の各アクションに対応するメソッドがあります。

  • 選択
  • 選択のクリア
  • コンテキスト メニューの表示
  • 現在の選択内容の保存
  • 選択状態の確認

選択マネージャーのインスタンスを作成する

選択マネージャーを使用するには、選択マネージャーのインスタンスを作成する必要があります。 通常は、視覚化によって、その視覚化オブジェクトの constructor セクション内で選択マネージャーのインスタンスが作成されます。

export class Visual implements IVisual {
    private target: HTMLElement;
    private host: IVisualHost;
    private selectionManager: ISelectionManager;
    // ...
    constructor(options: VisualConstructorOptions) {
        this.host = options.host;
        // ...
        this.selectionManager = this.host.createSelectionManager();
    }
    // ...
}

選択ビルダーのインスタンスを作成する

選択マネージャーのインスタンスを作成したら、そのビジュアルのデータ ポイントごとに selections を作成する必要があります。 視覚化ホスト オブジェクトの createSelectionIdBuilder メソッドを使って、各データ ポイントの選択を生成します。 このメソッドからは、インターフェイス powerbi.visuals.ISelectionIdBuilder を持つオブジェクトのインスタンスが返されます。

export interface ISelectionIdBuilder {
    withCategory(categoryColumn: DataViewCategoryColumn, index: number): this;
    withSeries(seriesColumn: DataViewValueColumns, valueColumn: DataViewValueColumn | DataViewValueColumnGroup): this;
    withMeasure(measureId: string): this;
    withMatrixNode(matrixNode: DataViewMatrixNode, levels: DataViewHierarchyLevel[]): this;
    withTable(table: DataViewTable, rowIndex: number): this;
    createSelectionId(): ISelectionId;
}

このオブジェクトには、さまざまな種類のデータ ビュー マッピングの selections を作成するための、対応するメソッドが備わっています。

注意

メソッド withTablewithMatrixNode は、Power BI ビジュアルの API 2.5.0 で導入されました。 テーブルまたはマトリックスのデータ ビュー マッピングに対する選択を使用する必要がある場合は、API バージョンを 2.5.0 以上に更新します。

カテゴリ別のデータ ビュー マッピングに対する選択を作成する

選択によって、サンプル セマンティック モデルのカテゴリ別のデータ ビュー マッピングがどのように表されるかを確認しましょう。

メーカー 種類
Chrysler Domestic Car 28883
Chrysler Domestic Truck 117131
Chrysler Import Car 0
Chrysler Import Truck 6362
Ford Domestic Car 50032
Ford Domestic Truck 122446
Ford Import Car 0
Ford Import Truck 0
GM Domestic Car 65426
GM Domestic Truck 138122
GM Import Car 197
GM Import Truck 0
Honda Domestic Car 51450
Honda Domestic Truck 46115
Honda Import Car 2932
Honda Import Truck 0
Nissan Domestic Car 51476
Nissan Domestic Truck 47343
Nissan Import Car 5485
Nissan Import Truck 1430
Toyota Domestic Car 55643
Toyota Domestic Truck 61227
Toyota Import Car 20799
Toyota Import Truck 23614

この視覚化では、次のデータ ビュー マッピングが使用されます。

{
    "dataRoles": [
        {
            "displayName": "Columns",
            "name": "columns",
            "kind": "Grouping"
        },
        {
            "displayName": "Rows",
            "name": "rows",
            "kind": "Grouping"
        },
        {
            "displayName": "Values",
            "name": "values",
            "kind": "Measure"
        }
    ],
    "dataViewMappings": [
        {
            "categorical": {
                "categories": {
                    "for": {
                        "in": "columns"
                    }
                },
                "values": {
                    "group": {
                        "by": "rows",
                        "select": [
                            {
                                "for": {
                                    "in": "values"
                                }
                            }
                        ]
                    }
                }
            }
        }
    ]
}

上記の例では、Manufacturercolumns で、Typerows です。 rows (Type) で値をグループ化することによって系列が作成されます。

ビジュアルでは、Manufacturer または Type によってデータをスライスすることもできます。

たとえば、ユーザーが ManufacturerChrysler を選択すると、他のビジュアルには次のデータが表示されます。

製造元 種類
Chrysler Domestic Car 28883
Chrysler Domestic Truck 117131
Chrysler Import Car 0
Chrysler Import Truck 6362

ユーザーが TypeImport Car を選択 (系列でデータを選択) すると、他のビジュアルには次のデータが表示されます。

製造元 種類
Chrysler Import Car 0
Ford Import Car 0
GM Import Car 197
Honda Import Car 2932
Nissan Import Car 5485
Toyota Import Car 20799

Screenshot that shows the visual with selections.

スライスされたデータを表示するには、視覚化のデータ バスケットを次のように設定します。

Screenshot that shows visual's data baskets.

上記の例では、カテゴリ (列) として Manufacturer が、系列 (行) として Type が、系列の Values として Sales があります。

Note

Values は系列を表示するために必要です。データ ビュー マッピングに従い、ValuesRows データ別にグループ化されるためです。

カテゴリに対する選択を作成する

// categories
const categories = dataView.categorical.categories;

// create label for 'Manufacturer' column
const p = document.createElement("p") as HTMLParagraphElement;
p.innerText = categories[0].source.displayName.toString();
this.target.appendChild(p);

// get count of category elements
const categoriesCount = categories[0].values.length;

// iterate all categories to generate selection and create button elements to use selections
for (let categoryIndex = 0; categoryIndex < categoriesCount; categoryIndex++) {
    const categoryValue: powerbi.PrimitiveValue = categories[0].values[categoryIndex];

    const categorySelectionId = this.host.createSelectionIdBuilder()
        .withCategory(categories[0], categoryIndex) // we have only one category (only one `Manufacturer` column)
        .createSelectionId();
    this.dataPoints.push({
        value: categoryValue,
        selection: categorySelectionId
    });
    console.log(categorySelectionId);

    // create button element to apply selection on click
    const button = document.createElement("button") as HTMLButtonElement;
    button.value = categoryValue.toString();
    button.innerText = categoryValue.toString();
    button.addEventListener("click", () => {
        // handle click event to apply correspond selection
        this.selectionManager.select(categorySelectionId);
    });
    this.target.appendChild(button);
}

前のサンプル コードでは、すべてのカテゴリを反復処理しています。 それぞれの反復で、createSelectionIdBuilder を呼び出し、その選択ビルダーの withCategory メソッドを呼び出すことで各カテゴリに対する次の選択を作成しています。 createSelectionId メソッドは、生成された selection オブジェクトを返すための最後のメソッドとして使用されています。

withCategory メソッドには、category の列 (このサンプルでは Manufacturer) と、カテゴリ要素のインデックスを渡します。

系列に対する選択を作成する

// get groupped values for series
const series: powerbi.DataViewValueColumnGroup[] = dataView.categorical.values.grouped();

// create label for 'Type' column
const p2 = document.createElement("p") as HTMLParagraphElement;
p2.innerText = dataView.categorical.values.source.displayName;
this.target.appendChild(p2);

// iterate all series to generate selection and create button elements to use selections
series.forEach( (ser: powerbi.DataViewValueColumnGroup) => {
    // create selection id for series
    const seriesSelectionId = this.host.createSelectionIdBuilder()
        .withSeries(dataView.categorical.values, ser)
        .createSelectionId();

    this.dataPoints.push({
        value: ser.name,
        selection: seriesSelectionId
    });

    // create button element to apply selection on click
    const button = document.createElement("button") as HTMLButtonElement;
    button.value =ser.name.toString();
    button.innerText = ser.name.toString();
    button.addEventListener("click", () => {
        // handle click event to apply correspond selection
        this.selectionManager.select(seriesSelectionId);
    });
    this.target.appendChild(button);
});

テーブルのデータ ビュー マッピングに対する選択を作成する

次の例は、テーブル データ ビューのマッピングを示しています。

{
    "dataRoles": [
        {
            "displayName": "Values",
            "name": "values",
            "kind": "GroupingOrMeasure"
        }
    ],
    "dataViewMappings": [
        {
            "table": {
                "rows": {
                    "for": {
                        "in": "values"
                    }
                }
            }
        }
    ]
}

テーブルのデータ ビュー マッピングの各行に対する選択を作成するには、選択ビルダーの withTable メソッドを呼び出します。

public update(options: VisualUpdateOptions) {
    const dataView = options.dataViews[0];
    dataView.table.rows.forEach((row: DataViewTableRow, rowIndex: number) => {
        this.target.appendChild(rowDiv);
        const selection: ISelectionId = this.host.createSelectionIdBuilder()
            .withTable(dataView.table, rowIndex)
            .createSelectionId();
    }
}

ビジュアルのコードでは、テーブルの行が反復処理され、各行で withTable テーブル メソッドが呼び出されます。 withTable メソッドのパラメーターは、table オブジェクトと、テーブル行のインデックスです。

マトリックスのデータ ビュー マッピングに対する選択を作成する

public update(options: VisualUpdateOptions) {
    const host = this.host;
    const rowLevels: powerbi.DataViewHierarchyLevel[] = dataView.matrix.rows.levels;
    const columnLevels: powerbi.DataViewHierarchyLevel[] = dataView.matrix.rows.levels;

    // iterate rows hierarchy
    nodeWalker(dataView.matrix.rows.root, rowLevels);
    // iterate columns hierarchy
    nodeWalker(dataView.matrix.columns.root, columnLevels);

    function nodeWalker(node: powerbi.DataViewMatrixNode, levels: powerbi.DataViewHierarchyLevel[]) {
        const nodeSelection = host.createSelectionIdBuilder().withMatrixNode(node, levels);

        if (node.children && node.children.length) {
            node.children.forEach(child => {
                nodeWalker(child, levels);
            });
        }
    }
}

このサンプルでは、nodeWalker が各ノードと子ノードを再帰的に呼び出します。

nodeWalker は、呼び出されるごとに nodeSelection オブジェクトを作成します。 それぞれの nodeSelection が対応するノードの selection を表します。

データ ポイントを選択して他のビジュアルをスライスする

次の例では、ボタン要素のクリック ハンドラーを作成しました。 このハンドラーでは、選択マネージャーの select メソッドが呼び出されて選択オブジェクトが渡されます。

button.addEventListener("click", () => {
    // handle click event to apply correspond selection
    this.selectionManager.select(categorySelectionId);
});

select メソッドのインターフェイスは次のとおりです。

interface ISelectionManager {
    // ...
    select(selectionId: ISelectionId | ISelectionId[], multiSelect?: boolean): IPromise<ISelectionId[]>;
    // ...
}

select メソッドには選択の配列を指定できます。 これにより、ビジュアルで一度に複数のデータ ポイントを選択できます。 2 番目のパラメーター multiSelect を使用して、複数選択を行います。 multiSelect が true の場合、Power BI では現在の選択を適用するときに、前の選択状態をクリアしません。 この値が false の場合、前の選択は上書きされます。

multiSelect を使用する一般的な例は、クリック イベント時の Ctrl ボタンの状態の処理です。 Ctrl ボタンを押した状態だと、複数のオブジェクトを選択できます。

button.addEventListener("click", (mouseEvent) => {
    const multiSelect = (mouseEvent as MouseEvent).ctrlKey;
    this.selectionManager.select(seriesSelectionId, multiSelect);
});