{"id":80201,"date":"2017-10-27T19:00:59","date_gmt":"2017-10-27T19:00:59","guid":{"rendered":"http:\/\/www.esri.com\/arcgis-blog\/products\/product\/uncategorized\/creating-a-custom-tile-layer-with-typescript\/"},"modified":"2018-04-17T16:42:15","modified_gmt":"2018-04-17T16:42:15","slug":"creating-a-custom-tile-layer-with-typescript","status":"publish","type":"blog","link":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript","title":{"rendered":"Creating a custom tile layer with TypeScript"},"author":5981,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","format":"standard","meta":{"_acf_changed":false,"_searchwp_excluded":""},"categories":[22941],"tags":[24921,27491,34861],"industry":[],"product":[36831,36601],"class_list":["post-80201","blog","type-blog","status-publish","format-standard","hentry","category-mapping","tag-javascript","tag-jsapi4","tag-typescript","product-js-api-arcgis","product-developers"],"acf":{"short_description":"The ArcGIS API for JavaScript provides you with many different layer types that support various data types and visualizations. We also pr...","flexible_content":[{"acf_fc_layout":"content","content":"<p><a href=\"https:\/\/developers.arcgis.com\/javascript\/\">The ArcGIS API for JavaScript<\/a> provides you with many different layer types that support various data types and visualizations. We also provide you with the building blocks for creating your own custom layer types. These are <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-BaseTileLayer.html\">BaseTileLayer<\/a>, <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-BaseDynamicLayer.html\">BaseDynamicLayer<\/a>, and <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-BaseElevationLayer.html\">BaseElevationLayer<\/a> which were introduced in the 4.4 version of the API.<\/p>\n<div>Custom layers are useful in the following situations:<\/div>\n<ul>\n<li> Display\u00a0an unsupported data source in your JavaScript application without having to convert it to a data format supported by ArcGIS.<\/li>\n<li> Process the data returned from the service before it is displayed. This could be because the service returns binary data, and the data needs to be processed to generate an image so it can be displayed on the view.<\/li>\n<li> Display synthesized data such as an <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/sample-code\/layers-custom-elevation-exaggerated\/index.html\"> exaggerated elevation layer<\/a>.<\/li>\n<\/ul>\n<div>In this post, we will discuss about creating a custom tile layer in 4.x with TypeScript. Prior to creating custom layers with TypeScript, we need to make certain that we have the needed requirements.<\/div>\n<div><\/div>\n<ol>\n<li>TypeScript: You will need to <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/guide\/typescript-setup\/index.html\">set up your TypeScript development environment<\/a>. TypeScript is a strict syntactical superset of JavaScript. Once written, it can be compiled to plain JavaScript. There is a multitude of great <a href=\"https:\/\/www.sitepen.com\/blog\/2013\/12\/31\/definitive-guide-to-typescript\/\">online resources<\/a>\u00a0that go into detail on what TypeScript is, why it is used, and how you use it.<\/li>\n<li>Familiarity with <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-core-Accessor.html\">esri\/core\/Accessor<\/a>: Accessor\u00a0aims to make developing classes easy by providing a mechanism to\u00a0get,\u00a0set, and\u00a0watch\u00a0properties. Please refer to the <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/guide\/implementing-accessor\/index.html\">Implementing Accessor<\/a> topic for additional details on how this works and its usage patterns.<\/li>\n<li>Understanding the loadable pattern: If your custom layer requires loadable resources, then you must load all loadable dependencies on the layer. Please see the <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/guide\/loadable\/index.html\">Understanding the loadable pattern topic<\/a> for additional details on how this works.<\/li>\n<\/ol>\n<div>We will walk through how to create a BlendLayer, based on <a href=\"https:\/\/ubatsukh.github.io\/blendlayer\/\">this working sample<\/a>. This layer will apply\u00a0<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/CanvasRenderingContext2D\/globalCompositeOperation\">multiply blending operation<\/a> to the <a href=\"https:\/\/services.arcgisonline.com\/arcgis\/rest\/services\/Elevation\/World_Hillshade\/MapServer\">ArcGIS World Hillshade<\/a> and <a href=\"https:\/\/services.arcgisonline.com\/arcgis\/rest\/services\/NatGeo_World_Map\/MapServer\">National Geographic World Map services<\/a>. The multiply blend mode multiplies the values of each pixel of the top layer with the corresponding pixel value of the bottom layer. 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.<\/div>\n<p><\/p>\n<p><a href=\"https:\/\/ubatsukh.github.io\/blendlayer\/\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-3073\" src=\"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2017\/10\/blendlayer.png\" alt=\"\" width=\"778\" height=\"353\" \/><\/a> <\/p>\n<p><strong>Implement BlendLayer class<\/strong><br \/>\nWe will create the BlendLayer class (<a href=\"https:\/\/github.com\/ubatsukh\/arcgis-js-api-demos\/blob\/master\/blendlayer\/app\/BlendLayer.ts\">app\/BlendLayer.ts<\/a>) which will extend\u00a0<a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-BaseTileLayer.html\">BaseTileLayer<\/a>. You can view or download the source code for the entire application from <a href=\"https:\/\/github.com\/ubatsukh\/arcgis-js-api-demos\/tree\/master\/blendlayer\">here<\/a>. The application has the following folder structure.<\/p>\n<pre><code>root-folder\/\r\n  index.html\r\n  package.json\r\n  tsconfig.json\r\n  app\/\r\n    main.ts\r\n    BlendLayer.ts\r\n  node_modules\/\r\n<\/code><\/pre>\n<p><strong><em>Add dependency paths and import statements<\/em><\/strong><br \/>\nWhen creating custom classes for ArcGIS API for JavaScript with TypeScript, the following <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/triple-slash-directives.html\">triple-slash references<\/a> are always added at the top of the class. They instruct the compiler to import AMD modules: <em>__extends<\/em> and <em>__decorate<\/em>, which are helpers when extending a class or <a href=\"https:\/\/www.typescriptlang.org\/docs\/handbook\/decorators.html\">decorating<\/a> members of a class.<\/p>\n<pre><span style=\"color: #998;font-style: italic\">\/\/\/ &lt;amd-dependency path=\"esri\/core\/tsSupport\/declareExtendsHelper\" name=\"__extends\" \/&gt;<\/span>\r\n<span style=\"color: #998;font-style: italic\">\/\/\/ &lt;amd-dependency path=\"esri\/core\/tsSupport\/decorateHelper\" name=\"__decorate\" \/&gt;<\/span>\r\n<\/pre>\n<p>Next, we will import the modules that will be used in this class as shown below. In the first line, we are importing subclass, declared and property decorators from <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-core-accessorSupport-decorators.html\">esri\/core\/accessorSupport\/decorators<\/a> module. These decorators can be thought of as the underlying glue that is used to create 4.x classes.<\/p>\n<pre><span style=\"color: #333;font-weight: bold\">import<\/span> { subclass, property, declared } <span style=\"color: #333;font-weight: bold\">from<\/span> <span style=\"color: #d14\">\"esri\/core\/accessorSupport\/decorators\"<\/span>;\r\n\r\n<span style=\"color: #333;font-weight: bold\">import<\/span> TileLayer = require(<span style=\"color: #d14\">\"esri\/layers\/TileLayer\"<\/span>);\r\n<span style=\"color: #333;font-weight: bold\">import<\/span> BaseTileLayer = require(<span style=\"color: #d14\">\"esri\/layers\/BaseTileLayer\"<\/span>);\r\n<\/pre>\n<p><strong><em>Extend BaseTileLayer class<\/em><\/strong><br \/>\nHere, we are extending the BaseTileLayer\u00a0class. The <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-core-accessorSupport-decorators.html#subclass\">@subclass decorator<\/a> is used in conjunction with <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-core-accessorSupport-decorators.html#declared\">declared<\/a> and is necessary as they are both key components needed for instructing subclasses off of a given base class.<\/p>\n<pre>@subclass(\"esri.layers.BlendLayer\")\r\n<span style=\"color: #333;font-weight: bold\">class<\/span> <span style=\"color: #458;font-weight: bold\">BlendLayer<\/span> <span style=\"color: #333;font-weight: bold\">extends<\/span> <span style=\"color: #458;font-weight: bold\">declared<\/span>(<span style=\"color: #458;font-weight: bold\">BaseTileLayer<\/span>) {\r\n\r\n}\r\n<\/pre>\n<p><strong><em>Add properties to BlendLayer class<\/em><\/strong><br \/>\nWithin this class implementation, we can define properties of the class using <a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-core-accessorSupport-decorators.html#property\">@property decorator<\/a>. We define a property called\u00a0<em>multiplyLayers<\/em>, which is an array of tile layers that will be blended together as shown below:<\/p>\n<pre>@property()\r\nmultiplyLayers: TileLayer[] = [];\r\n<\/pre>\n<p><strong><em>Add methods to BlendLayer class<\/em><\/strong><br \/>\nWe can now add public and private methods to the class. The tile layers added to the\u00a0<em>multiplyLayers<\/em>\u00a0property are\u00a0<a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/guide\/loadable\/index.html\">loadable resources<\/a>. If a custom tile layer requires loadable resources, then you must load them in the layer using the\u00a0<a>load()<\/a>\u00a0method. This ensures that all loadable resources required for the layer to function are loaded prior to the custom layer resolving and becoming\u00a0loaded.<\/p>\n<pre>load(): any {\r\n  <span style=\"color: #998;font-style: italic\">\/\/ call load method on each tile layer stored in multiple property<\/span>\r\n  <span style=\"color: #333;font-weight: bold\">this<\/span>.multiplyLayers.forEach(<span style=\"color: #333;font-weight: bold\">function<\/span> (layer) {\r\n    <span style=\"color: #998;font-style: italic\">\/\/ The tile layers must load() prior to the BlendLayer<\/span>\r\n    <span style=\"color: #998;font-style: italic\">\/\/ resolving and moving to the \"loaded\" status.<\/span>\r\n    <span style=\"color: #333;font-weight: bold\">this<\/span>.addResolvingPromise(layer.load());\r\n  }, <span style=\"color: #333;font-weight: bold\">this<\/span>);\r\n}\r\n<\/pre>\n<p>Once the layer is loaded with its required resources, we must override the\u00a0<a href=\"https:\/\/developers.arcgis.com\/javascript\/latest\/api-reference\/esri-layers-BaseTileLayer.html#fetchTile\">fetchTile()<\/a>\u00a0method of the\u00a0<em>BlendLayer<\/em>. Within this method, call\u00a0<em>fetchTile<\/em>()\u00a0on each tile layer returned in the\u00a0<em>multiplyLayers<\/em>\u00a0property. Once each tile layer returns the tile(s) visible in the view, we apply\u00a0multiply\u00a0operation to the tiles so that the\u00a0BlendLayer\u00a0will show the blended image.<\/p>\n<pre><span style=\"color: #998;font-style: italic\">\/\/ Fetches the tile(s) visible in the view<\/span>\r\nfetchTile(level: number, row: number, col: number): IPromise&lt;HTMLCanvasElement&gt; {\r\n  \r\n      <span style=\"color: #333;font-weight: bold\">const<\/span> tilePromises = <span style=\"color: #333;font-weight: bold\">this<\/span>.multiplyLayers.map(layer =&gt; {\r\n        <span style=\"color: #998;font-style: italic\">\/\/ calls fetchTile() on the tile layers returned in multiplyLayers property<\/span>\r\n        <span style=\"color: #998;font-style: italic\">\/\/ for the tiles visible in the view<\/span>\r\n        <span style=\"color: #333;font-weight: bold\">return<\/span> layer.fetchTile(level, row, col, { allowImageDataAccess: <span style=\"color: #333;font-weight: 500\">true<\/span> });\r\n      });\r\n  \r\n      <span style=\"color: #333;font-weight: bold\">return<\/span> all(tilePromises)\r\n        .then(images =&gt; {\r\n          <span style=\"color: #998;font-style: italic\">\/\/ create a canvas<\/span>\r\n          <span style=\"color: #333;font-weight: bold\">let<\/span> width = <span style=\"color: #333;font-weight: bold\">this<\/span>.tileInfo.size[<span style=\"color: #008080\">0<\/span>];\r\n          <span style=\"color: #333;font-weight: bold\">let<\/span> height = <span style=\"color: #333;font-weight: bold\">this<\/span>.tileInfo.size[<span style=\"color: #008080\">0<\/span>];\r\n          <span style=\"color: #333;font-weight: bold\">let<\/span> canvas = <span style=\"color: #0086b3\">document<\/span>.createElement(<span style=\"color: #d14\">\"canvas\"<\/span>);\r\n          <span style=\"color: #333;font-weight: bold\">let<\/span> context = canvas.getContext(<span style=\"color: #d14\">\"2d\"<\/span>);\r\n  \r\n          canvas.width = width;\r\n          canvas.height = height;\r\n  \r\n          <span style=\"color: #998;font-style: italic\">\/\/ multiply - multiplies the numbers for each pixel of the top layer (nat geo)<\/span>\r\n          <span style=\"color: #998;font-style: italic\">\/\/ with the corresponding pixel for the bottom layer (hillshade).<\/span>\r\n          context.globalCompositeOperation = <span style=\"color: #d14\">\"multiply\"<\/span>;\r\n          images.forEach(<span style=\"color: #333;font-weight: bold\">function<\/span> (image) {\r\n            context.drawImage(image, <span style=\"color: #008080\">0<\/span>, <span style=\"color: #008080\">0<\/span>, width, height);\r\n          });\r\n  \r\n          <span style=\"color: #333;font-weight: bold\">return<\/span> canvas;\r\n        });\r\n    }\r\n<\/pre>\n<p>Finally, we export the BlendLayer class. The <em>export =<\/em> syntax specifies a single object that is exported from the class so that the class can imported using <em>import module = require(&#8220;Class&#8221;)<\/em> elsewhere.<\/p>\n<pre>export = BlendLayer;\r\n<\/pre>\n<p>We are done implementing the BlendLayer class. Now let&#8217;s use this custom layer in an application. We will import the class in in the <em>app\/main.ts<\/em> file as shown below:<\/p>\n<pre>import BlendLayer = require(\"app\/BlendLayer\")\r\n<\/pre>\n<p>Now the BlendLayer can be used in the <a href=\"https:\/\/ubatsukh.github.io\/blendlayer\/\">application<\/a>.<\/p>\n<pre><span style=\"color: #333;font-weight: bold\">const<\/span> natGeoLayer = <span style=\"color: #333;font-weight: bold\">new<\/span> TileLayer({\r\n  url: <span style=\"color: #d14\">\"https:\/\/services.arcgisonline.com\/arcgis\/rest\/services\/NatGeo_World_Map\/MapServer\"<\/span>\r\n});\r\n\r\n<span style=\"color: #333;font-weight: bold\">const<\/span> hillShadeLayer = <span style=\"color: #333;font-weight: bold\">new<\/span> TileLayer({\r\n  url: <span style=\"color: #d14\">\"https:\/\/services.arcgisonline.com\/arcgis\/rest\/services\/Elevation\/World_Hillshade\/MapServer\"<\/span>\r\n});\r\n\r\n<span style=\"color: #998;font-style: italic\">\/\/ Create a new instance of BlendLayer<\/span>\r\n<span style=\"color: #333;font-weight: bold\">const<\/span> blendLayer = <span style=\"color: #333;font-weight: bold\">new<\/span> BlendLayer({\r\n  multiplyLayers: [\r\n    hillShadeLayer,\r\n    natGeoLayer\r\n  ],\r\n  title: <span style=\"color: #d14\">\"Blended NatGeo World Map\"<\/span>,\r\n  copyright: <span style=\"color: #d14\">\"Blended National Geographic Layer\"<\/span>\r\n});\r\n<\/pre>\n"}],"authors":[{"ID":5981,"user_firstname":"Undral","user_lastname":"Batsukh","nickname":"Undral","user_nicename":"undr3986","display_name":"Undral Batsukh","user_email":"ubatsukh@esri.com","user_url":"","user_registered":"2018-03-02 00:17:50","user_description":"Undral is a Product Engineer at Esri, working on the ArcGIS Maps SDK for JavaScript.","user_avatar":"<img alt='' src='https:\/\/secure.gravatar.com\/avatar\/c1405160351c3e4722c0c72071122fe10e812710bb886abf9e09701c7c219563?s=96&#038;d=blank&#038;r=g' srcset='https:\/\/secure.gravatar.com\/avatar\/c1405160351c3e4722c0c72071122fe10e812710bb886abf9e09701c7c219563?s=192&#038;d=blank&#038;r=g 2x' class='avatar avatar-96 photo' height='96' width='96' loading='lazy' decoding='async'\/>"}],"related_articles":"","card_image":false,"wide_image":false},"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.9 (Yoast SEO v25.9) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Creating a custom tile layer with TypeScript<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Creating a custom tile layer with TypeScript\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript\" \/>\n<meta property=\"og:site_name\" content=\"ArcGIS Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/esrigis\/\" \/>\n<meta property=\"article:modified_time\" content=\"2018-04-17T16:42:15+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:site\" content=\"@ESRI\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript\"},\"author\":{\"name\":\"Undral Batsukh\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/e42c26b3a6a3ad517ec6148b1f8d4f6a\"},\"headline\":\"Creating a custom tile layer with TypeScript\",\"datePublished\":\"2017-10-27T19:00:59+00:00\",\"dateModified\":\"2018-04-17T16:42:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript\"},\"wordCount\":7,\"publisher\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#organization\"},\"keywords\":[\"JavaScript\",\"jsapi4\",\"TypeScript\"],\"articleSection\":[\"Mapping\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript\",\"name\":\"Creating a custom tile layer with TypeScript\",\"isPartOf\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#website\"},\"datePublished\":\"2017-10-27T19:00:59+00:00\",\"dateModified\":\"2018-04-17T16:42:15+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.esri.com\/arcgis-blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Creating a custom tile layer with TypeScript\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#website\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/\",\"name\":\"ArcGIS Blog\",\"description\":\"Get insider info from Esri product teams\",\"publisher\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.esri.com\/arcgis-blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#organization\",\"name\":\"Esri\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/04\/Esri.png\",\"contentUrl\":\"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/04\/Esri.png\",\"width\":400,\"height\":400,\"caption\":\"Esri\"},\"image\":{\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/esrigis\/\",\"https:\/\/x.com\/ESRI\",\"https:\/\/www.linkedin.com\/company\/5311\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/e42c26b3a6a3ad517ec6148b1f8d4f6a\",\"name\":\"Undral Batsukh\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/c1405160351c3e4722c0c72071122fe10e812710bb886abf9e09701c7c219563?s=96&d=blank&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/c1405160351c3e4722c0c72071122fe10e812710bb886abf9e09701c7c219563?s=96&d=blank&r=g\",\"caption\":\"Undral Batsukh\"},\"description\":\"Undral is a Product Engineer at Esri, working on the ArcGIS Maps SDK for JavaScript.\",\"url\":\"https:\/\/www.esri.com\/arcgis-blog\/author\/undr3986\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Creating a custom tile layer with TypeScript","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript","og_locale":"en_US","og_type":"article","og_title":"Creating a custom tile layer with TypeScript","og_url":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript","og_site_name":"ArcGIS Blog","article_publisher":"https:\/\/www.facebook.com\/esrigis\/","article_modified_time":"2018-04-17T16:42:15+00:00","twitter_card":"summary_large_image","twitter_site":"@ESRI","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript#article","isPartOf":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript"},"author":{"name":"Undral Batsukh","@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/e42c26b3a6a3ad517ec6148b1f8d4f6a"},"headline":"Creating a custom tile layer with TypeScript","datePublished":"2017-10-27T19:00:59+00:00","dateModified":"2018-04-17T16:42:15+00:00","mainEntityOfPage":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript"},"wordCount":7,"publisher":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/#organization"},"keywords":["JavaScript","jsapi4","TypeScript"],"articleSection":["Mapping"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript","url":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript","name":"Creating a custom tile layer with TypeScript","isPartOf":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/#website"},"datePublished":"2017-10-27T19:00:59+00:00","dateModified":"2018-04-17T16:42:15+00:00","breadcrumb":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.esri.com\/arcgis-blog\/products\/mapping\/mapping\/creating-a-custom-tile-layer-with-typescript#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.esri.com\/arcgis-blog\/"},{"@type":"ListItem","position":2,"name":"Creating a custom tile layer with TypeScript"}]},{"@type":"WebSite","@id":"https:\/\/www.esri.com\/arcgis-blog\/#website","url":"https:\/\/www.esri.com\/arcgis-blog\/","name":"ArcGIS Blog","description":"Get insider info from Esri product teams","publisher":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.esri.com\/arcgis-blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.esri.com\/arcgis-blog\/#organization","name":"Esri","url":"https:\/\/www.esri.com\/arcgis-blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/04\/Esri.png","contentUrl":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2018\/04\/Esri.png","width":400,"height":400,"caption":"Esri"},"image":{"@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/esrigis\/","https:\/\/x.com\/ESRI","https:\/\/www.linkedin.com\/company\/5311\/"]},{"@type":"Person","@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/e42c26b3a6a3ad517ec6148b1f8d4f6a","name":"Undral Batsukh","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.esri.com\/arcgis-blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/c1405160351c3e4722c0c72071122fe10e812710bb886abf9e09701c7c219563?s=96&d=blank&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/c1405160351c3e4722c0c72071122fe10e812710bb886abf9e09701c7c219563?s=96&d=blank&r=g","caption":"Undral Batsukh"},"description":"Undral is a Product Engineer at Esri, working on the ArcGIS Maps SDK for JavaScript.","url":"https:\/\/www.esri.com\/arcgis-blog\/author\/undr3986"}]}},"text_date":"October 27, 2017","author_name":"Undral Batsukh","author_page":"https:\/\/www.esri.com\/arcgis-blog\/author\/undr3986","custom_image":"https:\/\/www.esri.com\/arcgis-blog\/app\/uploads\/2025\/08\/Newsroom-Keyart-Wide-1920-x-1080.jpg","primary_product":"ArcGIS Maps SDK for JavaScript","tag_data":[{"term_id":24921,"name":"JavaScript","slug":"javascript","term_group":0,"term_taxonomy_id":24921,"taxonomy":"post_tag","description":"","parent":0,"count":151,"filter":"raw"},{"term_id":27491,"name":"jsapi4","slug":"jsapi4","term_group":0,"term_taxonomy_id":27491,"taxonomy":"post_tag","description":"","parent":0,"count":111,"filter":"raw"},{"term_id":34861,"name":"TypeScript","slug":"typescript","term_group":0,"term_taxonomy_id":34861,"taxonomy":"post_tag","description":"","parent":0,"count":6,"filter":"raw"}],"category_data":[{"term_id":22941,"name":"Mapping","slug":"mapping","term_group":0,"term_taxonomy_id":22941,"taxonomy":"category","description":"","parent":0,"count":2702,"filter":"raw"}],"product_data":[{"term_id":36831,"name":"ArcGIS Maps SDK for JavaScript","slug":"js-api-arcgis","term_group":0,"term_taxonomy_id":36831,"taxonomy":"product","description":"","parent":36601,"count":363,"filter":"raw"},{"term_id":36601,"name":"Developers","slug":"developers","term_group":0,"term_taxonomy_id":36601,"taxonomy":"product","description":"","parent":0,"count":765,"filter":"raw"}],"primary_product_link":"https:\/\/www.esri.com\/arcgis-blog\/?s=#&products=js-api-arcgis","_links":{"self":[{"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/blog\/80201","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/blog"}],"about":[{"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/types\/blog"}],"author":[{"embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/users\/5981"}],"replies":[{"embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/comments?post=80201"}],"version-history":[{"count":0,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/blog\/80201\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/media?parent=80201"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/categories?post=80201"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/tags?post=80201"},{"taxonomy":"industry","embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/industry?post=80201"},{"taxonomy":"product","embeddable":true,"href":"https:\/\/www.esri.com\/arcgis-blog\/wp-json\/wp\/v2\/product?post=80201"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}