本日は「Leaflet入門講座」にご参加いただきありがとうございます!この教科書では、ブラウザだけでプログラミングができる環境「CodePen」を使って、OpenStreetMapとLeafletによるオリジナルWEB地図の作り方を学びます。
1. 講座のゴール
- Webブラウザだけで動く地図アプリの開発環境(CodePen)に触れる
- JavaScriptを使って、長崎の地図をWEBページに表示する
- マーカーや円、さらにプラグインを使ったルート検索・表示切り替えに挑戦する
2. 準備するもの
- インターネットに接続されたパソコン
- WEBブラウザ(Google Chromeなど)
- CodePen のアカウント(事前にサインアップ・ログインしておいてください)
3. CodePenの画面の見方とテンプレートからの開始方法
今回は、講師があらかじめHTML・CSS・LeafletのCDN設定を済ませた専用テンプレートを用意しています。ゼロから入力する手間が省けるため、まずはこのテンプレートを自分のアカウントに複製(Fork)して始めましょう!
- 以下のテンプレートリンクを開きます:
https://codepen.io/editor/tetsuji-ishii/pen/019f2a4c-772a-7863-84be-b43a2738f8f5 - 画面下部(またはメニュー内)にある 「Fork」 ボタンをクリックします。
- これであなた専用の編集ページが作成され、自由にコードを書き換えられるようになります。
CodePenの編集画面は、主に以下のエリアに分かれています。
- HTMLエディタ:WEBページの「骨組み(構造)」を書く場所です(テンプレートではすでに地図用のエリアが用意されています)。
- CSSエディタ:WEBページの「見た目(デザイン)」を整える場所です(テンプレートですでに画面いっぱいに広げる設定がされています)。
- JS(JavaScript)エディタ:ここから地図を動かしたり、ピンを立てたりする「プログラム」を実際に書いていきます。
- Result(プレビュー)画面:画面の下部または右側にあり、書いたコードの結果がリアルタイムで反映されます。
[!NOTE]
無料プラン(Freeアカウント)の場合、作成したPenは基本的に「公開(Public)」状態になります。コードを非公開にしたい場合は有料プランへのアップグレードが必要になるため、機密情報やパスワードなどを誤って書き込まないようご注意ください。
4. ハンズオン:5つのステップ
ここからJavaScriptエディタにコードを書きながら進めていきましょう!
step 1. 地図の初期化
まずは、どの場所を中心に地図を表示するか(緯度・経度)と、ズーム倍率を設定して地図オブジェクトを作成します。
// [緯度, 経度] と ズームレベルを指定 (浦和駅周辺)
const map = L.map('map').setView([35.8590, 139.6571], 14);
チャレンジ
step 2. タイルレイヤーの追加 (OpenStreetMapを使用)
地図のデザイン(背景の地図画像)となるOpenStreetMapのタイルレイヤーを読み込んで、地図に追加します。
// 2. タイルレイヤーの追加 (OpenStreetMapを使用)
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
チャレンジ
1. 標準的な地図(ベースマップ)
-
OpenStreetMap 標準(Standard)
-
特徴: OpenStreetMap公式の標準スタイル。世界中で最も広く使われています。
-
URL:
[https://tile.openstreetmap.org/](https://tile.openstreetmap.org/){z}/{x}/{y}.png -
注意点: 利用規約(タイル利用ポリシー)が厳しく設定されており、大量のリクエストや商用での過度な利用には制限があります。
-
OpenStreetMap フランス版(OSM-FR)
-
特徴: フランスのコミュニティが管理するスタイル。フランス語圏の名称や独自のアイコンが優先されますが、日本国内でも綺麗に表示されます。
-
URL:
https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png -
Humanitarian(人道支援向けスタイル)
-
特徴: 災害時や人道支援用に最適化された、視認性の高い配色が特徴のスタイルです。
-
URL:
https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png
2. 特殊・専門的な地図
-
OpenTopoMap(地形図)
-
特徴: 等高線や標高の陰影(山岳・地形)が詳細に表現される、登山やアウトドア向けの地図です。
-
URL:
https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png -
CyclOSM(サイクリング向け)
-
特徴: 自転車道や駐輪場、サイクリングに役立つ情報が分かりやすくハイライトされるデザインです。
-
URL:
https://{s}.tile.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png -
ÖPNVKarte(公共交通機関向け)
-
特徴: バス停や鉄道の駅・路線などの交通インフラが強調して表示されるマップです。
-
URL:
[https://tile.memomaps.de/tilegen/](https://tile.memomaps.de/tilegen/){z}/{x}/{y}.png
3. シンプル・スタイリッシュな地図(Carto製)
WEBサイトのデザインになじみやすい、モノトーンやダーク調のデザインです(利用時は要クレジット表記)。
-
Positron(ライト・明るい白系)
-
URL:
https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png -
Dark Matter(ダーク・黒系)
-
URL:
https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png -
Voyager(カラー・ポップな街並み系)
-
URL:
https://cartodb-basemaps-{s}.global.ssl.fastly.net/rastertiles/voyager/{z}/{x}/{y}.png
💡 Leafletでの実装時のポイント
サブドメイン({s})を含むURLを使用する場合(OSMフランス版やCartoなど)、Leaflet側で以下のように設定すると、読み込みの負荷が分散されて表示がスムーズになります。
var map = L.map('map').setView([32.7448, 129.8737], 15);
L.tileLayer('https://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png', {
maxZoom: 20,
subdomains: ['a', 'b', 'c'],
attribution: '© OpenStreetMap France | © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
step 3. マーカーの追加
特定の場所にピン(マーカー)を立て、クリックしたときに説明文(ポップアップ)が表示されるようにします。
// 3. マーカーの追加
// スタート地点
const startPos = [35.8590, 139.6571];
const startMarker = L.marker(startPos).addTo(map);
startMarker.bindPopup("<b>スタート地点: 浦和駅</b><br>ここから散歩を開始します。").openPopup();
// 休憩ポイント
const restPos = [35.8710, 139.6460];
const restMarker = L.marker(restPos).addTo(map);
restMarker.bindPopup("<b>休憩ポイント: 北浦和公園</b><br>美術館や噴水があります。");
// ゴール地点
const goalPos = [35.8722, 139.6465];
const goalMarker = L.marker(goalPos).addTo(map);
goalMarker.bindPopup("<b>ゴール地点: 北浦和駅</b><br>お疲れ様でした!");
チャレンジ
基本的には、bindPopup() の中にHTMLタグ(<img>)を記述するだけで簡単に表示できます。
基本コード(JSエディタに追加する例)
// 1. マーカーを立てる
var marker = L.marker([32.7448, 129.8737]).addTo(map);
// 2. ポップアップに画像を表示する
marker.bindPopup(`
<div style="text-align: center;">
<b>埼玉の風景</b><br>
<p>ここに簡単な説明文が入ります。</p>
<!-- 画像を表示するHTMLタグ -->
<img src="https://images.unsplash.com/photo-1542051841857-5f90071e7989"
alt="埼玉の景色"
style="width: 200px; height: auto; border-radius: 4px; margin-top: 5px;">
</div>
`);
💡 きれいに表示するためのポイント
- バッククォート(
)を使う** JavaScriptの文字列を囲む際、通常のシングルクォート(')やダブルクォート(")ではなく、バッククォート(:Shift+@キーなど)を使うと、複数行にわたるHTMLタグをそのまま書きやすくなります。 -
画像のサイズ調整(CSS / インラインスタイル)
インターネット上の画像はサイズが大きすぎることが多いため、style="width: 200px; height: auto;"のように幅を指定しておくと、ポップアップからはみ出さず綺麗に収まります。 - 自分の持っている写真を使いたい場合
-
CodePenを使う場合:CodePenの「Assets」機能(Proプラン等)に画像をアップロードするか、Imgurなどの画像ホスティングサービス、または自身のGitHubなどに画像をアップロードして、その直リンク(URL)を
src="..."に指定します。 - ローカル(自分のパソコン内)の画像を使う場合:CodePenなどのブラウザ環境ではそのまま読み込めないため、Web上に公開されているフリー素材のURLなどをテスト用に使うのが一番スムーズです。
step 4. 円を表示してみる (付近の注目エリアなど)
指定した地点の周囲に円を描画して、注目エリアや行動範囲を視覚的に分かりやすく表示します。
// 4. 円を表示してみる (付近の注目エリアなど)
const circle = L.circle([35.8710, 139.6460], {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.2,
radius: 200 // 半径(メートル)
}).addTo(map);
circle.bindPopup("このエリアは桜がきれいです。");
step 5. 【挑戦】散歩コースのルート検索 (Leaflet Routing Machine)
OSMのデータを使用して道沿いの最短ルートを自動算出するプラグイン「Leaflet Routing Machine」に挑戦します!
① ルート検索用のプラグインをindex.htmlに追加する
※テンプレートを利用する場合はすでに追加してあります。
- CSS追加CDN (index.html):
<!-- Leaflet Routing MachineのCSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet-routing-machine.css" />
- JS追加 (index.html):
<!-- Leaflet Routing MachineのJavaScript -->
<script src="https://unpkg.com/leaflet-routing-machine@latest/dist/leaflet-routing-machine.js"></script>
② ルート検索と表示・非表示の切り替えコードを書く
JSエディタの最後尾に以下のコードを追加してみましょう。
// 5. 散歩コースのルート検索 (Leaflet Routing Machine)
// OSMのデータを使用して道沿いの最短ルートを自動算出します
// マーカーの座標 (getLatLng()) を利用してルートを設定します
const routingControl = L.Routing.control({
waypoints: [
startMarker.getLatLng(),
restMarker.getLatLng(),
goalMarker.getLatLng()
],
routeWhileDragging: true,
lineOptions: {
styles: [{ color: 'blue', opacity: 0.6, weight: 6 }]
},
// language: 'ja', // エラー回避のため一旦コメントアウト(または 'en' を指定)
show: true // 右上にルート案内を表示
}).addTo(map);
// ルートの表示・非表示切り替え
const routeSwitch = document.getElementById('route-switch');
routeSwitch.addEventListener('change', (e) => {
if (e.target.checked) {
// 表示する
routingControl.addTo(map);
} else {
// 非表示にする
map.removeControl(routingControl);
}
});
