leaflet.js を使った Web地図
  ここでは leaflet.js を使った Web地図の例を示します。  他のWeb地図
  1. 地図例一覧
    1. 基本的なコード・・・・・・・・・・・・・・ 国土地理院地図タイルを利用した基本地図  具体例  参考
    2. ベースレイヤの切替・・・・・・・・・・ ベース地図タイルを切替えて利用する  具体例  例2  参考
    3. マーカを設置する・・・・・・・・・・・・ 色々なマーカを設置する    具体例  参考
    4. レイヤを切替・・・・・・・・・・・・・・・・ レイヤの表示を切替える    具体例  参考
    5. ライン&マーカを追加・・・・・・・・ クリック点にライン&マーカを追加/削除する  具体例  参考
    6. JSON マーカを追加・・・・・・・・・・ マーカ情報を持つ JSON を読込んでマーカを追加  具体例  他の例  参考
    7. google mapも表示・・・・・・・・・・・・ Leaflet に google mapも表示する  具体例  参考  例2
    8. 住所検索を追加・・・・・・・・・・・・・・ Leaflet で住所検索を行う  具体例  参考  例2  (*google geo を推奨)
    9. 緯度・経度を指定・・・・・・・・・・・・ 緯度・経度を指定して map を表示する  具体例
    10. レイヤ・マーカー切替・・・・・・・・ zoom レベルにより、レイヤ・マーカーを変更する  具体例  参考
    11. Web map に加筆、保存・・・・・・・ Leaflet map に加筆して、それを保存する  具体例  参考
    12. 行政区分地図を表示・・・・・・・・・・ 行政区分地図を表示する。 人口密度図  神奈川県区分   参考1  参考2
    13. 左右同期地図を表示・・・・・・・・・・ 左右地図のレイヤを同期 して地図を表示する  具体例  参考
    14. 現在地を表示・・・・・・・・・・・・・・・・ 現在地を取得し Web 地図を表示する  具体例
  2. 具体的コード例
    1. 基本的なコード 例表示
      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>Leaflet の基本的な記述</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css" />
        <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js"></script>
        <script>
          function init() {
            var mapobj = L.map('mapDiv'); // 'mapDiv' に表示する地図を変数 mapobj で指定
            mapobj.setView([35.36063,138.72731],10); //地図の中心位置とズームレベルを指定
            //表示するタイルレイヤと Attribution の記述を指定し、地図に追加
            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(mapobj);
          }
        </script>
      </head>
      <body onload="init()">
        <div id="mapDiv" style="width:900px;height:540px;margin:0 auto;"></div>
      </body>
      </html>
       【基本サンプルを表示
      ( 6,7行目)  Leafletを使うための cssとJavaScriptを読込
      (10行目) 'mapDiv' に表示する地図を変数 mapobj で L.mapオブジェクトに設定 参考
      (11行目) setViewメソッドで地図中心の緯経度とズームレベルを指定 参考
      (13行目) 地図データとして地理院タイルレイヤし、
      (14行目) それが地理院のタイルであることを表記して、
      (15行目) addToメソッドで地図mapobj に取り込みます
      (19行目) ページを読み込んだらinit()を実行します
      (20行目) divタグに idを設定 'mapDiv' としました

    2. ベースレイヤを切替える例 例表示
      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>ベースレイヤを切り替える</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css" />
        <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js"></script>
        <script>
          function init(){
            var mapobj = L.map('mapDiv',{zoomControl:false});
            mapobj.setView([35.36063,138.72731],10);
            L.control.scale({maxWidth:200,position:'bottomright',imperial:false}).addTo(mapobj);
            L.control.zoom({position:'bottomleft'}).addTo(mapobj);
            var gsi =L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', 
              {minZoom:2,maxZoom:18,attribution: "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>地理院タイル</a>"});   //地理院地図の標準地図タイル
            var gsiphoto = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg',
              {minZoom:2,maxZoom:18,attribution: "<a href='http://portal.cyberjapan.jp/help/termsofuse.html' target='_blank'>地理院タイル</a>"});  //地理院地図の写真タイル
            var gsipho78 = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/gazo1/{z}/{x}/{y}.jpg',
              {minZoom:10,maxZoom:17,attribution: "<a href='http://portal.cyberjapan.jp/help/termsofuse.html' target='_blank'>地理院タイル</a>"});  //地理院地図の写真タイル-78
            var relief = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/relief/{z}/{x}/{y}.png',
              {minZoom:5,maxZoom:15,attribution: "<a href='http://portal.cyberjapan.jp/help/termsofuse.html' target='_blank'>地理院タイル</a>「海域部は海上保安庁海洋情報部の資料を使用して作成」"}); //地理院地図の色別標高図
            var gsipale = L.tileLayer('http://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png',
              {minZoom:2,maxZoom:18,attribution: "<a href='http://portal.cyberjapan.jp/help/termsofuse.html' target='_blank'>地理院タイル</a>"});    //地理院地図の淡色地図タイル
            var osm = L.tileLayer('http://tile.openstreetmap.jp/{z}/{x}/{y}.png',
              {attribution: "<a href='http://osm.org/copyright' target='_blank'>OpenStreetMap</a> contributors" });    //オープンストリートマップのタイル
            //baseMapsオブジェクトに複数のタイルを設定
            var baseMaps = {
              "地理院地図" : gsi,
              "地理院写真" : gsiphoto,
              "院写真-78" : gsipho78,
              "色別標高図" : relief,
              "淡色地図" : gsipale,
              "O.S.Map"  : osm
            };
            // layersコントロールにbaseMapsオブジェクトを設定して地図に追加
            L.control.layers(baseMaps).addTo(mapobj);
            gsiphoto.addTo(mapobj);   // 初期表示地図を設定
          }
        </script>
        <style>
          #mapDiv{position:absolute;top:5px;left:5px;right:5px;bottom:5px;}
        </style>
      </head>
      <body onload="init()">
        <header style="text-align:center;">ベースレイヤを切り替える(右上アイコン)</header>
        <div id="mapDiv"></div>
      </body>
      </html>
       【ベースレイヤ切替え例を表示
      ( 6,7行目)  Leafletを使うための cssとJavaScriptを読込
      (10行目) 'mapDiv' に表示する地図を変数 mapobj で L.mapオブジェクトに設定。zoomControl を一旦削除(false)
      (11行目) setViewメソッドで地図中心の緯経度とズームレベルを指定
      (12行目) scale control を右下に設置 参考
      (13行目) zoom control を左下に設置 参考
      (14-36行) 地図データとして利用するベースタイルをそれぞれ定義し、layersコントロールを設置します。ベースレイヤ切替ボタンは右上に設置されます 参考
      (37行目) 初期のベースタイルはgsiphotoにしました
      (41行目) css で地図表示域のスタイルを設定します
      (44行目) ページを読み込んだらinit()を実行します
      (46行目) 地図表示域の idを 'mapDiv' と設定しました

    3. マーカを設置する例 例表示
      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>マーカの設置</title>
        <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js"></script>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css">
        <style>
          #link{ position:absolute; top:8px; left:10px; }
          #mapDiv{position:absolute;top:35px;left:5px;right:5px;bottom:5px;}
        </style>
        <script>
          var mapobj; var myIcon1, myIcon2, myIcon3, myIcon4, myIcon5;
          function init(){ 
            var mypoint = [35.196262,139.026013];  // 図中心:恩賜公園 
            mapobj = L.map('mapDiv',{zoomControl:true}).setView(mypoint,14); //中心&ズーム値
            L.control.scale({imperial:false}).addTo(mapobj);  // スケール(mのみ)を追加
            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(mapobj);
            myIcon1 = L.icon({
              iconUrl: '../img/mkg.gif',
              iconSize: [27, 45],
              iconAnchor: [14, 44]
            });
            myIcon2 = L.icon({
              iconUrl: '../img/mkr.gif',
              iconSize: [27, 45],
              iconAnchor: [14, 44]
            });
            myIcon3 = L.icon({
              iconUrl: '../img/mkc.gif', 
              iconSize: [27, 45],
              iconAnchor: [14, 44]
            });
            myIcon4 = L.icon({
              iconUrl: '../img/mkm.gif', 
              iconSize: [27, 45],
              iconAnchor: [14, 44]
            });
            // ポップアップする文字(HTML可、ここでは画像を表示)
            var sucontents = "箱根関所跡です<br>ドラッグは不可です<br><a href='https://kurage.ready.jp/jfuji/fj1674.jpg' target='_blank' title='クリックして'><img src='https://kurage.ready.jp/jfuji/fj1674s.jpg' width='140'></a>"
            // ポップアップオブジェクトを作成
            var popup1 = L.popup().setContent("これは恩賜箱根公園のマーカーですが<br>このマーカーはドラッグ可能です");
            var popup4 = L.popup({ maxWidth:200,maxHeight:160}).setContent(sucontents);
            // マーカにポップアップを紐付けする。同時にbindTooltipでツールチップも追加
            L.marker(mypoint,{draggable:true,icon:myIcon1}).bindPopup(popup1).bindTooltip("クリックで popup します<br>ドラッグ可能です").addTo(mapobj);
            L.marker([35.204794,139.025357],{icon:myIcon2}).bindTooltip("箱根神社です<br>クリックで削除可能").on('click', onMkClick).addTo(mapobj); 
            L.marker([35.189311,139.024623],{draggable:true,icon:myIcon3}).bindTooltip("箱根駅伝 goal・start点です<br>ドラッグ可能、クリックでは不変").addTo(mapobj);
            L.marker([35.192362,139.026346],{title:"箱根関所跡 クリック可"}).bindPopup(popup4).addTo(mapobj);// マーカを追加
            // 地図のclickイベントでonMapClick関数を呼び出し
            mapobj.on('click', onMapClick);
          }; // init()  -----------------------
          function onMapClick(e) {
            // クリック地点にマーカを追加、マーカのclickイベントでonMkClick関数を呼び出し
            var mk = L.marker(e.latlng,{icon:myIcon4}).bindPopup("ここの緯度,経度は、<br>" + e.latlng.lat.toFixed(6) + ", " + e.latlng.lng.toFixed(6) + "<br>です" ).bindTooltip(e.latlng+"<br>クリックで Popup").addTo(mapobj);
          }
          function onMkClick(e) { // クリックされたマーカを地図のレイヤから削除
            mapobj.removeLayer(e.target);
          }; // onMkClick(e)  -----------------------
        </script>
      </head>
      <body onload="init()">
        <header style="text-align:center;">マーカを設置する(クリックで追加・消去等)</header>
        <div id="link"><a href="../ex-opn.html">leaflet地図</a></div>
        <div id="mapDiv"></div>
      </body>
      </html>
       【マーカを設置する例を表示
      ( 6,7行目)  Leafletを使うための JavaScriptとcssを読込み
      (10行目) css で地図表示域 'mapDiv' のスタイルを設定
      (16行目) 'mapDiv' に表示する地図を変数 mapobj で L.mapオブジェクトに設定 参考 setViewメソッドで地図中心の緯経度とズームレベルを指定 参考
      (17行目) 地図の距離スケールを追加 参考
      (18行目) 地図データとして地理院タイルレイヤし、
      (19行目) それが地理院のタイルであることを表記して、
      (20行目) addToメソッドで地図mapobj に取り込みます
      (21-40行) 後で使う4個のアイコンを定義します 参考
      (42-45行) popup1,popup4 の定義をします 参考
      (47行目) 図中心mypointにpopup1を持つmyIcon1 のマーカを Tooltip を付与して設置します 参考
      (48行目) クリック時に onMkClick 動作する myIcon2 マーカを設置します
      (49行目) ドラッグ可能な myIcon3 マーカ を設置します
      (50行目) アイコンを指定せず default の popup4 を付与したマーカを設置します
      (52-57行) 地図クリック点に myIcon4 マーカを設置します
      (58-60行) クリックされたマーカを削除する関数を設置
      (63行目) ページを読み込んだらinit()を実行します
      (66行目) divタグに idを設定 'mapDiv' としました

    4. レイヤを切替える例 例(雨雲レイヤ)を表示  参考
      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>各レイヤを描く</title>
        <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js"></script>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css"/>
        <style>
          #mapDiv{ position:absolute;top:35px;left:5px;right:5px;bottom:5px; }
        </style>
        <script>
          function init() {
            var mapobj = L.map('mapDiv', { zoomControl: false });
            var mypoint = [35.196262,139.026013];   // 図中心:恩賜箱根公園 
            mapobj.setView(mypoint, 14);            // 図中心とズームレベルを設定
            var gsi= 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(mapobj);               // 地理院タイルを貼付け
            var gsiphoto = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg',
              {attribution: "<a href='http://portal.cyberjapan.jp/help/termsofuse.html' target='_blank'>地理院タイル</a>"});       //地理院地図の写真タイルの設定
            var osm = L.tileLayer('http://tile.openstreetmap.jp/{z}/{x}/{y}.png',
              {  attribution: "c<a href='http://osm.org/copyright' target='_blank'>OpenStreetMap</a> contributors" }); // オープンストリートマップのタイルの設定
            var ClsGroup = L.layerGroup();  // 同心円群を layerGroupオブジェクトに纒める
            var Clscenter = [35.192362,139.026346]; // 同心円中心 箱根関所跡
            for (var i =0; i <5; i++) {             // 4同心円描画
              var r = i * 1000;
              ClsGroup.addLayer(L.circle(Clscenter,{ radius:r,color:"#e55",fill:false,weight:2 }));
            }
      //      var circleMarker = L.circleMarker([35.189311,139.024623], { radius:30,color:"#5555ff",weight:2, fill:true, fillColor:"#0000ff", opacity:0.5 }).addTo(mapobj); // 円マーカを地図に付加
            var roadPts = [ [35.189311,139.024623],[35.189052,139.025025],[35.191502,139.027394],[35.192102,139.026511],[35.192273,139.026372],[35.192358,139.026340],[35.193125,139.026308],[35.193779,139.026731],[35.193893,139.026474],[35.194046,139.026544],[35.194112,139.026367],[35.194198,139.026276],[35.194754,139.025702],[35.195276,139.025837],[35.195386,139.025815],[35.195523,139.025654],[35.195637,139.025412],[35.195913,139.025756],[35.196005,139.025627],[35.196073,139.025627],[35.196358,139.025815],[35.196262,139.026013]];
            var polyline = L.polyline(roadPts,{color:"#2b2",weight:5}).addTo(mapobj); // 配列データ roadPts の polyline を mapobj に追加
            var arealatlons = [[35.1952632,139.0275431],[35.1955350,139.0276289],[35.1961312,139.0277040],[35.1960961,139.0279025],[35.1961882,139.0279669],[35.1962890,139.0278381],[35.1963855,139.0278167],[35.1965652,139.0278381],[35.1966529,139.0278167],[35.1969860,139.0279400],[35.1971482,139.0279454],[35.1972666,139.0279239],[35.1973849,139.0279186],[35.1976830,139.0277791],[35.1978759,139.0276074],[35.1979986,139.0275216],[35.1982529,139.0275323],[35.1983756,139.0275216],[35.1985334,139.0274143],[35.1986825,139.0273607],[35.1988666,139.0271998],[35.1990156,139.0270066],[35.1990419,139.0267921],[35.1989981,139.0265238],[35.1989367,139.0263414],[35.1988491,139.0261912],[35.1987702,139.0261376],[35.1986211,139.0260732],[35.1984019,139.0258050],[35.1981652,139.0256333],[35.1979022,139.0252364],[35.1977269,139.0251613],[35.1974989,139.0249145],[35.1973586,139.0248823],[35.1971044,139.0249682],[35.1968940,139.0249038],[35.1967011,139.0245926],[35.1964030,139.0243566],[35.1962539,139.0240455],[35.1962101,139.0237773],[35.1961575,139.0235949],[35.1956928,139.0231979],[35.1954386,139.0232408],[35.1951668,139.0234447],[35.1950353,139.0235305],[35.1949213,139.0237236],[35.1949213,139.0238309],[35.1949476,139.0239167],[35.1949038,139.0240455],[35.1949125,139.0244210],[35.1949564,139.0246677],[35.1949038,139.0250218],[35.1947898,139.0251184],[35.1945618,139.0251935],[35.1943777,139.0252686],[35.1942286,139.0253437],[35.1941936,139.0254188],[35.1941410,139.0257835],[35.1940270,139.0259123],[35.1939568,139.0259338],[35.1938516,139.0259445],[35.1939656,139.0261912],[35.1939656,139.0264165],[35.1946320,139.0270281]];
            var polygon = L.polygon(arealatlons,{ color:'#2b2',weight:3,fill:true,fillColor: 'green',opacity:0.5 }); // 配列データ arealatlons の polygon を追加
            L.YimgTileLayer = L.TileLayer.extend({   // 雨雲画像をオーバーレイ作業
              getTileUrl: function (coords) {
                //雨雲リクエスト日付の作成
                var now = new Date();
                var year = now.getFullYear();
                var month = now.getMonth() + 1;
                var day = now.getDate();
                var hours = now.getHours();
                var minutes = now.getMinutes();
                if (month < 10) month = '0' + month;
                if (day < 10) day = '0' + day;
                if (hours < 10) hours = '0' + hours;
                minutes *= 0.1;
                minutes = Math.floor(minutes);
                minutes *= 10;
                if (minutes < 10) minutes = '0' + minutes;
                date = "" + year + month + day + hours + minutes;
                return L.Util.template(this._url, L.extend({
                  d: date,
                  x: coords.x,
                  y: Math.pow(2, this._getZoomForUrl() - 1) - 1 - coords.y,
                  z: this._getZoomForUrl() + 1
                }, this.options));
              }
            });
            // 雨雲画像をオーバーレイとしてマップに追加
            var rainmap = new L.YimgTileLayer('http://weather.map.c.yimg.jp/weather?x={x}&y={y}&z={z}&size=256&date={d}', {
              attribution: 'Rain map',
              maxZoom: 18,
              opacity: 0.6
            }).addTo(mapobj);
            var baseMaps = {        // 各ベースレイヤをオブジェクト baseMaps に設定
              "地理院地図" : gsi,
              "地理院写真" : gsiphoto,
              "O.S.Map"  : osm
            };
            var overlay = {         // 各ベクタレイヤをオブジェクト overlay に設定
              "polyline": polyline,
      //        "円マーカ": circleMarker,  // 今回これは layersコントロールには含めず
              "等距離円": ClsGroup,
              "雨雲マップ": rainmap,
              "polygon": polygon
            }
            L.control.layers(baseMaps,overlay).addTo(mapobj); // layersコントロールを mapobj に追加
          }; // init() -----------------------------------
        </script>
      </head>
      <body onload="init()">
        <header style="text-align:center;">オーバーレイ(雨雲マップ等)を追加</header>
        <div id="mapDiv"></div>
      </body>
      </html>
       【レイヤを切替える例を表示
      ( 6,7行目)  Leafletを使うための JavaScriptとcssを読込み
      ( 9行目) css で地図表示域 'mapDiv' のスタイルを設定
      (13行目) 'mapDiv' に表示する mapobj を L.mapオブジェクトに設定。zoomControl は不使用(false)とした
      (15行目) 地図変数 mapobj に setViewで地図中心の緯経度(mypoint)とズームレベルを指定 参考
      (16行目) 地図データとして地理院タイルレイヤし、
      (17行目) それが地理院のタイルであることを表記して、
      (18行目) addToメソッドで地図mapobj に取り込みます
      (19-20行) 地図データとして航空写真タイルレイヤを著作表示して定義します 参考
      (21-22行) 地図データとしてオープンストリートマップの地図レイヤを著作表示して定義します
      (23-28行) 同心円群用にlayerGroupを定義し、中心点Clscenterより半径の異なる円群を記述します
      (29行目) 円形のマーカを定義して設置します
      (30-31行) 配列roadPtsをpolylineとしてmapobjに貼付け、
      (32-33行) 配列arealatlonsをpolygonとしてmapobjに貼付け、
      (34-58行) さらに雨雲レイヤを作成し、 参考
      (60-64行) 雨雲レイヤ(rainmap)をmapobjに貼付けて、
      (65-69行) まずベースレイヤ群(baseMaps)を作成し、
      (70-76行) オーバーレイヤ群をoverlayとして定義します
      (77行目) baseMapsとoverlayのレイヤ選択controlとを設置
      (81行目) ページを読み込んだらinit()を実行します
      (83行目) divタグのidを地図領域 'mapDiv'に設定

    5. ライン&マーカを追加する例 例を表示
      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>マーカの追加・削除</title>
        <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js"></script>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css"/>
        <style>
          #mapDiv{position:absolute;top:5px;left:5px;right:5px;bottom:5px;}
        </style>
        <script>
          var mapobj; var pline;
          function init() {
            mapobj = L.map('mapDiv', { zoomControl: false });
            var mypoint = [35.192362,139.026346];  // 図中心: 箱根関所跡
            mapobj.setView(mypoint, 15);
            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(mapobj);
            mapobj.on('click', onMapClick); // 地図のclickイベントでonMapClick関数を呼出す
            // plineをpolylineオブジェクトとし空座標を入れて地図に追加。bubblingMouseEvents属性をfalseに設定して、イベントがmapobjオブジェクトに連鎖するのを防ぐ
            pline = L.polyline([],{color:'blue',weight:5,bubblingMouseEvents:false}).addTo(mapobj);
            pline.on('click', onLineClick); // clickイベントでonLineClick関数を呼出す
          }; // init() -----------------------
          
          function onMapClick(e) {
            pline.addLatLng(e.latlng);      // plineにクリック地点の座標を追加
            var mk = L.marker(e.latlng).bindTooltip(e.latlng+"<br>クリックで削除可能").on('click',onMkClick).addTo(mapobj);
          }; // onMapClick(e) ----------------------- 
          
          function onLineClick(e) {         // plineのclickイベントで呼出し、
            pline.setLatLngs([]);           // plineに空座標を入れて非表示にする
          }; // onLineClick(e)  -----------------------
          
          function onMkClick(e) { 
            var dots = pline.getLatLngs();
            dots.pop();                  // クリックされたマーカ位置を位置配列から削除
            pline.setLatLngs(dots);      // 縮小された位置配列をplineデータに再設定
            mapobj.removeLayer(e.target);// クリックされたマーカを地図レイヤから削除
          }; // onMkClick(e)  -----------------------
        </script>
      </head>
      <body onload="init()">
        <header style="text-align:center;">クリック点にマーカ(クリックで消去)、ラインを追加</header>
        <div id="mapDiv"></div>
      </body>
      </html>
       【ライン&マーカを追加する例を表示
      ( 6,7行目)  Leafletを使うための cssとJavaScriptを読込み
      ( 9行目) 地図表示域 'mapDiv' のスタイルを設定
      (14行目) 'mapDiv' に表示する mapobj を L.mapオブジェクトに設定。zoomControl は不使用(false)
      (16行目) 地図変数 mapobj に setViewで地図中心の緯経度mypointとズームレベルを指定 参考
      (17行目) 地図データとして地理院タイルレイヤし、
      (18行目) それが地理院のタイルであることを表記して、
      (19行目) addToメソッドで地図変数mapobj に取込み
      (20行目) 地図のclickでonMapClick関数を呼出します
      (22行目) polyline plineを定義します
      (23行目) plineのclickでonLineClick関数を呼出します
      (26-29行) 動作時に plineの座標を追加し、onMkClick動作を有するマーカを追加する関数onMapClickを定義します
      (31-33行) plineを消去する関数onLineClickを定義します
      (34-40行) マーカクリックで該マーカを削除し、plineを短縮する関数onMkClickを定義します
      (43行目) ページを読み込んだらinit()を実行します
      (45行目) divタグのidを地図領域 'mapDiv'に設定

    6. JSON を読込んでマーカを追加する例 例を表示  geojsonの例  他の例
      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>JSON マーカの設置</title>
        <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js"></script>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css"/>
        <style>
          body { line-height:1.5em; }
          .page { width:1400px; height:95vh; margin: 0 auto; padding:5px; background:#efe; display:flex; }
            #main{ width:400px; margin-right:8px; }
              #drop { height:50px; margin:5px 35px; padding: 8px; border:3px #aaa dotted; }
              #disp { height:400px; margin:3px; padding:5px; border:1px #3d3 solid; overflow:auto; }
            #mapDiv{ flex:3; }
            #txt{ margin-top:8px; }
        </style>
      </head>
      <body onload="init()">
        <div class="page" >
          <section id="main">
              <h3> マーカー指定 json を読込む</h3>
              <div id="drop" ondragover="onDragOver(event)">
                  ここにマーカーファイル(<a href="datah.json">datah.json</a>) をドロップします。
              </div>
              <div id="disp" >ここにドロップしたファイルの内容を表示します。</div>
              <div id="txt">
                【 datah.json サンプル 】<br>
                { "marker":[ {"lat":35.204794,"lng":139.025357,"name":"箱根神社"}, {"lat":35.192362,"lng":139.026346,"name":"箱根関所跡"}, {"lat":35.182194,"lng":139.014074,"name":"箱根峠"} ] }
              </div>
          </section>
          <section id="mapDiv">ここに地図を表示</section>
        </div>
        
        <script>
          var mapobj; var myIcon2;
          if (window.File) {
                  //    window.alert("File APIが実装されてます。");
                      document.getElementById("drop").addEventListener("drop", onDrop, false);
          } else {
                      window.alert("本ブラウザではFile APIが使えません");
          }
              
              // Drop領域にドロップした際のファイルのプロパティ情報読み取り処理
          function onDrop(event){
             var files = event.dataTransfer.files;
             var disp = document.getElementById("disp");
             var encode_type = "utf-8";     // 'utf-8' 'shift-jis' ・・・・・
             disp.innerHTML ="";
             // 複数のファイルから1つずつファイルを選択
             for(var i=0; i< files.length; i++){
                var f = files[i];
                // ①FileReaderオブジェクトの生成
                var reader = new FileReader();
                // ②ファイルの種別を確認
                if( !f.type.match('application.json')  ){
                   alert("jsonファイル以外は表示できません。");
                   continue;
                }
                // ③エラー発生時の処理
                reader.onerror = function (evt) {
                    disp.innerHTML = "読み取り時にエラーが発生しました。";
                }
                // ファイル読取が完了した際に呼ばれる処理
                reader.onload = function (evt) {
                   // FileReaderが取得したテキストをそのままdivタグに出力
                      disp.innerHTML ="[ "+ f.name+" ]<br>"+reader.result;
                      let mks = JSON.parse( reader.result ).marker;
                      bound = L.latLngBounds( [ mks[0].lat, mks[0].lng ], [ mks[0].lat, mks[0].lng ] );
                      for ( let i = 0; i < mks.length; i++ ){  
                         L.marker([ mks[i].lat, mks[i].lng ],{title:mks[i].name }).on('click',onMkClick).addTo(mapobj);// マーカを追加
                         bound.extend( [ mks[i].lat, mks[i].lng ] ); //マーカー全体が入るボックスを広げる
                      }   
                      mapobj.fitBounds(bound); //マーカー全体が入るように地図範囲を設定する
                }
                // readAsTextメソッドでファイル内容の取得を実行
                reader.readAsText(f, encode_type);    // 'utf-8' 'shift-jis' ・・・・・
             }
             // ⑥ブラウザ上でファイルを展開する挙動を抑止
             event.preventDefault();
          }; // onDrop(event  -----------------------
      
          function onDragOver(event){ 
                 // ⑥ブラウザ上でファイルを展開する挙動を抑止
                 event.preventDefault(); 
          }; // onDragOver(event)  -----------------------
          
          function init(){ 
            var mypoint = [35.196262,139.026013];  // 図中心:恩賜公園 
            mapobj = L.map('mapDiv',{zoomControl:true}).setView(mypoint,14); //中心&ズーム値
            L.control.scale({imperial:false}).addTo(mapobj);  // スケール(mのみ)を追加
            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(mapobj);
          }; // init()  -----------------------
      
          function onMkClick(e) { // クリックされたマーカを地図のレイヤから削除
            mapobj.removeLayer(e.target);
          }; // onMkClick(e)  --------------------
        </script>
        
      </body>
      </html>
       【JSON マーカを追加する例を表示
      ( 6,7行目)  Leafletを使う為、JavaScriptとcssを読込み
      (14行目) 地図表示域 'mapDiv' のスタイルを設定
      (22行目) マーカを指定する JSON ファイル(datah.json)をドロップするエリアを設定
      (25行目) ドロップしたJSON の内容をここに表示
      (31行目) divタグのidを地図領域 'mapDiv'に設定
      (36行目) File オブジェクトの利用確認をします
      (38行目) JSON がドロップされると、onDrop()を発火します
      (44行目) function onDrop()を定義します
      (50行目) 複数のファイルがドロップ可能なのでその対応をします
      (55行目) ファイルの種別を確認
      (60行目) エラー時の処理
      (64行目) ファイル読取後の処理
      (67行目) 読取後、JSON の merker 配列部分を取出し、設定
      (68行目) 地図表示領域拡大用に、bound を定義しておく
      (70行目) 取出した配列をマーカの位置と、title に入力します
      (76行目) ファイル内容の取得を実行
      (79行目) ブラウザ上のファイル展開を抑止
      (84行目) ドラッグ時のファイル展開を抑止
      (87行~) ロード時 L.mapを表示します
      (89行目) 'mapDiv' に表示する mapobj を L.mapオブジェクトに設定。zoomControl は不使用(false)
      (90行目) 地図 mapobj に mスケールを表示 参考
      (91行目) 地図データとして地理院タイルレイヤし、
      (92行目) それが地理院のタイルであることを表記して、
      (93行目) addToメソッドで地図変数mapobj に取込みます
      (96行目) マーカの clickで消去する関数 onMkClickを定義

    7. Leaflet に google mapも表示する例 例を表示
      <!DOCTYPE html>
      <html lang="ja">
      <head>
        <meta charset="utf-8">
        <title>GoogleMap も表示</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" >
        <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet-src.js"  integrity="sha512-I5Hd7FcJ9rZkH7uD01G3AjsuzFy3gqz7HIJvzFZGFt2mrCS4Piw9bYZvCgUE0aiJuiZFYIJIwpbNnDIM6ohTrg==" crossorigin=""></script>
      <!-- Google Maps API を利用 -->
         <script src="https://maps.googleapis.com/maps/api/js?key=【google API キー】" async defer></script>
         <script src="https://unpkg.com/leaflet.gridlayer.googlemutant@latest/dist/Leaflet.GoogleMutant.js"></script>
      <style>
          html, body, #mapDiv { width: 100%; height: 100%; padding: 0px; margin: 0px; }
      </style>
      </head>
      <body>
        <div id="mapDiv"></div>
              
        <script>
            mapobj = L.map('mapDiv', { zoomControl: true });
            mapobj.setView( [35.36063,138.72731],10 );  // 図中心 富士山
            L.control.scale({maxWidth:300,position:'topright',imperial:false}).addTo(mapobj);  // スケールを表示
            var gsiattr = "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>国土地理院</a>";
            var gsi = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', { minZoom:5, attribution: gsiattr });
            var gsiphot = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg', { minZoom:5, attribution: gsiattr });
            var osm = L.tileLayer('http://tile.openstreetmap.jp/{z}/{x}/{y}.png',
                { minZoom:5, attribution: "©<a href='http://osm.org/copyright' target='_blank'>OpenStreetMap</a> contributors" });
            var GmapsHYB = L.gridLayer.googleMutant({ minZoom:5, type:'hybrid' });     // 航空写真&ラベル
            var GmapsTER  = L.gridLayer.googleMutant({ minZoom:5, type:'terrain' });    // 地形地図
            // オーバーレイ用のタイルレイヤ
            // opacityで透過度を設定、maxNativeZoom以上のズームレベルのタイルは、指定レベルのタイル画像を拡大表示
            var gsirelief = L.tileLayer('http://cyberjapandata.gsi.go.jp/xyz/relief/{z}/{x}/{y}.png', { opacity: 0.4, maxNativeZoom: 15, minZoom:5, attribution: gsiattr });
            var gsirehillshademap = L.tileLayer('http://cyberjapandata.gsi.go.jp/xyz/hillshademap/{z}/{x}/{y}.png', { opacity: 0.35, maxNativeZoom: 16, attribution: gsiattr });
            var baseMaps = {
              "地理院地図": gsi,
              "地理院写真": gsiphot,
              "O.S.Map": osm,
              'Google Hybrid':GmapsHYB,
              'Google Terrain':GmapsTER
            };
            var overlayMaps = {
              "色別標高図": gsirelief,
              "陰影起伏図": gsirehillshademap
            };
            L.control.layers(baseMaps,overlayMaps,{maxWidth:200,position:'topleft',imperial:false}).addTo(mapobj); 
            GmapsHYB.addTo(mapobj);  // 初期設定でgoogleHYBを表示
      </script>
      </body>
      </html>
       【google mapも表示する例
      (6,7行目)  Leafletを使う為、JavaScriptとcssを読込み
      ( 9行目) google mapも使う為、googleの【API キー】を書込む
      (10行目) Leaflet.GridLayer.GoogleMutantプラグインを読込む
      (12行目) 地図表示域 'mapDiv' のスタイルを設定
      (16行目) 地図表示域の idを 'mapDiv' としました
      (19行目) 表示地図を変数 mapobj で L.mapオブジェクトに設定
      (21行目) scaleの表示位置などを設定
      (23,24行) 地理院タイルと写真を指定
      (25行目) openstreetmapタイルを指定
      (27行目) google mapの写真を指定
      (28行目) google mapの地形地図を指定
      (31行目) オーバーレイ用の色別標高図を指定
      (32行目) オーバーレイ用の陰影起伏図を指定
      (33-39行) 基盤図のセレクタを設定
      (40-43行) オーバーレイ用のセレクタを設定
      (44行目) 基盤図のセレクタをセット
      (45行目) 初期設定でgoogleHYBを表示します

    8. 住所検索する例 例を表示
      <!DOCTYPE html>
      <html lang="ja">
        <head>
          <title>Leaflet Geocoder</title>
          <meta charset="utf-8">
          <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css">
          <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
          <link rel="stylesheet" href="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.css">
          <script src="https://unpkg.com/leaflet-control-geocoder/dist/Control.Geocoder.js"></script>
      <style>
         html, body, #mapDiv { width: 100%; height: 100%; padding: 0px; margin: 0px; }
      </style>
      </head>
      <body>
        <div id="mapDiv"></div>
          <script>
            mapobj = L.map('mapDiv', { zoomControl: true });
            mapobj.setView( [35.36063,138.72731],11 );  // 図中心 富士山
            L.control.scale({maxWidth:300,position:'topright',imperial:false}).addTo(mapobj);  // スケールを表示
            var gsiattr = "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>国土地理院</a>";
            var gsi = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', { minZoom:5, attribution: gsiattr });
            var gsiphot = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg', { minZoom:5, attribution: gsiattr });
            var osm = L.tileLayer('http://tile.openstreetmap.jp/{z}/{x}/{y}.png',
                { minZoom:5, attribution: "©<a href='http://osm.org/copyright' target='_blank'>OpenStreetMap</a> contributors" });
            var gsirelief = L.tileLayer('http://cyberjapandata.gsi.go.jp/xyz/relief/{z}/{x}/{y}.png', { opacity: 0.4, maxNativeZoom: 15, minZoom:5, attribution: gsiattr });
            var gsirehillshademap = L.tileLayer('http://cyberjapandata.gsi.go.jp/xyz/hillshademap/{z}/{x}/{y}.png', { opacity: 0.35, maxNativeZoom: 16, attribution: gsiattr });
            var baseMaps = {
              "地理院地図": gsi,
              "地理院写真": gsiphot,
              "O.S.Map": osm
            };
            var overlayMaps = {
              "色別標高図": gsirelief,
              "陰影起伏図": gsirehillshademap
            };
            L.control.layers(baseMaps,overlayMaps,{maxWidth:200,position:'topleft',imperial:false}).addTo(mapobj); 
            osm.addTo(mapobj);  // 初期設定で osm を表示
            L.Control.geocoder({ // 地点検索を行う
              geocoder: L.Control.Geocoder.nominatim()
            }).addTo(mapobj);
          </script>
        </body>
      </html>
       【住所検索する例
      (6,7行目)  Leafletを使う為、cssとJavaScriptを読込み
      (8,9行目)  Geocoderを使う為、cssとJavaScriptを読込み
      (11行目) 地図表示域 'mapDiv' のスタイルを設定
      (15行目) 地図表示域の idを 'mapDiv' としました
      (17行目) 表示地図を変数 mapobj で L.mapオブジェクトに設定
      (19行目) scaleの表示位置などを設定
      (20-24行) 各タイル(地理院、osm 地図等)とその変数を設定
      (25,26行) 各オーバーレイ(色別標高図等)とその変数を設定
      (27-31行) 各タイルのセレクタの表示名を設定
      (32-35行) オーバーレイのセレクタの表示名を設定
      (36行目) 基盤図、オーバーレイ、各コントローラをセット
      (37行目) 初期設定で osm を表示します
      (38-40行) 地点検索コントローラをセット

    9. 緯度経度を指定する例 例を表示
      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>緯度・経度位置を表示</title>
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1">
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.0/dist/leaflet.css" />
        <script src="https://unpkg.com/leaflet@1.3.0/dist/leaflet.js"></script>
        <script>
            var mapobj; var Pset = []; 
            function init() {
              mapobj = L.map('mapDiv', { zoomControl:true });
              mapobj.setView([35.360631,138.727307], 11);  //初期中心 富士山
              L.control.scale({maxWidth:200,position:'bottomleft',imperial:false}).addTo(mapobj);  // 右下にスケールを表示
              var gsiattr = "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>国土地理院</a>";
              var gsi = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', { attribution: gsiattr });
              var gsiphot = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg', { attribution: gsiattr });
              var osm = L.tileLayer('http://tile.openstreetmap.jp/{z}/{x}/{y}.png',
                { attribution: "<a href='http://osm.org/copyright' target='_blank'>OpenStreetMap</a> contributors" });
              var baseMaps = {
                "地理院地図": gsi,
                "地理院写真": gsiphot,
                "O.S.Map": osm
              };
              L.control.layers(baseMaps).addTo(mapobj);
              osm.addTo(mapobj);
            }; // init()  ==============
            
            function set(){  // 中心位置変更
              var input = document.getElementById('latlng').value;
              var latlngStr = input.split(',', 2);
              var zm = document.getElementById('zom').value; 
              zm = parseInt (zm);
              let Pset = new L.LatLng( parseFloat(latlngStr[0]),parseFloat(latlngStr[1]) );
              mapobj.setView(Pset, zm); // 中心位置変更
              marker= L.marker(Pset).bindTooltip( latlngStr+"").addTo(mapobj); // 中心にマーカー
            }; // set() =============
            
        </script>
        <style>
           html, body{ height:100%; margin:0; padding:0; }
           #mapDiv {position:absolute;top:64px;left:3px;right:3px;bottom:3px;}
            section{ width:98%; margin: 0 auto; text-align:center; padding: 5px; }
            article{ font-size:20px; }
            #link{ position:absolute; top:8px; left:10px; }
            #latlng { width:220px; }
            #zom { width:30px; }
        </style>
      </head>
      <body onload="init()" background="../img/p_bcg007.gif">
          <div id="link"><a href="../ex-opn.html">leaflet地図</a></div>
          <section>
            <article>緯度,経度を入力して地図を表示</article>
            <div>
              北緯,東経:<input id="latlng" type="text" value="35.68,139.76">  
              Zoom:<input id="zom" type="textbox" value="13" size=2> 
              <input id="submit" type="button" value="セット" onclick="set()">
            </div>
          </section>
          <div id="mapDiv">ここに地図を表示</div>
      </body>
      </html>
       【緯度経度を指定する例
      (7,8行目)  Leafletを使う為、cssとJavaScriptを読込み
      (12行目) 表示地図を変数 mapobj で L.mapオブジェクトに設定
      (13行目) 初期地図で富士山を表示
      (14行目) scaleの表示位置などを設定
      (15-24行) 各タイル(地理院、osm 地図等)とその変数を設定
      (25-26行) 初期設定で osm 地図を表示します
      (29-37行) 中心位置変更のための function を記述
      (35行目) 変更中心位置をセット
      (36行目) その中心位置に Tooltip 付きマーカーをセット
      (40-48行) 各スタイルを設定
      (55-57行) 中心位置変更のための入力要素を記述
      (60行目) 地図表示域の idを 'mapDiv' としました

    10. レイヤ・マーカー切替地図  別窓表示  参考1  参考2
      <!DOCTYPE html>
      <html lang="ja">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">	
        <title>レイヤ・マーカー切替地図</title>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin=""/>
        <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
      <style>
        header { text-align:center; font-size:1.5rem; }
        #link{ position:absolute; top:8px; left:10px; }
        #map { position:absolute;top:2.8rem;left:5px;right:5px;bottom:5px; }
      </style> 
      </head>
      <body>
        <header>レイヤ・マーカー切替地図</header>
        <div id="link"><a href="../ex-opn.html">leaflet地図</a></div>
        <div id="map"></div>
      
      <script>
        var mymap;
        
        //(1)保持変数
        var tileList=[];          //タイル一覧
        var tileNowId=-1;      //変更したタイル番号(未変更時は-1)
        var tileSelectName='レイヤ切替';//タイル選択名保持(注意:(3)のL.control.layersでaddToする事)
        
        //(2) 「レイヤ切替」用
        tileList[0]=L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/hillshademap/{z}/{x}/{y}.png', { attribution: 'Map data <a href="https://maps.gsi.go.jp/development/ichiran.html" target="_blank">国土地理院</a>'});
        tileList[1]=L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/blank/{z}/{x}/{y}.png', { attribution: 'Map data <a href="https://maps.gsi.go.jp/development/ichiran.html" target="_blank">国土地理院</a>'});
        tileList[2]=L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/anaglyphmap_color/{z}/{x}/{y}.png', { attribution: 'Map data <a href="https://maps.gsi.go.jp/development/ichiran.html" target="_blank">国土地理院</a>'});  
        //「航空写真」用 3=zoom0〜1、4=zoom2〜8、5=zoom9〜13、6=zoom14〜18
        tileList[3]=L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', { attribution: 'Map data <a href="https://maps.gsi.go.jp/development/ichiran.html" target="_blank">国土地理院</a>'});
        tileList[4]=L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg', { attribution: 'Map data <a href="https://maps.gsi.go.jp/development/ichiran.html" target="_blank">国土地理院</a> Images on 世界衛星モザイク画像 obtained from <a href="https://lpdaac.usgs.gov/data_access">site</a> maintained by the NASA Land Processes Distributed Active Archive Center (LP DAAC), USGS/Earth Resources Observation and Science (EROS) Center, Sioux Falls, South Dakota, (Year). Source of image data product.'});
        tileList[5]=L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg', { attribution: 'Map data <a href="https://maps.gsi.go.jp/development/ichiran.html" target="_blank">国土地理院</a> データソース:Landsat8画像(GSI,TSIC,GEO Grid/AIST), Landsat8画像(courtesy of the U.S. Geological Survey), 海底地形(GEBCO)'});
        tileList[6]=L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg', { attribution: 'Map data <a href="https://maps.gsi.go.jp/development/ichiran.html" target="_blank">国土地理院</a>'});
            
          const hokkaidou = L.marker([43.064611, 141.346806]).bindPopup('北海道庁');const yamanashi = L.marker([35.664139, 138.568389]).bindPopup('山梨県庁');const fukuoka = L.marker([33.606766, 130.418304]).bindPopup('福岡県庁');const okinawa = L.marker([26.212410, 127.680885]).bindPopup('沖縄県庁');
          const addmarks = L.layerGroup([hokkaidou,yamanashi,fukuoka,okinawa]);
          var overlay = { 
          '追加 marks':addmarks // 追加マークグループを作成
          }
      
          mymap = L.map('map');  
          //(3)タイルメニューを登録
          //(注意:変更するマップは attributionを指定しない事)
          //(注意:(1)のtileSelectNameで指定した項目をaddToする事)
          L.control.layers({
            'OpenStreetMap':L.tileLayer('https://c.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: 'Map data © <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors, '}),
            '地理院地図'   :L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', { attribution: 'Map data <a href="https://maps.gsi.go.jp/development/ichiran.html" target="_blank">国土地理院</a>'}), 
            'レイヤ切替'   :L.tileLayer('https://www.achiachi.net/blog/_outside/1x1.png', { minZoom:4,maxZoom: 11,opacity:0}).addTo(mymap),
            '航空写真'     :L.tileLayer('https://www.achiachi.net/blog/_outside/1x1.png', { opacity:0})
          },overlay).addTo(mymap); 
        
          mymap.setView([35.6896, 139.6918], 8); 
            //レイヤーを2つ準備
            iconMarkers = L.featureGroup();
            iconMarkers2 = L.featureGroup();
        
            //アイコンマーカーをiconレイヤーに登録
            iconMarkers.addLayer( L.marker([35.6896, 139.6918]).bindPopup("東京都庁") );
            iconMarkers.addLayer( L.marker([35.4475, 139.6423]).bindPopup("神奈川県庁") );
            iconMarkers.addLayer( L.marker([35.6050, 140.1234]).bindPopup("千葉県庁") );
            iconMarkers.addLayer( L.marker([35.8572, 139.6490]).bindPopup("埼玉県庁") );
            iconMarkers.addLayer( L.marker([36.34172,140.44683]).bindPopup("茨城県庁") );
            iconMarkers.addLayer( L.marker([36.56544,139.88353]).bindPopup("栃木県庁") );
            iconMarkers.addLayer( L.marker([36.39067,139.06044]).bindPopup("群馬県庁") );
            
            iconMarkers2.addLayer( L.marker([35.6896, 139.6918]).bindPopup("東京都庁") );
            iconMarkers2.addLayer( L.marker([35.18032, 136.90667]).bindPopup("愛知県庁") );
            iconMarkers2.addLayer( L.marker([34.68627,135.51964]).bindPopup("大阪府庁") );
        
          //(4)初回処理
          tileChange();
        
          //(5)レイヤー変更イベント
          mymap.on('baselayerchange', function(e){
            tileSelectName=e.name;
            tileChange();
          });
        
          //(6)ズーム変更イベント
          mymap.on('zoomend', function(){
            tileChange();
          });
        
      //(7)レイヤー変更関数
      function tileChange(){
        mymap.removeLayer(iconMarkers);
        mymap.removeLayer(iconMarkers2);
        var id=-1; //次に表示するid(-1なら表示しない)
        var zoom=mymap.getZoom(); //ズーム取得
      
        if(tileSelectName==='レイヤ切替'){ 
          if      (zoom===4) { id=0;
          }else if(zoom===5 || zoom===6) { id=0;
            mymap.addLayer(iconMarkers2);
          }else if(zoom===7) { id=1;
            mymap.addLayer(iconMarkers2);
          }else if(zoom===8) { id=1;
            mymap.addLayer(iconMarkers);
          }else if(zoom===9 || zoom===10) { id=2;
            mymap.addLayer(iconMarkers);
          }else if(zoom===11){ id=2;
          }
        }else if(tileSelectName==='航空写真'){
          if(zoom<=1)       { id=3; //Zoom0~1の時
          }else if(zoom<=8) { id=4; //Zoom2~8の時
            mymap.addLayer(iconMarkers2);
          }else if(zoom<=13){ id=5; //Zoom9~13の時
            mymap.addLayer(iconMarkers);
          }else             { id=6; //Zoom14~18の時
          }
        }
        //現在マップの削除と新マップの表示
        if(tileNowId !== id){
          if(tileNowId === -1){
            tileNowId = id;
            tileList[tileNowId].addTo(mymap);
          }else{
            tileList[tileNowId].remove(mymap);
            if(id === -1){
              tileNowId = -1;
            }else{
              tileNowId = id;
              tileList[tileNowId].addTo(mymap);
            }
          }
        } 
      }
      </script>
      </body>
      </html>

    11. Web map に加筆、保存 (作図後は GeoJSON として export / import)  別窓表示  参考
      <!DOCTYPE html>
      <html lang="ja">
      <head>
        <meta charset="utf-8">
        <title>leaflet map 上に加筆、保存</title>  
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
        <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==" crossorigin="" >
        <script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet-src.js"  integrity="sha512-I5Hd7FcJ9rZkH7uD01G3AjsuzFy3gqz7HIJvzFZGFt2mrCS4Piw9bYZvCgUE0aiJuiZFYIJIwpbNnDIM6ohTrg==" crossorigin=""></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw-src.js"></script>
        <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.9/leaflet.draw-src.css' />
        <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-minimap/3.5.0/Control.MiniMap.js"></script>
        <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/leaflet-minimap/3.5.0/Control.MiniMap.css' />
      <!-- Google Maps API を利用 -->
          <script src="https://maps.googleapis.com/maps/api/js?key=【API key】" async defer></script>
          <script src="https://unpkg.com/leaflet.gridlayer.googlemutant@latest/dist/Leaflet.GoogleMutant.js"></script>
      <style>
          header{ width:98%; margin: 0 auto; text-align:center; padding: 4px; font-size:1.5em; }
          header span{ margin-left: 1em; font-size:0.7em; }
          #link{ position:absolute; top:8px; left:10px; }
          #mapDiv { z-index: 0; height: calc( 100vh - 88px ); }
          .actions {
            display: inline-block; cursor: pointer; text-decoration: none;
            color: black; font-family: 'Helvetica Neue'; font-size: 12px;
            background: linear-gradient(to bottom, #fff 0%, #f0f0f0 100%);
            border: 1px solid #ccc; box-shadow: 0 -1px 0 rgba(255, 255, 255, 1) inset;
            margin: 0.3em 0; padding: 0.2em 0.5em;
          } 
          .input-file { position: relative; display: inline-block; } 
          .input-file input[type="file"] {
            position: absolute; width: 100%; height:100%; left: 0; top: 0; opacity: 0; }
          .notes { border: 1px solid #ccc; }
      </style>
      </head>
      <body><!-- 作図は GeoJSON として export / import -->
        <header>map 上に加筆、保存 <span> <a href="http://bl.ocks.org/TetsuyaKimotsuki/0156c511e3217edf58beb206633308f8" target="_blank">参考</a></span></header>
        <div id="link"><a href="../ex-opn.html">leaflet地図</a></div>
        <div id="mapDiv"></div>
        <div class='actions' id='delete'>Delete Features</div>
        <a href='#' class='actions' id='export'>Export Features</a>
        <div class="input-file">
          <span class="actions">Import Features</span>
          <input type="file" id='import'>
        </div>
        <script>
            mapobj = L.map('mapDiv', { zoomControl: true });
            mapobj.setView( [35.36063,138.72731],10 );  // 図中心 富士山
            L.control.scale({maxWidth:300,position:'bottomleft',imperial:false}).addTo(mapobj);  // スケールを表示
            var gsiattr = "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>国土地理院</a>";
            var gsi = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', { minZoom:5, attribution: gsiattr });
            var gsiphot = L.tileLayer('https://cyberjapandata.gsi.go.jp/xyz/seamlessphoto/{z}/{x}/{y}.jpg', { minZoom:5, attribution: gsiattr });
            var osm = L.tileLayer('http://tile.openstreetmap.jp/{z}/{x}/{y}.png',
                { minZoom:5, attribution: "©<a href='http://osm.org/copyright' target='_blank'>OpenStreetMap</a> contributors" });
            var GmapsHYB = L.gridLayer.googleMutant({ minZoom:5, type:'hybrid' });   // 航空写真&ラベル
            var GmapsTER  = L.gridLayer.googleMutant({ minZoom:5, type:'terrain' });  // 地形地図
            // オーバーレイ用のタイルレイヤ   opacityで透過度を設定、maxNativeZoom以上のズームレベルのタイルは、指定レベルのタイル画像を拡大表示
            var gsirelief = L.tileLayer('http://cyberjapandata.gsi.go.jp/xyz/relief/{z}/{x}/{y}.png', { opacity: 0.4, maxNativeZoom: 15, minZoom:5, attribution: gsiattr });
            var gsirehillshademap = L.tileLayer('http://cyberjapandata.gsi.go.jp/xyz/hillshademap/{z}/{x}/{y}.png', { opacity: 0.35, maxNativeZoom: 16, attribution: gsiattr });
            var baseMaps = {
              "地理院地図": gsi,
              "地理院写真": gsiphot,
              "O.S.Map": osm,
              'Google Hybrid':GmapsHYB,
              'Google Terrain':GmapsTER
            };
            var overlayMaps = {
              "色別標高図": gsirelief,
              "陰影起伏図": gsirehillshademap
            };
            L.control.layers(baseMaps,overlayMaps,{maxWidth:200,position:'topright',imperial:false}).addTo(mapobj);
            osm.addTo(mapobj);  // 初期設定でgoogleHYBを表示
          // 描画レイヤの初期化
          var drawnItems = new L.FeatureGroup().addTo( mapobj );
          var drawControl = new L.Control.Draw({
            draw: {
              circle: {
                feet: false
              },
            },
            edit: {
              featureGroup: drawnItems,
            },
          }).addTo( mapobj );
          // 何かを描画した際の生成やら設定やら
            mapobj.on(L.Draw.Event.CREATED, function (e) {
            // https://gis.stackexchange.com/questions/202966/leaflet-popups-preserving-user-input-on-close-reopen
            // https://stackoverflow.com/questions/35760126/leaflet-draw-not-taking-properties-when-converting-featuregroup-to-geojson
            drawnItems.addLayer(e.layer);
            e.layer.feature = e.layer.feature || {};
            e.layer.feature.properties = e.layer.feature.properties || {};
            e.layer.feature.properties.note = e.layer.feature.properties.note || "";
            e.layer.feature.type = "Feature";
            popup = e.layer.bindPopup("");
            setFeatureProperties(e.layer);
            popup.on("popupopen", function (p) {
              $('#note_' + p.target._leaflet_id).attr('value', p.target.feature.properties.note).focus();
            });
            popup.on("popupclose", function (p) {
              p.target.feature.properties.note = $('#note_' + p.target._leaflet_id).val();
            });
          });
            mapobj.on(L.Draw.Event.EDITED, function (e) {
            e.layers.eachLayer(function (layer) {
              setFeatureProperties(layer);
            });
          });
          // http://leaflet.github.io/Leaflet.draw/docs/examples/popup.html
          var setFeatureProperties = function (layer) {
            // 線と多角形と四角形
            if (layer instanceof L.Polyline) {
              var latlngs = layer._defaultShape ? layer._defaultShape() : layer.getLatLngs();
              if (latlngs.length >= 2) {
                var distance = 0;
                for (var i = 0; i < latlngs.length - 1; i++) {
                  distance += latlngs[i].distanceTo(latlngs[i + 1]);
                }
                layer.feature.properties.distance = distance.toFixed(2) + " m"; // ex. distance 3728.81 m
              }
              layer.feature.properties.drawtype = L.Draw.Polyline.TYPE;
            }
            // 多角形と四角形
            if (layer instanceof L.Polygon) {
              var latlngs = layer._defaultShape ? layer._defaultShape() : layer.getLatLngs();
              var area = L.GeometryUtil.geodesicArea(latlngs);
              layer.feature.properties.area = L.GeometryUtil.readableArea(area, true); // ex. area 174.19 ha
              layer.feature.properties.drawtype = L.Draw.Polygon.TYPE;
            }
            // 四角形
            if (layer instanceof L.Rectangle) {
              layer.feature.properties.drawtype = L.Draw.Rectangle.TYPE;
            }
            // 円
            if (layer instanceof L.Circle) {
              layer.feature.properties.radius = layer.getRadius().toFixed(2) + " m"; // ex. radius 1097.02 m
              layer.feature.properties.drawtype = L.Draw.Circle.TYPE;
            }
            // マーカー
            if (layer instanceof L.Marker) {
              layer.feature.properties.drawtype = L.Draw.Marker.TYPE;
            }
            // popup時の表示内容の差し替え
            var contents = "";
            for (var key in layer.feature.properties) {
              if (key != 'note' && key != 'drawtype') {
                contents = contents + key + " " + layer.feature.properties[key] + "<br />";
              }
            }
            contents += "note <input type='text' class='notes' id='note_" + layer._leaflet_id + "' value=''>";
            layer.setPopupContent(contents);
          };  
          // geoJSONのdeleteボタン有効化
          document.getElementById('delete').onclick = function (e) {
            drawnItems.clearLayers();
          }
          // geoJSONのexportボタン有効化
          document.getElementById('export').onclick = function (e) {
            // Extractions GeoJson from featureGroup
            var geojson = drawnItems.toGeoJSON();
            // Stringify the GeoJson
            var convertedData = 'text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(geojson));
            // Create export
            document.getElementById('export').setAttribute('href', 'data:' + convertedData);
            document.getElementById('export').setAttribute('download', 'data.geojson');
          }
          // geoJSONのimportボタン有効化
          document.getElementById('import').onchange = function (e) {
            var reader = new FileReader();
            reader.onload = function () {
              var features;
              try {
                features = JSON.parse(reader.result).features;
              }
              catch (ex) {
                console.log("Imported file is not a JSON file.");
              }
              // importするfeatureをleaflet.drawで描画したかのように差し込む
              for (var feature of features) {
                if (feature.type == 'Feature') {
                  // 線
                  if (feature.geometry.type == 'LineString') {
                    var latlngs = [];
                    for (var point of feature.geometry.coordinates) {
                      latlngs.push(L.latLng(point[1], point[0]));
                    }
                    var handler = drawControl._toolbars.draw._modes.polyline.handler;
                    var layer = new L.Polyline(latlngs, handler.options.shapeOptions);
                    layer.feature = feature;
                    L.Draw.Feature.prototype._fireCreatedEvent.call(handler, layer);
                  }
                  else if (feature.geometry.type == 'Polygon') {
                    if (feature.properties.drawtype == L.Draw.Rectangle.TYPE) {
                      // 四角形
                      var handler = drawControl._toolbars.draw._modes.rectangle.handler;
                      var corner1 = L.latLng(feature.geometry.coordinates[0][0][1], feature.geometry.coordinates[0][0][0]);
                      var corner2 = L.latLng(feature.geometry.coordinates[0][2][1], feature.geometry.coordinates[0][2][0]);
                      var layer = new L.Rectangle(new L.LatLngBounds(corner1, corner2), handler.options.shapeOptions);
                      layer.feature = feature;
                      L.Draw.SimpleShape.prototype._fireCreatedEvent.call(handler, layer);
                    }
                    else {
                      // 多角形
                      var rings = [];
                      for (var ring of feature.geometry.coordinates) {
                        var latlngs = [];
                        for (var point of ring) {
                          latlngs.push(L.latLng(point[1], point[0]));
                        }
                        latlngs.pop(); // geoJsonのPolygonでは、最後に先頭と同じ点が入ってくるので削る
                        rings.push(latlngs);
                      }
                      var handler = drawControl._toolbars.draw._modes.polygon.handler;
                      var layer = new L.Polygon(rings, handler.options.shapeOptions);
                      layer.feature = feature;
                      L.Draw.Feature.prototype._fireCreatedEvent.call(handler, layer);
                    }
                  }
                  else if (feature.geometry.type == 'Point') {
                    var latlng = L.latLng(feature.geometry.coordinates[1], feature.geometry.coordinates[0]);
                    if (feature.properties.drawtype == L.Draw.Circle.TYPE) {
                      // 円
                      var handler = drawControl._toolbars.draw._modes.circle.handler;
                      var radius = parseFloat(feature.properties.radius); //" m"が勝手にとれるとは…
                      var layer = new L.Circle(latlng, radius, handler.options.shapeOptions);
                      layer.feature = feature;
                      L.Draw.SimpleShape.prototype._fireCreatedEvent.call(handler, layer);
                    }
                    else {
                      // マーカー
                      var handler = drawControl._toolbars.draw._modes.marker.handler;
                      var layer = new L.Marker(latlng, handler.options);
                      layer.feature = feature;
                      L.Draw.Feature.prototype._fireCreatedEvent.call(handler, layer);
                    }
                  }
                }
              }
            }
            console.log("Imported file: " + e.target.files[0].name);
            reader.readAsText(e.target.files[0]);
            // input type fileで同じファイルで2回目以降onChangeが発火しない問題への対応(IE10だと下記ではダメらしい)
            $('input[type=file]').val('');
          }
      </script>
      </body>
      </html>

    12. 行政区分地図   左別窓表示   右別窓表示

    13. 2画面レイヤ同期マップ   別窓表示

  3. 関連サイト
    1. reference  使い方  Leaflet 使い方  Leaflet入門  リファレンス  Leaflet 1.9  地図を表示  逆引き  
    2. Plugins  おすすめ  プラグイン  Web地図  距離計測  色マーカ  同期  utilize
    3. Overlay表示  雨雲レーダ  GoogleMapに雨雲  雲等を表示  Windy.com  地理院タイル  MapFan API  RainViewer
    4. removeLayer  Layers Control  あれこれ描く  Leaflet Drawプラグイン  サンプル  ESRI japan  晴歩雨描  DrawTrail
    5. 都道府県 geojson  行政区域データ  選挙区データ  行政区域マップ  地理院Vector
    6. CRS  地図以外の画像  平面図
    7. OSRMで経路探索  住所検索  古地図  マーカークラスター
    8. 地図タイルの仕組み  タイル地図入門  地理院タイル  QGISマニュアル  Leafletの使い方  地図タイル
    9. Bing Maps   チュートリアル  Bing Mapsを使う  サンプルコード