block by ThomasG77 5bf03d9c2acaa4562fecb94aadfb04e4

Use ol.source.Raster to mask only 2 layers instead of playing between full canvas and a particular layer

Full Screen

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset=utf-8>
    <meta name=description content="">
    <meta name=viewport content="width=device-width, initial-scale=1">
    <title>Simple Map with mask between 2 layers</title>
    <link rel="stylesheet" href="https://openlayers.org/en/v4.6.5/css/ol.css" type="text/css">
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://openlayers.org/en/v4.6.5/build/ol.js"></script>
  </head>
  <body>
    <div id="map" class="map"></div>
    <select id="filtercountry"></select>
    <script>
      var initialCenter = [0, 0];
      var initialZoom = 2;

      var view = new ol.View({
        center: initialCenter,
        zoom: initialZoom
      });

      var map = new ol.Map({
        layers: [
          new ol.layer.Tile({
            source: new ol.source.OSM()
          })
        ],
        target: 'map',
        view: view
      });

      var style = new ol.style.Style({
        fill: new ol.style.Fill({
          color: [0, 0, 0, 1]
        })
      });

      var geoJSONFormat = new ol.format.GeoJSON();
      var vectorSource = new ol.source.Vector();

      var features;
      fetch('//openlayers.org/en/v4.6.5/examples/data/geojson/countries.geojson')
        .then(response => response.json())
        .then(json => {
          features = geoJSONFormat.readFeatures(json, {
            dataProjection: 'EPSG:4326',
            featureProjection: 'EPSG:3857'
          });
          vectorSource.addFeatures(features);

          var rasterSource = new ol.source.ImageVector({
            source: vectorSource,
            style: style
          });
          var clipLayer = new ol.layer.Image({
            source: rasterSource
          });

          var raster = new ol.source.Raster({
            sources: [
              new ol.source.Stamen({
                layer: 'watercolor',
                transition: 0
              }),
              rasterSource
            ],
            operation: function(pixels, data) {
              if (pixels[1][3] == 0) {
                return [0, 0, 0, 1];
              } else {
                return pixels[0];
              }
            }
          });
          var rasterLayer = new ol.layer.Image({
            source: raster
          });
          map.addLayer(rasterLayer);


          var filterCountry = document.getElementById('filtercountry');
          var options = [
            ['', 'Unfiltered'],
            ...features.map(feature => {
              return [feature.getId(), feature.get('name')];
            })
          ].reduce((acc, curr) => {
            var option = document.createElement('option');
            option.text = curr[1];
            option.value = curr[0];
            acc.appendChild(option);
            return acc;
          }, document.createDocumentFragment());
          filterCountry.appendChild(options);

          filterCountry.addEventListener("change", function() {
            if(filterCountry.value.length > 0) {
              console.log('One country', filterCountry.options[filterCountry.selectedIndex].text);
              vectorSource.clear();
              vectorSource.addFeature(features.find(el => el.getId() === filterCountry.options[filterCountry.selectedIndex].value));
              map.getView().fit(vectorSource.getExtent());
            } else {
              console.log('Unfiltered', filterCountry.options[filterCountry.selectedIndex].text);
              vectorSource.clear();
              vectorSource.addFeatures(features);
              map.getView().setCenter([0, 0]);
              map.getView().setZoom(2);
            }
            raster.changed();
          });
        });
    </script>
  </body>
</html>