OpenStreetMap + Leaflet で地図とマーカーと情報ウインドウ

# 単一marker

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
<style>
html { width: 100%; height: 100%; }
body { width: 100%; height: 100%; margin: 0; }
#map { width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
// 即時関数
(() => {
  // 地図の設定
  const map = L.map('map').setView([30.37486500, 130.9576461], 14);
  // 地図タイルの設定
  L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors',
  }).addTo(map);
  // markerとpopupの設定
  L.marker([30.37486500, 130.9576461], { title: 'marker-title' })
    // 以下のコメント部分を有効化してurlなどを指定すればマーカーイメージの変更が可能
    // .setIcon(
    //   L.icon({
    //     iconUrl: 'https://placehold.jp/cc9999/993333/32x32.png',
    //     iconAnchor: [16, 16],
    //     popupAnchor: [0, -16],
    //   }),
    // )
    .addTo(map)
    .bindPopup('<h3>test</h3><p>hogehoge</p>')
    .openPopup();
})();
</script>
</body>
</html>
```

# 複数marker

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
<style>
html { width: 100%; height: 100%; }
body { width: 100%; height: 100%; margin: 0; }
#map { width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
// 即時関数
(() => {
  // 地図の設定
  const map = L.map('map').setView([30.37486500, 130.9576461], 14);
  // 地図タイルの設定
  L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors',
  }).addTo(map);
  // markerとpopupの設定
  L.marker([30.37486500, 130.9576461], { title: 'marker-title1' })
    // .setIcon(
    //   L.icon({
    //     iconUrl: 'https://placehold.jp/cc9999/993333/32x32.png',
    //     iconAnchor: [16, 16],
    //     popupAnchor: [0, -16],
    //   }),
    // )
    .addTo(map)
    .bindPopup('<h3>test1</h3><p>hogehoge</p>')
    .openPopup();
  // markerとpopupの設定
  L.marker([30.39205130, 130.9612252], { title: 'marker-title2' })
    // .setIcon(
    //   L.icon({
    //     iconUrl: 'https://placehold.jp/cc9999/993333/32x32.png',
    //     iconAnchor: [16, 16],
    //     popupAnchor: [0, -16],
    //   }),
    // )
    .addTo(map)
    .bindPopup('<h3>test2</h3><p>fugafuga</p>');
  L.marker([30.40160000, 130.9674100], { title: 'marker-title3' })
    // .setIcon(
    //   L.icon({
    //     iconUrl: 'https://placehold.jp/cc9999/993333/32x32.png',
    //     iconAnchor: [16, 16],
    //     popupAnchor: [0, -16],
    //   }),
    // )
    .addTo(map)
    .bindPopup('<h3>test3</h3><p>piyopiyo</p>');
})();
</script>
</body>
</html>
```

# 地図の中心の緯度と経度と縮尺を自動調整

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
<style>
html { width: 100%; height: 100%; }
body { width: 100%; height: 100%; margin: 0; }
#map { width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
// 即時関数
(() => {
  // 地図の設定
  const map = L.map('map').setView([30.37486500, 130.9576461], 14);
  // 地図タイルの設定
  L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors',
  }).addTo(map);
  // markerとpopupの設定
  L.marker([30.37486500, 130.9576461], { title: 'marker-title1' })
    // .setIcon(
    //   L.icon({
    //     iconUrl: 'https://placehold.jp/cc9999/993333/32x32.png',
    //     iconAnchor: [16, 16],
    //     popupAnchor: [0, -16],
    //   }),
    // )
    .addTo(map)
    .bindPopup('<h3>test1</h3><p>hogehoge</p>')
    .openPopup();
  // markerとpopupの設定
  L.marker([30.39205130, 130.9612252], { title: 'marker-title2' })
    // .setIcon(
    //   L.icon({
    //     iconUrl: 'https://placehold.jp/cc9999/993333/32x32.png',
    //     iconAnchor: [16, 16],
    //     popupAnchor: [0, -16],
    //   }),
    // )
    .addTo(map)
    .bindPopup('<h3>test2</h3><p>fugafuga</p>');
  L.marker([30.40160000, 130.9674100], { title: 'marker-title3' })
    // .setIcon(
    //   L.icon({
    //     iconUrl: 'https://placehold.jp/cc9999/993333/32x32.png',
    //     iconAnchor: [16, 16],
    //     popupAnchor: [0, -16],
    //   }),
    // )
    .addTo(map)
    .bindPopup('<h3>test3</h3><p>piyopiyo</p>');
  // 地図の中心の緯度と経度と縮尺の設定
  const bounds = L.latLngBounds([30.37486500, 130.9576461]);
  bounds.extend([30.37486500, 130.9576461]);
  bounds.extend([30.39205130, 130.9612252]);
  bounds.extend([30.40160000, 130.9674100]);
  map.fitBounds(bounds);
})();
</script>
</body>
</html>
```

# 地図とmarkerおよびpopupのデータを変数で管理

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css" />
<style>
html { width: 100%; height: 100%; }
body { width: 100%; height: 100%; margin: 0; }
#map { width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.3/dist/leaflet.js"></script>
<script>
// 即時関数
(() => {
  // 地図情報
  const mapData = {
    map: undefined,
    pos: {
      lat: 30.37486500,
      lng: 130.9576461,
    },
    zoom: 14,
    fitBounds: undefined,
    fitBoundsFlag: true,
  };
  // markerとpopupの情報
  const markerData = [
    {
      marker: undefined,
      pos: {
        lat: 30.37486500,
        lng: 130.9576461,
      },
      title: 'popup-title1',
      icon: '',
      // infoWindow: undefined,
      infoWindowOpen: true,
      infoWindowContent: '<h3>test1</h3><p>hogehoge</p>',
    },
    {
      marker: undefined,
      pos: {
        lat: 30.39205130,
        lng: 130.9612252,
      },
      title: 'popup-title2',
      icon: '',
      // infoWindow: undefined,
      infoWindowOpen: false,
      infoWindowContent: '<h3>test2</h3><p>fugafuga</p>',
    },
    {
      marker: undefined,
      pos: {
        lat: 30.40160000,
        lng: 130.9674100,
      },
      title: 'popup-title3',
      icon: '',
      // infoWindow: undefined,
      infoWindowOpen: false,
      infoWindowContent: '<h3>test3</h3><p>piyopiyo</p>',
    },
  ];
  // 地図の設定
  mapData.map = L.map('map').setView([30.37486500, 130.9576461], 14);
  // 地図タイルの設定
  L.tileLayer('https://{s}.tile.osm.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://osm.org/copyright">OpenStreetMap</a> contributors',
  }).addTo(mapData.map);
  // markerとpopupの設定
  markerData.forEach((md, i) => {
    markerData[i].marker = L.marker(md.pos, { title: md.title });
    if (md.icon) {
      markerData[i].marker.setIcon(L.icon({ iconUrl: md.icon }));
    }
    markerData[i].marker.addTo(mapData.map);
    markerData[i].marker.bindPopup(md.infoWindowContent);
    if (md.infoWindowOpen) {
      markerData[i].marker.openPopup();
    }
    // 地図の中心の緯度と経度と縮尺の設定
    if (!mapData.fitBounds) {
      mapData.fitBounds = L.latLngBounds(md.pos);
    }
    mapData.fitBounds.extend(md.pos);
  });
  // 地図の中心の緯度と経度と縮尺の設定
  if (mapData.fitBoundsFlag) {
    mapData.map.fitBounds(mapData.fitBounds);
  }
})();
</script>
</body>
</html>
```

<!--

# DEMO

http://bl.ocks.org/feo52/raw/51318908033ed23764f1520ae9a3bfe5/

https://gist.github.com/feo52/51318908033ed23764f1520ae9a3bfe5

-->

# 参考情報

https://osm.org/
https://openstreetmap.org/

https://leafletjs.com/
https://leafletjs.com/examples/quick-start/

https://leafletjs.com/reference.html
https://leafletjs.com/reference.html#map
https://leafletjs.com/reference.html#marker
https://leafletjs.com/reference.html#popup
https://leafletjs.com/reference.html#tooltip
https://leafletjs.com/reference.html#tilelayer
https://leafletjs.com/reference.html#icon
https://leafletjs.com/reference.html#latlng
https://leafletjs.com/reference.html#latlngbounds

https://www.google.com/search?q=leaflet+popup+autopan
https://www.google.com/search?q=leaflet+popup+autoclose

## あとがき

ノンプログラマーの素人が記述をしたコードです。
狭い利用範囲と少ない利用頻度での確認ですので、
記載内容に間違いや勘違いがあるかもしれません。
上記内容を参照の際は自己責任でお願い致します。