The VControlLayer component provides an interactive control for managing layer visibility and opacity. It supports both MapLibre native layers and deck.gl layers, automatically detecting the layer type.
Features:
<script setup lang="ts">
import { VMap, VControlLayer, VLayerMaplibreGeojson } from '@geoql/v-maplibre';
const mapOptions = {
style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
center: [-74.5, 40],
zoom: 9,
};
const geojsonSource = {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: { type: 'Point', coordinates: [-74.5, 40] },
properties: {},
},
],
},
};
const layerSpec = {
id: 'points-layer',
type: 'circle',
paint: {
'circle-radius': 10,
'circle-color': '#007cbf',
},
};
</script>
<template>
<VMap :options="mapOptions" style="height: 500px">
<VLayerMaplibreGeojson
source-id="points"
layer-id="points-layer"
:source="geojsonSource"
:layer="layerSpec"
/>
<VControlLayer
layer-id="points-layer"
position="top-right"
title="Points Layer"
/>
</VMap>
</template>
stringtrueThe ID of the layer to control. Must match either a MapLibre layer ID or a deck.gl layer ID.
'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'false'top-right'Position of the control on the map.
booleanfalsetrueInitial visibility state of the layer. Supports v-model binding with v-model:visible.
numberfalse1Initial opacity of the layer (0-1). Supports v-model binding with v-model:opacity.
stringfalse'Layer Control'Title displayed in the control panel.
'maplibre' | 'deckgl'falseForce the layer type. If not specified, the component auto-detects whether the layer is a MapLibre or deck.gl layer.
Emitted when the layer visibility changes.
booleanEmitted when the layer opacity changes.
numberEmitted for v-model:visible binding.
booleanEmitted for v-model:opacity binding.
numberThe component supports two-way binding for both visibility and opacity:
<script setup lang="ts">
import { ref } from 'vue';
const isVisible = ref(true);
const layerOpacity = ref(1);
</script>
<template>
<VControlLayer
layer-id="my-layer"
v-model:visible="isVisible"
v-model:opacity="layerOpacity"
/>
<p>Visible: {{ isVisible }}</p>
<p>Opacity: {{ layerOpacity }}</p>
</template>
For MapLibre native layers, the control automatically maps to the correct opacity property:
| Layer Type | Opacity Property |
|---|---|
fill | fill-opacity |
line | line-opacity |
circle | circle-opacity |
symbol | icon-opacity |
For deck.gl layers, the control uses the layer's visible and opacity props. The component clones the layer with updated properties using the immutable pattern required by deck.gl.
<script setup lang="ts">
import { VMap, VControlLayer, VLayerDeckglScatterplot } from '@geoql/v-maplibre';
const mapOptions = {
style: 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json',
center: [-122.4, 37.8],
zoom: 11,
};
const data = [
{ coordinates: [-122.4, 37.8], size: 100 },
{ coordinates: [-122.5, 37.7], size: 200 },
];
</script>
<template>
<VMap :options="mapOptions" style="height: 500px">
<VLayerDeckglScatterplot
id="scatter-layer"
:data="data"
:get-position="(d) => d.coordinates"
:get-radius="(d) => d.size"
:get-fill-color="[255, 140, 0]"
/>
<VControlLayer
layer-id="scatter-layer"
position="top-left"
title="Scatter Points"
/>
</VMap>
</template>
import type { ControlPosition, LayerType } from '@geoql/v-maplibre';
// Props interface
interface LayerControlOptions {
layerId: string;
position?: ControlPosition;
visible?: boolean;
opacity?: number;
title?: string;
layerType?: LayerType;
}
The VControlLayerGroup component provides a collapsible panel for controlling multiple layers at once. Each layer gets its own visibility toggle and opacity slider within a single unified control.
Use VControlLayerGroup when you need to:
VControlLayer componentsFeatures:
<script setup lang="ts">
import { VMap, VControlLayerGroup, VLayerMaplibreGeojson } from '@geoql/v-maplibre';
const mapOptions = {
style: 'https://basemaps.cartocdn.com/gl/positron-gl-style/style.json',
center: [-96, 37.8],
zoom: 4,
};
const statesGeoJson = ref(null);
// ... fetch GeoJSON data
const layerGroupConfig = [
{ id: 'states-fill', title: 'US States', visible: true, opacity: 0.5 },
{ id: 'states-outline', title: 'State Borders', visible: true, opacity: 1 },
];
</script>
<template>
<VMap :options="mapOptions" style="height: 500px">
<VLayerMaplibreGeojson
source-id="states"
layer-id="states-fill"
:source="{ type: 'geojson', data: statesGeoJson }"
:layer="{
id: 'states-fill',
type: 'fill',
source: 'states',
paint: { 'fill-color': '#627BC1', 'fill-opacity': 0.5 }
}"
/>
<VLayerMaplibreGeojson
source-id="states"
layer-id="states-outline"
:source="{ type: 'geojson', data: statesGeoJson }"
:layer="{
id: 'states-outline',
type: 'line',
source: 'states',
paint: { 'line-color': '#627BC1', 'line-width': 2 }
}"
/>
<VControlLayerGroup
:layers="layerGroupConfig"
title="Map Layers"
position="top-right"
:collapsible="true"
/>
</VMap>
</template>
LayerConfig[]trueArray of layer configurations. Each layer config has:
| Property | Type | Default | Description |
|---|---|---|---|
id | string | - | Layer ID (must match MapLibre or deck.gl layer) |
title | string | - | Display title in the control |
visible | boolean | true | Initial visibility |
opacity | number | 1 | Initial opacity (0-1) |
type | 'maplibre' | 'deckgl' | Auto-detected | Force layer type |
'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'false'top-right'Position of the control on the map.
stringfalse'Layers'Title displayed in the panel header.
booleanfalsetrueWhether the panel can be collapsed by clicking the header.
booleanfalsefalseInitial collapsed state of the panel.
Emitted when a layer's visibility changes.
{ layerId: string; visible: boolean }Emitted when a layer's opacity changes.
{ layerId: string; opacity: number }Emitted when the layers array should be updated (for v-model binding).
LayerConfig[]VControlLayerGroup supports controlling both MapLibre and deck.gl layers in the same panel:
<script setup lang="ts">
const mixedLayers = [
{ id: 'maplibre-fill-layer', title: 'Fill Layer', type: 'maplibre' },
{ id: 'deckgl-scatter-layer', title: 'Scatter Points', type: 'deckgl' },
{ id: 'maplibre-line-layer', title: 'Roads', type: 'maplibre' },
];
</script>
<template>
<VControlLayerGroup
:layers="mixedLayers"
title="All Layers"
/>
</template>
import type { ControlPosition, LayerType, LayerConfig } from '@geoql/v-maplibre';
// LayerConfig interface
interface LayerConfig {
id: string;
title: string;
visible?: boolean;
opacity?: number;
type?: LayerType;
}
// Props interface
interface LayerGroupOptions {
layers: LayerConfig[];
position?: ControlPosition;
title?: string;
collapsible?: boolean;
collapsed?: boolean;
}