Power BI カスタムビジュアル開発 : InteractivityUtils でビジュアルのクロス選択とクロスフィルターを実施する

# InteractivityUtils

`InteractivityUtils` はビジュアル上のどのアイテムが選択されているかを管理する機能を提供し、これによりビジュアル韓の、クロスセレクト、クロスフィルタリングを容易にします。

- クロスセレクト: 他のビジュアルで選択した内容を、カスタムビジュアルでも選択する。またはその逆。
- クロスフィルター: 他のビジュアルで実施したフィルターを、カスタムビジュアルでも実施する。またはその逆。

# インストール

以下手順で追加。

1\. npm コマンドでインストール。powerbi-models は依存している型解決のため必要。

```shell
npm install powerbi-visuals-utils-interactivityutils --save
npm install powerbi-models --save
```

2\. tsconfig.json の files に型情報を追加。

```json:tsconfig.json
{
  "compilerOptions": {
  ...
  },
  "files": [
    ...,　
    "node_modules/powerbi-models/dist/models-noexports.d.ts",
    "node_modules/powerbi-visuals-utils-svgutils/lib/index.d.ts",
  ]
}
```

3\. pbiviz.json の externalJS に追加。

```json:pbiviz.json
{
  ...
  "externalJS": [
    ...,
    "node_modules/powerbi-visuals-utils-interactivityutils/lib/index.js"
  ],
  ...
}
```

4\. デザインの情報を style/visual.less に追加。

```css:visual.less
@import (less) "node_modules/powerbi-visuals-utils-interactivityutils/lib/index.css";
...
```

# 機能

- [InteractivityService](#interactivityservice) - ビジュアル上のアイテムのインタラクションを管理

# InteractivityService
`InteractivityService` はビジュアルのインタラクションに関する関数を提供。

`powerbi.extensibility.utils.interactivity` モジュールは以下の機能を提供:

* [createInteractivityService](#createinteractivityservice)
* [appendClearCatcher](#appendclearcatcher)
* [applySelectionStateToData](#applyselectionstatetodata)
* [handleSelection](#handleselection)
* [hasSelection](#hasselection)
* [legendHasSelection](#legendhasselection)

## createInteractivityService

IInteractivityService インスタンスの作成

```typescript
function createInteractivityService(hostServices: IVisualHost): IInteractivityService
```

### createInteractivityService の例

```typescript
import createInteractivityService = powerbi.extensibility.utils.interactivity.createInteractivityService;

export class Visual implements IVisual {
    // Implementation of IVisual

    constructor(options: VisualConstructorOptions) {
        createInteractivityService(options.host); // IInteractivityService インスタンス
    }
}
```

## appendClearCatcher

選択解除の SVG RECT 領域を作成。

```typescript
function appendClearCatcher(selection: d3.Selection<any>): d3.Selection<any>
```

### appendClearCatcher の例

```typescript
import appendClearCatcher = powerbi.extensibility.utils.interactivity.appendClearCatcher;

export class Visual implements IVisual {
    // Implementation of IVisual

    constructor(options: VisualConstructorOptions) {
        appendClearCatcher(d3.select(options.element)); 
    }
}
```

## applySelectionStateToData

選択状態をデータポイントに反映

```typescript
public applySelectionStateToData(dataPoints: SelectableDataPoint[], hasHighlights?: boolean): boolean
```

### applySelectionStateToData の例

```typescript
import SelectableDataPoint = powerbi.extensibility.utils.interactivity.SelectableDataPoint;
import IInteractivityService = powerbi.extensibility.utils.interactivity.IInteractivityService;
import createInteractivityService = powerbi.extensibility.utils.interactivity.createInteractivityService;

export class Visual implements IVisual {
    // Implementation of IVisual

    private interactivityService: IInteractivityService;

    constructor(options: VisualConstructorOptions) {
        this.interactivityService = createInteractivityService(options.host);
    }

    public update(options: VisualUpdateOptions): void {
        let dataPoints: SelectableDataPoint[] = [...];

        this.interactivityService.applySelectionStateToData(dataPoints); 
    }
}
```

## handleSelection

アイテムが選択されたことを通知。他の項目が非選択になる。

```typescript
public handleSelection(dataPoint: SelectableDataPoint, multiSelect: boolean): void
```

### handleSelection の例

```typescript
import ISelectionHandler = powerbi.extensibility.utils.interactivity.ISelectionHandler;
import SelectableDataPoint = powerbi.extensibility.utils.interactivity.SelectableDataPoint;
import IInteractiveBehavior = powerbi.extensibility.utils.interactivity.IInteractiveBehavior;

export interface YourBehaviorOptions {
    selection: d3.Selection<SelectableDataPoint>;
}

export class YourBehavior implements IInteractiveBehavior {
    // Implementation of IInteractiveBehavior

    public bindEvents(
        behaviorOptions: YourBehaviorOptions,
        selectionHandler: ISelectionHandler): void {

        const multiSelect: boolean = true;

        behaviorOptions.selection.on("click", (dataPoint: SelectableDataPoint) => {
            selectionHandler.handleSelection(subDataPoint, multiSelect); 
        });
    }
}
```

## hasSelection

選択されたアイテムが含まれるか確認。

```typescript
public hasSelection(): boolean
```

### hasSelection の例

```typescript
import IInteractivityService = powerbi.extensibility.utils.interactivity.IInteractivityService;
import createInteractivityService = powerbi.extensibility.utils.interactivity.createInteractivityService;

export class Visual implements IVisual {
    // Implementation of IVisual

    private interactivityService: IInteractivityService;

    constructor(options: VisualConstructorOptions) {
        this.interactivityService = createInteractivityService(options.host);
    }

    public update(options: VisualUpdateOptions): void {
         this.interactivityService.hasSelection(); 
    }
}
```

## legendHasSelection

凡例で選択されたアイテムがあるか確認

```typescript
public legendHasSelection(): boolean
```

### legendHasSelection の例

```typescript
import IInteractivityService = powerbi.extensibility.utils.interactivity.IInteractivityService;
import createInteractivityService = powerbi.extensibility.utils.interactivity.createInteractivityService;

export class Visual implements IVisual {
    // Implementation of IVisual

    private interactivityService: IInteractivityService;

    constructor(options: VisualConstructorOptions) {
        this.interactivityService = createInteractivityService(options.host);
    }

    public update(visualUpdateOptions: VisualUpdateOptions): void {
         this.interactivityService.legendHasSelection();     }
}
```
# まとめ

InteractivityUtils はビジュアル上の項目の選択を容易にしますが、これだけでクロス選択やフィルターが行えるわけではありません。別の機会の詳細を紹介します。


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

# 参照
[InteractivityUtils](https://github.com/Microsoft/powerbi-visuals-utils-interactivityutils)