---
title: "MapLibre Layers"
description: "Native MapLibre GL layers and custom derived layers"
canonical_url: "https://v-maplibre.geoql.in/layers/maplibre-layers"
---
# MapLibre Layers

> Native MapLibre GL layers and custom derived layers

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

# MapLibre Layers

Native MapLibre GL layer components for common use cases.

## Base Layers

These components wrap MapLibre's native layer types:

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

<tbody>
  <tr>
    <td>
      <code>
        VLayerMaplibreGeojson
      </code>
    </td>
    
    <td>
      GeoJSON data visualization
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        VLayerMaplibreVector
      </code>
    </td>
    
    <td>
      Vector tile layers
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        VLayerMaplibreRaster
      </code>
    </td>
    
    <td>
      Raster tile layers
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        VLayerMaplibreImage
      </code>
    </td>
    
    <td>
      Georeferenced images
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        VLayerMaplibreVideo
      </code>
    </td>
    
    <td>
      Georeferenced video
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        VLayerMaplibreCanvas
      </code>
    </td>
    
    <td>
      Custom canvas rendering
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        VLayerMaplibrePmtile
      </code>
    </td>
    
    <td>
      PMTiles archives
    </td>
  </tr>
</tbody>
</table>

## Custom Layers

Higher-level components that compose multiple MapLibre layers:

### VLayerMaplibreCluster

Clustered point visualization with automatic grouping.

#### Props

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

<tbody>
  <tr>
    <td>
      <code>
        sourceId
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'cluster-source'
      </code>
    </td>
    
    <td>
      GeoJSON source ID
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        baseLayerId
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'cluster'
      </code>
    </td>
    
    <td>
      Base ID for generated layers
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        source
      </code>
    </td>
    
    <td>
      <code>
        GeoJSONSourceSpecification
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      GeoJSON source configuration
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        visibility
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Layer visibility
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        clusterPaint
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      See below
    </td>
    
    <td>
      Cluster circle styling
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        unclusteredPaint
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      See below
    </td>
    
    <td>
      Individual point styling
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        textPaint
      </code>
    </td>
    
    <td>
      <code>
        object
      </code>
    </td>
    
    <td>
      See below
    </td>
    
    <td>
      Cluster count text styling
    </td>
  </tr>
</tbody>
</table>

#### Events

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

<tbody>
  <tr>
    <td>
      <code>
        cluster-click
      </code>
    </td>
    
    <td>
      <code>
        { features, coordinates }
      </code>
    </td>
    
    <td>
      Cluster circle clicked
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        point-click
      </code>
    </td>
    
    <td>
      <code>
        { features, coordinates }
      </code>
    </td>
    
    <td>
      Individual point clicked
    </td>
  </tr>
</tbody>
</table>

#### Example

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

const earthquakes = ref({
  type: 'FeatureCollection',
  features: [], // Load your point data
});
</script>

<template>
  <VMap :options="mapOptions">
    <VLayerMaplibreCluster
      source-id="earthquakes"
      base-layer-id="quakes"
      :source="{ type: 'geojson', data: earthquakes }"
      @cluster-click="handleClusterClick"
      @point-click="handlePointClick"
    />
  </VMap>
</template>
```

---

### VLayerMaplibreRoute

Route/path visualization for navigation and delivery tracking.

#### 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>
      Auto-generated
    </td>
    
    <td>
      Unique route identifier
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        coordinates
      </code>
    </td>
    
    <td>
      <code>
        [number, number][]
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      Array of <span>
        lng, lat
      </span>
      
       coordinates
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#4285F4'
      </code>
    </td>
    
    <td>
      Line color
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        width
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        4
      </code>
    </td>
    
    <td>
      Line width in pixels
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        opacity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Line opacity (0-1)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lineCap
      </code>
    </td>
    
    <td>
      <code>
        'butt' | 'round' | 'square'
      </code>
    </td>
    
    <td>
      <code>
        'round'
      </code>
    </td>
    
    <td>
      Line cap style
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lineJoin
      </code>
    </td>
    
    <td>
      <code>
        'bevel' | 'round' | 'miter'
      </code>
    </td>
    
    <td>
      <code>
        'round'
      </code>
    </td>
    
    <td>
      Line join style
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        visible
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Route visibility
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        interactive
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Enable hover/click
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        dashArray
      </code>
    </td>
    
    <td>
      <code>
        number[]
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      Dash pattern for dashed lines
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        blur
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Line blur in pixels
    </td>
  </tr>
</tbody>
</table>

#### Events

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

<tbody>
  <tr>
    <td>
      <code>
        click
      </code>
    </td>
    
    <td>
      <code>
        { coordinates }
      </code>
    </td>
    
    <td>
      Route line clicked
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mouseenter
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      Mouse enters route
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mouseleave
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      Mouse leaves route
    </td>
  </tr>
</tbody>
</table>

#### Example

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

const routeCoordinates = ref([
  [-122.4194, 37.7749],
  [-122.4089, 37.7855],
  [-122.3984, 37.7925],
]);
</script>

<template>
  <VMap :options="mapOptions">
    <VLayerMaplibreRoute
      id="my-route"
      :coordinates="routeCoordinates"
      color="#10b981"
      :width="5"
      @click="handleRouteClick"
    />
  </VMap>
</template>
```

---

### VLayerMaplibreIsochrone

Isochrone/isodistance polygon visualization for travel time analysis.

<alert type="info">

Isochrones show areas reachable within a specific time or distance from a point. They're commonly used for delivery coverage, commute analysis, and accessibility mapping.

</alert>

#### 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>
      Auto-generated
    </td>
    
    <td>
      Unique layer identifier
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        data
      </code>
    </td>
    
    <td>
      <code>
        IsochroneData | null
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      GeoJSON FeatureCollection from routing API
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fillOpacity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.4
      </code>
    </td>
    
    <td>
      Polygon fill opacity (0-1)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lineWidth
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2
      </code>
    </td>
    
    <td>
      Outline width in pixels
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        lineOpacity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.8
      </code>
    </td>
    
    <td>
      Outline 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>
        interactive
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Enable hover/click
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reverseOrder
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Reverse feature order for proper stacking
    </td>
  </tr>
</tbody>
</table>

#### Events

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

<tbody>
  <tr>
    <td>
      <code>
        click
      </code>
    </td>
    
    <td>
      <code>
        { feature, coordinates }
      </code>
    </td>
    
    <td>
      Polygon clicked
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mouseenter
      </code>
    </td>
    
    <td>
      <code>
        feature
      </code>
    </td>
    
    <td>
      Mouse enters polygon
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        mouseleave
      </code>
    </td>
    
    <td>
      -
    </td>
    
    <td>
      Mouse leaves polygon
    </td>
  </tr>
</tbody>
</table>

#### Data Format

The component accepts GeoJSON from routing APIs like Valhalla or OSRM. It automatically handles color format conversion (Valhalla returns colors without `#` prefix).

```typescript
interface IsochroneData {
  type: 'FeatureCollection';
  features: Array<{
    type: 'Feature';
    properties: {
      color: string;      // e.g., '2563eb' or '#2563eb'
      contour?: number;   // Time in minutes or distance
      metric?: string;    // 'time' or 'distance'
    };
    geometry: Polygon | MultiPolygon;
  }>;
}
```

#### Example with Valhalla API

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

const originPoint = ref<[number, number]>([-73.985, 40.758]);
const isochroneData = ref(null);

async function fetchIsochrone() {
  const params = {
    locations: [{ lat: originPoint.value[1], lon: originPoint.value[0] }],
    costing: 'auto',
    contours: [
      { time: 5, color: '2563eb' },
      { time: 10, color: '7c3aed' },
      { time: 15, color: 'db2777' },
    ],
    polygons: true,
  };

  const response = await fetch(`/api/isochrone?json=${encodeURIComponent(JSON.stringify(params))}`);
  isochroneData.value = await response.json();
}

function handleMarkerDrag(event) {
  const lngLat = event.target.getLngLat();
  originPoint.value = [lngLat.lng, lngLat.lat];
  fetchIsochrone();
}
</script>

<template>
  <VMap :options="mapOptions" @loaded="fetchIsochrone">
    <VLayerMaplibreIsochrone
      id="travel-zones"
      :data="isochroneData"
      :fill-opacity="0.5"
      @click="handleZoneClick"
    />
    <VMarker
      :coordinates="originPoint"
      :options="{ draggable: true }"
      @dragend="handleMarkerDrag"
    />
  </VMap>
</template>
```

#### Use Cases

- **Real Estate**: Show commute times to office locations
- **Logistics**: Determine delivery coverage areas
- **Urban Planning**: Analyze accessibility of public services
- **Emergency Services**: Visualize response time coverage


## Sitemap

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