これは MapLibre AdventCalendar 2023 16日目の記事です。
昨日は @qazsato さんによる MapLibre GL JS と japanmesh で地域メッシュを表示する でした。
@Kanahiro さんが8日目に書いた、[MapLibre GL JS]ReactやVueでレイヤー管理する際のプラクティスをSvelteでやる場合こう書くよという例になります
リアクティブな配列の変数を用意して、setMapstyleでstyleを書き換えていく感じになります
ポイントはcreateMapstyle
関数で、こいつを上手く作ることでレイヤーの重なり順や、様々なタイル形式に対応させていくことになります(今回はラスタータイルのみ対応バージョンになっています)
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最高!!
明日は@freedom-techさんの記事です!お楽しみにー