@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
344 lines (342 loc) • 17.5 kB
TypeScript
import type SpatialReference from "../geometry/SpatialReference.js";
import type Layer from "./Layer.js";
import type TileInfo from "./support/TileInfo.js";
import type { EsriPromiseMixin } from "../core/Promise.js";
import type { AbortOptions } from "../core/promiseUtils.js";
import type { BlendLayer, BlendLayerProperties } from "./mixins/BlendLayer.js";
import type { RefreshableLayer, RefreshableLayerProperties } from "./mixins/RefreshableLayer.js";
import type { ScaleRangeLayer, ScaleRangeLayerProperties } from "./mixins/ScaleRangeLayer.js";
import type { TileInfoProperties } from "./support/TileInfo.js";
import type { SpatialReferenceProperties } from "../geometry/SpatialReference.js";
import type { LayerProperties } from "./Layer.js";
export interface BaseTileLayerProperties extends LayerProperties, RefreshableLayerProperties, ScaleRangeLayerProperties, BlendLayerProperties {
/**
* The spatial reference of the layer.
*
* @default {@link geometry/SpatialReference#WebMercator}
*/
spatialReference?: SpatialReferenceProperties;
/** The tiling scheme information for the layer. */
tileInfo?: TileInfoProperties;
}
/**
* This class may be extended to create a custom TileLayer. It is a generic tile layer class designed to work with various tile sources,
* not just ArcGIS cached [map services](https://enterprise.arcgis.com/en/server/latest/publish-services/windows/what-is-a-map-service.htm),
* which are specifically handled by the [TileLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/TileLayer/) class. Tile layers are composed of images, such as satellite imagery,
* that are composed of square tiles mosaicked together in columns and rows, giving the layer the appearance that it is one continuous image.
* They have several levels of detail (LOD) that permit users to zoom in to any region of the map and load additional tiles that depict features
* in higher resolution at larger map scales.
*
* Tile layers often provide geographic context for other layers such as
* [FeatureLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/FeatureLayer/) and tend to perform better than other layers,
* such as [MapImageLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/MapImageLayer/) and [ImageryLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/ImageryLayer/),
* that request and display a single image per view.
*
* You can create a custom tile layer by calling [Accessor.createSubclass()](https://developers.arcgis.com/javascript/latest/references/core/core/Accessor/#createSubclass)
* on the `BaseTileLayer` class. You may create a custom tile layer for one of the following reasons:
*
* * The source of the images isn't explicitly supported by the ArcGIS Maps SDK for JavaScript
* * Images need to be preprocessed prior to display in the view
*
* ### Setting up a custom tile layer
* Unlike TileLayer, the BaseTileLayer does not make assumptions about the type of data it retrieves, making it more flexible and capable of working
* with a wider variety of tile sources. By default, the BaseTileLayer is configured to use the Web Mercator spatial reference.
* If a custom tile source does not use the Web Mercator spatial reference, the BaseTileLayer must be explicitly configured with three key properties
* in its constructor to ensure proper alignment with the source. Those properties are [tileInfo](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#tileInfo), [spatialReference](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#spatialReference),
* and [fullExtent](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#fullExtent).
*
* ```js
* // set the spatial reference to New Zealand Transverse Mercator
* const spatialReference = new SpatialReference({
* wkid: 2193
* });
*
* // create the origin point for the tileInfo
* // The upper left corner of the tiling scheme,
* const origin = new Point({
* x: -4020900,
* y: 19998100,
* spatialReference
* });
*
* // Create LODs based on the source tiles
* const tileInfo = new TileInfo({
* spatialReference,
* origin: origin,
* format: "mixed",
* lods: [{
* "level": 0,
* "resolution": 156543.03392799935,
* "scale": 591657527.591552
* },
* {
* "level": 1,
* "resolution": 78271.51696399967,
* "scale": 295828763.795776
* },
* // other LODs
* ]
* });
*
* const MyCustomTileLayer = BaseTileLayer.createSubclass({
* constructor() {
* this.tileInfo = tileInfo;
* this.spatialReference = spatialReference;
* this.fullExtent = new Extent ({
* xmin: -1497310.4689000002,
* ymin: 3678220.3271,
* xmax: 4749968.6755,
* ymax: 7192314.8459,
* spatialReference
* })
* },
* // properties of the custom tile layer
* properties: {
* urlTemplate: null,
* }
* });
* ```
*
* ### Request images as they are defined
*
* To request images as they are predefined from a data source, overwrite the [getTileUrl()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#getTileUrl)
* method so it returns the URL for the requested tile for a given level, row and column.
*
* ```js
* // 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);
* }
* ```
*
* ### Preprocess images prior to display
*
* If data needs to be preprocessed prior to display, then override the [fetchTile()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#fetchTile)
* method. For example, if you need to apply a
* [compositing operation](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation)
* to the image returned from the server before the image is displayed then you would override this method.
*
* ```js
* // override fetchTile() method to process the data returned
* // from the server.
* fetchTile: function (level, row, col, options) {
* // call getTileUrl method to construct the Url for the image
* // for given level, row and column
* let url = this.getTileUrl(level, row, col);
*
* // request for the tile based on the url returned from getTileUrl() method.
* // the signal option ensures that obsolete requests are aborted.
* return esriRequest(url, {
* responseType: "image",
* signal: options && options.signal
* })
* .then(function (response) {
* // when esriRequest resolves successfully,
* // process the image that is returned
* let image = response.data;
* let width = this.tileInfo.size[0];
* let height = this.tileInfo.size[0];
*
* // create a canvas with a filled rectangle
* let canvas = document.createElement("canvas");
* let context = canvas.getContext("2d");
* canvas.width = width;
* canvas.height = height;
*
* // Apply the color provided by the layer to the fill rectangle
* if (this.tint) {
* context.fillStyle = this.tint.toCss();
* context.fillRect(0, 0, width, height);
* // apply multiply blend mode to canvas' fill color and the tile
* // returned from the server to darken the tile
* context.globalCompositeOperation = "multiply";
* }
* context.drawImage(image, 0, 0, width, height);
* return canvas;
* }.bind(this));
* }
* ```
*
* See the following samples for examples of how this works:
*
* * [Sample - Custom TileLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-tilelayer/)
* * [Sample - Custom LERC Layer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-lerc-2d/)
* * [Sample - Custom BlendLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-blendlayer/)
*
* If the custom tile layer requires loadable resources, then you must load all loadable
* dependencies on the layer, within the [load()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#load) method. Add the promise returned
* from the loadable resource with the [addResolvingPromise()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#addResolvingPromise) method.
* The layer will then wait for all of dependencies to
* finish loading before it is considered [loaded](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#loaded).
*
* ```js
* // Override load method
* load: function () {
* // multiply property is an array of ArcGIS cached map services
* this.multiply.forEach(function (layer) {
* // loop through each tile layers and call
* // load method on each layer
* let promise = layer.load();
*
* // add the promise of each load() method to addResolvingPromise()
* // the custom tile layer will be loaded when every promise is resolved
* this.addResolvingPromise(promise);
* }, this);
* }
* ```
* The layer is responsible for generating the tile URL and fetching tiles from the server for the
* level, row, and column provided by the [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/). The
* LayerView displays the fetched tiles.
*
* @since 4.4
* @see [Creating Custom Layers and LayerViews (slides) - 2017 Esri Dev Summit](https://proceedings.esri.com/library/userconf/devsummit17/papers/dev_int_97.pdf)
* @see [Creating Custom Layers and LayerViews (video)](https://youtu.be/QOoZ1lgWESA)
* @see [Sample - Custom TileLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-tilelayer/)
* @see [Sample - Custom LERC Layer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-lerc-2d/)
* @see [Sample - Custom BlendLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-blendlayer/)
*/
export default abstract class BaseTileLayer extends BaseTileLayerSuperclass {
/**
* The spatial reference of the layer.
*
* @default {@link geometry/SpatialReference#WebMercator}
*/
get spatialReference(): SpatialReference;
set spatialReference(value: SpatialReferenceProperties);
/** The tiling scheme information for the layer. */
get tileInfo(): TileInfo;
set tileInfo(value: TileInfoProperties);
/**
* For [BaseTileLayer](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/) the type is `base-tile`.
*
* @default "base-tile"
*/
get type(): "base-tile" | "bing-maps";
/**
* Adds a Promise to the layer's loadable chain.
* This is typically used in the [load()](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#load) method to ensure that all
* loadable resources required for the layer
* to function are loaded prior to this layer resolving and becoming [loaded](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#loaded).
*
* @param promiseToLoad - A promise that must resolve for the layer
* to resolve and move from the `loading` [status](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#loadStatus) to being
* [loaded](https://developers.arcgis.com/javascript/latest/references/core/layers/BaseTileLayer/#loaded).
* @see [Sample - Custom BlendLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-blendlayer/)
* @example
* // The requiredLayer must load() prior to the MyCustomTileLayer
* // resolving and moving to the "loaded" status.
* let MyCustomTileLayer = BaseTileLayer.createSubclass({
* load: function() {
* let promise = this.requiredLayer.load();
* this.addResolvingPromise(promise);
* }
* });
*/
addResolvingPromise<U, V extends EsriPromiseMixin>(promiseToLoad: PromiseLike<U> | V | PromiseLike<V> | null | undefined): void;
/**
* This method fetches a tile for the given level, row and column present in the view. Override this method if the data or image
* returned from the server needs to be processed before it can be displayed.
*
* @param level - Level of detail of the tile to fetch. This value is provided by [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
* @param row - The row (y) position of the tile fetch. This value is provided by [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
* @param col - The column (x) position of the tile to fetch. This value is provided by [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
* @param options - Optional settings for the tile request. The options have the following properties.
* @returns Returns a promise that resolves to an
* [HTMLImageElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement) or
* [HTMLCanvasElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement).
* @see [Sample - Custom BlendLayer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-blendlayer/)
* @see [Sample - Custom LERC Layer](https://developers.arcgis.com/javascript/latest/sample-code/layers-custom-lerc-2d/)
* @example
* // Process the image returned from the server before
* // it is displayed.
* fetchTile: function (level, row, col, options) {
* // call getTileUrl method to construct the URL for
* // the image for the given level, row and col
* let url = this.getTileUrl(level, row, col);
*
* // request for the tile based on the generated url.
* // the signal option ensures that obsolete requests are aborted.
* return esriRequest(url, {
* responseType: "image",
* signal: options && options.signal
* })
* .then(function (response) {
* // get the image from the response
* let image = response.data;
* let width = this.tileInfo.size[0];
* let height = this.tileInfo.size[0];
*
* let canvas = document.createElement("canvas");
* canvas.width = width;
* canvas.height = height;
* let context = canvas.getContext("2d");
*
* // tint is a custom property of this layer
* // Apply the tint color provided by the application
* // to the canvas
* if (this.tint) {
* context.fillStyle = this.tint.toCss();
* context.fillRect(0, 0, width, height);
*
* // The pixels of the top layer are multiplied by the corresponding
* // pixel of the bottom layer. A darker picture is the result.
* context.globalCompositeOperation = "multiply";
* }
* context.drawImage(image, 0, 0, width, height);
* return canvas;
* }.bind(this));
* }
*/
fetchTile(level: number, row: number, col: number, options?: AbortOptions): Promise<HTMLImageElement | HTMLCanvasElement>;
/**
* Returns the bounds of the tile as an array of four numbers that be readily
* converted to an [Extent](https://developers.arcgis.com/javascript/latest/references/core/geometry/Extent/) object.
* The value for each item in the array is described in the following table:
*
* Index | Value
* ------|------
* 0 | Minimum x-value
* 1 | Minimum y-value
* 2 | Maximum x-value
* 3 | Maximum y-value
*
* @param level - The level of detail (LOD) of the tile.
* @param row - The tile's row (y) position in the dataset.
* @param column - The tiles column (x) position in the dataset.
* @param out - Array for storing the tile bounds or extent.
* @returns Returns an array representing the tile bounds or extent.
*/
getTileBounds(level: number, row: number, column: number, out?: [
number,
number,
number,
number
]): [
number,
number,
number,
number
];
/**
* This method returns a URL to an image for a given level, row and column.
* Override this method to construct the URL for the image based on user interaction.
*
* @param level - Level of detail. This value is provided by the
* [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
* @param row - Tile row. This value is provided by the
* [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
* @param col - Tile column. This value is provided by the
* [LayerView](https://developers.arcgis.com/javascript/latest/references/core/views/layers/LayerView/).
* @returns Returns the URL to the tile image.
* @example
* // generate the tile url for a given level, row and column
* getTileUrl: function (level, row, col) {
* // urlTemplate is a property of the custom layer.
* // value is provided by the application
* return this.urlTemplate.replace("{z}", level).replace("{x}", col).replace("{y}", row);
* },
*/
getTileUrl(level: number, row: number, col: number): string | null | undefined;
}
declare const BaseTileLayerSuperclass: typeof Layer & typeof RefreshableLayer & typeof ScaleRangeLayer & typeof BlendLayer