---
title: Layer Operations
source: https://vjmap.com/en/guide/layerop.html
---

# Layer Operations

## Adding Layers

Add a data source first, then add the corresponding layer based on the source. For example, adding a `wms` raster layer:

```js
map.addSource('wms-test-source', {
    'type': 'raster',
    'tiles': [
        wmsurl
    ],
    'tileSize': 256
});
map.addLayer({
        'id': 'wms-test-layer',
        'type': 'raster',
        'source': 'wms-test-source',
        'paint': { "raster-opacity": 1 }
    }
);
```

[Online example: Tianditu overlaid with CAD map](https://vjmap.com/demo/#/demo/map/web/04webWms)


```js
// Create a GeoJSON data source named "ids"
map.addGeoJSONSource('ids');
// Create a circle layer with id 'ids-circle' linked to "ids"
map.addCircleLayer('ids-circle', 'ids', {
    // Set different colors based on hover state
    circleColor: ['case', ['to-boolean', ['feature-state', 'hover']], 'red', '#FFA0FD'],
    // Set different stroke width based on hover state
    circleStrokeWidth: ['case', ['to-boolean', ['feature-state', 'hover']], 2, 1],
});
// Set the circle radius for the layer
map.setCircleRadius(['ids-circle'], 12);
// Set mouse to 'pointer' shape when over this layer
map.hoverPointer(['ids-circle']);
// Enable hover feature state for this layer to set different values based on hover
map.hoverFeatureState('ids-circle');

// Randomly generate some GeoJSON points
let data = mapBounds.randomGeoJsonPointCollection(1000);
// Set data source data
map.setData('ids', map.toLngLat(data))
```


<mapFrameEx>
<pre>
let svc = new vjmap.Service(env.serviceUrl, env.accessToken)
// Open map
let res = await svc.openMap({
    mapid: "sys_hello", // map ID
    mapopenway: vjmap.MapOpenWay.GeomRender, // geometry render
    style: vjmap.openMapLightStyle() // use dark style when container has dark background
})
if (res.error) {
    showError(res.error)
    return;
}
// Map bounds
let mapBounds = vjmap.GeoBounds.fromString(res.bounds);
// Create projection
let prj = new vjmap.GeoProjection(mapBounds);
//
// Map instance
let map = new vjmap.Map({
    container: 'map', // container ID
    style: svc.rasterStyle(), // raster style
    center: prj.toLngLat(mapBounds.center()), // center
    zoom: 1, // zoom level
    pitch: 0,
    renderWorldCopies: false // no world copies
});
// Attach service and projection
map.attach(svc, prj);
await map.onLoad();
// Add GeoJSON source "ids"
map.addGeoJSONSource('ids');
// Add circle layer "ids-circle" from source "ids"
map.addCircleLayer('ids-circle', 'ids', {
    // Color by hover state
    circleColor: ['case', ['to-boolean', ['feature-state', 'hover']], 'red', '#FFA0FD'],
    // Stroke width by hover state
    circleStrokeWidth: ['case', ['to-boolean', ['feature-state', 'hover']], 2, 1],
});
// Set circle radius
map.setCircleRadius(['ids-circle'], 12);
// Pointer cursor on hover
map.hoverPointer(['ids-circle']);
// Enable hover feature state for styling
map.hoverFeatureState('ids-circle');
// Random GeoJSON points
let data = mapBounds.randomGeoJsonPointCollection(1000);
// Set source data
map.setData('ids', map.toLngLat(data))
setInterval(() => {
    data = mapBounds.randomGeoJsonPointCollection(Math.floor(Math.random() * 1000));
    // Simulate data update
    map.setData('ids', map.toLngLat(data))
}, 5000)
</pre>
</mapFrameEx>
<br/>
<br/>

Other methods for adding layers
```ts
 /** Add a layer with given id, source, type, and properties.
    * @param id
    * @param source
    * @param type
    * @param props
    * @param before
    */
addLayerEx(
    id: string,
    source: string,
    type: string,
    props: {},
    before: string | null | undefined
): SourceBoundUtils;

/** Add a layer before another layer, with given id, source, type, and properties.
    * @param id
    * @param source
    * @param type
    * @param props
    * @param before
    */
addLayerBefore(
    id: string,
    source: SourceOrData,
    type: string,
    props: {},
    before?: string
): SourceBoundUtils | null | undefined;

/** Add a layer of type "line".
 * @param id
 * @param props
 * @param before
 * @param source
 */
addLineLayer(id: string, source: string, props: LineLayerStyleProp, before?: string): void;

/** Add a layer of type "fill".
 * @param id
 * @param props
 * @param before
 * @param source
 */
addFillLayer(id: string, source: string, props: FillLayerStyleProp, before?: string): void;

/** Add a layer of type "circle".
 * @param id
 * @param props
 * @param before
 * @param source
 */
addCircleLayer(
    id: string,
    source: string,
    props: CircleLayerStyleProp,
    before?: string
): void;

/** Add a layer of type "symbol".
 * @param id
 * @param props
 * @param before
 * @param source
 */
addSymbolLayer(
    id: string,
    source: string,
    props: SymbolLayerStyleProp,
    before?: string
): void;

/** Add a layer of type `video`.
 * @param id
 * @param props
 * @param before
 * @param source
 */
addVideoLayer(id: string, source: string, props: object, before?: string): void;

/** Add a layer of type `raster`.
 * @param id
 * @param props
 * @param before
 * @param source
 */
addRasterLayer(
    id: string,
    source: string,
    props: RasterLayerStyleProp,
    before?: string
): void;

/** Add a layer of type "fill-extrusion".
 * @param id
 * @param props
 * @param before
 * @param source
 */
addFillExtrusionLayer(
    id: string,
    source: string,
    props: FillExtrusionLayerStyleProp,
    before?: string
): void;

/** Add a layer of type "heatmap".
 * @param id
 * @param props
 * @param before
 * @param source
 */
addHeatmapLayer(
    id: string,
    source: string,
    props: HeatmapLayerStyleProp,
    before?: string
): void;

/** Add a layer of type "hillshade".
 * @param id
 * @param props
 * @param before
 * @param source
 */
addHillshadeLayer(
    id: string,
    source: string,
    props: HillshadeLayerStyleProp,
    before?: string
): void;

/** Add a `raster` source
 @param sourceId ID of the new source.
    @param {object} props Properties defining the source, per the style spec.
    */
addRasterSource(sourceId: string, props: RasterSourceSpecification): SourceBoundUtils;

/** Add a `raster-dem` source
 @param sourceId ID of the new source.
    @param {object} props Properties defining the source, per the style spec.
    */
addRasterDemSource(sourceId: string, props: RasterDEMSourceSpecification): SourceBoundUtils;

/** Add an `image` source
 @param sourceId ID of the new source.
    @param {object} props Properties defining the source, per the style spec.
    */
addImageSource(sourceId: string, props: ImageSourceSpecification): SourceBoundUtils;

/** Add a "video" source
 @param sourceId ID of the new source.
    @param {object} props Properties defining the source, per the style spec.
    */
addVideoSource(sourceId: string, props: VideoSourceSpecification): SourceBoundUtils;
```

## Removing Layers

`removeLayer` removes the layer with the given ID from the map style. If no such layer exists, an `error` event is triggered.
```js
if (map.getLayer('state-data')) map.removeLayer('state-data');
```

`removeLayerEx` removes one or more layers; does not throw if they do not exist
```js
map.removeLayerEx('state-data');
map.removeLayerEx(['state-data', "layer2"]);
```

`removeSourceEx` removes one or more sources, first removing all layers that depend on them. Does not error if the source does not exist
```js
map.removeSourceEx('ids');
map.removeSourceEx(['source1', "source2"]);
```


## Showing Layers

Show a layer by setting the layout `visibility` property to `visible`
```js
map.setLayoutProperty(layerid, "visibility", "visible");
```

Or show by layer id
```js
map.show(layerid);
```
or
```js
map.toggle(layerid, true)
```

Or make all layers associated with a data source visible
```js
map.showSource(sourceid);
```
or
```js
map.toggleSource(sourceid, true)
```

## Hiding Layers

Hide a layer by setting the layout `visibility` property to `none`
```js
map.setLayoutProperty(layerid, "visibility", "none");
```

Or hide by layer id
```js
map.hide(layerid);
```
or
```js
map.toggle(layerid, false)
```


Or hide all layers associated with a data source
```js
map.hideSource(sourceid);
```
or
```js
map.toggleSource(sourceid, false)
```


## Setting Layer Properties

```js
// They all work on multiple layers at once: 
map.setLineWidth([ 'mylayer' , 'mylayer-highlight' ], 4 );
map.setLineOpacity( /^ border- / , 0 );
map.setFillColor( layer => layer.source === 'farms' , 'green' );

// There is also a more familiar setProperty() form.
map.setProperty( 'mylayer' , 'line-width' , 3 );
// Simpler way to update source data: 
map.setData( 'mysource' , data);

// You can omit the data parameter to clear a GeoJSON source: 
map.setData( 'mysource' );

// Update multiple filters at once.
map.setFilter([ 'buildings-fill' , 'buildings-outline' , 'buildings-label' ], [...]);
```

## Layer Events

Listen via `map` events, e.g.
```js
map.on("click", layerid, e => {
    console.log(e)
})
```

or

```js
// clickLayer() is similar to .on('click)', but can accept an array and adds a 'features' member to the event for the clicked content.
map.clickLayer([ 'towns' , 'town-labels' ], e => panel.selectedId = e.features[ 0 ].id);
```

```js
// Use mouse "pointer" cursor when hovering over this layer.
map.hoverPointer( 'mylayer' );

// If you pass multiple layers, it correctly handles moving from one layer to another
// Use mouse "pointer" cursor when hovering over that layer.
map.hoverPointer([ 'regions-border' , 'regions-fill' ]);

// When the mouse moves over a feature on this layer, set the "hover" feature state to true or false.
// Requires features to have an `id`.
map.hoverFeatureState( 'mylayer' );

// Want to apply hover feature state to a different source?
// E.g. you hover over a label but want to highlight the surrounding boundary.
map.hoverFeatureState( 'town-labels' , 'boundaries' , 'town-boundaries' );

// You can also add other event handlers: 
map.hoverFeatureState( 'mylayer' , 'mysource' , 'mysourcelayer' ,
    e => console.log(`Entered ${e.features[0].id}`),
    e => console.log(`Left ${e.oldFeatureid}`);

// Show a popup when a feature is hovered or clicked.
// The third parameter is an options object passed to the Popup constructor.
// Callback is called as: (feature, popup) => htmlString 
map.hoverPopup( 'mylayer' , f =>  `<h3> ${f.properties.Name} </h3> ${f.properties.Description} ` , { anchor : 'left' });
map.clickPopup( 'mylayer' , f =>  `<h3> ${f.properties.Name} </h3> ${f.properties.Description} ` , { maxWidth : 500 });

// clickOneLayer tests multiple layers in order, triggering the callback on the first hit. Callback receives { features, feature, layer, event }.
map.clickOneLayer([ 'town-labels' , 'state-boundaries' ], e => {
    if (e.layer === 'town-labels') {
        setView('town');
        panel.selectedId = e.features[0].id;
    } else if (e.layer === 'state-boundaries') {
        setView('state');
        panel.selectedId = e.features[0].id;
    }
});

// Optionally pass an extra callback that fires for clicks that miss all layers: 
map.clickOneLayer(['town-labels', 'state-boundaries'], e => {...}, e => {
    console.log('Missed everything');
});


// All these functions return an "undo" function that removes the added handler:
const remove = map.hoverPopup( 'mylayer' , showPopupFunc);
//...
remove(); // No more hover popup
```
