Reactとリーフレットを使用してマップを作成する方法
公開: 2022-03-10CSVまたはJSONファイルから情報を取得することは、複雑であるだけでなく、面倒でもあります。 同じデータを視覚補助の形で表現する方が簡単です。 この記事では、SF消防署が対応した非医療火災事件の場所を地図上に示します。
このチュートリアルでは、次のツールを使用します。
- リーフレット
インタラクティブマップ用のJavaScriptライブラリ - React
ユーザーインターフェイスを構築するためのJavaScriptライブラリ - React-Leaflet
LeafletマップのReactコンポーネント
リーフレットとは何ですか?
約27kの星で、Leaflet.jsはモバイルフレンドリーなインタラクティブマップ用の主要なオープンソースJavaScriptライブラリの1つです。 最新のブラウザではHTML5とCSS3を利用しながら、古いブラウザでもアクセスできます。 全体として、すべての主要なデスクトップおよびモバイルプラットフォームをサポートします。
リーフレットの重さは約38KBで、基本的なものに最適です。 追加の拡張機能については、膨大な量のプラグインで拡張できます。
NPR、ワシントンポスト、ボストングローブなど、多くの新聞やその他の組織が、詳細なデータプロジェクトにLeafletを使用しています。
たとえば、サンフランシスコクロニクルは、カリフォルニアファイアトラッカーと呼ばれるプロジェクトを実施しました。これは、リーフレットを使用して、カリフォルニア全体で燃えている山火事に関する情報を提供するインタラクティブマップです。 彼らは火事の原因を特定しただけでなく、火事の軌跡も示してくれました。
これは入門チュートリアルであるため、火災事故の場所をマークし、それに関する詳細を表示するだけです。
Reactに飛び込む前に、Leafletの基本を理解しましょう。 このために、リーフレットマップを設定し、マーカーとポップアップを操作する簡単な例を作成します。
まず、 /project
フォルダーにindex.htmlファイルとapp.jsファイルを作成し、後者をindex.htmlファイルにリンクしましょう。
Leafletの使用を開始するには、headタグでLeafletCSSとLeafletJSをリンクする必要があります。 覚えておくべきことの1つは、LeafletCSSがLeafletJSの前にあるということです。 リーフレットは以上です。
index.htmlファイルに追加する必要があるものがもう1つあります。それは、マップを保持するコンテナーです。
<div></div>
忘れる前に、divに高さを与えましょう。
#mapid { height: 1000px; }
今、楽しい部分が来ます。 新しいJavaScriptファイルを作成する場合でも、スクリプトタグを続行する場合でも、 L.map('mapid')
を呼び出す前に、 <div id="mapid">
がdomに追加されていることを確認してください。
あなたはおそらく「しかし、なぜ?」と尋ねているでしょう。 まあ、それは、まだ存在していないコンテナにマップをバインドするとエラーが発生するためです。
Uncaught Error: Map container not found
マップの作成
さて、楽しい部分に移りましょう。 マップを初期化するために、いくつかのオプションを使用してdivをL.map()
に渡します。
const myMap = L.map('mapid', { center: [37.7749, -122.4194], zoom: 13 })
何が起こったのかを理解するために、一歩一歩進んでいきましょう。 Leaflet APIのMapクラスを使用して、ページ上にマップを作成します。 このクラスに2つのパラメーターを渡します。
-
DOM
を表す文字列変数を渡しました - マップオプションを備えたオプションのオブジェクトリテラル
クラスに渡すことができるオプションはたくさんありますが、主な2つのオプションは中央とズームです。 中心はマップの初期の地理的中心を定義し、ズームは初期のマップズームレベルを指定します。 どちらもデフォルトでは未定義です。
センターはサンフランシスコの座標を通過しました。 順方向および逆方向のジオコーディングを実行できる場所はたくさんありますが、このような基本的な検索では、グーグルで検索できます。
通常、ズームの値は、表示する内容によって異なります。 都市または州を表示しますか? 国または大陸? 先に進み、ズーム値を試して、より良いアイデアを得てください。 この例では、都市全体を示しているため、13を選択しました。
マップを初期化する別の方法は、setView()を使用することです。 座標の配列とズームレベルの整数を取ります。
const myMap = L.map('map').setView([37.7749, -122.4194], 13);
デフォルトでは、マップ上のすべてのマウスとタッチの操作が有効になっており、ズームと属性のコントロールがあります。
レイヤーの作成
次に、マップにタイルレイヤーを追加します。 私たちの場合、それはMapboxStreetsタイルレイヤーです。 TileLayerクラスをインスタンス化することにより、さまざまなタイプのタイルレイヤーを追加できます。
タイルレイヤーを作成するには、タイル画像のURLテンプレート、アトリビューションテキスト、およびレイヤーの最大ズームレベルを設定する必要があります。 URLテンプレートは、サービスプロバイダーから目的のタイルレイヤーにアクセスできるようにするものです。 MapboxのStaticTiles APIを使用しているため、アクセストークンをリクエストする必要があります。
L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', { attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery (c) <a href="https://www.mapbox.com/">Mapbox</a>', maxZoom: 18, id: 'mapbox/streets-v11', accessToken: 'your.mapbox.access.token' }).addTo(mymap);
この時点で、ブラウザでindex.htmlを開くと、サンフランシスコの地図が表示されるはずです。 地図にピンを落としましょう。
マーカーとサークル
マップとレイヤーはありますが、具体的なものは何も示されていません。 マップ上の特定の場所を指すために、Leafletはマーカーを提供します。
場所を固定するには、Markerクラスを使用してマーカーをインスタンス化し、座標を渡して、それを地図に追加します。 ここでは、市内のツインピークスの座標を使用しています。
const marker = L.marker([37.7544, -122.4477]).addTo(mymap);
同様に、 Circle
クラスを使用して円をマップにバインドできます。 半径、色など、いくつかのオプションオプションを渡します。 circle
マーカーは、ポイントボニータ灯台の座標を渡します。
const circle = L.circle([37.8157, -122.5295], { color: 'gold', fillColor: '#f03', fillOpacity: 0.5, radius: 200 }).addTo(mymap);
ポップアップ
これはすべて素晴らしいことですが、場所に関する詳細情報を伝えたい場合はどうでしょうか。 これはポップアップを使用して行います。
circle.bindPopup("I am pointing to Point Bonita Lighthouse"); marker.bindPopup("I am pointing to Twin Peaks");
bindPopupメソッドは、指定されたHTMLコンテンツを取り込んでマーカーに追加するため、マーカーをクリックするとポップアップが表示されます。
React-Leaflet
これで、マップを作成し、LeafletとvanillaJavaScriptを使用してマーカーを追加する方法がわかりました。 Reactで同じ結果を達成する方法を見てみましょう。 同じアプリケーションを作成するのではなく、高度なアプリケーションを作成します。
私たちの最初のタスクは、サンフランシスコのオープンデータポータルからアクセストークンを取得することです。 これは、サンフランシスコ市と郡の何百ものデータセットを見つけることができるオンラインポータルです。 このリソースを使用することにしましたが、代わりに使用できるリソースは他にもたくさんあります。
APIキーにアクセス
- アカウントを作成し、ポータルにサインインします。
- 右下にある管理リンクをクリックします。
- [Create New API Key]をクリックして、名前を付けます。
- キーIDとキーシークレットをコピーします。 データにアクセスするにはこれが必要です。
このために、React-Leaflet –Leafletマップのreactコンポーネントを使用します。 反応アプリを作成しましょう。
npx create-react-app react-fire-incidents cd react-fire-incidents
次に、ターミナルで次のコマンドを実行して、 react-leaflet
とLeafletをインストールしましょう。
npm install react-leaflet leaflet
App.js
src
内にフォルダ/components
を作成しましょう。 コンポーネント内で、 Map.jsという名前のファイルを作成しましょう。 これは私たちの地図が住む場所です。 次に、不要なコードを削除し、 react-leaflet axios
leafletaxiosと新しく作成されたMap.jsからモジュールをインポートしてApp.jsを編集しましょう。
import React, { Component, Fragment } from 'react'; import axios from 'axios'; import Map from './components/Map'
Appクラスでは、インシデントと呼ばれる状態の配列を定義します。ページが読み込まれると、データをこの配列にプッシュします。
class App extends Component { state = { incidents: [], } render() { return ( <div> </div> ); } } export default App;
次に、コンポーネントがマウントされたときにGETリクエストを作成します。 アプリトークンはありますが、それでもエンドポイントが必要です。 エンドポイントはどこにありますか?
ポータルに移動して、[データの参照]をクリックしてみましょう。 検索バーで、火災事故を検索しましょう。 表示される最初の結果は、私たちが探しているものです。 リンクをクリックすると、右上のAPIボタンをクリックしてURLを取得できます。
エンドポイントをGETリクエストに渡し、制限とアプリトークンをパラメーターとして渡します。 元のデータには数千のレコードがありますが、簡単にするために、500に制限しています。インシデントの配列を結果で更新します。
データを取得したら、状態を更新します。
async componentDidMount() { const res = await axios.get('https://data.sfgov.org/resource/wr8u-xric.json', { params: { "$limit": 500, "$$app_token": YOUR_APP_TOKEN } }) const incidents = res.data; this.setState({incidents: incidents }); };
これは、App.jsがどのように表示されるかを示しています。
class App extends Component { state = { incidents: [], } async componentDidMount() { const res = await axios.get('https://data.sfgov.org/resource/wr8u-xric.json', { params: { "$limit": 500, "$$app_token": YOUR_APP_TOKEN } }) const incidents = res.data; this.setState({incidents: incidents }); }; render() { return ( <Map incidents={this.state.incidents}/> ); } } export default App;
Map.js
リーフレットマップの作成方法はすでにわかっているので、この部分は比較的簡単です。 Map
、 TileLayer
、 Marker
、 Popup
コンポーネントをreact-leaflet
からインポートします。
import React, { Component } from 'react' import { Map, TileLayer, Marker, Popup } from 'react-leaflet'
前の例を思い出すと、マップを初期化するための座標とズームレベルが必要です。 Map
クラスでは、 lat
、 lng
、 zoom
変数を使用して状態でそれらを定義します。
export default class Map extends Component { state = { lat: 37.7749, lng: -122.4194, zoom: 13, } render() { return ( <div></div> ) } }
次に、インシデントの配列が空かどうかを確認します。 空の場合、「データが読み込まれています」というメッセージが返されます。 それ以外の場合は、マップを返します。
react-leaflet
のMap
コンポーネントでは、中心座標とズームレベルをいくつかのスタイルとともに渡します。 TileLayer
コンポーネントでは、前の例と同様の属性とURLを渡します。
render() { return ( this.props.incidents ? <Map center={[this.state.lat, this.state.lng]} zoom={this.state.zoom} style={{ width: '100%', height: '900px'}} > <TileLayer attribution='© <a href="https://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> </Map> : 'Data is loading...' ) } }
次に、 props.incident
をループして、すべてのインシデントの座標をMarkerコンポーネントに渡します。 Reactは配列内のすべてのアイテムにキーを渡すように警告するので、マーカーにもキーを渡します。
Marker
コンポーネント内で、 Popup
コンポーネントを渡します。 ポップアップ内にインシデントに関する情報を追加しました。
<Map center={[this.state.lat, this.state.lng]} zoom={this.state.zoom} style={{ width: '100%', height: '900px'}}> <TileLayer attribution='© <a href="https://osm.org/copyright">OpenStreetMap</a> contributors' url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" /> { this.props.incidents.map(incident => { const point = [incident['point']['coordinates'][1], incident['point']['coordinates'][0]] return ( <Marker position={point} key={incident['incident_number']} > <Popup> <span>ADDRESS: {incident['address']}, {incident['city']} - {incident['zip_code']}</span> <br/> <span>BATTALION: {incident['battalion']}</span><br/> </Popup> </Marker> ) }) } </Map>
そして、これはそれです。 アプリを実行し、すべてがうまくいけば、火災事故の場所を示す500個のマーカーが付いたサンフランシスコの地図を見ることができるはずです。 これらのマーカーの1つをクリックすると、インシデントに関する詳細情報を示すポップアップが表示されます。
まとめ
たくさん取り上げましたが、これは基本的なことでした。 リーフレットは非常に強力なツールであり、さまざまな種類のマップを作成できます。 遊んでみたい場合は、別のレイヤーまたはカスタムアイコンを追加してみてください。 または、インタラクティブなコロプレスマップを作成したい場合もあります。