[MapLibre GL JS]レイヤー管理するプラクティスのSvelteKit版

:::note info
これは [MapLibre AdventCalendar 2023](https://qiita.com/advent-calendar/2023/maplibre)　16日目の記事です。
昨日は @qazsato さんによる [MapLibre GL JS と japanmesh で地域メッシュを表示する](https://zenn.dev/qazsato/articles/1093a50c1e7804) でした。
:::

@Kanahiro さんが8日目に書いた、[[MapLibre GL JS]ReactやVueでレイヤー管理する際のプラクティス](https://qiita.com/Kanahiro/items/e8e4f2d5846fa42eaf8a)をSvelteでやる場合こう書くよという例になります

リアクティブな配列の変数を用意して、setMapstyleでstyleを書き換えていく感じになります
ポイントは`createMapstyle`関数で、こいつを上手く作ることでレイヤーの重なり順や、様々なタイル形式に対応させていくことになります（今回はラスタータイルのみ対応バージョンになっています）
```javascript:Map.svelte
<script lang="ts">
  import { onMount } from "svelte";
  import maplibregl, { type StyleSpecification } from "maplibre-gl";
  import type { Map } from "maplibre-gl";
  import "maplibre-gl/dist/maplibre-gl.css";

  // 型の定義
  interface LayerData {
    id: string;
    type: string;
    name: string;
    opacity: number;
    tiles: string[];
    attribution: string;
  }

  interface Source {
    [key: string]: {
      type: string;
      tiles: string[];
      tileSize: number;
      attribution: string;
    };
  }

  interface Layer {
    id: string;
    type: string;
    source: string;
    minzoom: number;
    maxzoom: number;
    paint?: {
      "raster-opacity": number;
    };
  }

  // 地図
  let map: Map | undefined;

  // レイヤー定義
  const layerDataList = [
    {
      id: "pale",
      type: "raster",
      name: "地理院地図（淡色地図）",
      opacity: 1.0,
      tiles: [
        "https://cyberjapandata.gsi.go.jp/xyz/pale/{z}/{x}/{y}.png",
      ],
      attribution:
	    "<a href='https://maps.gsi.go.jp/development/ichiran.html' target='_blank'>地理院タイル</a>",
    },
    {
      id: "flood-shinsui",
      type: "raster",
      name: "洪水浸水想定区域（想定最大規模）",
      opacity: 0.5,
      tiles: [
        "https://disaportaldata.gsi.go.jp/raster/01_flood_l2_shinsuishin_data/{z}/{x}/{y}.png",
      ],
      attribution:
        "<a href='https://disaportal.gsi.go.jp/index.html' target='_blank'>ハザードマップポータルサイト</a>",
    },
  ];

  // 選択されたレイヤー
  let selectedLayers: Array<LayerData> = [layerDataList[0]];
  // レイヤー選択時に地図を更新
  $: if (map) {
    const style = createMapstyle(selectedLayers);
    map.setStyle(style);
  }

  onMount(() => {
    const lng = 137.767;
    const lat = 35.681;
    const zoom = 7;

    map = new maplibregl.Map({
      container: "map",
      center: new maplibregl.LngLat(lng, lat),
      zoom: zoom,
      style: createMapstyle(selectedLayers),
    });

    map.addControl(new maplibregl.NavigationControl(), "bottom-right");
    map.addControl(new maplibregl.GeolocateControl({}), "bottom-right");
    map.addControl(new maplibregl.ScaleControl({}), "bottom-left");
  });

  // 地図スタイルの作成
  const createMapstyle = (layers: Array<LayerData>) => {
    let selectSources: Source = {};
    let selectLayers: Array<Layer> = [];

    layers.forEach((layerData) => {
      selectSources[layerData.id] = {
        type: layerData.type,
        tiles: layerData.tiles,
        tileSize: 256,
        attribution: layerData.attribution,
      };

      selectLayers.push({
        id: layerData.id,
        type: layerData.type,
        source: layerData.id,
        minzoom: 0,
        maxzoom: 23,
        paint: {
          "raster-opacity": layerData.opacity,
        },
      });
    });

    return {
      version: 8,
      sources: selectSources,
      layers: selectLayers,
    } as StyleSpecification;
  };
</script>

<div id="map" class="h-screen w-screen" />
<div class="absolute top-0 left-0 p-4">
  <ul>
    {#each layerDataList as layerData}
      <li>
        <input type="checkbox" bind:group={selectedLayers} value={layerData} />
        {layerData.name}
      </li>
    {/each}
  </ul>
</div>
```

このケース、他のライブラリーでも書いたことが何回かあるのですが、Svelteが一番スッキリ書けますね
Svelte最高！！

:::note info
明日は@freedom-techさんの記事です！お楽しみにー
:::