MapBox GL JS でラベル付きマーカー

MapBox GL のサンプルにカスタムマーカーがあるので、それを参考に「ラベル付きのマーカー」を実現してみた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8227/6332001c-8d5c-f095-235e-672f1ccf4bd7.png)

動作するサンプルはこちら。

* [MapBox GL JS Marker with label / JSFiddle - Code Playground](https://jsfiddle.net/amay077/vn3741o6/15/)

## ソースコード

**index.html**

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset='utf-8' />
  <title></title>
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
  <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
  <script src='https://api.tiles.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.js'></script>
  <link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.8.0/mapbox-gl.css' rel='stylesheet' />
  <link rel="stylesheet" type="text/css" href="./index.css" media="screen">
  <style>
  </style>
</head>
<body>

<div id='map'></div>

<template id="marker">
  <div class="marker-container">
    <span id="title" class="marker-title"></span>
    <img id="marker-icon" src="https://img.icons8.com/ios-filled/40/0000FF/marker.png">
  </div>>
</template>

<script src="./index.js"></script>

</body>
</html>
```

**index.css**

```css
body {
  margin: 0;
  padding: 0;
}

#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}

.marker-container {
  display: flex; 
  flex-direction: column; 
  align-items: center; 
  cursor: pointer;
}

.marker-title {
  max-width: 100px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.marker-icon {
  height: 30px; 
  width: auto; 
  background-size: cover;
}

.mapboxgl-popup {
  max-width: 200px;
}

.mapboxgl-popup-content {
  text-align: center;
  font-family: 'Open Sans', sans-serif;
}
```

**index.js**

```javascript
const geojson = {
  type: 'FeatureCollection',
  features: [{
    type: 'Feature',
    geometry: {
    type: 'Point',
      coordinates: [-77.032, 38.913]
    },
    properties: {
      title: 'Mapbox',
      description: 'Washington, D.C.'
    }
  },
  {
    type: 'Feature',
    geometry: {
      type: 'Point',
      coordinates: [-122.414, 37.776]
    },
    properties: {
      title: 'Mapbox',
      description: 'San Francisco, California'
    }
  }]
};

const map = new mapboxgl.Map({
  container: 'map',
  center: [-96, 37.8],
  zoom: 3,
  style: {
    "version": 8,
    "sources": {
      "OSM": {
        "type": "raster",
        "tiles": ['http://a.tile.openstreetmap.org/{z}/{x}/{y}.png'],
        "tileSize": 256
      }
    },
    "layers": [{
      "id": "OSM",
      "type": "raster",
      "source": "OSM"
    }]
  }
});

geojson.features.forEach(marker => {

  // Create element for marker from template
  const template = document.getElementById('marker');
  const clone = document.importNode(template.content, true);
  const el = clone.firstElementChild;
  
  clone.getElementById('title').innerHTML = marker.properties.description;
  
  new mapboxgl.Marker(el, { anchor: 'bottom' })
    .setLngLat(marker.geometry.coordinates)
    .setPopup(new mapboxgl.Popup({ offset: 60, anchor: 'bottom' }) // add popups
    .setHTML('<h3>' + marker.properties.title + '</h3><p>' + marker.properties.description + '</p>'))
    .addTo(map);
});
```

1. マーカーとして使用する HTML 要素を ``template`` タグで用意しておきます。
2. マーカーごとに ``template`` から要素を生成(``importNode`` で複製しないと同じ要素が使い回されるので注意)してラベルを設定、その要素から MapBox の Marker を生成します。

※地図を OpenStreetMaps にしているのは、MapBox の地図を表示するには AccessToken を設定する必要があるためです。

 

## 参考

* [Add custom markers in Mapbox GL JS | Help | Mapbox](https://docs.mapbox.com/help/tutorials/custom-markers-gl-js/)
* [mapbox-gl.jsでOSMを表示 - hinosita's diary](http://hinoshita.hatenadiary.com/entry/2018/07/31/163225)