1

Using maplibre-gl-leaflet I want to load an existing vector tiles styles from style.json and remove its background raster layer with the id "swissimage" and then add a raster dataset URL COG GeoTIFF on to which the vectortiles are added.

Download Complete code

I'm stuck with removing the swissimage raster layer with map.removeLayer('swissimage') command.

    <html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        <title>Vector Map Demo (Leaflet)</title>
            <style>
      #map {
        bottom: 0;
        left: 0;
        position: absolute;
        right: 0;
        top: 0;
      }
    </style>
        <!-- Leaflet -->
        <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
        <script type="text/javascript" src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>

        <!-- MapLibre GL JS (still required to handle the rendering) -->
      <link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" />
      <script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
      <!-- Add maplibre-gl-js -->
      <link href='https://unpkg.com/[email protected]/dist/maplibre-gl.css' rel='stylesheet' />
      <script src='https://unpkg.com/[email protected]/dist/maplibre-gl.js'></script>
      <!-- Add maplibre-gl-leaflet -->
      <script src="https://unpkg.com/@maplibre/[email protected]/leaflet-maplibre-gl.js"></script>>
      <script src="https://unpkg.com/proj4"></script>
      <script src="https://unpkg.com/georaster"></script>
      <script src="https://unpkg.com/georaster-layer-for-leaflet"></script>
    
    

    </head>
    <body>
        <div id="map"></div>
        <script type="text/javascript">
            // Initialize a map centered at (53, 12) at zoom level 5
            var map = L.map('map').setView([53, 12], 5);

            L.maplibreGL({
                style: 'https://vectortiles.geo.admin.ch/styles/ch.swisstopo.leichte-basiskarte-imagery.vt/style.json',  // Style URL; see our documentation for more options
                
            }).addTo(map);
            // Wait for the style to load
            map.on('styledata', function() {
                // Check if the layer exists
                if (map.hasLayer('swissimage')) {
                    // Remove the layer
                    map.removeLayer('swissimage');
                }
            });
            


    const url_to_geotiff_file = new URLSearchParams(location.search).get("url");
    console.log("url_to_geotiff_file:", url_to_geotiff_file);

    if (!url_to_geotiff_file) {
        setTimeout(function() {
            // If no URL is provided, redirect to a sample GeoTIFF
            const parser = new URL(window.location);
            parser.searchParams.set("url", "https://d29cp2gnktw6by.cloudfront.net/data/S2_LEVEL_2A/20240101T102431/S2_L2A_SR_20240101T102431_20240101T102428_10M_run20240102.tif");
            window.location = parser.href;
        }, 2 * 1000);
    } else {
        console.log("url_to_geotiff_file:", url_to_geotiff_file);
        // Parse the GeoTIFF data
        parseGeoraster(url_to_geotiff_file).then(function (georaster) {
            console.log("georaster:", georaster);
        // based on https://custom-scripts.sentinel-hub.com/custom-scripts/sentinel-2/l2a_optimized/    
        
        // Contrast enhance / highlight compress
        const maxR = 3.0; // max reflectance
        const midR = 0.13;
        const sat = 1.2;
        const gamma = 1.8;
        
        
        function evaluatePixel(val0,val1,val2) {
            //console.log("val0:", val0, "val1:", val1, "val2:", val2);
            const rgbLin = satEnh(sAdj(val0), sAdj(val1), sAdj(val2));
            //console.log("rgbLin:", rgbLin);
            //console.log("sRGB0:", sRGB(rgbLin[0]), "sRGB1:", sRGB(rgbLin[1]), "sRGB2:", sRGB(rgbLin[2]));
            return [sRGB(rgbLin[0]), sRGB(rgbLin[1]), sRGB(rgbLin[2])];
        }
        
        function sAdj(a) {
            return adjGamma(adj(a, midR, 1, maxR));
        }

        
        const gOff = 0.01;
        const gOffPow = Math.pow(gOff, gamma);
        const gOffRange = Math.pow(1 + gOff, gamma) - gOffPow;


        function adjGamma(b) {
            return (Math.pow((b + gOff), gamma) - gOffPow) / gOffRange;
        }
        
        // Saturation enhancement
        function satEnh(r, g, b) {
            const avgS = (r + g + b) / 3.0 * (1 - sat);
            return [clip(avgS + r * sat), clip(avgS + g * sat), clip(avgS + b * sat)];
        }

        function clip(s) {
            return s < 0 ? 0 : s > 1 ? 1 : s;
        }

        //contrast enhancement with highlight compression
        function adj(a, tx, ty, maxC) {
            var ar = clip(a / maxC, 0, 1);
            return ar * (ar * (tx / maxC + ty - 1) - ty) / (ar * (2 * tx / maxC - 1) - tx / maxC);
        }

        const sRGB = (c) => c <= 0.0031308 ? (12.92 * c) : (1.055 * Math.pow(c, 0.41666666666) - 0.055);


            const layer = new GeoRasterLayer({
                attribution: "swisstopo, contains modified Copernicus Sentinel data 2024",
                debugLevel: 0,
                georaster,
                resolution: 128,
                opacity:1,
                resampleMethod: "nearest",
                pixelValuesToColorFn: values => {
                    // Check if any of the bands have a value of 9999 
                    if (values.some(value => value === 9999 )) {
                    //if (values.some(value => value === 9999 || value === 0)) {
                        // If any band has a value of 9999 , return transparent color
                        return 'rgba(0, 0, 0, 0)'; // Transparent color
                    } else {
                        // Apply min-max normalization to each band
                        const r = Math.round(evaluatePixel(values[0]/10000, values[1]/10000, values[2]/10000)[0] * 255);
                        const g = Math.round(evaluatePixel(values[0]/10000, values[1]/10000, values[2]/10000)[1] * 255);
                        const b = Math.round(evaluatePixel(values[0]/10000, values[1]/10000, values[2]/10000)[2] * 255);


                        // Return RGB color
                        return `rgba(${r},${g},${b},1)`;
                    }
                }
            });

            layer.addTo(map);
            map.fitBounds(layer.getBounds());
        });
    }
</script>
</body>
</html>

Result:

enter image description here

Expected Result:
The "removeLayer" removes the background swissimage map

1
  • GIS SE site has policy of focused questions, which amongst other things means one question per question. Currently your question contains two questions. Please edit your question and limit it to only one question, otherwise it's most likely be closed as not compliant with the GIS SE site policy.
    – TomazicM
    Commented Feb 21 at 14:11

1 Answer 1

1

When dealing with MapLibre layer in Leaflet environment, you have to use MapLibre map object, which is different than Leaflet map object. You get MapLibre map object with the .getMaplibreMap method of added MapLibre layer.

Also .hasLayer method of MapLibre map does not exist, you have to use .getLayer method insetad to check existence of a layer.

Relevant part of the code could then look something like this:

var map = L.map('map').setView([53, 12], 5);

var maplibreLayer = L.maplibreGL({
  style: 'https://vectortiles.geo.admin.ch/styles/ch.swisstopo.leichte-basiskarte-imagery.vt/style.json'          
}).addTo(map);

var maplibreMap = maplibreLayer.getMaplibreMap();           
maplibreMap.on('styledata', function() {
  if (maplibreMap.getLayer('swissimage')) {
    maplibreMap.removeLayer('swissimage');
  }
});

This is how the layer looks like then (georaster layer is left out since it's not relevant for this question):

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.