Power BI カスタムビジュアル開発 : Capabilities の Drilldown を詳しく見る

[前回の記事](https://qiita.com/kenakamu/items/308b1d28ec97a21741b6) では Sorting、SupportsHighlight、AdvancedEditModeSupport を試しました。今回はドリルダウン機能を検証してます。

# `Drilldown` : ビジュアル内でのドリルダウン

ドリルダウン用の別ビジュアルを用意することなく、DataView にドリルダウンした値を渡せるようになります。設定には drilldown の追加および、データロールに対して最大 1 フィールドしか置けないように制約を入れます。

## 前提条件

ドリルダウンを使うためには、階層構造のデータが必要です。一番簡単なものは日付型ですが、他にも「国」「地域」「都市」のような階層なども考えられます。

この記事でもこれまでと同じ売り上げデータを元にしますが、売上日を日付型に Power BI Desktop で変換したデータセットを利用します。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/214116/6c7e44b7-763b-0107-aad3-62587d5c5463.png)

# Drilldown の動作確認

以下の例では myCategory データロールをドリルダウンの対象にし、condition で 1 つしかフィールドを追加できないようにしています。

```json:capabities.json
{
    "dataRoles": [
        {
            "displayName": "サンプルカテゴリ",
            "name": "myCategory",
            "kind": "Grouping"
        },
        {
            "displayName": "グルーピングフィールド",
            "name": "myGrouping",
            "kind": "Grouping"
        },
        {
            "displayName": "サンプルメジャー",
            "name": "myMeasure",
            "kind": "Measure"
        }
    ],
    "drilldown": {
        "roles": [
            "myCategory"
        ]
    },
    "dataViewMappings": [
        {
            "conditions": [
                {
                    "myCategory":{ "max": 1}
                }
            ],
            "categorical": {
                "categories": {
                    "for": {
                        "in": "myCategory"
                    }
                },
                "values": {
                    "group": {
                        "by": "myGrouping",
                        "select": [
                            {
                                "bind": {
                                    "to": "myMeasure"
                                }
                            }
                        ]
                    }
                }
            }
        }
    ]    
}
```
```typescript:visual.ts
module powerbi.extensibility.visual {
    "use strict";

    export class Visual implements IVisual {

        private area: d3.Selection<HTMLElement>
        private table: d3.Selection<HTMLElement>
        private thead: d3.Selection<HTMLElement>
        private tbody: d3.Selection<HTMLElement>
        private host: IVisualHost;
        private settings: VisualSettings;

        constructor(options: VisualConstructorOptions) {
            // カスタムビジュアルを配置しているホストの情報を取得
            this.host = options.host;
            // カスタムビジュアルのエリアを取得
            this.area = d3.select(options.element);
            this.table = this.area.append("table");
            this.thead = this.table.append("thead").append("tr");
            this.tbody = this.table.append("tbody");
        }

        public update(options: VisualUpdateOptions) {
            debugger;

            this.thead.selectAll("th").remove();
            this.tbody.selectAll("tr").remove();

            this.thead
                .selectAll("th")
                .data(options.dataViews[0].categorical.categories[0].values)
                .enter()
                .append("th")
                .text((value) => { return value.toString(); });

            // Add first blank header
            this.thead.insert("th", ":first-child");

            options.dataViews[0].categorical.values.forEach((values) => {

                let tr = this.tbody.append("tr");

                tr.selectAll("td")
                .data(values.values)
                .enter()
                .append("td")
                .text((value) => {
                    return value.toString(); });

                tr.insert("td",":first-child").text(() => { return values.source.groupName.toString() });
            });
        }

        private static parseSettings(dataView: DataView): VisualSettings {
            return VisualSettings.parse(dataView) as VisualSettings;
        }

        public enumerateObjectInstances(options: EnumerateVisualObjectInstancesOptions): VisualObjectInstance[] | VisualObjectInstanceEnumerationObject {
            return VisualSettings.enumerateObjectInstances(this.settings || VisualSettings.getDefault(), options);
        }
    }
}
```
画面では日付をカテゴリに設定して、ドリルダウンを試します。

[フィールドの設定]
![image.png](https://qiita-image-store.s3.amazonaws.com/0/214116/06ecbc7d-bd3e-9544-e7f4-b3c350ce390f.png)

[レポート]
上部に出ている下矢印や展開アイコンがドリルダウンのボタン
![image.png](https://qiita-image-store.s3.amazonaws.com/0/214116/656db633-d23d-c49f-87f4-0d7718b841b1.png)

[ドリルダウンをクリック]
四半期のデータ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/214116/ecb32336-cfcc-72d6-f0ba-6df31d6e80d1.png)

月別のデータ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/214116/46b8f57c-1e24-8318-0be8-a29edd224a2a.png)

[展開ボタンをクリック]
上位のカテゴリを表示しつつ下位カテゴリを表示
![image.png](https://qiita-image-store.s3.amazonaws.com/0/214116/f823cf97-19b6-e19b-78a6-acf7a0b2981b.png)

月別のデータ
![image.png](https://qiita-image-store.s3.amazonaws.com/0/214116/271a45a1-e941-d02f-54c0-b5f6f23b4880.png)


# まとめ
今回の例ではドリルダウン時に同じ用なテーブル表記をしましたが、データの粒度によって異なるグラフを出すのも面白いです。是非試してください。

[目次へ戻る](https://qiita.com/kenakamu/items/f57ab7f73d6ea10bc9d9)