Angular Material に追加された google-maps を使ってみた

私は現在、グーグルマップを利用した Angular アプリケーションを開発しています。

Angular 経験の浅い自分でも簡単に利用できる GoogleMap ライブラリーを調査していたところ、先日、[Angular Material UI component library](https://material.angular.io/) のパッケージとして、`@angular/google-maps` [components/src/google-maps at master · angular/components · GitHub](https://github.com/angular/components/tree/master/src/google-maps)　がリリースされたので、早速検証がてら触ってみました。


この記事では、`@angular/google-maps` の簡単な使い方を紹介していきます。



## インストールとセットアップ

npm からインストールします。

```
$ npm i @angular/google-maps
```

インストールが完了したら、GoogleMapsModule を import します.

```typescript:app.module.ts
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { GoogleMapsModule } from "@angular/google-maps";

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule, GoogleMapsModule],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}

```

### Maps JavaScript API のセットアップ
[Maps JavaScript API](https://developers.google.com/maps/documentation/javascript/tutorial) を利用するために、index.html に下記 script タグを追加します。API Key の取得方法については、[こちら](https://developers.google.com/maps/documentation/javascript/get-api-key) を参照してください。

```html:index.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>GoogleMapExample</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"
  type="text/javascript"></script>
</head>
<body>
  <app-root></app-root>
</body>
</html>

```

以上でセットアップは完了です。


## 利用できるコンポーネント

GoogleMapsModule は、現時点では下記の3つのコンポーネントをexport しています。

- [GoogleMap](https://github.com/angular/components/tree/master/src/google-maps/google-map)
  - [google.maps.Map クラス](https://developers.google.com/maps/documentation/javascript/reference/map#Map) をラップしているコンポーネント。地図の描画や操作ができる。`


- [MapMarker](https://github.com/angular/components/tree/master/src/google-maps/map-marker)
  - [google.maps.Marker クラス](https://developers.google.com/maps/documentation/javascript/reference/marker#Marker) をラップしているコンポーネント。マーカーの設置、操作ができる。 

- [MapInfoWindow](https://github.com/angular/components/tree/master/src/google-maps/map-info-window) (この記事では触れていません。)
  - [google.maps.InfoWindow クラス](https://developers.google.com/maps/documentation/javascript/reference/info-window#InfoWindow) を ラップしているコンポーネント.  

これらを組み合わせることで、簡単に Angular アプリケーションにグーグルマップを統合することができます。

## 地図を表示する
早速アプリケーションに地図を表示してみます。
GoogleMap コンポーネントには、下記の @Input プロパティが定義されています。

- zoom : 地図のズームレベル
- center : 地図の中心座標
- width : 地図の横幅
- height : 地図の高さ
- options : その他のオプション[google.Maps.MapOptions](https://developers.google.com/maps/documentation/javascript/reference/map#MapOptions) インターフェースで定義されているオプションを指定できる。

このプロパティを使って、東新宿駅を中心に地図を表示してみます。

```typescript:map.component.ts
import { Component, OnInit } from "@angular/core";

@Component({
  selector: "app-map",
  templateUrl: "./map.component.html",
  styleUrls: ["./map.component.scss"]
})
export class MapComponent implements OnInit {
  zoom = 16;
  // 東新宿駅の座標
  center: google.maps.LatLngLiteral = {
    lat: 35.697695,
    lng: 139.707354
  };
  // 地図のオプション
  options: google.maps.MapOptions = {
    disableDefaultUI: true
  };

  constructor() {}

  ngOnInit() {}
}

```

テンプレートでは、`<google-map>` を設置するだけです。

```html:map.component.html
<google-map
  height="500px"
  width="500px"
  [center]="center"
  [zoom]="zoom"
  [options]="options"
></google-map>
```



アプリケーションを起動すると、設定通り東新宿駅周辺の地図が表示されました :smile: 
<img width="760" alt="スクリーンショット 2019-12-07 18.42.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46222/0408140a-9dcb-2fa7-2472-e065a34436ce.png">


## マーカーを表示する
地図にマーカーを表示するには、MapMarker コンポーネントを利用します。
試しに、現在位置を取得して、カスタム画像に変更したマーカーとして表示してみます。

MapMarker の options プロパティには、[google.maps.MarkerOptions](https://developers.google.com/maps/documentation/javascript/reference/marker#MarkerOptions) インターフェイスで定義されている値をセットできます。


```typescript:map.component.ts
import { Component, OnInit } from "@angular/core";

@Component({
  selector: "app-map",
  templateUrl: "./map.component.html",
  styleUrls: ["./map.component.scss"]
})
export class MapComponent implements OnInit {
  zoom = 16;
  center: google.maps.LatLngLiteral = {
    lat: 35.697695,
    lng: 139.707354
  };
  options: google.maps.MapOptions = {
    disableDefaultUI: true
  };
  
  // 現在位置マーカーの座標
  currentPosition: google.maps.LatLngLiteral;
  // 現在位置マーカーのオプション
  currentPositionMarkerOption: google.maps.MarkerOptions = {
    icon: {
      url: "assets/point.png",
      scaledSize: new google.maps.Size(32, 32)
    }
  };

  constructor() {}

  ngOnInit() {
    // 現在位置を取得する。
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(position => {
        this.currentPosition = {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        };
      });
    }
  }
}

```

テンプレートには、`<map-marker>` を設置します。

```html:map.component.html
<google-map
  height="500px"
  width="500px"
  [center]="center"
  [zoom]="zoom"
  [options]="options"
>
  <map-marker
    *ngIf="currentPosition"
    [position]="currentPosition"
    [options]="currentPositionMarkerOption"
  >
  </map-marker>
</google-map>

```


いい感じに現在位置を表示できました :smile: 
<img width="663" alt="スクリーンショット 2019-12-07 18.24.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46222/26329d25-d0cc-de42-ce37-b96e79dadee5.png">



## 地図を親コンポーネントから操作する
親コンポーネントから GoogleMap コンポーネントのAPIにアクセスするには、@ViewChild デコレーターを使います。

下記は、現在位置のマーカーがクリックされたら、マーカーの座標にパン(なめらかにカメラを移動)させるサンプルです。

```typescript:map.component.ts
import { Component, OnInit, ViewChild } from "@angular/core";
import { GoogleMap, MapMarker } from "@angular/google-maps";

@Component({
  selector: "app-map",
  templateUrl: "./map.component.html",
  styleUrls: ["./map.component.scss"]
})
export class MapComponent implements OnInit {
  // GoogleMap コンポーネントへの参照を得る.
  @ViewChild(GoogleMap, { static: false }) map: GoogleMap;

  zoom = 16;
  center: google.maps.LatLngLiteral = {
    lat: 35.697695,
    lng: 139.707354
  };
  options: google.maps.MapOptions = {
    disableDefaultUI: true
  };
  currentPosition: google.maps.LatLngLiteral;
  currentPositionMarkerOption: google.maps.MarkerOptions = {
    icon: {
      url: "assets/point.png",
      scaledSize: new google.maps.Size(32, 32)
    }
  };

  constructor() {}

  ngOnInit() {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(position => {
        this.currentPosition = {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        };
      });
    }
  }

  // 現在位置マーカーがクリックされた時のハンドラー
  onCurrentPositionMarkerClick(marker: MapMarker) {
    // 地図をマーカーの座標までパンさせる。
    this.map.panTo(marker.getPosition());
  }
}

```

#### テンプレート

```html:map.component.html
<google-map
  height="500px"
  width="500px"
  [center]="center"
  [zoom]="zoom"
  [options]="options"
>
  <map-marker
    #markerElem
    *ngIf="currentPosition"
    [position]="currentPosition"
    [options]="currentPositionMarkerOption"
    (mapClick)="onCurrentPositionMarkerClick(markerElem)"
  >
  </map-marker>
</google-map>

```

#### スクリーンショット
![ezgif-2-59ca5efc08b5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46222/a0002da6-855b-b7e0-029f-6df764e7039d.gif)





## まとめ
`@angular/google-maps`  を使うと、Angular アプリケーションから、GoogleMap の表示、操作をとても簡単に実行できることがわかりました。

Angular 経験が浅い自分でも非常に簡単にやりたいことを実現できたので、
これから GoogleMap を使った Angular アプリケーションを作成する場合は、一度利用を検討してみることをおすすめします。

また、より複雑なマップアプリケーションを作りたい場合は、AngularGoogleMaps(AGM) [Angular 2+ Google Maps Components](https://angular-maps.com/) というこちらも素晴らしく良くできたサードパテーィのライブラリもあるので、要件に合わせて選択してみると良いと思います :smile: