Sveltekit+MicroCMSの投稿にオリジナルの地図をつけてみる
MIERUNE(弊社)が開発した「Svelte Maplibre GL」というライブラリを使って、MicroCMS上のデータを地図に表示してみます。
このライブラリは、MapLibre GL JS を Svelte の世界で快適に使うためのライブラリです。
こちらのサイトに実装するために作成しました(まだ地図機能の公開はしてません)。
MapLibreとは
MapLibreとは、モダンなWeb地図にまつわるOSSを傘下に収める開発者コミュニティです。特に「MapLibre GL JS」は、ウェブ上で地図ビューアを作成するのに使われるライブラリで、複雑なデータでもスムーズに動作することが特徴です。
完成イメージ
地図のイメージ
地点の記事(投稿)に地図が追加されるようにしてみます。
地点にマーカーを置き、中心に表示させます。
ポップアップのイメージ
マーカーをクリックするとポップアップが表示されて、各地点の記事に飛べるようになってます。
想定するページの場所
各記事の[id]ディレクトリ内の+page.svelteで地図を表示する想定です。
地点データの繋ぎこみ
各地点が投稿として保存されています。
投稿には経度緯度を示す、「lat」および「lng」が保存されています。
例
{
"name": "きたぎんボールパーク",
"lat": 39.650296,
"lng": 141.137466
},
microcmsの導入はこちらを参考にして、以下のように書いています
...
export type Spot = {
id: string;
name: string;
lat: number;
lng: number;
adress: string;
url: string;
}
...
export const getSpotDetail = async (
contentId: string,
queries?: MicroCMSQueries
) => {
return await client.getListDetail<Spot>({
endpoint: "spot",
contentId,
queries,
});
};
import { getSpotDetail} from '$lib/microcms';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ params }) => {
const { id } = params;
// IDに基づいてデータを取得
const content = await getSpotDetail(id);
return {
content
};
}
地図の実装
Map.svelte上で地図を作成します。
簡単な構成であれば、Svelte MapLibre GLのExamplesをそのまま使えると思います。
今回は、Examplesのうち、「Marker and Popup」をほとんどそのまま活用しています。
lat,lngを用いてマーカーを作成し、地図の中心をlat,lngにしています。
ポップアップでは、nameを表示した上で、リンクとしてidから個別ページを呼び出すようにしています。
<script lang="ts">
import {
MapLibre,
Marker,
Popup,
FullScreenControl,
NavigationControl,
ScaleControl,
} from "svelte-maplibre-gl";
export let mapinit: {
lat: number;
lng: number;
name: string;
id: string;
};
let lnglat = { lng: mapinit.lng, lat: mapinit.lat };
</script>
<section>
<MapLibre
class="h-[45vh] w-full mx-auto"
style="/path/to/style.json"
zoom={15}
center={{ lng: mapinit.lng, lat: mapinit.lat }}
>
<Marker bind:lnglat>
<Popup anchor="bottom" offset={[0, -30]}>
<!-- Popupの中身をタイトルとリンクに -->
<span class="text-lg text-center">
<a href="/spot/{mapinit.id}">
{mapinit.name}
</a>
</span>
</Popup>
</Marker>
<FullScreenControl position="top-left" />
<NavigationControl />
<ScaleControl />
</MapLibre>
</section>
+page.svelteにコンポーネントを差し込みます。
<script lang="ts">
import type { PageData } from "./$types";
export let data: PageData;
import Map from "$lib/components/Map.svelte";
</script>
<section>
<Map
mapinit={{
lat: data.lat,
lng: data.lng,
name: data.name,
id: data.id,
}}
/>
</section>
以上で実装が可能です。
今回は、マーカー1つの場合ですが、複数の場合もこのように対応が可能です。
<MapLibre
class="h-[70vh] w-[80%] mx-auto"
style="/path/to/style.json"
zoom={3.5}
center={{ lng: 137, lat: 37 }}
>
<FullScreenControl position="top-left" />
<NavigationControl />
<ScaleControl />
{#each data.contents as spot (spot.id)}
{#if spot.lat !== undefined}
<Marker lnglat={{ lng: spot.lng, lat: spot.lat }}>
<Popup anchor="bottom" offset={[0, -30]}>
<span class="text-lg">
<a href="/spot/{spot.id}">
{spot.name}
</a>
</span>
</Popup>
</Marker>
{/if}
{/each}
</MapLibre>
Discussion