直線やポリゴン(多角形)を様々な属性(色や不透明度など)に設定し、 地図レイヤ上に配置できる。
L.polyline()
で連続する線分を、
L.polygon()
でポリゴンを描画し、それを含むレイヤを返す。
百聞は一見にしかずで、例を示す。
<!DOCTYPE html>
<html lang="ja">
<head>
<title>マップ: Objects on a Map!</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="../src/leaflet.css" />
<script src="../src/leaflet.js"></script>
<style type="text/css">
<!--
div#mymap {width: 90vw; height: 80vh; margin: 0 auto;}
-->
</style>
</head>
<body>
<h1>Objects on a Map</h1>
<div id="mymap"></div>
<!-- #mymap であるdivを配置したあとで -->
<script type="text/javascript" src="domon.js" charset="utf-8"></script>
<!-- 最初のマップ作成プログラム例をそのまま利用する -->
<script type="text/javascript" src="mapobj.js" charset="utf-8"></script>
<!-- ↑この行だけ追加 -->
</body>
</html>
この HTML ファイルで読み込む JavaScript プログラム
mapobj.js
を示す。
/* Add some objects on a Map */ var pl = [ // Polyline: 連続線分 [38.892123,139.818884], [38.891187,139.819313], [38.891780,139.823411] ]; var plProp = { // polylineのプロパティを定義 color: "red", // 線分の色 opacity: 0.4, // 線分の透明度 weight: 9 // 線分の太さ }; var plobj = L.polyline(pl, plProp).addTo(mymap); var pg = [ // Polygon: ポリゴン [38.895,139.821], [38.895,139.822], [38.894,139.822], [38.894,139.820], // 終点と始点は連結される ]; var pgOpt = { // polygonに与えるオプション color: "blue", // 線分の色 fillColor: "pink", // 塗りつぶし部分の色 fillOpacity: 0.2 // 塗りつぶし部分の透明度 }; var pgobj = L.polygon(pg, pgOpt).addTo(mymap); var marker1 = pl[0], marker2 = pg[0]; // polylineとpolygon各々の始点 var m1opt = {title: "その1"}, m2opt = {title: "その2"}; var m1 = L.marker(marker1, m1opt).addTo(mymap); var m2 = L.marker(marker2, m2opt).addTo(mymap); /* オブジェクトレイヤ.bindPopup() でクリック時のポップアップを定義できる */ plobj.bindPopup("ポリラインですよ!"); pgobj.bindPopup("ポリゴンですよ!"); m1.bindPopup("その1ですよ!"); // 次のようにあらかじめ1つのポップアップを開いておくことも可能 m2.bindPopup("その2ですよ!").openPopup();
図形、あるいはマーカに類するものを生成するメソッド一覧を示す。
引数に指定する LatLng
は
[緯度, 経度]
であり、
直後につけた []
は緯度経度の1次元の並び、
[][]
は緯度経度の2次元の並びを意味する。
L.polyline(LatLng[][, Options])
ポリライン(連続線分)を生成する。
L.multiPolyline(LatLng[][][, Options])
ポリライン(連続線分)集合を生成する。
L.polygon(LatLng[][, Options])
ポリゴンを生成する。第1引数に配列の配列を渡した場合は、 先頭の配列が初期ポリゴン、残りの配列が初期ポリゴンに開ける 穴ポリゴンとして扱われる。
L.multiPolygon(LatLng[][, Options])
ポリゴン集合を生成する。
L.rectangle(LatLngBnd[, Options])
2つのLatLng
からなる
LatLngBnd
をいずれかの対角2点の座標とした矩形を生成する。
L.circle(LatLng, radius[, Options])
LatLng
の位置を中心とし、半径
radius
メートルの円を生成する。
L.circleMarker(LatLng, radius[, Options])
LatLng
の位置を中心とし、
ズームに依らず半径一定の円を生成する。半径のデフォルトは10ピクセルで
Options
で radius
キーの値でピクセル値を指定して変更できる。
パスに関連するオブジェクトの様々な属性はオプションで設定できる。
http://leafletjs.com/reference.html#path-options
より主要値を抜粋しておく。
オプション | 型 | 既定値 | 意味 |
---|---|---|---|
stroke | ブール値 | true | パスを囲む線を描くか |
color | 文字列 | '#03f' | 線の色 |
weight | 数値 | 5 | 線の太さ(ピクセル値) |
opacity | 数値 | 0.5 | 線の不透明度 |
fill | ブール値 |
| 囲みを塗りつぶすか |
fillColor | 文字列 | 線色と同じ | 塗りつぶしの色 |
fillOpacity | 数値 | 0.2 | 塗りつぶしの不透明度 |
clickable | ブール値 | true | クリック可能にするか(true)、 地図の一部とするか(false) |
マーカに付けられるアイコンのデフォルトは青の逆しずく型だが、これを自作アイコンに変えることもできる。
マーカ本体となる画像と、さらに欲しければそれの影となる画像を用意する。
独自アイコン使用例
アイコン | ![]() |
影 | ![]() |
作成した画像は、L.icon()
でアイコンオブジェクトに変換する。
上記の2枚を指定する例を示す。
var qIcon = L.icon({ iconUrl: 'q.png', iconSize: [50, 80], iconAnchor: [19, 79], shadowUrl: 'q-shadow.png', shadowSize: [48, 23], shadowAnchor: [19, 19], });
作成したアイコンをマーカ作成時のオプションで指定し、 地図に貼り付けると図:独自アイコン使用例のようになる。
イベント処理例
地図に配置したオブジェクト上でのクリックやドラッグといったイベント は捕捉して、あらかじめ定めた挙動をさせることができる。
イベントに追随した処理を定義したいときは、
イベントを捕捉したいオブジェクトのもつ on()
メソッドに、捕捉したいイベントの種類とそのときの処理を行なう関数を指定する。
たとえば、地図上に配置するあるマーカをドラッグしたら、 それに応じてポップアップするメッセージを変えるものを定義するとしたら 以下のようになる。
var mrk = L.marker(LatLng, {draggable: true}).addTo(map) mrk.bindPopup("初期のポップアップメッセージ"); mrk.on('dragend', function(e) { /* イベントオブジェクトを持つ引数 e を用いた処理 */ });
この例では変数 mrk
が保持するマーカに対し
mrk.on('drag', function(e){...})
として、
ドラッグイベント発生時の処理を割り当てている。
処理を定義する無名関数が受け取る引数(この例では e
)は
Event Object で、以下2つのプロパティを持つ。
type | 発生したイベントの種類('click'など) |
target | イベント発生のオブジェクト |
e.target
はマーカオブジェクト自身になるので、
これから配置された緯度経度を得るには latlng
プロパティにアクセスすればよい。これを利用して、
マーカをドラッグして位置を変えたら、
その位置をマーカのポップアップメッセージに示すようにイベント処理関数を定義すると以下のようになる。
/* ここまでに mymap 変数に L.map オブジェクトが代入されているとする */ center = L.latLng([38.891, 139.824]); var dragmarker = L.marker(center, { draggable: true, icon: qIcon }).addTo(mymap); dragmarker.bindPopup("この位置は"+center+"です。"); dragmarker.on('dragend', function(e) { var latlng = e.target.getLatLng(); e.target.setPopupContent("この位置は"+latlng+"です。"); });
なお、この例では e.target
から緯度経度を求めたが、
この例では、発生イベントが MouseEvent
であるため、e.latlng
としてイベントから直接求めることもできる。
MouseEvent
の場合は以下のプロパティも定義される。
latlng | 地図上での緯度経度位置 |
layerPoint | レイヤ上の相対ピクセル位置 |
containerPoint | マップコンテナ上の相対ピクセル位置 |
originalEvent | DOMレベルでのマウスイベント |
また、受け取るイベントが LocationEvent
の場合は以下のプロパティも定義される。
latlng | GPSで取得した緯度経度位置 |
bounds | GPS精度を考慮した現在位置範囲 |
accuracy | GPS誤差(メートル) |
altitude | WGS84高度 |
altitudeAccuracy | altitudeの誤差 |
heading |
前回からの移動方向(北から反時計回り360度まで) |
speed | 移動速度(m/s) |
timestamp | 位置取得時刻 |
その他、イベント処理を行ないたい場合に受け取ることができる イベント一覧を示す。
イベント | 何で発生するか |
---|---|
click | クリックまたはタップ |
dblclick | ダブルクリックまたはダブルタップ |
mousedown | マウスボタン押下 |
mouseup | マウスボタン開放 |
mouseover | マウスポインタが地図に入ったとき |
mouseout | マウスポインタが地図から出たとき |
mousemove | 地図上でマウスが動いたとき |
contextmenu | 右クリックまたは長タップ |
focus | 地図にフォーカスを入れたとき |
blur | 地図がフォーカスを失うとき |
preclick | クリックイベント直前 |
load | 地図ロード時 |
unload | 地図がremove() されたとき |
viewreset | 地図再描画時 |
movestart | 移動開始時 |
move | 移動時 |
moveend | 移動終了時 |
dragstart | ドラッグ開始時 |
drag | ドラッグ中その都度 |
dragend | ドラッグ終了時 |
zoomstart | ズーム開始時 |
zoomend | ズーム終了時 |
zoomlevelchange | ズーム変更時 |
resize | 地図リサイズ時 |
autopanstart | ポップアップによる自動パン開始時 |
layeradd | レイヤ追加時 |
layerremove | レイヤ追加時 |
baselayerchange | ベースレイヤ変更時 |
overlayadd | オーバーレイ追加時 |
overlayremove | オーバーレイ削除時 |
locationfound | geolocation捕捉時 |
locationerror | geolocation捕捉エラー時 |
popupopen | ポップアップが開く時 |
popupclose | ポップアップが閉じる時 |
これまで紹介したようなプログラムでは、様々な地図オブジェクトを 作成するための値を変数代入していたが、このようにすると代入する数だけ グローバル変数が必要になる。仮に、Leaflet以外のJavaScriptプログラムを利 用するときに、各グローバル変数同士が衝突する可能性が生ずる。
作成するJavaScriptプログラムの汎用性を高めるためには、 可能なかぎりグローバル変数の使用を控えることが重要である。 このために、作成プログラムで利用する変数を、外を被う関数内に入れ、 関数内スコープに閉じ込める工夫をするのが望ましい。
たとえば、以下のようなプログラム片を考える(leaflet.js を読み込んでいることを仮定)。
var mymap = L.map("mymap").setView([38.891, 139.824], 16); L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' }).addTo(mymap); var pl = [ [38.892123,139.818884], [38.891187,139.819313], [38.891780,139.823411] ]; var plProp = {color: "red", opacity: 0.4, weight: 9}; var plobj = L.polyline(pl, plProp).addTo(mymap);
4つの変数 mymap, pl, plProp, plobj を利用しているがこのような処理を 1つの関数内に入れ、ブラウザがページを読み込みDOM構築が終わったときに その関数を呼ぶように改める。
(() => { function myMapInit() { var mymap = L.map("mymap").setView([38.891, 139.824], 16); L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors' }).addTo(mymap); var pl = [ [38.892123,139.818884], [38.891187,139.819313], [38.891780,139.823411] ]; var plProp = {color: "red", opacity: 0.4, weight: 9}; var plobj = L.polyline(pl, plProp).addTo(mymap); } document.addEventListener("DOMContentLoaded", function(){ myMapInit("mymap")}, false); })();
1行目と最終行にあるように、プログラム全体をアロー関数
() => { …… }
で無名関数定義してさらに
(無名関数)()
で即座に呼び出している。
このようにすることでグローバル空間で定義される関数がなくなり
名前の衝突の可能性が消える。
ソース: mymap3.js
mapobj.js をこのような形で書き変えた ものを示す。
<!DOCTYPE html>
<html lang="ja">
<head>
<title>マップ: My First Map!</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="../src/leaflet.css" />
<script src="../src/leaflet.js"></script>
<script type="text/javascript" src="mymap.js" charset="utf-8"></script>
<!-- ここで mymap.js をロードするが start() 関数が呼ばれるのは -->
<!-- HTML文書ロードが完了してから。 -->
<style type="text/css">
<!--
div#mymap {width: 90vw; height: 80vh; margin: 0 auto;}
-->
</style>
</head>
<body>
<h1>My First Map!</h1>
<div id="mymap"></div>
<!-- bodyでは #mymap であるdivを配置するのみ -->
</body>
</html>
これから呼ばれる JavaScript プログラムは以下のとおり。
(() => { function MyMap(id) { var mymap; function init(id) { mymap = L.map(id).setView([38.891, 139.824], 16); L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', { attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> \ contributors' }).addTo(mymap); } function mapObjs() { var pl = [ // Polyline: 連続線分 [38.892123,139.818884], [38.891187,139.819313], [38.891780,139.823411] ]; var plProp = { // polylineに与えるオプション color: "red", // 線分の色 opacity: 0.4, // 線分の透明度 weight: 9 // 線分の太さ }; L.polyline(pl, plProp).addTo(mymap); var pg = [ // Polygon: ポリゴン [38.895,139.821], [38.895,139.822], [38.894,139.822], [38.894,139.820], // 終点と始点は連結される ]; var pgOpt = { // polygonに与えるオプション color: "blue", // 線分の色 fillColor: "pink", // 塗りつぶし部分の色 fillOpacity: 0.2 // 塗りつぶし部分の透明度 }; L.polygon(pg, pgOpt).addTo(mymap); var marker1 = pl[0], marker2 = pg[0]; var m1opt = {title: "その1"}, m2opt = {title: "その2"}; var m1 = L.marker(marker1, m1opt).addTo(mymap); var m2 = L.marker(marker2, m2opt).addTo(mymap); m1.bindPopup("その1ですよ!"); m2.bindPopup("その2ですよ!"); } // ↓初期化時にすぐ実行される init(id); mapObjs(); }; document.addEventListener("DOMContentLoaded", function(){ MyMap("mymap");}, false); })();
以後は、domon-mymap.html と同様の形式で書くものとする。