3
4

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-09-26

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

画像が使えるのだからPhotoShopなんかで自由にお絵かきすればいいんだけど、
個人的にはDOMをCSSでデザインするほうが楽だし、
クリックなんかのイベントでマーカーの色を変えたりしたい。

Custom Overlays

結構苦労して探したらどうやらCustom OverlaysなるものでDOMは配置できるらしい。

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

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

CustomMarker.prototype = new google.maps.OverlayView();

でもどうせならES6でやりたい。
できもしないのに変に拘る。ハマる元。

血眼で探したらようやくあったサンプル

これを参考に

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で装飾

    .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

自由にデザインしたいとか言っておいてこのセンス・・・。
とりあえずできたからよし。
あとは用途に合わせてカスタマイズすればいい。
実務ではVueなんかと組み合わせて使ってたりしている。

リポジトリ

感想

結構重宝すると思うんだけど情報少なすぎない?

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4