MIERUNE/svelte-maplibre-glでWebメルカトルのゆがみを見る

これは [MapLibre Advent Calendar 2024](https://qiita.com/advent-calendar/2024/maplibre) の14日目の記事です。

# 概要
GoogleMapで使われるWebメルカトルが『メルカトル図法』というものとは別物だ、ということを`伊達と酔狂`で知られる[WINGFIELD先生の本](https://amzn.asia/d/103PjLa)で知りました。

:::note warn
思いついてから夜なべして書きましたが、全部終わってから同じアドベントカレンダーでテーマが似ている記事があることに気づきました🫢この記事は私のポエム + [MIERUNE/svelte-maplibre-gl](https://github.com/MIERUNE/svelte-maplibre-gl)でできています。
:::

https://qiita.com/frogcat/items/b38b5e37535b65c5464b

普段の仕事では、パワポばかり書いている私ですが、
- `SvelteKit`の入門
- `Github Actions` & `Github Pages`の入門
- TypeScriptの入門
- [MIERUNE/svelte-maplibre-gl](https://svelte-maplibre-gl.mierune.dev/examples/plain)の入門
などを兼ねて`SvelteKit`で人生初のポートフォリオなるものを作成してみます！

## 作ったもの
SevlteKitでインパクトのあるものとは？が想像できず、
下記を読んで「これ使えば簡単なのでは？」と思い挑戦しました。

https://qiita.com/ciscorn/items/6f97f681f31cafe513bd

作ったものは下記になります。
デモサイト：👉https://shinyanakashima.github.io/santa-magical-map/

https://github.com/shinyanakashima/santa-magical-map

### よもやま話
楕円体である地図を地図に描く（投影）ときは、どうしても歪みが出てしまう。例えば、AとBでは同じように「10度」分の距離がありますがBの方が長く見えます。※CとDは「10度」分の距離がありますが、同じに見えます。
- 経線（南北）では緯度が変わると、長さが長くなっているように「描かれる」
- 緯線（東西）では経度が変わっても、同じような長さに「描かれる」
下記サイトでは、投影法の種類によって、どのような歪みが出るのかをわかり易く見ることができます。
https://www.wingfield.gr.jp/demos/map-projections/

測量士でもなければ、地理学を学んだことのない私には、とてつもなく難しい話なのですが『経線を横にしたら緯線！』という単純なものではないようです。
- 緯線は大小様々なドーナツ🍩が地球の表面に乗っかっている（😇）線
- 経線は地球を（角度を変えながら）真っ二つにした線で、スイカ🍉を切るような線
と理解することにしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30994/2363e15d-433b-5582-9f56-8406e5f2fba4.png)

ちなみに、下記の本で緯度と経度の違いに興味を持つことができました。

https://www.shoeisha.co.jp/book/detail/9784881355053

### ハマったこと
- `MapLibre GL JS`には、LineString描画する方法がない?!
    - `Leaflet`の[L.polyline](https://leafletjs.com/reference.html#polyline)のようにLineStringを描画するものがない(?)
    - GeoJSONを作ってそれを描画する必要がありそう
- `SvelteKit`で`Script`に書いた`TypeScript`が実行されない？！
    - `JavaScript`では`<script>`を、TypeScriptでは`<script lang="ts">`
    - https://svelte.jp/docs/typescript#script-lang-ts
- 画面が真っ白
    - 理由は[TailwindCSSを入れないと](https://tailwindcss.com/docs/guides/sveltekit)地図にCSSが当たらないず表示されなかったのです


## 実装のポイント
等間隔で緯度経度の線を描画して、高緯度では距離や面積が誇張されていることを確認してみようと思います。LineStringでのマウスホバー時のイベントハンドラや、GeoJSONを動的に生成するサンプルが見つからなかったので[MIERUNE/svelte-maplibre-gl](https://svelte-maplibre-gl.mierune.dev/examples/plain)のソースを読みながら実装しました。

### 緯度経度のLineStringの生成
緯度経度のLineStringを作成するにあたり、Pythonの`range`関数がほしくなりましたが、TypeScript(JavaScript)では無さそうでした。それで下記のような[関数を作りました](https://github.com/shinyanakashima/santa-magical-map/blob/113db35a27b154893d0f8ffbbebb76b29cd9faf2/src/routes/%2Bpage.svelte#L19-L36)。

```typescript
	const range = (min: number, max: number, step = 1) => {
		return [...Array(Math.floor((max - min) / step) + 1).keys()].map((i) => min + i * step);
	};
```

使い方としては、下記のように[指定した範囲でLineStringを生成](https://github.com/shinyanakashima/santa-magical-map/blob/113db35a27b154893d0f8ffbbebb76b29cd9faf2/src/routes/%2Bpage.svelte#L38-L53)します。
今回、TypeScript初挑戦でしたので型がこれで良かったのか疑問です。
```typescript
	// 南緯80度～北緯80度までを、10度刻みで生成
	const lines_lat = range(-80, 80, 10).map((_lat) => {
		const featureLine: Feature<LineString, GeoJsonProperties> = {
			type: "Feature",
			properties: {},
			geometry: {
				coordinates: [
					[-MAX_LNG, _lat],
					[MAX_LNG, _lat],
				],
				type: "LineString",
			},
		};

		return featureLine;
	});
```
### サンタの吹き出しの変更
日本の範囲を適当に決めて[🎅のマーカーの吹き出しが変わる](https://github.com/shinyanakashima/santa-magical-map/blob/113db35a27b154893d0f8ffbbebb76b29cd9faf2/src/routes/%2Bpage.svelte#L144-L150)ようにしました。判定は`Maplibre GL JS`を使いました。
```svelte
	<Marker bind:lnglat draggable>
		{#snippet content()}
			<div class="text-center leading-none">
				<div class="text-3xl">🎅🏽</div>
				<div class="font-bold text-white drop-shadow-sm">{lngLatText}</div>
			</div>
		{/snippet}
		<Popup class="text-black" bind:open={popupOpen} offset={offsets}>
			{#if BOUNDS_JAPAN.contains(lnglat)}
				<span class="text-lg">メリークリスマス🎄</span>
			{:else}
				<span class="text-lg">日本が恋しいのぅ...</span>
			{/if}
		</Popup>
	</Marker>
 ```