React.jsで一通り地図を扱う【React-Leaflet】
目次
用語説明
Reactとは?
→JavaScriptフレームワーク御三家の一。
Leafletとは?
→Webアプリで地図を扱うためのライブラリ。
React-Leafletとは?
→Reactに入れて使うLeafletのモジュール。
はじめに
Reactで地図を使ってる記事が少なかったので。
素のJavaScriptで地図を使おうとすると、画面の状態管理がめちゃくちゃしんどいですが、Reactの力である程度のりきることができます。
(Leafletが2.0に更新されてReactのContext APIをサポートしてたり、国土地理院がベクトルタイルを公開し始めたりと、地図を使ったWebアプリを作るのになにかと追い風な状況です。)
皆さんも地図を使ったWebアプリ始めましょう。
⭐️とりあえず地図を表示する⭐️
Reactアプリを立ち上げて、react-leafletを導入します。
npx create-react-app app cd app npm install react-leaflet leaflet
まずは、LeafletのMap要素だけを表示してみましょう。
説明のため、コードにコメントをつけています。
/* src/App.js */ import React from 'react'; import './App.css'; import {Map} from 'react-leaflet'; // leafletのCSSを別に読み込む必要があります(これ公式に書いてなくて結構詰まった) import '../node_modules/leaflet/dist/leaflet.css'; const App = () => ( // Map要素は画面読み込み時の座標(center: LatLngTupple)と縮尺(zoom: number)を指定する必要があります。 // viewport: {center, zoom} 形式で指定することもできます。 <Map center={[34.9843, 135.7596]} zoom={7}/> ); export default App;
/* src/App.css */ .leaflet-container { height: 100vh; width: 100vw; } /* デフォルトではMap要素の高さが0なので、なんらかの高さを指定する必要があります。Map要素のクラス名前はleaflet-containerです。 */
こんな感じで灰色の空っぽの地図が表示されます。
このままでは地図としての役割を果たさないので、地図タイル(説明は後述)を追加します。
import React from 'react'; import './App.css'; import '../node_modules/leaflet/dist/leaflet.css'; import { Map, TileLayer } from 'react-leaflet'; // 国土地理院の地図タイルを利用します。 // 国土地理院に限らず、Attributionの記述は必須です。 const tileAttribution = '<a href="https://maps.gsi.go.jp/development/ichiran.html">地理院タイル</a>'; const tileUrl = 'https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png'; const App = () => ( <Map center={[34.9843, 135.7596]} zoom={7}> <TileLayer attribution={tileAttribution} url={tileUrl} /> </Map> ); export default App;
ここまで書くと、いい感じで地図が表示されます。
地図タイルの説明😉✨↓
そこで、小さな正方形の画像に区切ってサーバーに保存しておき、必要な領域の画像だけサーバーから受け取る方法が考え出されました。
この区切られた正方形の画像が地図タイルで、地図タイルを配布しているサーバーをタイルサーバーといいます。
TileLayer要素にタイルサーバーのURLを指定することで、Leafletがユーザーの操作に応じて地図タイルをリクエストして表示してくれます。
地図タイルの概念はこちらのページがわかりやすいと思いますタイル座標 | 国土地理院。
⭐️Leaflet要素いろいろ⭐️
Map要素の内側にReact-Leafletの要素を追記することで、地図に色々書くことができます。
・範囲円を表示
<Circle center={[34.9843, 135.7596]} radius={100000} />
・線を表示
<Polyline positions={[[35, 136], [34, 135], [34.5, 137]]} color='red' />
・マーカーを表示
import {icon} from 'leaflet'; import iconImage from './marker.png' ... const markerIcon = icon({ iconUrl: iconImage, iconSize: [20, 32], iconAnchor: [20/2, 32], }); ... <Marker position={[34.9843, 135.7596]} icon={markerIcon} />
marker.pngの部分は好きな画像に置き換えることができます。
ここらへんの詳しいことはReact-Leaflet ComponentsとLeaflet API referenceを参考にしてみてください。
最後に1つ、GeoJsonというモノを紹介しておきます。
GeoJsonは2016年ごろにRFC 7946で標準化された、地理情報をJSON形式で扱うためのフォーマットです。
LeafletでももちろんGeoJSON形式を読み込むことができます。
地理情報のデータセットを表示する場合は、MarkerやCircleをArray.mapするより、GeoJSON形式で表示してしまうほうが、コードの見通しがよくなります。
・GeoJSONを表示
今回は例として京都駅のバス停のデータセットを利用します。(国土数値情報 バス停留所データの詳細)
データをこんな感じでGeoJSON形式に整形します。
Reactのソースコード
... import { Map, TileLayer, GeoJSON } from 'react-leaflet'; import {icon, marker} from 'leaflet'; import geoData from './geodata.json'; import iconImage from './marker-icon.png'; ... const markerIcon = icon({ iconUrl: iconImage, iconSize: [20, 32], iconAnchor: [20/2, 32], popupAnchor: [0, -32], }); ... <Map ... > ... <GeoJSON data={geoData} // pointToLayerは、GeoJSONの中のそれぞれのFeature(要素)ごとにLeaflet要素を返し、レイヤに追加する。 pointToLayer={(_feature, latlng) => marker(latlng, {icon: markerIcon})} // onEachFeatureは、それぞれのFeatureに対してイベントを指定したり設定を適用したりできる。 onEachFeature={(feature, layer) => layer.bindPopup(feature.properties.label)} /> </Map> ...
⭐️イベント管理いろいろ⭐️
後日追記