Custom BlendLayer
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 Default | Custom Blend Layer (ArcGIS Hillshade + National Geographic) |
---|---|
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));
}