Power BI カスタムビジュアル開発 : FormattingUtils で値をフォーマットする

# FormattingUtils 

`FormattingUtils` はカスタムビジュアルのデータなどの出力をフォーマットする機能を提供します。通常は他のユーティリティーと一緒に使うことが多いです。

# インストール

以下手順で追加。

1\. npm コマンドでインストール。

```shell
npm install powerbi-visuals-utils-formattingutils --save
```
2\. tsconfig.json の files に型情報を追加。

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

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

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

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

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

# 機能

- [TextMeasurementService](#textmeasurementservice) - テキストのプロパティを計測
- [stringExtensions](#stringextensions) - テキストや文字列の編集
- [valueFormatter](#valueformatter) - 数字や文字、日付などのフォーマット

# TextMeasurementService

`textMeasurementService` はテキストの幅や高さ、フォントサイズなどのプロパティを取得する機能を提供、

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

- [TextProperties](#textproperties)
- [measureSvgTextWidth](#measuresvgtextwidth)
- [measureSvgTextHeight](#measuresvgtextheight)
- [measureSvgTextRect](#measuresvgtextrect)
- [getMeasurementProperties](#getmeasurementproperties)
- [getSvgMeasurementProperties](#getsvgmeasurementproperties)

## TextProperties

テキストの基本プロパティの型定義

```typescript
interface TextProperties {
    text?: string;
    fontFamily: string;
    fontSize: string;
    fontWeight?: string;
    fontStyle?: string;
    fontVariant?: string;
    whiteSpace?: string;
}
```

## measureSvgTextWidth

テキストプロパティに対して必要となる SVG の幅を取得。

```typescript
function measureSvgTextWidth(textProperties: TextProperties, text?: string): number;
```

### measureSvgTextWidth の例

```typescript
import TextProperties = powerbi.extensibility.utils.formatting.TextProperties;
import textMeasurementService = powerbi.extensibility.utils.formatting.textMeasurementService;

let textProperties: TextProperties = {
    text: "Microsoft PowerBI",
    fontFamily: "sans-serif",
    fontSize: "24px"
};

textMeasurementService.measureSvgTextWidth(textProperties); // 194.71875
```

## measureSvgTextHeight

テキストプロパティに対して必要となる SVG の高さを取得。

```typescript
function measureSvgTextHeight(textProperties: TextProperties, text?: string): number;
```

### measureSvgTextHeight の例

```typescript
import TextProperties = powerbi.extensibility.utils.formatting.TextProperties;
import textMeasurementService = powerbi.extensibility.utils.formatting.textMeasurementService;

let textProperties: TextProperties = {
    text: "Microsoft PowerBI",
    fontFamily: "sans-serif",
    fontSize: "24px"
};

textMeasurementService.measureSvgTextHeight(textProperties); // 27
```

## テキストプロパティに必要な SVG 四角形領域のサイズを取得

```typescript
function measureSvgTextRect(textProperties: TextProperties, text?: string): SVGRect;
```

### measureSvgTextWidth の例

```typescript
import TextProperties = powerbi.extensibility.utils.formatting.TextProperties;
import textMeasurementService = powerbi.extensibility.utils.formatting.textMeasurementService;

let textProperties: TextProperties = {
    text: "Microsoft PowerBI",
    fontFamily: "sans-serif",
    fontSize: "24px"
};

textMeasurementService.measureSvgTextRect(textProperties);
// { x: 0, y: -22, width: 194.71875, height: 27 }
```

## getMeasurementProperties

DOM エレメントのテキストプロパティの取得

```typescript
function getMeasurementProperties(element: Element): TextProperties;
```

### getMeasurementProperties の例

```typescript
import textMeasurementService = powerbi.extensibility.utils.formatting.textMeasurementService;

let element: JQuery = $(document.createElement("div"));

element.text("Microsoft PowerBI");

element.css({
    "width": 500,
    "height": 500,
    "font-family": "sans-serif",
    "font-size": "32em",
    "font-weight": "bold",
    "font-style": "italic",
    "white-space": "nowrap"
});

textMeasurementService.getMeasurementProperties(element.get(0));

/* returns: {
    fontFamily:"sans-serif",
    fontSize: "32em",
    fontStyle: "italic",
    fontVariant: "",
    fontWeight: "bold",
    text: "Microsoft PowerBI",
    whiteSpace: "nowrap"
}*/
```

## getSvgMeasurementProperties

SVG エレメントのテキストプロパティの取得

```typescript
function getSvgMeasurementProperties(svgElement: SVGTextElement): TextProperties;
```

### getSvgMeasurementProperties の例

```typescript
import textMeasurementService = powerbi.extensibility.utils.formatting.textMeasurementService;

let svg: D3.Selection = d3.select("body").append("svg");

let textElement: D3.Selection = svg.append("text")
    .text("Microsoft PowerBI")
    .attr({
        "x": 25,
        "y": 25
    })
    .style({
        "font-family": "sans-serif",
        "font-size": "24px"
    });

textMeasurementService.getSvgMeasurementProperties(textElement.node());

/* returns: {
    "text": "Microsoft PowerBI",
    "fontFamily": "sans-serif",
    "fontSize": "24px",
    "fontWeight": "normal",
    "fontStyle": "normal",
    "fontVariant": "normal",
    "whiteSpace": "nowrap"
}*/
```

# stringExtensions

`stringExtensions` はテキストや文字列の操作を容易にする機能を提供。

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

- [endsWith](#endswith)
- [equalIgnoreCase](#equalignorecase)
- [startsWith](#startswith)
- [contains](#contains)
- [isNullOrEmpty](#isnullorempty)

## endsWith

指定した文字列で終わっているか確認。

```typescript
function endsWith(str: string, suffix: string): boolean;
```

### endsWith の例

```typescript
import stringExtensions = powerbi.extensibility.utils.formatting.stringExtensions;

stringExtensions.endsWith("Power BI", "BI"); // true
```

## equalIgnoreCase

大文字小文字を無視して、二つの文字列が同一か確認。

```typescript
function equalIgnoreCase(a: string, b: string): boolean;
```

### equalIgnoreCase の例

```typescript
import stringExtensions = powerbi.extensibility.utils.formatting.stringExtensions;

stringExtensions.equalIgnoreCase("Power BI", "power bi"); // true
```

## startsWith

指定した文字列で始まっているか確認。

```typescript
function startsWith(a: string, b: string): boolean;
```

### startsWith の例

```typescript
import stringExtensions = powerbi.extensibility.utils.formatting.stringExtensions;

stringExtensions.startsWith("Power BI", "Power"); // true
```

## contains

指定した文字列を含むか確認。

```typescript
function contains(source: string, substring: string): boolean;
```

### contains の例

```typescript
import stringExtensions = powerbi.extensibility.utils.formatting.stringExtensions;

stringExtensions.contains("Microsoft Power BI Visuals", "Power BI"); // true
```

## isNullOrEmpty

文字列が定義されていないか、空白かを確認。

```typescript
function isNullOrEmpty(value: string): boolean;
```

### isNullOrEmpty の例

```typescript
import stringExtensions = powerbi.extensibility.utils.formatting.stringExtensions;

stringExtensions.isNullOrEmpty(null); // true
stringExtensions.isNullOrEmpty("Power BI"); // false
```

# ValueFormatter
`ValueFormatter` は数字や文字列、日付などのフォーマット機能を提供。

`powerbi.extensibility.utils.formatting.valueFormatter` モジュールは以下の機能を提供。

- [IValueFormatter](#ivalueformatter)
  - [format](#ivalueformatterformat)
- [ValueFormatterOptions](#valueformatteroptions)
- [create](#create)

## IValueFormatter

フォーマット機能の関数やプロパティが定義されたインターフェース。

```typescript
interface IValueFormatter {
    format(value: any): string;
    displayUnit?: DisplayUnit;
    options?: ValueFormatterOptions;
}
```

## IValueFormatter.format

値をフォーマットする。

```typescript
function format(value: any, format?: string, allowFormatBeautification?: boolean): string;
```

### IValueFormatter.format の例

#### 千の単位を K としてフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let iValueFormatter = valueFormatter.create({ value: 1001 });

iValueFormatter.format(5678); // "5.68K"
```

#### 百万の単位を M としてフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let iValueFormatter = valueFormatter.create({ value: 1e6 });

iValueFormatter.format(1234567890); // "1234.57M"
```

#### 十億を bn としてフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let iValueFormatter = valueFormatter.create({ value: 1e9 });

iValueFormatter.format(1234567891236); // 1234.57bn
```

#### 兆を T としてフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let iValueFormatter = valueFormatter.create({ value: 1e12 });

iValueFormatter.format(1234567891236); // 1.23T
```

#### 指数でフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let iValueFormatter = valueFormatter.create({ format: "E" });

iValueFormatter.format(1234567891236); // 1.234568E+012
```

#### カルチャーの指定でフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let valueFormatterUK = valueFormatter.create({ cultureSelector: "en-GB" });

valueFormatterUK.format(new Date(2007, 2, 3, 17, 42, 42)); // 03/03/2007 17:42:42

let valueFormatterUSA = valueFormatter.create({ cultureSelector: "en-US" });

valueFormatterUSA.format(new Date(2007, 2, 3, 17, 42, 42)); // 3/3/2007 5:42:42 PM
```

#### パーセンテージでのフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let iValueFormatter = valueFormatter.create({ format: "0.00 %;-0.00 %;0.00 %" });

iValueFormatter.format(0.54); // 54.00 %
```

#### 日付のフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let date = new Date(2016, 10, 28, 15, 36, 0),
    iValueFormatter = valueFormatter.create({});

iValueFormatter.format(date); // 11/28/2016 3:36:00 PM
```

#### ブール値のフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let iValueFormatter = valueFormatter.create({});

iValueFormatter.format(true); // True
```

#### カスタム精度でのフォーマット

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

let iValueFormatter = valueFormatter.create({ value: 0, precision: 3 });

iValueFormatter.format(3.141592653589793); // 3.142
```

## ValueFormatterOptions

フォーマット用のオプション定義

```typescript
interface ValueFormatterOptions {
    /** The format string to use. */
    format?: string;
    /** The data value. */
    value?: any;
    /** The data value. */
    value2?: any;
    /** The number of ticks. */
    tickCount?: any;
    /** The display unit system to use */
    displayUnitSystemType?: DisplayUnitSystemType;
    /** True if we are formatting single values in isolation (e.g. card), as opposed to multiple values with a common base (e.g. chart axes) */
    formatSingleValues?: boolean;
    /** True if we want to trim off unnecessary zeroes after the decimal and remove a space before the % symbol */
    allowFormatBeautification?: boolean;
    /** Specifies the maximum number of decimal places to show*/
    precision?: number;
    /** Detect axis precision based on value */
    detectAxisPrecision?: boolean;
    /** Specifies the column type of the data value */
    columnType?: ValueTypeDescriptor;
    /** Specifies the culture */
    cultureSelector?: string;
}
```

## create

IValueFormatter の作成。

```typescript
function create(options: ValueFormatterOptions): IValueFormatter;
```

### create の例

```typescript
import valueFormatter = powerbi.extensibility.utils.formatting.valueFormatter;

valueFormatter.create({});
```

# まとめ

値をそのまま使うとグラフとして分かりずらいため、フォーマットは必須です。手動でやっている場合は是非ユーティリティーを試してください。

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

# 参考
[FormattingUtils](https://github.com/Microsoft/powerbi-visuals-utils-formattingutils)