目次

🌏Leaflet 地図タイル切り替え(改)

Leafletの標準的なタイルレイヤーコントロール(L.control.layers)(関連記事)ではズームによってタイルサーバーや著作権表を切り替える事ができないようなので、ズームによってタイルサーバーや著作権表を切り替える機能を(無理矢理)追加してみました。

これによって高倍率時にマップタイル無い場合に代替のマップタイルを表示したり、国土地理院の写真などでズーム別に著作権表記を書き換える必要がある場合などに利用できます。

注意:「Leaflet勉強のための試作プログラムなので間違っている可能性があります」「DokuWikiは個別にヘッダを編集できないので通常とは少し違う構造になっています」


デモ

地図右上のタイルコントロールから「デモ」または「デモ写真」を選びズーム変更するとズームによって地図が切り替わります。

タイルの「デモ」を選ぶとズームによって地図タイルが白地図・カラー地形図・モノクロ地形図に切り替わります。「デモ写真」を選ぶとズームによってタイルサーバーと著作権表示が切り替わります。

ソースコード

主にコメント行のある部分がLeaflet - OpenStreetMap表示から追加された部分です(削除された部分は書いてありません)

html部分

<div id="mapid" style="width: 100%; height: 400px;"></div>

JavaScript部分

<div id="mapid" style="width: 100%; height: 400px;"></div>
<script src="https://【自分のサーバーアドレスとパス】/leaflet.js"></script>
<script>
  function cssLoad(cssFile){
    if(document.all){
      document.createStyleSheet(cssFile);
    }else{
      var link = document.createElement("link");
      link.rel = "stylesheet";
      link.href = cssFile;
      link.type = "text/css"
      document.getElementsByTagName('head')[0].appendChild(link);
    }
  }
  cssLoad("https://【自分のサーバーアドレスとパス】/leaflet.css");
  function addOnload(evtFunc){
    if(window.addEventListener) {
      window.addEventListener('load', evtFunc, false);
    } else if(window.attachEvent){ //IE用
      window.attachEvent('onload', evtFunc);
    } else {
      //alert('window.onload エラー');
    }
  }  
  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>'});
 
 
  addOnload(function(){
    mymap = L.map('mapid');
 
 
    //(3)タイルメニューを登録
    //(注意:変更するマップは(attributionを指定しない事)
    //(注意:(1)のtileSelectNameで指定した項目をaddToする事)
    L.control.layers({
      'OpenStreetMap':L.tileLayer('https://c.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors, '}),
      'デモ'         :L.tileLayer('https://www.achiachi.net/blog/_outside/1x1.png', { minZoom:5,maxZoom: 10,opacity:0}).addTo(mymap),
      '標準地図'     :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', { opacity:0})
    }).addTo(mymap);
 
 
    mymap.setView([35.6896, 139.6918], 8);
 
 
    //(4)初回処理
    tileChange();
 
    //(5)レイヤー変更イベント
    mymap.on('baselayerchange', function(e){
      tileSelectName=e.name;
      tileChange();
    });
 
    //(6)ズーム変更イベント
    mymap.on('zoomend', function(){
      tileChange();
    });
 
});
 
 
//(7)レイヤー変更関数
function tileChange(){
  var id=-1; //次に表示するid(-1なら表示しない)
  var zoom=mymap.getZoom(); //ズーム取得
  if(tileSelectName==='デモ'){
    if      (zoom===5) { id=0;
    }else if(zoom===6) { id=0;
    }else if(zoom===7) { id=1;
    }else if(zoom===8) { id=1;
    }else if(zoom===9) { id=2;
    }else if(zoom===10){ id=2;
    }
  }else if(tileSelectName==='デモ写真'){
    if(zoom<=1)       { id=3; //Zoom0~1の時
    }else if(zoom<=8) { id=4; //Zoom2~8の時
    }else if(zoom<=13){ id=5; //Zoom9~13の時
    }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>

説明

処理の概要は、通常のタイルコントロールによる地図表示は透過度ゼロで見えない状態にし、代わりに選択したタイル名とズームから表示したいマップを重ね表示しているだけです。

主な処理内容と使用するマップタイルごとの変更箇所は下記のようになります。

(1)保持変数

タイルの表示状態を自己管理するための変数です。

タイル名を取得する方法がわからないので、最初に表示するタイル名は tileSelectName に手動登録します。

var tileSelectName='タイル名2';

(2)タイルチェンジ用

タイル変更で使用するタイルサーバーや著作権情報などを登録します。(番号は通し番号でなくても良い)

tileList[番号]=L.tileLayer('タイルアドレス', { attribution: '著作権表示'});

(3)タイルメニューを登録

地図タイルズームで切り替えない項目は通常と同じように登録します。(関連記事)

地図タイルを切り替える項目は透過度を0(opacity:0)にして著作権表示(attribution)は未登録にして下さい。著作権表示は上記2番の上書きする側の登録を利用します。またタイルの名前で切り替えるので名称は他と重複しないようにして下さい。デモでは透過度を0にして見えない状態にしているので通常の地図タイルで登録せず1×1ピクセルの小さいpngファイル読み込ませて通信が極力発生しないようにしています。

(1)のtileSelectNameで指定したタイルにはaddTo()を付けて下さい。

minZoom,maxZoom を指定するとズームを制限できます。

L.control.layers({
  'タイル名1':L.tileLayer('タイルアドレス1', { attribution: '著作権表示1'         }),
  'タイル名2':L.tileLayer('タイルアドレス2', { opacity:0                          }).addTo(マップ名),
  'タイル名3':L.tileLayer('タイルアドレス3', { minZoom:数値,maxZoom:数値,opacity:0}),
  'タイル名4':L.tileLayer('タイルアドレス4', { attribution: '著作権表示4'         })
}).addTo(マップ名);

(4)初回処理

初回のタイル変更用です。

(5)タイル変更イベント

レイヤーコントロールでタイルを変更した時に発生するイベントです。選択したタイル名を取得して(7)レイヤー変更関数をを呼び出す。

(6)ズーム変更イベント

ズームが変更した時に発生するイベント。(7)レイヤー変更関数を呼び出す

(7)レイヤー変更関数

レイヤーコントロールで選択したタイル名とズームから実際に表示したいタイルを追加表示します。既に別のタイルが表示されている場合は先にそのタイルを削除します。

下記の部分の id= に2番で登録した tileList[番号] の番号を割り当ててると地図を変更します。「デモ写真」のように範囲指定でidを割り当てても良いし、「デモ」のように各ズーム単位でidをセットしてもよいです。

  if(tileSelectName==='デモ'){
    if      (zoom===5) { id=0;
    }else if(zoom===6) { id=0;
    }else if(zoom===7) { id=1;
    }else if(zoom===8) { id=1;
    }else if(zoom===9) { id=2;
    }else if(zoom===10){ id=2;
    }
  }else if(tileSelectName==='デモ写真'){
    if(zoom<=1)       { id=3; //Zoom0~1の時
    }else if(zoom<=8) { id=4; //Zoom2~8の時
    }else if(zoom<=13){ id=5; //Zoom9~13の時
    }else             { id=6; //Zoom14~18の時
    }
  }