Custom BlendLayer

Loading...

Note: Support for 3D on mobile devices may vary, view the system requirements for more information.

This sample demonstrates how to create a custom tile layer by applying the multiply blending operation to the ArcGIS World Hillshade and National Geographic World Map services. The multiply blend mode multiplies the values of each pixel of the top layer with the corresponding pixel value of the bottom layer. In this sample, multiplying the hillshade tiles with the National Geographic tiles creates a more detailed representation of the terrain than you see from the default National Geographic basemap. You can toggle the blended layer on and off using the LayerList widget in the sample. The BlendLayer is toggled on by default.

National Geographic DefaultCustom Blend Layer (ArcGIS Hillshade + National Geographic)
custom-layers-no-blendcustom-layers-blend

To create a custom tile layer, you must call createSubclass() on BaseTileLayer. BaseTileLayer is a class designed specifically for creating custom tile layers, such as the BlendLayer created in this sample. When creating a BlendLayer we define a property called multiplyLayers, which is an array of tile layers that will be blended together.

var BlendLayer = BaseTileLayer.createSubclass({

  // multiplyLayers stores tile layers
  // used as the basis for creating
  // a blend layer. Layers stored in this property
  // will be blended using "multiply" operation.

  properties: {
    multiplyLayers: null
  }

});

The tile layers added to the multiplyLayers array are loadable resources. If a custom tile layer requires loadable resources, then you must load them in the layer using the load() method. This ensures that all loadable resources required for the layer to function are loaded prior to the custom layer resolving and becoming loaded.

var BlendLayer = BaseTileLayer.createSubclass({

  properties: {
    multiplyLayers: null
  },

  // Called when the layer is added to the map
  // prior to it being rendered in the view.
  load: function() {

    // iterate through each layer in multiplyLayers property
    this.multiplyLayers.forEach(function(layer) {

      // call load method on each layer and add as
      // a resolving promise of the custom layer.
      // The tile layers must load() prior to the BlendLayer
      // resolving and moving to the "loaded" status.
      this.addResolvingPromise(layer.load());
    }, this);
  }

});

Once the layer is loaded with its required resources, we must override the fetchTile() method of the BlendLayer. Within this method, call fetchTile() on each tile layer returned in the multiplyLayers property. Once each tile layer returns the tile(s) visible in the view, we apply multiply operation to the tiles so that the BlendLayer will show the blended image.

// Fetches the tile(s) visible in the view
fetchTile: function (level, row, col) {
  var tilePromises = this.multiplyLayers.map(function (layer) {
    // calls fetchTile() on the tile layers returned in multiplyLayers property
    // for the tiles visible in the view
    return layer.fetchTile(level, row, col);
  });

  return promiseUtils.eachAlways(tilePromises)
    .then(function (images) {

      // create a canvas
      var width = this.tileInfo.size[0];
      var height = this.tileInfo.size[0];
      var canvas = document.createElement("canvas");
      var context = canvas.getContext("2d");

      canvas.width = width;
      canvas.height = height;

      // multiply - multiplies the numbers for each pixel of the top layer (nat geo)
      // with the corresponding pixel for the bottom layer (hillshade).
      context.globalCompositeOperation = "multiply";
      images.forEach(function (result) {
        var image = result.value;
        context.drawImage(image, 0, 0, width, height);
      });

      return canvas;
    }.bind(this));
  }

Sample search results

TitleSample
Loading...