deck.gl Overlay

Interleaving deck.gl with MapLibre layers

<script lang="ts">
  import { onMount } from 'svelte';
  import { MapLibre, FillExtrusionLayer } from 'svelte-maplibre-gl';
  import { DeckGLOverlay } from 'svelte-maplibre-gl/deckgl';
  import { ArcLayer } from '@deck.gl/layers';

  const NUM = 30;
  let data: { source: [number, number]; target: [number, number] }[] = $state([]);

  onMount(() => {
    let handle = requestAnimationFrame(function updateFrame(t) {
      data = Array.from({ length: NUM }, (_, i) => {
        const O = (2 * Math.PI) / NUM;
        const r = (1.3 + Math.sin(t / 510 + i * O)) * 0.002;
        return {
          source: [139.7672, 35.6812],
          target: [139.7672 + Math.cos(t / 730 + i * O) * r, 35.6812 + Math.sin(t / 730 + i * O) * r]
        };
      });
      handle = requestAnimationFrame(updateFrame);
    });
    return () => cancelAnimationFrame(handle);
  });
</script>

<MapLibre
  class="h-[55vh] min-h-[300px]"
  style="https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json"
  zoom={15}
  pitch={60}
  minZoom={4}
  bearing={-45}
  center={[139.7672, 35.6812]}
>
  <DeckGLOverlay
    interleaved
    layers={[
      new ArcLayer({
        id: 'deckgl-arc',
        data,
        getSourcePosition: (d) => d.source,
        getTargetPosition: (d) => d.target,
        getSourceColor: [0, 255, 100],
        getTargetColor: [0, 190, 255],
        getWidth: 5
      })
    ]}
  />
  <FillExtrusionLayer
    source="carto"
    sourceLayer="building"
    minzoom={14}
    paint={{
      'fill-extrusion-color': '#aaa',
      'fill-extrusion-height': ['interpolate', ['linear'], ['zoom'], 14, 0, 14.05, ['get', 'render_height']],
      'fill-extrusion-base': ['interpolate', ['linear'], ['zoom'], 14, 0, 14.05, ['get', 'render_min_height']],
      'fill-extrusion-opacity': 0.8
    }}
  />
</MapLibre>