Custom TileLayer
Note: Support for 3D on mobile devices may vary, view the system requirements for more information.
Introduction to layer extensibility
ArcGIS API for JavaScript provides a number of predefined layers. These layers retrieve images or data from servers and display them in the view.
In addition to this sample, the following samples demonstrate the basic fundamentals of creating custom layers.
- Custom BlendLayer
- Custom LERC Layer
- Custom DynamicLayer
- Custom ElevationLayer - Exaggerating elevation
- Custom ElevationLayer - Thematic data as elevation
Creating custom layers is useful when you need to:
- display data from a source not exclusively supported in the ArcGIS API for JavaScript
- preprocess data before it is displayed in the view (this could be because the service returns binary data, which needs to be processed to generate an image)
- create custom visualizations not explicitly supported in the API
- display synthesized data such as an exaggerated elevation
Writing a custom layer enables you to support the drawing of new data formats. Before you get started on creating custom layers, it is helpful to have some familiarity with the following topics:
Create a custom tile layer
This sample demonstrates how to create a custom TileLayer from Stamen's toner black and white tiles. Tile layers are composed of images, such as satellite imagery, which are square tiles stitched together in columns and rows, giving the layer the appearance that it is one continuous image. These layers have several levels of detail (LOD) that permit users to zoom to any region of the map and load more tiles that depict features in higher resolution at larger map scales.
To create a custom tile layer, you must call the createSubclass() method on the BaseTileLayer class. We'll name the custom layer TintLayer
.
Since this layer needs to know where to access predefined tiles, we will create a urlTemplate
property. The application will provide the urlTemplate
value for the layer, and the layer will fetch tiles from the generated URL. The difference blending operation is then applied to the Stamen tiles prior to displaying each image. We will create a tint
property on this layer so that the application can specify a color, which will be used in the blending operation.
var TintLayer = BaseTileLayer.createSubclass({
// set up the properties specific to this layer
properties: {
// url to the tiles, provided by the application
urlTemplate: null,
// tint color that will be used to change
// steman's black and white tiles
// value provided by the application
tint: {
value: null,
type: Color
}
},
// override necessary methods here
});
You extend BaseTileLayer two different ways:
- Request tiles as they are predefined from a data source
- Images or data need to be pre-processed prior to display in the view
Request tiles as they are predefined from a data source
To request images as they are predefined from a data source, overwrite the getTileUrl() method so it returns the URL for the requested tile at a given level, row, and column.
var MyCustomTileLayer = BaseTileLayer.createSubclass({
// properties of the custom tile layer
properties: {
urlTemplate: null,
},
// override getTileUrl()
// generate the tile url for a given level, row and column
getTileUrl: function (level, row, col) {
return this.urlTemplate.replace("{z}", level).replace("{x}", col).replace("{y}", row);
}
});
Images or data need preprocessing prior to display in the view
If data or tiles need to be preprocessed prior to display, then override the fetchTile() method. This sample uses this approach by fetching Stamen's toner tiles and applying the difference blending operation with a given color to the canvas. Once the image and color are blended, the final result will display in the view.
// This method fetches tiles for the specified level and size.
// Override this method to process the data returned from the server.
fetchTile: function (level, row, col) {
// call getTileUrl() method to construct the URL to tiles
// for a given level, row and col provided by the LayerView
var url = this.getTileUrl(level, row, col);
// request for tiles based on the generated url
return esriRequest(url, {
responseType: "image"
})
.then(function (response) {
// when esri request resolves successfully
// get the image from the response
var image = response.data;
var width = this.tileInfo.size[0];
var height = this.tileInfo.size[0];
// create a canvas with 2D rendering context
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
canvas.width = width;
canvas.height = height;
// Apply the tint color provided by
// by the application to the canvas
if (this.tint) {
// Get a CSS color string in rgba form
// representing the tint Color instance.
context.fillStyle = this.tint.toCss();
context.fillRect(0, 0, width, height);
// Applies "difference" blending operation between canvas
// and steman tiles. Difference blending operation subtracts
// the bottom layer (canvas) from the top layer (tiles) or the
// other way round to always get a positive value.
context.globalCompositeOperation = "difference";
}
// Draw the blended image onto the canvas.
context.drawImage(image, 0, 0, width, height);
return canvas;
}.bind(this));
}
Using the custom tile layer in JavaScript application
Once the custom layer is created, you can add it to the layers of the Map and add the map to a MapView or SceneView instance.
// Create a new instance of the TintLayer and set its properties.
var stamenTonerLayer = new TintLayer({
urlTemplate: "https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png",
tint: "#71DE6E", // blue color
title: "Stamen Toner"
});
var map = new Map({
layers: [ stamenTonerLayer ]
});
var view = new SceneView({
container: "viewDiv",
map: map,
center: [ 0, 30 ],
zoom: 3
});