Custom Control

Custom Control allows to easily create user defined controls.

<script lang="ts">
  import { HillshadeLayer, MapLibre, RasterDEMTileSource, Terrain, CustomControl } from 'svelte-maplibre-gl';
  import maplibregl from 'maplibre-gl';
  import Sun from 'lucide-svelte/icons/sun';
  import Moon from 'lucide-svelte/icons/moon';
  import ArrowUpLeft from 'lucide-svelte/icons/arrow-up-left';
  import ArrowUpRight from 'lucide-svelte/icons/arrow-up-right';
  import ArrowDownLeft from 'lucide-svelte/icons/arrow-down-left';
  import ArrowDownRight from 'lucide-svelte/icons/arrow-down-right';
  import { MyControl } from './MyControl.js';

  let isHillshadeVisible = $state(true);
  let isTerrainVisible = $state(true);
  let isDarkMode = $state(false);
  const mapStyle = $derived(
    isDarkMode
      ? 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json'
      : 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json'
  );
  let center = $state({ lng: 11.09085, lat: 47.3 });
  let controlPosition: maplibregl.ControlPosition = $state('top-left');

  const myControl = new MyControl({
    toggleHillshade: () => (isHillshadeVisible = !isHillshadeVisible),
    toggleTerrain: () => (isTerrainVisible = !isTerrainVisible)
  });
</script>

<MapLibre class="h-[55vh] min-h-[200px]" style={mapStyle} zoom={12} pitch={40} maxPitch={85} bind:center>
  <!-- inject IControl (useful for plugin) -->
  <CustomControl position="top-left" control={myControl} />

  <!-- Control / Group / Icon -->
  <CustomControl position="bottom-left">
    <button onclick={() => (isDarkMode = !isDarkMode)} class="!flex items-center justify-center text-gray-900">
      {#if isDarkMode}
        <Moon class="w-5" />
      {:else}
        <Sun class="w-5" />
      {/if}
    </button>
  </CustomControl>

  <!-- Group -->
  <CustomControl position={controlPosition} class="text-gray-900">
    <button class="!flex items-center justify-center" onclick={() => (controlPosition = 'top-left')}
      ><ArrowUpLeft class="w-5" /></button
    >
    <button class="!flex items-center justify-center" onclick={() => (controlPosition = 'top-right')}
      ><ArrowUpRight class="w-5" /></button
    >
    <button class="!flex items-center justify-center" onclick={() => (controlPosition = 'bottom-right')}
      ><ArrowDownRight class="w-5" /></button
    >
    <button class="!flex items-center justify-center" onclick={() => (controlPosition = 'bottom-left')}
      ><ArrowDownLeft class="w-5" /></button
    >
  </CustomControl>

  <!-- Control / Group / any svelte elements -->
  <CustomControl position="top-right">
    <div class="p-2 text-yellow-700">Arbitrary HTML</div>
    <div class="border-t border-t-[#ddd] p-2 text-center text-yellow-700">
      ({center.lat.toFixed(4)}, {center.lng.toFixed(4)})
    </div>
  </CustomControl>

  <RasterDEMTileSource
    tiles={['https://demotiles.maplibre.org/terrain-tiles/{z}/{x}/{y}.png']}
    minzoom={0}
    maxzoom={12}
    attribution="<a href='https://earth.jaxa.jp/en/data/policy/'>AW3D30 (JAXA)</a>"
  >
    {#if isTerrainVisible}
      <Terrain />
    {/if}
  </RasterDEMTileSource>
  <RasterDEMTileSource
    tiles={['https://demotiles.maplibre.org/terrain-tiles/{z}/{x}/{y}.png']}
    minzoom={0}
    maxzoom={12}
    attribution="<a href='https://earth.jaxa.jp/en/data/policy/'>AW3D30 (JAXA)</a>"
  >
    {#if isHillshadeVisible}
      <HillshadeLayer />
    {/if}
  </RasterDEMTileSource>
</MapLibre>