地図ライブラリ「Leaflet」のマーカー(アイコン)を変更するのに Canvas API を使う

##はじめに
地図ライブラリ「Leaflet」のマーカー(アイコン)を標準のマーカーからカスタムのものに変更するのに Canvas API を使う例を紹介します。
※Firefox Quantum 68 と Gooogle Chrome 71 で検証しました。
##Canvas API を使おうと考えた背景
「Leaflet」のマーカーを変更する方法を検索すると、およそ、
 1. アイコンの画像ファイルを用意する方法
 2. プラグインを使用する方法
 3. CSS を使用する方法
がヒットします。

私は手元の1個の html ファイルだけを編集してマーカーを変更する方法を模索していて、上記の中では 3. が該当します。

しかし、Canvas API を使えば 1. の方法の応用としても目的を果たせるのではないかと考えました。

##表示例
<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="js,result" data-user="HideakiAnnaka" data-slug-hash="qedbEV" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="qedbEV">
  <span>See the Pen <a href="https://codepen.io/HideakiAnnaka/pen/qedbEV/">
  qedbEV</a> by HideakiAnnaka (<a href="https://codepen.io/HideakiAnnaka">@HideakiAnnaka</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

##コード例
要点としては、
1. Canvas API でマーカーとなるアイコンの画像を描画
2. HTMLCanvasElement.toDataURL() メソッドで 1. の画像を表す DataURL を取得
3. Leaflet で地図を表示し、2. の DataURL をマーカーのアイコンの画像として指定
の 3 点になります。

```html:sample.htm
<!DOCTYPE html>
<html>
    <head>
        <meta charset='UTF-8'>
        <title>地図ライブラリ「Leaflet」のマーカー(アイコン)を変更するのに Canvas API を使う</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.5.1/dist/leaflet.css" 
            integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" 
            crossorigin=""/>
        <script src="https://unpkg.com/leaflet@1.5.1/dist/leaflet.js" 
            integrity="sha512-GffPMF3RvMeYyc1LWMHtK8EbPv0iNZ8/oTtHPx9/cc2ILxQ+u905qIwdpULaqDkyBKgOaB57QTMg7ztg8Jm2Og==" 
            crossorigin=""></script>
	    <style>
        #canvas {
            display:none;
        }
        #mapid {
            width: 90vw;
            height: 90vh;
        }
	    </style>
    </head>
    <body>
        <canvas id='canvas' width='25' height='41'></canvas>
        <div id="mapid"></div>
    </body>
    <script>
    {
        window.addEventListener('load', (event) => {
            init();
        });

        const init = () => {
            let canvasIconUrl = getCanvasIconUrl();

            let mymap = L.map('mapid').setView([35.360628, 138.727365], 12);

            L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', {
                attribution: "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>地理院タイル</a>"
            }).addTo(mymap);

            const myIcon= L.icon({
                iconUrl: canvasIconUrl,
                shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/images/marker-shadow.png',
                iconSize: [25, 41],
                shadowSize: [41, 41],
                iconAnchor: [12.5, 41],
                popupAnchor: [0, -50],
            });

            L.marker([35.360628, 138.727365], {icon: myIcon}).addTo(mymap)
                .bindPopup('Canvas で描画したマーカーです。');
        }

        const getCanvasIconUrl = () => {
            const canvas = document.getElementById('canvas');
            if (canvas.getContext) {
                const ctx = canvas.getContext('2d');

                ctx.beginPath();
                ctx.arc(12.5, 12.5, 12.5, (Math.PI / 180) * 30, (Math.PI / 180) * 150, true);
                ctx.lineTo(12.5, 41);
                ctx.closePath();
                ctx.fillStyle = 'rgb(255, 102, 102)';
                ctx.fill();

                ctx.beginPath();
                ctx.arc(12.5, 12.5, 12, (Math.PI / 180) * 30, (Math.PI / 180) * 150, true);
                ctx.lineTo(12.5, 40.5);
                ctx.closePath();
                ctx.strokeStyle = 'rgb(102, 0, 51)';
                ctx.lineWidth = '1';
                ctx.stroke();

                ctx.beginPath();
                ctx.arc(12.5, 12.5, 5, (Math.PI / 180) * 0, (Math.PI / 180) * 360, true);
                ctx.closePath();
                ctx.fillStyle = 'rgb(102, 0, 51)';
                ctx.fill();

                return canvas.toDataURL();
            }
            else {
                return "https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/images/marker-icon.png";
            }
        }
    }
    </script>
</html>
```
##参考記事
- [公式][Quick Start Guide - Leaflet - a JavaScript library for interactive maps](https://leafletjs.com/examples/quick-start/)
- [公式][Markers With Custom Icons - Leaflet - a JavaScript library for interactive maps](https://leafletjs.com/examples/custom-icons/)
- [canvas に図形を描く - 開発者ガイド | MDN](https://developer.mozilla.org/ja/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes)
- [HTMLCanvasElement.toDataURL() - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL/)
- [Leafletの使い方|オープンソースWeb地図ライブラリ|谷謙二研究室](http://ktgis.net/service/leafletlearn/index.html)
- [Leafletのマーカーを変更する - Qiita](https://qiita.com/hsgucci/items/c47057268af1416a18c2)
- [自作地図: leafletで使えるおすすめプラグインまとめ - Qiita](https://qiita.com/pokohide/items/6329f1f92253ced23599)
- [Leaflet.js：マーカーのデザインをCSSで変える - データを追いかけるイヌ](https://datadog.hatenablog.com/entry/2018/06/16/070000)