Google Maps APIのマーカーをDOMでつくる

Google Maps APIで利用して設置できるマーカーは
精々画像が使えるくらいで融通が利かないなと常々思っていた。

画像が使えるのだからPhotoShopなんかで自由にお絵かきすればいいんだけど、
個人的にはDOMをCSSでデザインするほうが楽だし、
クリックなんかのイベントでマーカーの色を変えたりしたい。
#Custom Overlays
結構苦労して探したらどうやら[Custom Overlaysなるもの](https://developers.google.com/maps/documentation/javascript/customoverlays)でDOMは配置できるらしい。

サンプルなんかも拾えた。
http://www.mwsoft.jp/programming/googlemap/google_map_v3_custom_overlay.html

リファレンスでもサンプルでもprototypeの新しいインスタンスに追加って書いてある。

```js
CustomMarker.prototype = new google.maps.OverlayView();
```
でもどうせならES6でやりたい。
できもしないのに変に拘る。ハマる元。

#血眼で探したらようやくあったサンプル
https://codepen.io/mock/pen/rWzPeR

これを参考に

```src/js/CustomMarker.js
/**
 * class CustomMarker
 */
export default class CustomMarker extends google.maps.OverlayView{
  /**
   * constructor
   * @param object map
   * @param float lat
   * @param float lng
   * @param boolean isDisplay
   * @param boolean isSelected
   */
  constructor(map,lat,lng,isDisplay = true,isSelected = false){
    super();
    this.position = {
      lat:lat,
      lng:lng
    };
    this.isDisplay = isDisplay;
    this.isSelected = isSelected;

    this.setMap(map);

    this.el = null;
  }

  /**
   * onAdd
   */
  onAdd(){
    this.el = document.createElement('div');

    const className = 'custom-marker' + ((this.isSelected) ? '--selected': '');
    this.el.classList.add(className);

    if(!this.isDisplay){
      this.el.style.display = 'none';
    }

    const panes = this.getPanes();
    panes.overlayLayer.appendChild(this.el);

    // click event
    panes.overlayMouseTarget.appendChild(this.el);
    google.maps.event.addDomListener(this.el, 'click', () => {
      google.maps.event.trigger(this, 'click');
      this.setSelected(true);
    });
  }


  /**
   * draw
   */
  draw(){
    if(!this.el) return;

    const point = this.getProjection().fromLatLngToDivPixel(new google.maps.LatLng(this.position.lat, this.position.lng));
    this.el.style.position = 'absolute';
    this.el.style.left = point.x + 'px';
    this.el.style.top = point.y + 'px';
  }

  /**
   * onRemove
   */
  onRemove(){
    if(!this.el) return;
    this.el.parentNode.removeChild(this.el);
    this.el = null;
  }

  /**
   * 選択状態のset
   */
  setSelected(boolean){
    if(boolean === this.isSelected) return;

    this.isSelected = boolean;
    this.switchClass();
  }

  /**
   * 表示フラグのset
   */
  setDisplay(boolean){
    if(boolean === this.isDisplay) return;

    this.isDisplay = boolean;
    this.applyStlyes();
  }

  /**
   * switch class list
   */
  switchClass(){
    if(!this.el) return;

    const className = 'custom-marker' + ((this.isSelected) ? '--selected': '');
    this.el.classList.replace(this.el.classList.item(0),className);
  }

  /**
   * apply styles
   */
  applyStlyes(){
    if(!this.el) return;

    this.el.style.display = (!this.isDisplay) ? 'none' : '';
  }
}
```
リファレンスを読む限りでは`onAdd()`、`draw()`、`onRemove()`のメソッドを実装しなければいけないらしい、
- `onAdd()`でDOMの用意とイベントの追加
- `draw()`で描画
- `onRemove()`は削除
って認識で合っているのかな？

ついでに選択や表示のフラグを追加して、class名を変えたりstyleを変えたり。

あとは↑のオブジェクトをimportしてGoogle Mapを初期化した後に呼び出す。

```src/js/index.js
import CustomMarker from './CustomMarker';

document.addEventListener('DOMContentLoaded', () => {
  initMap();
});

function initMap(){
  const lat = 36.0652196;
  const lng = 136.219452;

  const options = {
    gestureHandling: 'greedy',
    disableDefaultUI: true,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    center: new google.maps.LatLng(lat,lng),
    zoom: 14,
    clickableIcons: false
  };

  const map = new google.maps.Map(document.getElementById('map'), options);

  const marker = new CustomMarker(map,lat,lng);

  document.getElementById('deselected').addEventListener('click',() => {
    marker.setSelected(false);
  });

  document.getElementById('switch-display').addEventListener('click',() => {
    marker.setDisplay(!marker.isDisplay);
  });
}
```
CSSで装飾

```css
    .custom-marker{
      background:#00FF00;
      width:10px;
      height:10px;
      border-radius:50%;
      cursor:pointer;
    }
    .custom-marker--selected{
      background:#FF0000;
      width:10px;
      height:10px;
      border-radius:50%;
      cursor:pointer;
    }
```
#結果
![CustomMarker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266668/cac7d5dc-ba75-3ff6-4ec1-f553c6121e8d.png)

自由にデザインしたいとか言っておいてこのセンス・・・。
とりあえずできたからよし。
あとは用途に合わせてカスタマイズすればいい。
実務ではVueなんかと組み合わせて使ってたりしている。
#リポジトリ
https://github.com/torabe/custom-marker
#感想
結構重宝すると思うんだけど情報少なすぎない？