---
title: "Raster Layers"
description: "Cloud-Optimized GeoTIFF and satellite imagery visualization"
canonical_url: "https://v-maplibre.geoql.in/layers/raster-layers"
---
# Raster Layers

> Cloud-Optimized GeoTIFF and satellite imagery visualization

> See [Peer Dependencies](https://v-maplibre.geoql.in/guide/peer-dependencies) for the complete list of required packages for each component.

<callout icon="i-lucide-external-link" target="_blank" to="https://mapcn-vue.geoql.in/examples/deckgl-cog">

**Live Demo** - GPU-accelerated COG visualization with Sentinel-2 imagery

</callout>

## COGLayer

[Live Demo](https://mapcn-vue.geoql.in/examples/deckgl-cog)

GPU-accelerated Cloud-Optimized GeoTIFF visualization with automatic reprojection.

### Installation

```bash
pnpm add @developmentseed/deck.gl-raster @developmentseed/deck.gl-geotiff @developmentseed/geotiff
```

### Features

- Fully client-side (no server required)
- GPU-accelerated rendering
- Automatic CRS reprojection
- Intelligent tile streaming
- Overview level selection
- Support for multi-band imagery

### Basic Usage

```vue
<script setup lang="ts">
  import { VMap } from '@geoql/v-maplibre';
  import { VLayerCog } from '@geoql/v-maplibre/geotiff';

  const mapOptions = {
    style: 'https://basemaps.cartocdn.com/gl/dark-matter-nolabels-gl-style/style.json',
    center: [31.5, 30.0],
    zoom: 8,
  };

  // Sentinel-2 RGB imagery COG
  const COG_URL = 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/36/Q/WD/2020/7/S2A_36QWD_20200701_0_L2A/TCI.tif';
</script>

<template>
  <VMap :options="mapOptions" style="height: 500px">
    <VLayerCog
      id="cog-layer"
      :geotiff="COG_URL"
      @geotiff-load="(tiff, { geographicBounds }) => console.log('Loaded:', geographicBounds)"
    />
  </VMap>
</template>
```

### Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        id
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      required
    </td>
    
    <td>
      Unique layer identifier
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        geotiff
      </code>
    </td>
    
    <td>
      <code>
        string | ArrayBuffer | Blob
      </code>
    </td>
    
    <td>
      required
    </td>
    
    <td>
      GeoTIFF source URL or data
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tileSize
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        256
      </code>
    </td>
    
    <td>
      Tile size in pixels
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        maxZoom
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      Maximum zoom level
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        minZoom
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Minimum zoom level
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        opacity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Layer opacity (0-1)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        visible
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Layer visibility
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pickable
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Enable picking
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        debug
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Show debug overlay
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        concurrencyLimiter
      </code>
    </td>
    
    <td>
      <code>
        ConcurrencyLimiter | null
      </code>
    </td>
    
    <td>
      shared default
    </td>
    
    <td>
      Per-origin limit for tile requests (deck.gl-geotiff 0.8+). Omit it for the shared default of 6 requests per origin (the HTTP/1.1 browser limit). Pass <code>
        null
      </code>
      
       to turn limiting off for HTTP/2 or HTTP/3 sources, or a <code>
        PerOriginSemaphore
      </code>
      
       from <code>
        @developmentseed/geotiff
      </code>
      
       for a custom limit. Ignored for an already-opened <code>
        GeoTIFF
      </code>
      
       instance. Also on <code>
        VLayerMultiCog
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

### Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        @geotiff-load
      </code>
    </td>
    
    <td>
      <code>
        (tiff, { geographicBounds })
      </code>
    </td>
    
    <td>
      GeoTIFF loaded with bounds
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @error
      </code>
    </td>
    
    <td>
      <code>
        Error
      </code>
    </td>
    
    <td>
      The COG could not be opened or a tile failed (deck.gl-geotiff 0.8+). Also on <code>
        VLayerMultiCog
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @click
      </code>
    </td>
    
    <td>
      <code>
        PickingInfo
      </code>
    </td>
    
    <td>
      Clicked on layer
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @hover
      </code>
    </td>
    
    <td>
      <code>
        PickingInfo
      </code>
    </td>
    
    <td>
      Hovering over layer
    </td>
  </tr>
</tbody>
</table>

```vue
<script setup lang="ts">
  import { PerOriginSemaphore } from '@developmentseed/geotiff';

  // HTTP/2 bucket: allow 24 parallel range requests instead of 6.
  const limiter = new PerOriginSemaphore({ maxRequests: 24 });
</script>

<template>
  <VLayerCog
    id="cog"
    geotiff="https://example.com/scene.tif"
    :concurrency-limiter="limiter"
    @error="(e) => console.error(e)"
  />
</template>
```

### Fit to Bounds

```vue
<script setup lang="ts">
  import { shallowRef } from 'vue';
  import type { Map } from 'maplibre-gl';

  const mapInstance = shallowRef<Map | null>(null);

  const handleGeotiffLoad = (
    _tiff: unknown,
    { geographicBounds }: { geographicBounds: { west: number; south: number; east: number; north: number } }
  ) => {
    const { west, south, east, north } = geographicBounds;
    mapInstance.value?.fitBounds(
      [[west, south], [east, north]],
      { padding: 40, duration: 1000 }
    );
  };
</script>

<template>
  <VMap :options="mapOptions" @loaded="(map) => mapInstance = map">
    <VLayerCog
      id="cog"
      :geotiff="cogUrl"
      @geotiff-load="handleGeotiffLoad"
    />
  </VMap>
</template>
```

### Land Cover Example

[Live Demo](https://mapcn-vue.geoql.in/examples/deckgl-landcover)

Visualize NLCD land use classification data:

```vue
<VLayerCog
  id="landcover"
  :geotiff="nlcdUrl"
  :opacity="0.7"
/>
```

## MosaicLayer

[Live Demo](https://mapcn-vue.geoql.in/examples/deckgl-naip-mosaic)

Client-side COG mosaic layer that renders multiple Cloud-Optimized GeoTIFFs from STAC items. All rendering happens in the browser with no server required.

### Installation

```bash
pnpm add @developmentseed/deck.gl-raster @developmentseed/deck.gl-geotiff @developmentseed/geotiff flatbush proj4
```

### Features

- Fully client-side mosaicking (no tile server required)
- STAC API integration for discovering imagery
- Multiple render modes: True Color, False Color Infrared, NDVI
- GPU-accelerated rendering with automatic reprojection
- Spatial indexing for efficient tile loading
- Support for 4-band imagery (RGBN)

### Basic Usage

```vue
<script setup lang="ts">
  import { ref, onMounted } from 'vue';
  import { VMap } from '@geoql/v-maplibre';
  import {
    VLayerMosaic,
    type MosaicSource,
    type MosaicRenderMode,
  } from '@geoql/v-maplibre/geotiff';

  const mapOptions = {
    style: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',
    center: [-104.9903, 39.7392],
    zoom: 10,
  };

  const renderMode = ref<MosaicRenderMode>('trueColor');
  const stacItems = ref<MosaicSource[]>([]);

  // Fetch STAC items from Microsoft Planetary Computer
  async function fetchSTACItems() {
    const params = {
      collections: 'naip',
      bbox: '-106.6,38.7,-104.6,40.4',
      datetime: '2023-01-01/2023-12-31',
      limit: '1000',
    };

    const response = await fetch(
      'https://planetarycomputer.microsoft.com/api/stac/v1/search?' +
      new URLSearchParams(params)
    );
    const { features } = await response.json();
    stacItems.value = features;
  }

  onMounted(fetchSTACItems);
</script>

<template>
  <VMap :options="mapOptions" style="height: 500px">
    <VLayerMosaic
      v-if="stacItems.length > 0"
      id="naip-mosaic"
      :sources="stacItems"
      :render-mode="renderMode"
    />
  </VMap>
</template>
```

### Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        id
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      required
    </td>
    
    <td>
      Unique layer identifier
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sources
      </code>
    </td>
    
    <td>
      <code>
        MosaicSource[]
      </code>
    </td>
    
    <td>
      required
    </td>
    
    <td>
      Array of STAC-like items with bbox and COG asset URLs
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        renderMode
      </code>
    </td>
    
    <td>
      <code>
        'trueColor' | 'falseColor' | 'ndvi' | 'custom'
      </code>
    </td>
    
    <td>
      <code>
        'trueColor'
      </code>
    </td>
    
    <td>
      Render mode for band combination
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        customRenderModules
      </code>
    </td>
    
    <td>
      <code>
        Function
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      Custom render modules (only used when renderMode is 'custom')
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        colormapData
      </code>
    </td>
    
    <td>
      <code>
        Uint8ClampedArray
      </code>
    </td>
    
    <td>
      cfastie
    </td>
    
    <td>
      Custom colormap texture data for NDVI (256 RGBA colors)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        maxCacheSize
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        Infinity
      </code>
    </td>
    
    <td>
      Maximum number of tiles to cache
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        beforeId
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      Insert layer before this layer ID
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        opacity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Layer opacity (0-1)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        visible
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Layer visibility
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        pickable
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Enable picking
    </td>
  </tr>
</tbody>
</table>

### Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        @source-load
      </code>
    </td>
    
    <td>
      <code>
        MosaicSource
      </code>
    </td>
    
    <td>
      COG source loaded successfully
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @error
      </code>
    </td>
    
    <td>
      <code>
        (Error, MosaicSource?)
      </code>
    </td>
    
    <td>
      Error loading a COG source
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @click
      </code>
    </td>
    
    <td>
      <code>
        PickingInfo
      </code>
    </td>
    
    <td>
      Clicked on layer
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        @hover
      </code>
    </td>
    
    <td>
      <code>
        PickingInfo
      </code>
    </td>
    
    <td>
      Hovering over layer
    </td>
  </tr>
</tbody>
</table>

### Render Modes

<table>
<thead>
  <tr>
    <th>
      Mode
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        trueColor
      </code>
    </td>
    
    <td>
      RGB composite (bands 1, 2, 3)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        falseColor
      </code>
    </td>
    
    <td>
      False Color Infrared - NIR, Red, Green (bands 4, 1, 2) - highlights vegetation
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ndvi
      </code>
    </td>
    
    <td>
      Normalized Difference Vegetation Index with cfastie colormap
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        custom
      </code>
    </td>
    
    <td>
      Use <code>
        customRenderModules
      </code>
      
       prop for custom band math
    </td>
  </tr>
</tbody>
</table>

### MosaicSource Type

```typescript
interface MosaicSource {
  bbox: [number, number, number, number]; // [west, south, east, north]
  assets: {
    image: {
      href: string; // URL to the COG file
    };
  };
}
```

This matches the STAC Item format, so you can pass STAC search results directly.

### Supported CRS

The component includes built-in support for:

- EPSG:4326 (WGS84)
- EPSG:3857 (Web Mercator)
- EPSG:26910-26919 (NAD83 / UTM zones 10-19 for continental US)

For other CRS, you'll need to register them with proj4 before using.

## IDW Interpolation Heatmap

[Live Demo](https://mapcn-vue.geoql.in/examples/maplibre-interpolate-heatmap)

For Inverse Distance Weighting interpolation (temperature, pollution, continuous values), use `maplibre-gl-interpolate-heatmap`:

```bash
pnpm add maplibre-gl-interpolate-heatmap
```

This is different from deck.gl's density heatmap - it calculates weighted averages rather than point density. See the [live example](https://mapcn-vue.geoql.in/examples/maplibre-interpolate-heatmap) for implementation details.


## Sitemap

See the full [sitemap](https://v-maplibre.geoql.in/sitemap.md) for all pages.
