AstroとLeafletを用いた地図アプリ『ワセメシマップ』を作った話

こんちには、バックエンドコースのAkinoriです!

普段はバックエンドエンジニアとしてDjangoというフレームワークを用いた開発に取り組んでいます。先日は、そのカンファレンスで発表をしてきました。

(緊張しすぎて大変でしたが、無事にやり遂げました。観に来てくださった方々ありがとうございます。)

今回はアドベントカレンダー16日目の記事として、「AstroとLeafletを用いた地図アプリ」について紹介しようと思います。

この記事を通して、地図情報、Astro、Leaflet、Vercelを知ることが出来ます!地図情報については非エンジニアの方も読める内容にさせて頂きました。

Ⅰ はじめに

今回作成したサービスは『ワセメシマップ』というサービスで、私が在籍する早稲田大学周辺の食事処をマップで表示するサービスです。ルーレット絞り込み機能がついており、優柔不断な性格の方には良いサービスかもしれません。

ワセメシマップ

ちなみに開発の目的「地図情報を扱いたい」×「Astroを使いたい」です。

Ⅱ 地図情報

技術的な話をする前に、地図情報について学習したことのいくつかを紹介したいと思います!

A. データ形式

地図情報のデータ形式は、一般には下記に大別されます。

  1. 地点情報・属性情報を持ち、点・線・面から構成されるベクトルデータ。
  2. 地点情報を持つ画像のラスターデータ。

A-1. ベクトルデータ

ベクトルデータは、点(ポイント)・線(ライン)・面(ポリゴン)から構成されています。

点は信号、線は鉄道、面は公園や建物などがイメージしやすいのではないでしょうか(もちろん目的に合わせてそれぞれ使い分けることになります)。

ベクトルデータでは属性情報を活用することで特定地点に意味を付与することが出来ます。例えば、建物の営業時間や建物名といった情報を保持することが可能です。

また点・線・面から構成されているため、地図を拡大してもぼやけることがありません。

A-2. ラスターデータ

ラスターデータは、地点情報を持つ画像から構成されています。航空写真をイメージして頂くのが良いと思います。

ベクトルデータとは異なり、地図を拡大した場合ぼやけてしまいます。

B. 地図タイル

例えば地図アプリを起動した場合に、地図アプリが全世界の地図情報をロードするとしたら、あまりにも巨大データを取得するため、莫大な時間がかかってしまいますよね。

そのため必要なデータを一部だけ取得するために生まれた手法が、地図タイルです。

簡潔に言えば、事前に全世界の地図情報を一定のルールに従って見出しを付与されたタイル状に分割するタイルインデックスという仕組みにより、必要なタイミングでタイルを取得できます。

タイルインデックスではタイルに、ズームレベル値(Z)・横軸上の値(X)・縦軸上の値(Y)によって構成される整数値3つの見出し「(Z, X, Y)」が割り振られます。

ズームレベルが一つ上がるごとにタイルを4分割ずつします。ズームレベル0では世界は1つのタイルですが、ズームレベル1では世界は4つのタイルに、さらにズームレベル2では世界は16のタイルに分割されて….、といったルールです。

ズームレベル1で4つのタイルに分割されていますが、この時日本は、右上のタイルにあります。右上のタイルということで、Xには1、Yには1が割り当てられます。

逆にタイルインデックスで、(1, 1, 1)となった場合日本を含む東アジアが大半を占めるタイルを指し示すということになります。

Ⅲ Astro

今回Astroを用いた開発に取り組みました。Astroとは「コンテンツ重視の高速なWEBサイトを構築するWEBフレームワーク」です。

この意味において、WEBアプリケーションを構築するでは昨今はデファクトスタンダードになりつつあるReactやNext.jsとは異なる路線を取っています。そのため公式も推奨していますが、WEBアプリを構築する目的にAstroは適合しないでしょう。

パフォーマンスはWEBサイトでは重要な価値を持っていることが多いと思われます。例えば公式では下記のような実例があるようです。

より詳しいことはAstroの公式ドキュメントをご覧ください。

Astroを選ぶ理由
Astroは、コンテンツにフォーカスした高速なWebサイトを構築するためのオールインワンWebフレームワークです。詳しくはこちら。

Twitter(X)で「ReactやVueなどの複数のフレームワークが使えるぞ」といった投稿を見かけて気になったので、今回利用することに決めました。

実態としてはアイランドと呼ばれる独立したUIコンポーネントによってページを構成させるアーキテクチャが背景にあるようです(参考)。

利用してみての感想ですが、複雑なことを学ばずに高速なWEBサイトを効率的に構築できる点にメリットを感じました。ファイルベースルーティングとコンポーネント指向さえ分かっていれば大半のことができるというわけです。

WEBサイトを構築するためだけなのに、Hooksや状態管理を学ぶ必要性を感じてしまうReactなどの他のフレームワークに比較して取っつきやすさがあります。

他方でReactやNext.jsの変化に追いつけていない身としては、Astroの変換でキャッチアップするのはしんどいだろうなとも感じてしまいます(CSSの変化も早すぎて追いつけていません)。

もちろん初心者の第一歩として、あるいは高速なWEBサイトを構築する必要がある方には良いのだろうと思います!

Ⅳ Leaflet

Leaflet(リーフレット)は、地図情報のためのオープンソースのJavaScriptライブラリで、簡単に地図上にマーカーを配置したりできる地図情報を扱う際にはとても便利なライブラリです。

Leaflet — an open-source JavaScript library for interactive maps
Leaflet is a modern, lightweight open-source JavaScript library for mobile-friendly interactive maps.

今回はこんな感じのコードでマップを表示しています。

const map = L.map("map").setView([35.7087, 139.7196], 16);
const backgroundLayer = L.tileLayer(
		"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
		{
			maxZoom: 19,
			attribution:
				'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors',
		}
	);
map.addLayer(backgroundLayer);

この時早稲田キャンパスの拠点の緯度・経度は「35.7087, 139.7196」の部分なのですが、その後ろにある16はズームレベルです。そう先ほど説明したタイルインデックスの仕組みを知っておくと、少し理解がしやすいのではないでしょうか。

ところで皆さんは緯度・経度と経度・緯度のどちらの流派ですか?厄介なことに地図情報を扱っている際に逆に使う流派もあるそうです。

このサービスを作成するためにGeoJsonと呼ばれるJSON形式で位置情報を格納していたのですが、こちらはまさかの経度・緯度派でした....。

Ⅴ Vercel

さて今回のサービスのデプロイではVercelを用いることにしたのですが、ちょこっと機能紹介です!

Vercelでは、ブランチごとにプレビュー環境を用意してくれる機能があります。こんな感じでPRにプレビュー環境のURL情報と教えてくれます!しかもプレビュー環境にはコメントを付けられるのでレビューもしやすいです、素晴らしいですね!!

Ⅵ さいごに

いかがでしたでしょうか。

地図情報の仕組みや、知らないフレームワーク・ライブラリ・サービスについて触れる機会になれれば幸甚です。

実際に制作してからもう半年もたっていることに驚きです。もう僕の卒業も間近ですね...。

最後までお読みいただきありがとうございました!!