@maptiler/sdk 3.10.0-rc.1 โ†’ 3.10.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,53 +1,78 @@
1
- <p align="center">
2
- <a href="https://docs.maptiler.com/sdk-js/">official page โ†’</a><br>
3
- <img src="images/maptiler-sdk-logo.svg" width="400px">
4
- </p>
1
+ <img src="images/maptiler-sdk-logo.svg" alt="Company Logo" height="32"/>
5
2
 
6
- <p align="center" style="color: #AAA">
7
- The Javascript & TypeScript map SDK tailored for <a href="https://www.maptiler.com/cloud/">MapTiler Cloud</a>
8
- </p>
3
+ # MapTiler SDK JS
9
4
 
10
- <p align="center">
11
- <img src="images/JS-logo.svg" width="20px">
12
- <img src="images/TS-logo.svg" width="20px">
13
- <img src="https://img.shields.io/npm/v/@maptiler/sdk"></img>
14
- <img src="https://img.shields.io/twitter/follow/maptiler?style=social"></img>
15
- </p>
5
+ The **MapTiler SDK JS** extends MapLibre GL JS, exposes all its features, and adds new ones on top. The SDK is designed to work with the well-established [MapTiler service](https://www.maptiler.com/cloud/), which provides all the data required to fuel a complete web mapping experience: vector tiles, satellite raster tiles, DEM with Terrain RGB, custom styles with an editor, etc.
6
+
7
+ **Why are we creating a new SDK?** To make things simpler for developers working in the MapTiler ecosystem! With **MapTiler SDK JS**, there is no need to load external plugins for the most basic things, copy-paste complex data source URLs, or look up the syntax to enable 3D terrain every time you start a project. All this is built-in, loaded when needed, or exposed with simple functions. Under the hood, this SDK is opinionated as it's being fed by [MapTiler service](https://www.maptiler.com/cloud/) data, but its MapLibre core makes it 100% compatible with other sources.
8
+
9
+ In addition, the MapTiler SDK JS provides well-documented and easy-to-use wrapper functions to the [MapTiler API services](https://docs.maptiler.com/cloud/api) such as: geocoding, static maps, geolocation, as well as a search engine for coordinate reference systems and transforming coordinates from one CRS to another.
10
+
11
+ > ๐Ÿ“ฃ _**Note:**_ If you need <ins>only the API Client library</ins> to use in a headless fashion and without any map display, check out [MapTiler Client JS](https://github.com/maptiler/maptiler-client-js) library for browser and NodeJS.
12
+
13
+ ![](https://img.shields.io/badge/npm-v3.8.0-f2f6ff?style=for-the-badge&labelColor=D3DBEC&logo=npm&logoColor=333359) ![](https://img.shields.io/badge/-white?style=for-the-badge&logo=javascript)![](https://img.shields.io/badge/-white?style=for-the-badge&logo=typescript)
16
14
 
17
- # What and why?
18
- The **MapTiler SDK JS** extends MapLibre GL JS, exposes all its features, and adds new ones on top. The SDK is designed to work with the well-established [MapTiler Cloud service](https://www.maptiler.com/cloud/), which provides all the data required to fuel a complete web mapping experience: vector tiles, satellite raster tiles, DEM with Terrain RGB, custom styles with an editor, etc.
15
+ ---
19
16
 
20
- **Why are we creating a new SDK?** To make things simpler for developers working in the MapTiler ecosystem! With **MapTiler SDK JS**, there is no need to load external plugins for the most basic things, copy-paste complex data source URLs, or look up the syntax to enable 3D terrain every time you start a project. All this is built-in, loaded when needed, or exposed with simple functions. Under the hood, this SDK is opinionated as it's being fed by [MapTiler Cloud](https://www.maptiler.com/cloud/) data, but its MapLibre core makes it 100% compatible with other sources.
17
+ ๐Ÿ“– [Documentation](https://docs.maptiler.com/sdk-js/) &nbsp; ๐Ÿ“ฆ [NPM Package](https://www.npmjs.com/package/@maptiler/sdk) &nbsp; ๐ŸŒ [Website](https://www.maptiler.com/interactive-maps/) &nbsp; ๐Ÿ”‘ [Get API Key](https://cloud.maptiler.com/account/keys/)
21
18
 
22
- In addition, the MapTiler SDK JS provides well-documented and easy-to-use wrapper functions to the [MapTiler Cloud API services](https://docs.maptiler.com/cloud/api) such as: geocoding, static maps, geolocation, as well as a search engine for coordinate reference systems and transforming coordinates from one CRS to another.
23
- > ๐Ÿ“ฃ *__Note:__* If you need <ins>only the API Client library</ins> to use in a headless fashion and without any map display, check out [MapTiler Client JS](https://github.com/maptiler/maptiler-client-js) library for browser and NodeJS.
19
+ ---
24
20
 
25
- ![Lake Louise, Canada, with MapTiler Outdoor style](images/screenshots/lake-louise.jpg)
21
+ <br>
22
+
23
+ <details> <summary><b>Table of Contents</b></summary>
24
+ <ul>
25
+ <li><a href="#-installation">Installation</a></li>
26
+ <li><a href="#-basic-usage">Basic Usage</a></li>
27
+ <li><a href="#-related-examples">Examples</a></li>
28
+ <li><a href="#-api-reference">API Reference</a></li>
29
+ <li><a href="#migration-guide">Migration Guide</a></li>
30
+ <li><a href="#-support">Support</a></li>
31
+ <li><a href="#-contributing">Contributing</a></li>
32
+ <li><a href="#-license">License</a></li>
33
+ <li><a href="#-acknowledgements">Acknowledgements</a></li>
34
+ </ul>
35
+ </details>
36
+
37
+ <p align="center">
38
+ <img src="images/screenshots/lake-louise.jpg" alt="Demo Screenshot" width="80%"/>
39
+ <br />
40
+ <a href="https://docs.maptiler.com/sdk-js/examples/ts-get-started/">See live interactive demo</a>
41
+ </p>
42
+ <br>
43
+
44
+ ## ๐Ÿ“ฆ Installation
26
45
 
27
- # Install
28
46
  ```shell
29
47
  npm install --save @maptiler/sdk
30
48
  ```
31
49
 
32
50
  โš ๏ธ Please keep in mind that if you use any additional [MapTiler modules](https://docs.maptiler.com/sdk-js/modules/), you must update them to a version that supports MapTiler SDK JS v3.
33
51
 
34
- # API documentation
35
- In addition to the details and examples provided in this readme, check out the [complete API documentation](https://docs.maptiler.com/sdk-js/api/)
52
+ From CDN and using the UMD bundle, in the `<head></head>` section of your HTML file:
53
+
54
+ ```html
55
+ <script src="https://cdn.maptiler.com/maptiler-sdk-js/<VERSION>/maptiler-sdk.umd.min.js"></script>
56
+ <link href="https://cdn.maptiler.com/maptiler-sdk-js/<VERSION>/maptiler-sdk.css" rel="stylesheet" />
57
+ ```
36
58
 
37
- # Quick start
59
+ <br>
60
+
61
+ ## ๐Ÿš€ Basic Usage
62
+
63
+ ### With ES modules
38
64
 
39
- ## With ES modules
40
65
  **Recommended for:** advanced applications
41
66
 
42
67
  ```ts
43
- import { config, Map } from '@maptiler/sdk';
68
+ import { config, Map } from "@maptiler/sdk";
44
69
 
45
70
  // Add your MapTiler Cloud API key to the config
46
71
  // (Go to https://cloud.maptiler.com/account/keys/ to get one for free!)
47
- config.apiKey = 'YOUR_API_KEY';
72
+ config.apiKey = "YOUR_API_KEY";
48
73
 
49
74
  // Let's say you have a DIV ready to receive a map
50
- const mapContainer = document.getElementById('my-container-div');
75
+ const mapContainer = document.getElementById("my-container-div");
51
76
 
52
77
  // Instantiate the map
53
78
  const map = new Map({
@@ -56,16 +81,17 @@ const map = new Map({
56
81
  ```
57
82
 
58
83
  Alternatively, the `apiKey` can be set as Map option instead of in the `config` object. Yet, this will still internally propagate to the `config` object:
84
+
59
85
  ```ts
60
- import { Map } from '@maptiler/sdk';
86
+ import { Map } from "@maptiler/sdk";
61
87
 
62
88
  // Let's say you have a DIV ready to receive a map
63
- const mapContainer = document.getElementById('my-container-div');
89
+ const mapContainer = document.getElementById("my-container-div");
64
90
 
65
91
  // Instantiate the map
66
92
  const map = new Map({
67
93
  container: mapContainer,
68
- apiKey: 'YOUR_API_KEY'
94
+ apiKey: "YOUR_API_KEY",
69
95
  });
70
96
  ```
71
97
 
@@ -74,18 +100,21 @@ By default, the map will be initialized with the style [streets-v2](https://www.
74
100
  Depending on the framework and environment you are using for your application, you will have to also include the CSS file.
75
101
 
76
102
  For example, with a [NextJS](https://nextjs.org/) app, this can take place at the top of the file `_app.ts/js`:
103
+
77
104
  ```ts
78
105
  import "@maptiler/sdk/dist/maptiler-sdk.css";
79
106
  ```
80
107
 
81
- ### TypeScript
108
+ #### TypeScript
109
+
82
110
  The SDK is fully typed, but it may happen that types defined in Maplibre GL JS are not visible in your project. This is a known issue that comes from Maplibre being a CommonJS bundle.
83
111
 
84
112
  There are mainly two ways to address this issue and access to the complete type definition.
85
113
 
86
- 1. **With `esModuleInterop`**
114
+ 1. **With `esModuleInterop`**
87
115
 
88
116
  Set the following in your `tsconfig.json`:
117
+
89
118
  ```js
90
119
  {
91
120
  "compilerOptions": {
@@ -93,11 +122,12 @@ Set the following in your `tsconfig.json`:
93
122
  "esModuleInterop": true,
94
123
  }
95
124
  }
96
- ```
125
+ ```
97
126
 
98
- 2. **With `moduleResolution`**
127
+ 2. **With `moduleResolution`**
99
128
 
100
129
  Set the following in your `tsconfig.json`:
130
+
101
131
  ```js
102
132
  {
103
133
  "compilerOptions": {
@@ -105,13 +135,13 @@ Set the following in your `tsconfig.json`:
105
135
  "moduleResolution": "Bundler",
106
136
  }
107
137
  }
108
- ```
109
- Note that this second option is not always possible as some frameworks and other dependencies won't let you use the "Bundler" mode.
138
+ ```
110
139
 
140
+ Note that this second option is not always possible as some frameworks and other dependencies won't let you use the "Bundler" mode.
111
141
 
142
+ ### With CDN
112
143
 
113
- ## With CDN
114
- The SDK hosted on our CDN is bundled as *[Universal Module Definition](https://github.com/umdjs/umd)* (UMD) to make it standalone and contain all its dependencies. The CDN also serves the style sheet (CSS).
144
+ The SDK hosted on our CDN is bundled as _[Universal Module Definition](https://github.com/umdjs/umd)_ (UMD) to make it standalone and contain all its dependencies. The CDN also serves the style sheet (CSS).
115
145
 
116
146
  **Recommended for:** simple map integration example and demos
117
147
 
@@ -120,7 +150,8 @@ The SDK hosted on our CDN is bundled as *[Universal Module Definition](https://g
120
150
  <head>
121
151
  <title>MapTiler JS SDK example</title>
122
152
  <style>
123
- html, body {
153
+ html,
154
+ body {
124
155
  margin: 0;
125
156
  }
126
157
 
@@ -132,43 +163,60 @@ The SDK hosted on our CDN is bundled as *[Universal Module Definition](https://g
132
163
  </style>
133
164
 
134
165
  <!-- Load the SDK CSS -->
135
- <link rel="stylesheet" href="dist/maptiler-sdk.css">
166
+ <link rel="stylesheet" href="dist/maptiler-sdk.css" />
136
167
  </head>
137
168
 
138
169
  <body>
139
170
  <div id="map-container"></div>
140
-
141
- <script src ="dist/maptiler-sdk.umd.min.js"></script>
142
-
171
+
172
+ <script src="dist/maptiler-sdk.umd.min.js"></script>
173
+
143
174
  <script>
144
- // Add your MapTiler Cloud API key to the config
175
+ // Add your MapTiler API key to the config
145
176
  // (Go to https://cloud.maptiler.com/account/keys/ to get one for free!)
146
- maptilersdk.config.apiKey = 'YOUR_API_KEY';
177
+ maptilersdk.config.apiKey = "YOUR_API_KEY";
147
178
 
148
- const mapContainer = document.getElementById('my-container-div');
179
+ const mapContainer = document.getElementById("my-container-div");
149
180
 
150
181
  const map = new maptilersdk.Map({
151
182
  container: mapContainer,
152
183
  style: maptilersdk.MapStyle.STREETS_DARK,
153
184
  hash: true,
154
- })
185
+ });
155
186
  </script>
156
187
  </body>
157
188
  </html>
158
-
159
189
  ```
160
190
 
161
191
  Check out the minimalist code samples in the [demos](demos) directory.
162
192
 
193
+ <br>
194
+
195
+ ## ๐Ÿ’ก Related Examples
196
+
197
+ - [How to use the MapTiler SDK JS](https://docs.maptiler.com/sdk-js/examples/how-to-use/)
198
+ - [Maps SDK with TypeScript](https://docs.maptiler.com/sdk-js/examples/ts-get-started/)
199
+ - [Built-in map styles](https://docs.maptiler.com/sdk-js/examples/built-in-styles/)
200
+
201
+ Check out more than 200 [examples and tutorials](https://docs.maptiler.com/sdk-js/examples/)
202
+
203
+ <br>
204
+
205
+ ## ๐Ÿ“˜ API Reference
206
+
207
+ In addition to the details and examples provided in this readme, check out the [complete API documentation](https://docs.maptiler.com/sdk-js/api/)
208
+
209
+ ### Many styles to choose from
163
210
 
164
- # Many styles to choose from
165
211
  MapTiler teams maintain a few styles that we have decided to expose from the SDK. This has two advantages:
212
+
166
213
  - they are easier to remember, no need to type along style URL
167
214
  - if we make an update to a style, you will benefit from it without modifying your codebase
168
215
 
169
216
  Here is how it works:
217
+
170
218
  ```ts
171
- import { Map, MapStyle } from '@maptiler/sdk'
219
+ import { Map, MapStyle } from "@maptiler/sdk";
172
220
 
173
221
  // When instanciating a map
174
222
  const map = new Map({
@@ -182,15 +230,14 @@ map.setStyle(MapStyle.STREETS.DARK);
182
230
 
183
231
  The styles with a shorthand provided by the SDK are the following:
184
232
 
185
- | ID | Screenshot | Comment |
186
- |:-:|:-:|:-:|
187
- |`MapStyle.STREETS`|[![](images/screenshots/style-streets-v2.jpeg)](https://www.maptiler.com/maps/#style=streets-v2&mode=2d&position=12.52/40.73676/-73.98418)|The classic default style, perfect for urban areas.<p>Also available in **dark** and **light** mode.</p>|
188
- |`MapStyle.DATAVIZ.DARK`| [![](images/screenshots/style-dataviz-dark.jpeg)](https://www.maptiler.com/maps/#style=dataviz-dark&mode=2d&position=2.01/38.7/-27.0)|A minimalist style for data visualization.<p>Also available in **color** and **light** mode</p> |
189
- |`MapStyle.SATELLITE`|[![](images/screenshots/style-satellite.jpeg)](https://www.maptiler.com/maps/#style=hybrid&mode=2d&position=7.87/24.518/-77.411)|Only high resolution satellite raster tiles without any labels|
190
- |`MapStyle.HYBRID`|[![](images/screenshots/style-hybrid.jpeg)](https://www.maptiler.com/maps/#style=hybrid&mode=2d&position=9.4/-26.175/122.6631)|Satellite tile with labels, landmarks, roads ways and political borders|
191
- |`MapStyle.OUTDOOR`|[![](images/screenshots/style-outdoor.jpeg)](https://www.maptiler.com/maps/#style=outdoor&mode=2d&position=11.96/46.02591/7.7273)|A solid hiking companion, with peaks, parks, isolines and more|
192
- |`MapStyle.BASIC`|[![](images/screenshots/style-basic-v2.jpeg)](https://www.maptiler.com/maps/#style=basic-v2&mode=2d&position=13.09/37.78734/-122.42025)|A minimalist alternative to `STREETS`, with a touch of flat design.<p>Also available in **dark** and **light** and **pastel** mode.</p>|
193
-
233
+ | ID | Screenshot | Comment |
234
+ | :---------------------: | :----------------------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: |
235
+ | `MapStyle.STREETS` | [![](images/screenshots/style-streets-v2.jpeg)](https://www.maptiler.com/maps/#style=streets-v2&mode=2d&position=12.52/40.73676/-73.98418) | The classic default style, perfect for urban areas.<p>Also available in **dark** and **light** mode.</p> |
236
+ | `MapStyle.DATAVIZ.DARK` | [![](images/screenshots/style-dataviz-dark.jpeg)](https://www.maptiler.com/maps/#style=dataviz-dark&mode=2d&position=2.01/38.7/-27.0) | A minimalist style for data visualization.<p>Also available in **color** and **light** mode</p> |
237
+ | `MapStyle.SATELLITE` | [![](images/screenshots/style-satellite.jpeg)](https://www.maptiler.com/maps/#style=hybrid&mode=2d&position=7.87/24.518/-77.411) | Only high resolution satellite raster tiles without any labels |
238
+ | `MapStyle.HYBRID` | [![](images/screenshots/style-hybrid.jpeg)](https://www.maptiler.com/maps/#style=hybrid&mode=2d&position=9.4/-26.175/122.6631) | Satellite tile with labels, landmarks, roads ways and political borders |
239
+ | `MapStyle.OUTDOOR` | [![](images/screenshots/style-outdoor.jpeg)](https://www.maptiler.com/maps/#style=outdoor&mode=2d&position=11.96/46.02591/7.7273) | A solid hiking companion, with peaks, parks, isolines and more |
240
+ | `MapStyle.BASIC` | [![](images/screenshots/style-basic-v2.jpeg)](https://www.maptiler.com/maps/#style=basic-v2&mode=2d&position=13.09/37.78734/-122.42025) | A minimalist alternative to `STREETS`, with a touch of flat design.<p>Also available in **dark** and **light** and **pastel** mode.</p> |
194
241
 
195
242
  <details>
196
243
  <summary>Know more about built-in map styles</summary>
@@ -198,6 +245,7 @@ The styles with a shorthand provided by the SDK are the following:
198
245
  MapTiler provides some **reference styles** as well as some **variants** for each. A **reference style** sets some guidelines about what kind of information is displayed, the granularity of the information, and more generally defines a purpose for which this style is the most relevant: street navigation, outdoor adventure, minimalist dashboard, etc. Then, each **reference style** offers a range of **variants** that contain the same level of information and have the same purpose but use different color schemes.
199
246
 
200
247
  Here is the full list:
248
+
201
249
  - `MapStyle.STREETS`, reference style for navigation and city exploration
202
250
  - `MapStyle.STREETS.DARK` (variant)
203
251
  - `MapStyle.STREETS.LIGHT` (variant)
@@ -227,7 +275,7 @@ Here is the full list:
227
275
  - `MapStyle.VOYAGER.DARK` (variant)
228
276
  - `MapStyle.VOYAGER.LIGHT` (variant)
229
277
  - `MapStyle.VOYAGER.VINTAGE` (variant)
230
- - `MapStyle.TONER` reference style for very high contrast stylish maps
278
+ - `MapStyle.TONER` reference style for very high contrast stylish maps
231
279
  - `MapStyle.TONER.BACKGROUND` (variant)
232
280
  - `MapStyle.TONER.LITE` (variant)
233
281
  - `MapStyle.TONER.LINES` (variant)
@@ -240,51 +288,54 @@ Here is the full list:
240
288
  - `MapStyle.AQUARELLE.VIVID` (variant)
241
289
  - `MapStyle.OPENSTREETMAP` (reference style, this one does not have any variants)
242
290
 
243
-
244
291
  All reference styles (instances of `ReferenceMapStyle`) and style variants (instances of `MapStyleVariant`) have methods to know the alternative styles and variants that belong to the same reference style (`.getVariants()`). This is handy to provide a default/dark/light alternative color scheme, yet preserving the same level of details as in the reference style. Read more about about [ReferenceMapStyle](https://docs.maptiler.com/sdk-js/api/map-styles/#referencemapstyle) and [MapStyleVariant](https://docs.maptiler.com/sdk-js/api/map-styles/#mapstylevariant).
245
- </details>
246
292
 
247
- ___
293
+ </details>
248
294
 
295
+ ---
249
296
 
250
- You can also use classic styles with just a *string* if you know their MapTiler Cloud ID:
297
+ You can also use classic styles with just a _string_ if you know their MapTiler ID:
251
298
 
252
299
  ```ts
253
- map.setStyle('outdoor-v2');
300
+ map.setStyle("outdoor-v2");
254
301
  ```
255
302
 
256
303
  And finally, you can use your own custom styles designed with [our style editor](https://cloud.maptiler.com/maps/). Every custom style is given a unique ID, for instance: `c912ffc8-2360-487a-973b-59d037fb15b8`.
257
304
 
258
305
  This ID can be provided as such:
306
+
259
307
  ```ts
260
308
  map.setStyle("c912ffc8-2360-487a-973b-59d037fb15b8");
261
309
  ```
262
310
 
263
311
  Or in its extended form:
312
+
264
313
  ```ts
265
314
  map.setStyle("https://api.maptiler.com/maps/c912ffc8-2360-487a-973b-59d037fb15b8/style.json");
266
315
  // this could be suffixed with the API token as well
267
316
  ```
268
317
 
269
318
  And can even be provided in the URI form:
319
+
270
320
  ```ts
271
321
  map.setStyle("maptiler://c912ffc8-2360-487a-973b-59d037fb15b8");
272
322
  ```
273
323
 
274
- # Globe or Mercator projection?
275
- The **Web Mercator projection** [*(Wikipedia)*](https://en.wikipedia.org/wiki/Web_Mercator_projection) has been the go-to standard in cartography since the early days or web mapping. Partly for technical reasons but also because it is great for navigation as well as for showing the entire world in one screen, with no hidden face. That being said, Mercator's heavy distorsion at high latitudes, as well a the discontinuity at the poles can be a limitation for data visualization and has been critisized for providing a biased view of the world.
324
+ ### Globe or Mercator projection?
276
325
 
277
- The **globe projection**, available starting from MapTiler SDK v3, does not suffer from these biases and can feel overall more playfull than Mercator. It can be a great choice for semi-global data visualization, especially for data close to the poles, thanks to its geographic continuity.
326
+ The **Web Mercator projection** [_(Wikipedia)_](https://en.wikipedia.org/wiki/Web_Mercator_projection) has been the go-to standard in cartography since the early days or web mapping. Partly for technical reasons but also because it is great for navigation as well as for showing the entire world in one screen, with no hidden face. That being said, Mercator's heavy distorsion at high latitudes, as well a the discontinuity at the poles can be a limitation for data visualization and has been critisized for providing a biased view of the world.
278
327
 
328
+ The **globe projection**, available starting from MapTiler SDK v3, does not suffer from these biases and can feel overall more playfull than Mercator. It can be a great choice for semi-global data visualization, especially for data close to the poles, thanks to its geographic continuity.
279
329
 
280
- | Mercator projection | Globe projection |
281
- | :--------: | :-------: |
330
+ | Mercator projection | Globe projection |
331
+ | :----------------------------------------------: | :-------------------------------------------: |
282
332
  | ![](images/screenshots/mercator_projection.jpeg) | ![](images/screenshots/globe_projection.jpeg) |
283
333
 
284
334
  The choice between Mercator and Globe can be done at different levels and moments in the lifecycle of the map, yet, unless stated otherwise, **Mercator remains the default**.
285
335
 
286
336
  - In the style, using the `projection` top-level property.
287
- For globe:
337
+ For globe:
338
+
288
339
  ```js
289
340
  {
290
341
  "version": ...,
@@ -298,10 +349,12 @@ For globe:
298
349
  "type": "globe"
299
350
  }
300
351
 
301
- // ...
352
+ // ...
302
353
  }
303
354
  ```
355
+
304
356
  or for Mercator:
357
+
305
358
  ```js
306
359
  {
307
360
  "version": ...,
@@ -315,27 +368,32 @@ or for Mercator:
315
368
  "type": "mercator"
316
369
  }
317
370
 
318
- // ...
371
+ // ...
319
372
  }
320
373
  ```
321
374
 
322
375
  - In the constructor of the `Map` class, using the `projection` option. For globe:
376
+
323
377
  ```ts
324
378
  const map = new maptilersdk.Map({
325
379
  container: "map",
326
380
  projection: "globe", // Force a globe projection
327
381
  });
328
382
  ```
383
+
329
384
  or for Mercator:
385
+
330
386
  ```ts
331
387
  const map = new maptilersdk.Map({
332
388
  container: "map",
333
389
  projection: "mercator", // Force a mercator projection
334
- })
390
+ });
335
391
  ```
392
+
336
393
  This will overwrite the `projection` property from the style (if any) and will persist it later if the map style was to change.
337
394
 
338
395
  - Use the built-in methods:
396
+
339
397
  ```ts
340
398
  map.enableGlobeProjection();
341
399
  // or
@@ -343,78 +401,88 @@ map.enableMercatorProjection();
343
401
  ```
344
402
 
345
403
  The projection setter built in Maplibre GL JS is also usable:
404
+
346
405
  ```ts
347
- map.setProjection({type: "mercator"});
406
+ map.setProjection({ type: "mercator" });
348
407
  // or
349
- map.setProjection({type: "globe"});
408
+ map.setProjection({ type: "globe" });
350
409
  ```
351
410
 
352
411
  - Using the `MaptilerProjectionControl`. Not mounted by default, it can easily be added with a single option in the `Map` constructor:
412
+
353
413
  ```ts
354
414
  const map = new maptilersdk.Map({
355
415
  container: "map",
356
- projectionControl: true, // or the position such as "top-left", "top-right",
357
- }); // "bottom-right" or "bottom-left"
416
+ projectionControl: true, // or the position such as "top-left", "top-right",
417
+ }); // "bottom-right" or "bottom-left"
358
418
  ```
419
+
359
420
  This dedicated control will show a globe icon <img src="images/screenshots/globe_icon.png" width="30px"/> to transition from Mercator to globe projection and will show a flat map icon <img src="images/screenshots/mercator_icon.png" width="30px"/> to transition from globe to Mercator projection. The chosen projection persist with future style changes.
360
421
 
361
- ## Field of view (FOV)
362
- The internal camera has a default vertical field of view [*(wikipedia)*](https://en.wikipedia.org/wiki/Field_of_view) of a wide ~36.86 degrees. In globe mode, such a large *FOV* reduces the amount of the Earth that can be seen at once and exaggerates the central part, comparably to a fisheye lens. In many cases, a narrower *FOV* is preferable. Here is how to update if:
422
+ #### Field of view (FOV)
423
+
424
+ The internal camera has a default vertical field of view [_(wikipedia)_](https://en.wikipedia.org/wiki/Field_of_view) of a wide ~36.86 degrees. In globe mode, such a large _FOV_ reduces the amount of the Earth that can be seen at once and exaggerates the central part, comparably to a fisheye lens. In many cases, a narrower _FOV_ is preferable. Here is how to update if:
363
425
 
364
426
  ```ts
365
427
  // Ajust de FOV, with values from 1 to 50
366
428
  map.setVerticalFieldOfView(10);
367
429
  ```
368
- > ๐Ÿ“ฃ *__Note:__* with the Mercator projection, it is possible to set a FOV of `0`, which yields a true orthographic projection [*(wikipedia)*](https://en.wikipedia.org/wiki/Orthographic_projection), but the globe projection does not allow this.
430
+
431
+ > ๐Ÿ“ฃ _**Note:**_ with the Mercator projection, it is possible to set a FOV of `0`, which yields a true orthographic projection [_(wikipedia)_](https://en.wikipedia.org/wiki/Orthographic_projection), but the globe projection does not allow this.
369
432
 
370
433
  Here is a table of FOV comparison:
371
- | 01ยฐ | 10ยฐ | 20ยฐ | 30ยฐ | 40ยฐ | 50ยฐ |
434
+ | 01ยฐ | 10ยฐ | 20ยฐ | 30ยฐ | 40ยฐ | 50ยฐ |
372
435
  | :--------: | :-------: |:-------: |:-------: |:-------: |:-------: |
373
- | ![](images/screenshots/fov_1.jpeg) | ![](images/screenshots/fov_10.jpeg) | ![](images/screenshots/fov_20.jpeg) | ![](images/screenshots/fov_30.jpeg) | ![](images/screenshots/fov_40.jpeg) | ![](images/screenshots/fov_50.jpeg) |
436
+ | ![](images/screenshots/fov_1.jpeg) | ![](images/screenshots/fov_10.jpeg) | ![](images/screenshots/fov_20.jpeg) | ![](images/screenshots/fov_30.jpeg) | ![](images/screenshots/fov_40.jpeg) | ![](images/screenshots/fov_50.jpeg) |
374
437
 
438
+ ### Globe screenshots
375
439
 
376
- ## Globe screenshots
377
440
  ![](images/screenshots/globe_topo_arctica.jpeg)
378
441
  ![](images/screenshots/globe_hybrid.jpeg)
379
442
  ![](images/screenshots/globe_outdoor_alaska.jpeg)
380
443
  ![](images/screenshots/globe_outdoor_emea.jpeg)
381
444
  ![](images/screenshots/globe_outdoor_panamerica.jpeg)
382
445
 
446
+ > ๐Ÿ“ฃ _**Note:**_ Terrain is not fully compatible with the globe projection yet so it's better to disable it at low zoom level (from afar) and to choose the Mercator projection at higher zoom level (from up close).
383
447
 
384
- > ๐Ÿ“ฃ *__Note:__* Terrain is not fully compatible with the globe projection yet so it's better to disable it at low zoom level (from afar) and to choose the Mercator projection at higher zoom level (from up close).
448
+ ### Centering the map on visitors
449
+
450
+ It is sometimes handy to center the map on the visitor's location, and there are multiple ways of doing it but for the SDK, we have decided to make this extra simple by using the [IP geolocation](#%EF%B8%8F%EF%B8%8F-geolocation) API provided by [MapTiler Geolocation API](https://docs.maptiler.com/cloud/api/geolocation/), directly exposed as a single option of the `Map` constructor. There are two strategies:
385
451
 
386
- # Centering the map on visitors
387
- It is sometimes handy to center the map on the visitor's location, and there are multiple ways of doing it but for the SDK, we have decided to make this extra simple by using the [IP geolocation](#%EF%B8%8F%EF%B8%8F-geolocation) API provided by [MapTiler Cloud](https://docs.maptiler.com/cloud/api/geolocation/), directly exposed as a single option of the `Map` constructor. There are two strategies:
388
452
  1. `POINT`: centering the map on the actual visitor location, optionally using the `zoom` option (zoom level `13` if none is provided). As a more precise option, if the user has previously granted access to the browser location (more precise) then this is going to be used.
389
453
  2. `COUNTRY`: fitting the map view on the bounding box of the visitor's country. In this case, the `zoom` option, if provided, will be ignored
390
454
 
391
455
  Here is how the map gets centered on the visitor's location:
456
+
392
457
  ```js
393
458
  new maptilersdk.Map({
394
459
  // ... other options
395
460
 
396
- geolocate: maptilersdk.GeolocationType.POINT
397
- })
461
+ geolocate: maptilersdk.GeolocationType.POINT,
462
+ });
398
463
  ```
399
464
 
400
465
  Here is how the map fits the visitor's country bounds:
466
+
401
467
  ```js
402
468
  new maptilersdk.Map({
403
469
  // ... other options
404
470
 
405
- geolocate: maptilersdk.GeolocationType.COUNTRY
406
- })
471
+ geolocate: maptilersdk.GeolocationType.COUNTRY,
472
+ });
407
473
  ```
408
474
 
409
475
  The `geolocation` options will not be taken into consideration in the following cases:
476
+
410
477
  - if the `center` option is provided, then it prevails
411
478
  - if the `hash` option is provided with the value `true` **AND** a location hash is already part of the URL. If `hash` is `true` but there is not yet a location hash in the URL, then the geolocation will work.
412
479
 
413
- > ๐Ÿ“ฃ *__Note:__* if none of the options `center` or `hash` is provided to the `Map` constructor, then the map will be centered using the `POINT` strategy, unless the `geolocate` has the value `false`.
480
+ > ๐Ÿ“ฃ _**Note:**_ if none of the options `center` or `hash` is provided to the `Map` constructor, then the map will be centered using the `POINT` strategy, unless the `geolocate` has the value `false`.
414
481
 
415
- > ๐Ÿ“ฃ *__Note 2:__* the term *IP geolocation* refers to finding the physical location of a computer using its *IP address*. The *IP address* is a numerical identifier of a computer within a network, just like the phone number for a telephone. The *IP geolocation* is **not** using the GPS of a device and usually provides a precision in the order of a few hundred meters. This precision may vary based on many local parameters such as the density of the network grid or the terrain, this is why it is generally better not to use a zoom level higher than `14`.
482
+ > ๐Ÿ“ฃ _**Note 2:**_ the term _IP geolocation_ refers to finding the physical location of a computer using its _IP address_. The _IP address_ is a numerical identifier of a computer within a network, just like the phone number for a telephone. The _IP geolocation_ is **not** using the GPS of a device and usually provides a precision in the order of a few hundred meters. This precision may vary based on many local parameters such as the density of the network grid or the terrain, this is why it is generally better not to use a zoom level higher than `14`.
483
+
484
+ ### Easy to add controls
416
485
 
417
- # Easy to add controls
418
486
  The term "control" is commonly used for all sorts of buttons and information displays that take place in one of the corners of the map area. The most well-known are probably the `[+]` and `[-]` zoom buttons as well as the attribution information. Plenty of others are possible and we have made a few easy to add and directly accessible from the `Map` constructor options:
419
487
 
420
488
  - `navigationControl`
@@ -434,12 +502,14 @@ The term "control" is commonly used for all sorts of buttons and information dis
434
502
  - a boolean or a corner position. Hidden by default, showing on top-right if `true`.
435
503
 
436
504
  The corner positions possible are:
505
+
437
506
  - `"top-left"`
438
507
  - `"top-right"`
439
508
  - `"bottom-left"`
440
509
  - `"bottom-right"`
441
510
 
442
- **Example:**
511
+ **Example:**
512
+
443
513
  ```ts
444
514
  import { Map } from "@maptiler/sdk";
445
515
 
@@ -448,31 +518,34 @@ const map = new Map({
448
518
  terrainControl: false,
449
519
  scaleControl: true,
450
520
  fullscreenControl: "top-left",
451
- })
521
+ });
452
522
  ```
453
523
 
454
- # ๐Ÿงฉ Custom Controls
524
+ ### ๐Ÿงฉ Custom Controls
455
525
 
456
526
  MapTiler SDK JS supports two flexible ways to add custom controls to your map interface. Whether you're building a dynamic application or integrating with static HTML, there's a matching approach for both.
457
527
 
458
- ## Programmatic Controls
528
+ #### Programmatic Controls
459
529
 
460
530
  Use `map.addControl()` with `MaptilerExternalControl` to register custom UI elements manually. This approach is ideal for dynamic logic, event-driven behavior, or integration with frameworks like React. The control element can be provided either as a reference to the **element itself**, or as its **CSS selector**. Optionally, two callback functions can be provided:
461
531
 
462
- * `onClick` function that is called when the element is clicked, and
463
- * `onRender` function that is called every time the map renders a new state.
532
+ - `onClick` function that is called when the element is clicked, and
533
+ - `onRender` function that is called every time the map renders a new state.
464
534
 
465
535
  Both callbacks receive the active `Map` instance, the associated control element itself, and an event object associated with the original event (`PointerEvent` and `MapLibreEvent` respectively).
466
536
 
467
- ### Example
537
+ ##### Example
468
538
 
469
539
  ```ts
470
540
  const panControl = new maptilersdk.MaptilerExternalControl(
471
541
  ".pan-control",
472
542
  (map) => map.panBy([10, 10]), // Move southeast on click
473
- (map, el) => el.classList.toggle( // Style based on hemisphere
474
- "northern-hemisphere", map.getCenter().lat > 0
475
- )
543
+ (map, el) =>
544
+ el.classList.toggle(
545
+ // Style based on hemisphere
546
+ "northern-hemisphere",
547
+ map.getCenter().lat > 0,
548
+ ),
476
549
  );
477
550
  map.addControl(panControl);
478
551
 
@@ -481,13 +554,13 @@ element.textContent = "Pan NW";
481
554
  map.addControl(
482
555
  new maptilersdk.MaptilerExternalControl(
483
556
  element,
484
- (map) => map.panBy([-10, -10]) // Move northwest
557
+ (map) => map.panBy([-10, -10]), // Move northwest
485
558
  ),
486
- "top-left"
559
+ "top-left",
487
560
  );
488
561
  ```
489
562
 
490
- ### Behavior Overview
563
+ ##### Behavior Overview
491
564
 
492
565
  - On add, control element is moved into the map UI
493
566
  - `onClick` binds user interaction
@@ -495,11 +568,11 @@ map.addControl(
495
568
  - Control maintains its own DOM context
496
569
  - On removal, element is returned to its original DOM position (if any) to not interfere with DOM handling of frameworks like React
497
570
 
498
- ## Declarative Controls
571
+ #### Declarative Controls
499
572
 
500
573
  Add controls using HTML attributes โ€“ no JavaScript required. This is perfect for simple UI setups.
501
574
 
502
- ### Enabling Detection
575
+ ##### Enabling Detection
503
576
 
504
577
  ```ts
505
578
  const map = new maptilersdk.Map({
@@ -510,7 +583,7 @@ const map = new maptilersdk.Map({
510
583
 
511
584
  You can pass `true` to enable detection globally, or a CSS selector to scope it.
512
585
 
513
- ### Declaring Controls
586
+ ##### Declaring Controls
514
587
 
515
588
  Use `data-maptiler-control` attribute:
516
589
 
@@ -521,20 +594,20 @@ Use `data-maptiler-control` attribute:
521
594
  Supported values:
522
595
 
523
596
  | Value | Description |
524
- |---------------------|--------------------------------------------------|
597
+ | ------------------- | ------------------------------------------------ |
525
598
  | `zoom-in` | Zooms in |
526
599
  | `zoom-out` | Zooms out |
527
- | `toggle-projection` | Switches Mercator โ†” Globe |
600
+ | `toggle-projection` | Switches Mercator โ†” Globe |
528
601
  | `toggle-terrain` | Toggles terrain layer |
529
602
  | `reset-view` | Resets bearing, pitch, and roll |
530
603
  | `reset-bearing` | Resets bearing only |
531
604
  | `reset-pitch` | Resets pitch only |
532
605
  | `reset-roll` | Resets roll only |
533
- | *(empty)* | Registers control without built-in functionality |
606
+ | _(empty)_ | Registers control without built-in functionality |
534
607
 
535
608
  > โš ๏ธ An error is thrown if an unrecognized value is used.
536
609
 
537
- ### Grouping Controls
610
+ ##### Grouping Controls
538
611
 
539
612
  Use `data-maptiler-control-group` to group buttons:
540
613
 
@@ -547,7 +620,7 @@ Use `data-maptiler-control-group` to group buttons:
547
620
 
548
621
  Groups are styled and positioned together but don't add functionality themselves. Functional behavior is attached to valid descendant elements.
549
622
 
550
- ### Positioning Controls
623
+ ##### Positioning Controls
551
624
 
552
625
  Use `data-maptiler-position` to set placement:
553
626
 
@@ -561,12 +634,12 @@ Use `data-maptiler-position` to set placement:
561
634
 
562
635
  Valid positions: `'top-left'`, `'top-right'`, `'bottom-left'`, `'bottom-right'`
563
636
 
564
- ## Styling with CSS Variables
637
+ ##### Styling with CSS Variables
565
638
 
566
639
  When declarative controls are enabled, the map container exposes dynamic CSS variables:
567
640
 
568
641
  | Variable | Description | Type |
569
- |----------------------------------|--------------------------------------------------|-----------------|
642
+ | -------------------------------- | ------------------------------------------------ | --------------- |
570
643
  | `--maptiler-center-lng` | Longitude of center | unitless number |
571
644
  | `--maptiler-center-lat` | Latitude of center | unitless number |
572
645
  | `--maptiler-zoom` | Zoom level | unitless number |
@@ -576,12 +649,11 @@ When declarative controls are enabled, the map container exposes dynamic CSS var
576
649
  | `--maptiler-is-globe-projection` | `true` if globe is active<br>`false` otherwise | string |
577
650
  | `--maptiler-has-terrain` | `true` if terrain is active<br>`false` otherwise | string |
578
651
 
579
- ### Example
652
+ ##### Example
580
653
 
581
654
  ```css
582
655
  .compass-icon {
583
- transform: rotateX(calc(var(--maptiler-pitch) * 1deg))
584
- rotateZ(calc(var(--maptiler-bearing) * -1deg));
656
+ transform: rotateX(calc(var(--maptiler-pitch) * 1deg)) rotateZ(calc(var(--maptiler-bearing) * -1deg));
585
657
  }
586
658
 
587
659
  @container style(--maptiler-is-globe-projection: true) {
@@ -591,14 +663,15 @@ When declarative controls are enabled, the map container exposes dynamic CSS var
591
663
  }
592
664
  ```
593
665
 
594
- # 3D terrain in one call
666
+ ### 3D terrain in one call
667
+
595
668
  <p align="center">
596
669
  <img src="images/screenshots/grandcanyon.gif" width="48%"></img>
597
670
  <img src="images/screenshots/alps.gif" width="48%"></img>
598
671
  </p>
599
672
 
600
-
601
673
  Do you want to enable 3D terrain? That's easy now with a single function call:
674
+
602
675
  ```ts
603
676
  // With the default exaggeration factor of 1
604
677
  map.enableTerrain();
@@ -614,22 +687,24 @@ const map = new Map({
614
687
  // some options...
615
688
  terrain: true,
616
689
  terrainExaggeration: 1.5,
617
- })
690
+ });
618
691
  ```
619
692
 
620
693
  At any point, you can modify the exaggeration factor:
694
+
621
695
  ```ts
622
696
  map.setTerrainExaggeration(2);
623
697
  ```
624
698
 
625
699
  Or simply disable it:
700
+
626
701
  ```ts
627
- map.disableTerrain()
702
+ map.disableTerrain();
628
703
  ```
629
704
 
630
- > ๐Ÿ“ฃ *__Note:__* Keep in mind that setting an exaggeration factor at `0` will result in the same result as disabling the elevation but that terrain RGB tiles will still be fetched in the background.
705
+ > ๐Ÿ“ฃ _**Note:**_ Keep in mind that setting an exaggeration factor at `0` will result in the same result as disabling the elevation but that terrain RGB tiles will still be fetched in the background.
631
706
 
632
- > ๐Ÿ“ฃ *__Note 2:__* please be aware that due to the volume and elevation of the map floor in 3D space, the navigation with the terrain enabled is slightly different than without.
707
+ > ๐Ÿ“ฃ _**Note 2:**_ please be aware that due to the volume and elevation of the map floor in 3D space, the navigation with the terrain enabled is slightly different than without.
633
708
 
634
709
  By default, enabling, disabling or even just updating the terrain exaggeration will result in a 1-second animation. This is possible to modify with the following `Map` method:
635
710
 
@@ -638,20 +713,21 @@ By default, enabling, disabling or even just updating the terrain exaggeration w
638
713
  map.setTerrainAnimationDuration(500);
639
714
  ```
640
715
 
641
- ## Terrain events
642
- - `"terrain"` event
716
+ #### Terrain events
717
+
718
+ - `"terrain"` event
643
719
 
644
720
  As an extension of Maplibre GL JS, MapTiler SDK is also exposing the terrain event `"terrain"`. This event is triggered when a terrain source is added or removed:
645
721
 
646
722
  ```ts
647
723
  map.on("terrain", (e) => {
648
724
  // your logic here
649
- })
725
+ });
650
726
  ```
651
727
 
652
728
  Since MapTiler SDK adds animation and the terrain data is necessary all along, the `"terrain"` event will be called at the very beginning of the terrain animation when enabling and at the very end when disabling.
653
729
 
654
- - `"terrainAnimationStart"` and `"terrainAnimationStop"` events
730
+ - `"terrainAnimationStart"` and `"terrainAnimationStop"` events
655
731
 
656
732
  With the animation of the terrain, it can sometimes be convenient to know when the animation starts and ends. These two events are made just for that, here are how they work:
657
733
 
@@ -668,6 +744,7 @@ map.on("terrainAnimationStop", (event) => {
668
744
  The `event` argument is an object that contains (among other things) a `terrain` attribute. In the case of `"terrainAnimationStop"`, this terrain attribute is `null` if the animation was about disabling the terrain, otherwise, this is just a propagation of `map.terrain`.
669
745
 
670
746
  In the following example, we decide to associate the terrain animation with a change of camera, e.g. from clicking on the terrain control:
747
+
671
748
  - when the terrain is enabled, it pops up with an animation and only **then** the camera is animated to take a lower point of view
672
749
  - when the terrain is disabled, it is flattened with an animation and only **then** the camera is animated to a top view
673
750
 
@@ -679,15 +756,19 @@ map.on("terrainAnimationStop", (e) => {
679
756
  });
680
757
  });
681
758
  ```
682
- # Halo and Space Options
683
759
 
684
- The `halo` and `space` options allow for enhanced visual customization of the map, especially for globe projections.
760
+ ### Halo and Space Options
761
+
762
+ The `halo` and `space` options allow for enhanced visual customization of the map, especially for globe projections.
685
763
 
686
- ## `halo` (Atmospheric Glow)
687
- The `halo` option adds a gradient-based atmospheric glow around the globe, simulating the visual effect of Earth's atmosphere when viewed from space.
764
+ #### `halo` (Atmospheric Glow)
765
+
766
+ The `halo` option adds a gradient-based atmospheric glow around the globe, simulating the visual effect of Earth's atmosphere when viewed from space.
767
+
768
+ ##### Usage:
769
+
770
+ You can enable a simple halo by setting it to `true`:
688
771
 
689
- ### Usage:
690
- You can enable a simple halo by setting it to `true`:
691
772
  ```ts
692
773
  const map = new maptilersdk.Map({
693
774
  container: document.getElementById("map"),
@@ -695,9 +776,10 @@ const map = new maptilersdk.Map({
695
776
  halo: true,
696
777
  });
697
778
  ```
779
+
698
780
  For more customization, you can define a radial gradient with scale and stops:
699
- ```ts
700
781
 
782
+ ```ts
701
783
  const map = new maptilersdk.Map({
702
784
  container: document.getElementById("map"),
703
785
  style: maptilersdk.MapStyle.OUTDOOR,
@@ -717,7 +799,9 @@ const map = new maptilersdk.Map({
717
799
  },
718
800
  });
719
801
  ```
802
+
720
803
  You can also set the halo dynamically after the map loads:
804
+
721
805
  ```ts
722
806
  map.on("load", () => {
723
807
  map.setHalo({
@@ -732,17 +816,20 @@ map.on("load", () => {
732
816
  ```
733
817
 
734
818
  To disable state transitions for halo or space:
819
+
735
820
  ```ts
736
821
  map.disableHaloAnimations();
737
822
  map.disableSpaceAnimations();
738
823
  ```
739
824
 
740
- ## `space` (Background Environment)
825
+ #### `space` (Background Environment)
741
826
 
742
827
  The space option allows customizing the background environment of the globe, simulating deep space or skybox effects.
743
- ### Usage
828
+
829
+ ##### Usage
744
830
 
745
831
  You can enable a simple space background with a solid color:
832
+
746
833
  ```ts
747
834
  const map = new maptilersdk.Map({
748
835
  container: document.getElementById("map"),
@@ -752,16 +839,17 @@ const map = new maptilersdk.Map({
752
839
  },
753
840
  });
754
841
  ```
842
+
755
843
  Alternatively, you can provide a cubemap for a space backround using one of the following methods:
756
844
 
757
- #### Predefined Presets:
845
+ ###### Predefined Presets:
758
846
 
759
847
  - `space`: Dark blue hsl(210, 100%, 4%) background and white stars (transparent background image). Space color changes the background color, stars always stay white.
760
- - `stars` (default): Black background (image mask), space color changes the stars color, background always stays black.
761
- - `milkyway`: Black half-transparent background with standard milkyway and stars. Space color changes the stars and milkyway color, background always stays black.
762
- - `milkyway-subtle`: Black half-transparent background with subtle milkyway and less stars. Space color changes the stars and milkyway color, background always stays black.Black half-transparent background with standard milkyway and stars. Space color changes the stars and milkyway color, background always stays black.
763
- - `milkyway-bright`: Black half-transparent background with bright milkyway and more stars. Space color changes the stars and milkyway color, background always stays black.
764
- - `milkyway-colored`: Full background image with natural space colors. Space color doesnโ€™t change anything (non transparent image).
848
+ - `stars` (default): Black background (image mask), space color changes the stars color, background always stays black.
849
+ - `milkyway`: Black half-transparent background with standard milkyway and stars. Space color changes the stars and milkyway color, background always stays black.
850
+ - `milkyway-subtle`: Black half-transparent background with subtle milkyway and less stars. Space color changes the stars and milkyway color, background always stays black.Black half-transparent background with standard milkyway and stars. Space color changes the stars and milkyway color, background always stays black.
851
+ - `milkyway-bright`: Black half-transparent background with bright milkyway and more stars. Space color changes the stars and milkyway color, background always stays black.
852
+ - `milkyway-colored`: Full background image with natural space colors. Space color doesnโ€™t change anything (non transparent image).
765
853
 
766
854
  ```ts
767
855
  const map = new maptilersdk.Map({
@@ -772,39 +860,45 @@ const map = new maptilersdk.Map({
772
860
  },
773
861
  });
774
862
  ```
775
- #### Cubemap Images (Custom Skybox):
863
+
864
+ ###### Cubemap Images (Custom Skybox):
865
+
776
866
  ```ts
777
867
  const map = new maptilersdk.Map({
778
868
  container: document.getElementById("map"),
779
869
  style: maptilersdk.MapStyle.OUTDOOR,
780
870
  space: {
781
871
  faces: {
782
- nX: '/path-to-image/nX.png',
783
- nY: '/path-to-image/nY.png',
784
- nZ: '/path-to-image/nZ.png',
785
- pX: '/path-to-image/pX.png',
786
- pY: '/path-to-image/pY.png',
787
- pZ: '/path-to-image/pZ.png',
872
+ nX: "/path-to-image/nX.png",
873
+ nY: "/path-to-image/nY.png",
874
+ nZ: "/path-to-image/nZ.png",
875
+ pX: "/path-to-image/pX.png",
876
+ pY: "/path-to-image/pY.png",
877
+ pZ: "/path-to-image/pZ.png",
788
878
  },
789
879
  },
790
880
  });
791
881
  ```
792
- #### Cubemap Path with image format
882
+
883
+ ###### Cubemap Path with image format
793
884
 
794
885
  This fetches all images from a path, this assumes all files are named px, nx, py, ny, pz, nz and suffixed with the appropriate extension specified in `format`.
886
+
795
887
  ```ts
796
- const map = new maptilersdk.Map({
797
- container: document.getElementById("map"),
798
- style: maptilersdk.MapStyle.OUTDOOR,
799
- space: {
800
- path: {
801
- baseUrl: "spacebox/transparent",
802
- format: "png", // Defaults to PNG
803
- },
804
- },
805
- });
888
+ const map = new maptilersdk.Map({
889
+ container: document.getElementById("map"),
890
+ style: maptilersdk.MapStyle.OUTDOOR,
891
+ space: {
892
+ path: {
893
+ baseUrl: "spacebox/transparent",
894
+ format: "png", // Defaults to PNG
895
+ },
896
+ },
897
+ });
806
898
  ```
807
- #### Set the space background dynamically:
899
+
900
+ ###### Set the space background dynamically:
901
+
808
902
  ```ts
809
903
  map.on("load", () => {
810
904
  map.setSpace({
@@ -820,7 +914,7 @@ Note: if `space.color` or `space.<faces | path | preset>` are not explicitly set
820
914
 
821
915
  Further code examples can be found in `~/demos/`
822
916
 
823
- # `ImageViewer`
917
+ ### `ImageViewer`
824
918
 
825
919
  MapTiler's `ImageViewer` component allows you to display tiled, non-georeferenced images but interact with them in almost the same way you would if you were displaying map. These can be handy for zoomable non-georeferenced, geographically "inaccurate" maps such as hotel maps, golf courses, theme parks etc. Think pixels instead of lattitudes and longtidues.
826
920
 
@@ -831,7 +925,7 @@ MapTiler's `ImageViewer` component allows you to display tiled, non-georeference
831
925
  container: string | HTMLElement // the container element you want to mount the viewer on
832
926
  apiKey: string; // your MapTiler API Key
833
927
  zoom?: number;
834
- maxZoom?: number;
928
+ maxZoom?: number;
835
929
  minZoom?: number;
836
930
  bearing?: number;
837
931
  debug?: boolean; // whether you want to debug the tiles
@@ -851,71 +945,82 @@ MapTiler's `ImageViewer` component allows you to display tiled, non-georeference
851
945
  imageViewer.on("imageviewerready", () => { console.log('Ready!') })
852
946
  ```
853
947
 
854
- ## Methods
948
+ #### Methods
949
+
855
950
  `ImageViewer` provides a subset of methods for interaction with the map. A major caveat is that the `ImageViewer` component works in pixels and not in LngLat. Thus, when using methods such as `setCenter` or `flyTo` the pixel values provided refer to the _absolute pixel position_ on the image, not screen pixel position.
856
951
 
857
952
  Imagine your image is 10,000px x 10,000px, if regardless if your zoom is 2 or 4, calling `.setCenter(500,500)` will always position the viewer over the same part of the image.
858
953
 
859
954
  For full details on supported methods see the type declaration for `ImageViewer` or visit the (docs)[https://docs.maptiler.com/sdk-js/examples/image-viewer/].
860
955
 
861
- ## Events
956
+ #### Events
957
+
862
958
  In a similar manner, a subset of map events are fired by the image viewer. All UI interaction events that would normally include a `LngLat` in the event data instead receive an `imageX` and `imageY` field, representing an absolute pixel position of the image. This is same for `flyTo`, `jumpTo`, `panTo` etc.
863
959
 
864
960
  A full list of supported events can be found in the exported type declaration `ImageViewerEventTypes`
865
961
 
866
- ## Markers with `ImageViewerMarker`
962
+ #### Markers with `ImageViewerMarker`
867
963
 
868
964
  An `ImageViewerMarker` can also be added and used like the usual `Marker`class, the main difference being it operates in _image pixels_, not LngLat coordinates.
869
965
 
870
966
  ```ts
871
- const marker = new ImageViewerMarker({ draggable: true });
967
+ const marker = new ImageViewerMarker({ draggable: true });
872
968
 
873
- marker
874
- .setPosition([100, 100]) // position in image pixels.
875
- .addTo(imageViewer)
876
- .on("dragend", (e) => {
877
- console.log("e.target.isWithinImageBounds()", e.target.isWithinImageBounds());
878
- });
969
+ marker
970
+ .setPosition([100, 100]) // position in image pixels.
971
+ .addTo(imageViewer)
972
+ .on("dragend", (e) => {
973
+ console.log("e.target.isWithinImageBounds()", e.target.isWithinImageBounds());
974
+ });
879
975
  ```
880
976
 
881
977
  Full API documentation can be found in the typedocs: `npm run doc`
882
978
 
883
- # Easy language switching
979
+ ### Easy language switching
980
+
884
981
  The language generally depends on the style but we made it possible to easily set and update from a built-in list of languages.
885
982
 
886
983
  The built-in list of supported languages is accessible from the `Language` object:
984
+
887
985
  ```ts
888
986
  import { Language } from "@maptiler/sdk";
889
987
  ```
988
+
890
989
  In the UMD bundle, it will be directly at `maptilersdk.Language`.
891
990
 
892
991
  There are three distinct ways to set the language of a map:
893
992
 
894
993
  1. **Global way, using the config object:**
994
+
895
995
  ```ts
896
996
  import { config } from "@maptiler/sdk";
897
997
 
898
998
  config.primaryLanguage = Language.ENGLISH;
899
999
  ```
900
- Then, if any further language setting is applied, all the map instances created afterward will use this language.
1000
+
1001
+ Then, if any further language setting is applied, all the map instances created afterward will use this language.
901
1002
 
902
1003
  2. **Set the language at instantiation time:**
1004
+
903
1005
  ```ts
904
1006
  const map = new Map({
905
1007
  // some options...
906
1008
  language: Language.ENGLISH, // the ISO codes can also be used (eg. "en")
907
- })
1009
+ });
908
1010
  ```
1011
+
909
1012
  It will only apply `ENGLISH` as the language of this specific map instance (and will not alter the global `config`).
910
1013
 
911
1014
  3. **Set the language after the map has been instantiated:**
1015
+
912
1016
  ```ts
913
1017
  map.setLanguage(Language.ENGLISH);
914
1018
  ```
1019
+
915
1020
  Again, it will only apply `ENGLISH` as the language of this specific map instance (and will not alter the global `config`).
916
1021
 
1022
+ The list of supported languages is built-in and can be found [here](src/language.ts). In addition, there are special language _flags_:
917
1023
 
918
- The list of supported languages is built-in and can be found [here](src/language.ts). In addition, there are special language *flags*:
919
1024
  - `Language.AUTO` **[DEFAULT]** uses the language defined in the web browser
920
1025
  - `Language.STYLE_LOCK` to strictly use the language defined in the style. Prevents any further language update
921
1026
  - `Language.LOCAL` uses the language local to each country
@@ -927,7 +1032,8 @@ Whenever a label is not supported in the defined language, it falls back to `Lan
927
1032
  Here is a sample of some compatible languages:
928
1033
  ![](images/screenshots/multilang.gif)
929
1034
 
930
- ## Built-in support for right-to-left languages
1035
+ #### Built-in support for right-to-left languages
1036
+
931
1037
  Languages that are written right-to-left such as Arabic and Hebrew are fully supported by default. No need to install any plugins!
932
1038
 
933
1039
  If you wish to opt of applying the rtl plugin or wish to use a different compatible rtl text plugin, you can pass the `rtlTextPlugin`
@@ -940,23 +1046,25 @@ constructor option as either `false` (disable the rtl plugin) or a url to load a
940
1046
  <img src="images/screenshots/lang-hebrew.jpeg" width="48%"></img>
941
1047
  </p>
942
1048
 
943
- ## Visitor language modes
944
- The *visitor* language modes are special built-in modes made to display labels in two different languages, concatenated when available:
945
- - `Language.VISITOR` concatenates labels in the language of your system and the *local* language
946
- - `Language.VISITOR_ENGLISH` concatenates labels in English and the *local* language
1049
+ #### Visitor language modes
1050
+
1051
+ The _visitor_ language modes are special built-in modes made to display labels in two different languages, concatenated when available:
1052
+
1053
+ - `Language.VISITOR` concatenates labels in the language of your system and the _local_ language
1054
+ - `Language.VISITOR_ENGLISH` concatenates labels in English and the _local_ language
947
1055
 
948
1056
  ```ts
949
1057
  const map = new Map({
950
1058
  // some options...
951
1059
  language: Language.VISITOR,
952
- })
1060
+ });
953
1061
 
954
1062
  // or
955
1063
 
956
1064
  const map = new Map({
957
1065
  // some options...
958
1066
  language: Language.VISITOR_ENGLISH,
959
- })
1067
+ });
960
1068
  ```
961
1069
 
962
1070
  We believe these two modes can be very handy to help the end users identify places, especially when the local labels are not using a latin charset. Here is how it looks like:
@@ -964,10 +1072,12 @@ We believe these two modes can be very handy to help the end users identify plac
964
1072
  ![](images/screenshots/visitor_athen.png)
965
1073
  ![](images/screenshots/visitor_osaka.png)
966
1074
 
1075
+ ### Custom Events and Map Lifecycle
1076
+
1077
+ #### Events
1078
+
1079
+ ##### The `ready` event
967
1080
 
968
- # Custom Events and Map Lifecycle
969
- ## Events
970
- ### The `ready` event
971
1081
  The `ready` event happens just after the `load` event but waits until all the controls managed by the `Map` constructor are dealt with, some having an asynchronous logic to set up.
972
1082
  Since the `ready` event waits until all the basic controls are nicely positioned, it is **safer** to use `ready` than `load` if you plan to add other custom controls with the `.addControl()` method.
973
1083
 
@@ -981,23 +1091,25 @@ const map = new maptilersdk.Map({
981
1091
  map.on("ready", (evt) => {
982
1092
  const terrainControl = new maptilersdk.MaptilerTerrainControl();
983
1093
  map.addControl(terrainControl);
984
- })
1094
+ });
985
1095
  ```
986
1096
 
987
- ### The `loadWithTerrain` event
988
- The `loadWithTerrain` event is triggered only *once* in a `Map` instance lifecycle, when both the `ready` event and the `terrain` event **with non-null terrain** are fired.
1097
+ ##### The `loadWithTerrain` event
1098
+
1099
+ The `loadWithTerrain` event is triggered only _once_ in a `Map` instance lifecycle, when both the `ready` event and the `terrain` event **with non-null terrain** are fired.
989
1100
 
990
1101
  **Why a new event?**
991
1102
  When a map is instantiated with the option `terrain: true`, then MapTiler terrain is directly added to it and some animation functions such as `.flyTo()` or `.easeTo()` if started straight after the map initialization will actually need to wait a few milliseconds that the terrain is properly initialized before running.
992
1103
  Relying on the `ready` or `load` event to run an animation with a map with terrain may fail in some cases for this reason, and this is why waiting for `loadWithTerrain` is safer in this particular situation.
993
1104
 
994
- ## Lifecycle Methods
995
- The events `load`, `ready` and `loadWithTerrain` are both called *at most once* and require a callback function to add more elements such as markers, layers, popups and data sources. Even though MapTiler SDK fully supports this logic, we have also included a *promise* logic to provide a more linear and less nested way to wait for a Map instance to be usable. Let's compare the two ways:
1105
+ #### Lifecycle Methods
1106
+
1107
+ The events `load`, `ready` and `loadWithTerrain` are both called _at most once_ and require a callback function to add more elements such as markers, layers, popups and data sources. Even though MapTiler SDK fully supports this logic, we have also included a _promise_ logic to provide a more linear and less nested way to wait for a Map instance to be usable. Let's compare the two ways:
996
1108
 
997
1109
  - Classic: with a callback on the `load` event:
1110
+
998
1111
  ```ts
999
1112
  function init() {
1000
-
1001
1113
  const map = new Map({
1002
1114
  container,
1003
1115
  center: [2.34804, 48.85439], // Paris, France
@@ -1008,18 +1120,18 @@ function init() {
1008
1120
  // Once triggered, the callback is ran in its own scope.
1009
1121
  map.on("load", (evt) => {
1010
1122
  // Adding a data source
1011
- map.addSource('my-gps-track-source', {
1123
+ map.addSource("my-gps-track-source", {
1012
1124
  type: "geojson",
1013
1125
  data: "https://example.com/some-gps-track.geojson",
1014
1126
  });
1015
- })
1127
+ });
1016
1128
  }
1017
1129
  ```
1018
1130
 
1019
1131
  - Modern: with a promise returned by the method `.onLoadAsync()`, used in an `async` function:
1132
+
1020
1133
  ```ts
1021
1134
  async function init() {
1022
-
1023
1135
  const map = new Map({
1024
1136
  container,
1025
1137
  center: [2.34804, 48.85439], // Paris, France
@@ -1031,7 +1143,7 @@ async function init() {
1031
1143
  await map.onLoadAsync();
1032
1144
 
1033
1145
  // Adding a data source
1034
- map.addSource('my-gps-track-source', {
1146
+ map.addSource("my-gps-track-source", {
1035
1147
  type: "geojson",
1036
1148
  data: "https://example.com/some-gps-track.geojson",
1037
1149
  });
@@ -1039,10 +1151,11 @@ async function init() {
1039
1151
  ```
1040
1152
 
1041
1153
  We deployed exactly the same logic for the `loadWithTerrain` event. Let's see how the two ways compare.
1154
+
1042
1155
  - Classic: with a callback on the `loadWithTerrain` event:
1156
+
1043
1157
  ```ts
1044
1158
  function init() {
1045
-
1046
1159
  const map = new Map({
1047
1160
  container,
1048
1161
  center: [2.34804, 48.85439], // Paris, France
@@ -1057,15 +1170,15 @@ function init() {
1057
1170
  map.flyTo({
1058
1171
  center: [-0.09956, 51.50509], // London, UK
1059
1172
  zoom: 12.5,
1060
- })
1061
- })
1173
+ });
1174
+ });
1062
1175
  }
1063
1176
  ```
1064
1177
 
1065
1178
  - Modern: with a promise returned by the method `.onLoadWithTerrainAsync()`, used in an `async` function:
1179
+
1066
1180
  ```ts
1067
1181
  async function init() {
1068
-
1069
1182
  const map = new Map({
1070
1183
  container,
1071
1184
  center: [2.34804, 48.85439], // Paris, France
@@ -1081,15 +1194,16 @@ async function init() {
1081
1194
  map.flyTo({
1082
1195
  center: [-0.09956, 51.50509], // London, UK
1083
1196
  zoom: 12.5,
1084
- })
1197
+ });
1085
1198
  }
1086
1199
  ```
1087
1200
 
1088
1201
  And finally, the lifecycle method corresponding to the `ready` event:
1202
+
1089
1203
  - Classic: with a callback on the `ready` event:
1204
+
1090
1205
  ```ts
1091
1206
  function init() {
1092
-
1093
1207
  const map = new Map({
1094
1208
  container,
1095
1209
  center: [2.34804, 48.85439], // Paris, France
@@ -1100,18 +1214,18 @@ function init() {
1100
1214
  // Once triggered, the callback is ran in its own scope.
1101
1215
  map.on("ready", (evt) => {
1102
1216
  // Adding a data source
1103
- map.addSource('my-gps-track-source', {
1217
+ map.addSource("my-gps-track-source", {
1104
1218
  type: "geojson",
1105
1219
  data: "https://example.com/some-gps-track.geojson",
1106
1220
  });
1107
- })
1221
+ });
1108
1222
  }
1109
1223
  ```
1110
1224
 
1111
1225
  - Modern: with a promise returned by the method `.onReadyAsync()`, used in an `async` function:
1226
+
1112
1227
  ```ts
1113
1228
  async function init() {
1114
-
1115
1229
  const map = new Map({
1116
1230
  container,
1117
1231
  center: [2.34804, 48.85439], // Paris, France
@@ -1123,48 +1237,51 @@ async function init() {
1123
1237
  await map.onReadyAsync();
1124
1238
 
1125
1239
  // Adding a data source
1126
- map.addSource('my-gps-track-source', {
1240
+ map.addSource("my-gps-track-source", {
1127
1241
  type: "geojson",
1128
1242
  data: "https://example.com/some-gps-track.geojson",
1129
1243
  });
1130
1244
  }
1131
1245
  ```
1132
1246
 
1133
- We believe that the *promise* approach is better because it does not nest scopes and will allow for a linear non-nested stream of execution. It also corresponds to more modern development standards.
1247
+ We believe that the _promise_ approach is better because it does not nest scopes and will allow for a linear non-nested stream of execution. It also corresponds to more modern development standards.
1134
1248
 
1135
- > ๐Ÿ“ฃ *__Note:__* Generally speaking, *promises* are not a go to replacement for all event+callback and are suitable only for events that are called only once in the lifecycle of a Map instance. This is the reason why we have decided to provide a *promise* equivalent only for the `load`, `ready` and `loadWithTerrain` events but not for events that may be called multiple time such as interaction events.
1249
+ > ๐Ÿ“ฃ _**Note:**_ Generally speaking, _promises_ are not a go to replacement for all event+callback and are suitable only for events that are called only once in the lifecycle of a Map instance. This is the reason why we have decided to provide a _promise_ equivalent only for the `load`, `ready` and `loadWithTerrain` events but not for events that may be called multiple time such as interaction events.
1250
+
1251
+ ##### The `webglContextLost` event
1136
1252
 
1137
- ### The `webglContextLost` event
1138
1253
  The map is rendered with WebGL, that leverages the GPU to provide high-performance graphics. In some cases, the host machine, operating system or the graphics driver, can decide that continuing to run such high performance graphics is unsustainable, and will abort the process. This is called a "WebGL context loss". Such situation happens when the resources are running low or when multiple browser tabs are competing to access graphics memory.
1139
1254
 
1140
1255
  The best course of action in such situation varies from an app to another. Sometimes a page refresh is the best thing to do, in other cases, instantiating a new Map dynamically at application level is more appropriate because it hides a technical failure to the end user. The event `webglContextLost` is exposed so that the most appropriate scenario can be implemented at application level.
1141
1256
 
1142
1257
  Here is how to respond to a WebGL context loss with a simple page refresh:
1143
- ```ts
1144
1258
 
1259
+ ```ts
1145
1260
  // Init the map
1146
1261
  const map = new maptilersdk.Map({
1147
1262
  container: "map-container",
1148
1263
  hash: true,
1149
- })
1264
+ });
1150
1265
 
1151
1266
  // Refresh the page if context is lost.
1152
1267
  // Since `hash` is true, the location will be the same as before
1153
1268
  map.on("webglContextLost", (e) => {
1154
1269
  location.reload();
1155
- })
1270
+ });
1156
1271
  ```
1157
1272
 
1158
- # Color Ramps
1159
- A color ramp is a color gradient defined in a specific interval, for instance in [0, 1], and for any value within this interval will retrieve a color. They are defined by at least a color at each bound and usually additional colors within the range.
1273
+ ### Color Ramps
1274
+
1275
+ A color ramp is a color gradient defined in a specific interval, for instance in [0, 1], and for any value within this interval will retrieve a color. They are defined by at least a color at each bound and usually additional colors within the range.
1160
1276
 
1161
- Color ramps are super useful to represent numerical data in a visual way: the temperature, the population density, the average commute time, etc.
1277
+ Color ramps are super useful to represent numerical data in a visual way: the temperature, the population density, the average commute time, etc.
1162
1278
 
1163
1279
  The SDK includes many built-in ready-to-use color ramps as well as extra logic to manipulate them and create new ones, here is the full list:
1164
1280
 
1165
1281
  ![](images/colorramps.png)
1166
1282
 
1167
1283
  To use an already existing color ramp and access some of its values:
1284
+
1168
1285
  ```ts
1169
1286
  import { ColorRampCollection } from "@maptiler/sdk";
1170
1287
 
@@ -1182,7 +1299,7 @@ const zeroColorHex = temperatureTurbo.getColorHex(0);
1182
1299
  // The color is a string: "#2ddabdff"
1183
1300
  ```
1184
1301
 
1185
- Creating a new one consists of defining all the colors for each *color stops*. The values can be in the range of interest and *do not* have to be in [0, 1]. For example, let's recreate a *Viridis* color ramp but with a range going from 0 to 100:
1302
+ Creating a new one consists of defining all the colors for each _color stops_. The values can be in the range of interest and _do not_ have to be in [0, 1]. For example, let's recreate a _Viridis_ color ramp but with a range going from 0 to 100:
1186
1303
 
1187
1304
  ```ts
1188
1305
  import { ColorRamp } from "@maptiler/sdk";
@@ -1198,55 +1315,60 @@ const myCustomRamp = new ColorRamp({
1198
1315
  { value: 75, color: [92, 200, 99] },
1199
1316
  { value: 88, color: [170, 220, 50] },
1200
1317
  { value: 100, color: [253, 231, 37] },
1201
- ]
1318
+ ],
1202
1319
  });
1203
1320
  ```
1204
1321
 
1205
- When defining a new *ramp*, the colors can be an RGB array (`[number, number, number]`) or an RGBA array (`[number, number, number, number]`).
1322
+ When defining a new _ramp_, the colors can be an RGB array (`[number, number, number]`) or an RGBA array (`[number, number, number, number]`).
1206
1323
 
1207
1324
  Many methods are available on color ramps, such as getting the `<canvas>` element of it, rescaling it, flipping it or [resampling it in a non-linear way](colorramp.md). Read more on [our reference page](https://docs.maptiler.com/sdk-js/api/color-ramp/) and have a look at our [examples](https://docs.maptiler.com/sdk-js/examples/?q=colorramp) to see how they work.
1208
1325
 
1326
+ ### Vector Layer Helpers
1209
1327
 
1210
- # Vector Layer Helpers
1211
1328
  **Let's make vector layers easy!** Originally, you'd have to add a source and then proceed to the styling of your layer, which can be tricky because there are a lot of `paint` and `layout` options and they vary a lot from one type of layer to another. **But we have helpers for this!** ๐Ÿ–‹๏ธ
1212
1329
  ![](images/screenshots/point-layer.jpg)
1213
1330
 
1214
- ## Shared logic
1331
+ #### Shared logic
1332
+
1215
1333
  Helpers come with a lot of **built-in defaults** and some fail-proof logic that makes creating vector layers much easier! As a result, a dataset can be displayed in one call, creating both the datasource and the layer(s) in one go!
1216
1334
 
1217
1335
  Depending on the type of feature to add (point, polyline, polygon or heatmap), a different helper function needs to be used, but datasource could contain mixed types of feature and the helper will only display a specific type.
1218
1336
 
1219
1337
  All the helpers are made available under the `helpers` object. If you are using ES Modules, this is how you access them:
1338
+
1220
1339
  ```ts
1221
1340
  import { Map, helpers } from "@maptiler/sdk";
1222
1341
  ```
1223
1342
 
1224
1343
  If you are using the UMD bundle of the SDK, for example from our CDN, you will find the `helpers` with:
1344
+
1225
1345
  ```js
1226
- maptilersdk.helpers
1346
+ maptilersdk.helpers;
1227
1347
  ```
1228
1348
 
1229
- **Example:** we have a *geoJSON* file that contains both *polygons* and *point* and we use it as the `data` property on the `helpers.addPoint(map, { options })`, this will only add the *points*.
1349
+ **Example:** we have a _geoJSON_ file that contains both _polygons_ and _point_ and we use it as the `data` property on the `helpers.addPoint(map, { options })`, this will only add the _points_.
1230
1350
 
1231
1351
  In addition to easy styling, the helpers' datasource can be:
1352
+
1232
1353
  - a URL to a geoJSON file or its string content
1233
1354
  - a URL to a GPX or KML file (only for the polyline helper) or its string content
1234
- - a UUID of a MapTiler Cloud dataset
1355
+ - a UUID of a MapTiler dataset
1356
+
1357
+ ##### Multiple Layers
1235
1358
 
1236
- ### Multiple Layers
1237
1359
  The key design principle of these vector layer helpers is **it's easy to make what you want**, which is very different from **making MapLibre easier to use**.
1238
1360
 
1239
- > For example, to create a road with an outline, one must draw two layers: a wider base layer and a narrower top layer, fueled by the same polyline data. This requires ordering the layers properly and computing not the width of the outline, but rather the width of the polyline underneath so that it outgrows the top road layer of the desired number of pixels.
1361
+ > For example, to create a road with an outline, one must draw two layers: a wider base layer and a narrower top layer, fueled by the same polyline data. This requires ordering the layers properly and computing not the width of the outline, but rather the width of the polyline underneath so that it outgrows the top road layer of the desired number of pixels.
1240
1362
 
1241
1363
  With the polyline helper, you just say if you want an outline and specify its size (or even a zoom-dependent size) and everything is handled for you. As a result, calling the method `helpers.addPolyline` will return an object with **multiple IDs**: the ID of the top/main layer, the ID of the outline layer (could be `null`) and the ID of the data source. This makes further layer and source manipulation possible.
1242
1364
 
1243
- ### Input
1365
+ ##### Input
1244
1366
 
1245
- The vector layer helper also shares some *I/O* logic: each of them can take many options but a subset of them is common across all the helpers:
1367
+ The vector layer helper also shares some _I/O_ logic: each of them can take many options but a subset of them is common across all the helpers:
1246
1368
 
1247
1369
  ```ts
1248
1370
  /**
1249
- * A geojson Feature collection or a URL to a geojson or the UUID of a MapTiler Cloud dataset.
1371
+ * A geojson Feature collection or a URL to a geojson or the UUID of a MapTiler dataset.
1250
1372
  */
1251
1373
  data: FeatureCollection | string;
1252
1374
 
@@ -1284,23 +1406,25 @@ minzoom?: number;
1284
1406
  maxzoom?: number;
1285
1407
  ```
1286
1408
 
1409
+ #### Polyline Layer Helper
1287
1410
 
1288
-
1289
- ## Polyline Layer Helper
1290
- The method `helpers.addPolyline` is not only compatible with the traditional GeoJSON source but also with **GPX** and **KML** files and the `.data` options can be a MapTiler Cloud dataset UUID and will be resolved automatically.
1411
+ The method `helpers.addPolyline` is not only compatible with the traditional GeoJSON source but also with **GPX** and **KML** files and the `.data` options can be a MapTiler dataset UUID and will be resolved automatically.
1291
1412
 
1292
1413
  here is the minimal usage, with the default line width and a random color (within a selected list):
1414
+
1293
1415
  ```ts
1294
- helpers.addPolyline(map, {
1416
+ helpers.addPolyline(map, {
1295
1417
  // A URL, relative or absolute
1296
1418
  data: "some-trace.geojson",
1297
1419
  });
1298
1420
  ```
1421
+
1299
1422
  ![](images/screenshots/default-trace.jpg)
1300
1423
 
1301
- We can add many options, such as specific color, a custom width or a dash pattern, this time sourcing the data from MapTiler Cloud, using the UUID of a dataset:
1424
+ We can add many options, such as specific color, a custom width or a dash pattern, this time sourcing the data from MapTiler, using the UUID of a dataset:
1425
+
1302
1426
  ```ts
1303
- helpers.addPolyline(map, {
1427
+ helpers.addPolyline(map, {
1304
1428
  data: "74003ba7-215a-4b7e-8e26-5bbe3aa70b05",
1305
1429
  lineColor: "#FF6666",
1306
1430
  lineWidth: 4,
@@ -1308,20 +1432,24 @@ helpers.addPolyline(map, {
1308
1432
  lineCap: "butt",
1309
1433
  });
1310
1434
  ```
1435
+
1311
1436
  ![](images/screenshots/custom-trace.jpg)
1312
- As you can see, we've come up with a fun and easy way to create **dash arrays**, just use *underscores* and *white spaces* and this pattern will repeat!
1437
+ As you can see, we've come up with a fun and easy way to create **dash arrays**, just use _underscores_ and _white spaces_ and this pattern will repeat!
1313
1438
 
1314
1439
  Adding an outline is also pretty straightforward:
1440
+
1315
1441
  ```ts
1316
- helpers.addPolyline(map, {
1442
+ helpers.addPolyline(map, {
1317
1443
  data: "74003ba7-215a-4b7e-8e26-5bbe3aa70b05",
1318
1444
  lineColor: "#880000",
1319
1445
  outline: true,
1320
1446
  });
1321
1447
  ```
1448
+
1322
1449
  ![](images/screenshots/polyline-outline.png)
1323
1450
 
1324
1451
  Endless possibilities, what about a glowing wire?
1452
+
1325
1453
  ```ts
1326
1454
  helpers.addPolyline(map, {
1327
1455
  data: "74003ba7-215a-4b7e-8e26-5bbe3aa70b05",
@@ -1334,12 +1462,13 @@ helpers.addPolyline(map, {
1334
1462
  outlineOpacity: 0.5,
1335
1463
  });
1336
1464
  ```
1337
- ![](images/screenshots/polyline-glow.png)
1338
1465
 
1466
+ ![](images/screenshots/polyline-glow.png)
1339
1467
 
1340
1468
  All the other options are documented on [our reference page](https://docs.maptiler.com/sdk-js/api/helpers/#polyline) and more examples are available [here](https://docs.maptiler.com/sdk-js/examples/?q=polyline+helper).
1341
1469
 
1342
- ## Polygon Layer Helper
1470
+ #### Polygon Layer Helper
1471
+
1343
1472
  The polygon helper makes it easy to create vector layers that contain polygons, whether they are *multi*polygons, *holed*polygons or just simple polygons. Whenever it's possible and it makes sense, we use the same terminology across the different helpers.
1344
1473
 
1345
1474
  Here is a minimalist example, with a half-transparent polygon of Switzerland, from a local file:
@@ -1367,33 +1496,40 @@ helpers.addPolygon(map, {
1367
1496
  fillOpacity: 0.7,
1368
1497
  });
1369
1498
  ```
1499
+
1370
1500
  ![](images/screenshots/swiss-cheese.png)
1371
1501
 
1372
1502
  All the other options are documented on [our reference page](https://docs.maptiler.com/sdk-js/api/helpers/#polygon) and more examples are available [here](https://docs.maptiler.com/sdk-js/examples/?q=polygon+helper).
1373
1503
 
1374
- ## Point Layer Helper
1504
+ #### Point Layer Helper
1505
+
1375
1506
  A point visualization may appear like the simplest of all, but we noticed this is where people get the most creative: cluster, data-driven variable radius, but also scaled with zoom, with or without labels, data-driven colors, etc. Our helper supports all of these and will fill-in with built-in default for what's missing.
1376
1507
 
1377
1508
  Here is the simplest example, with a dataset loaded from a local file:
1509
+
1378
1510
  ```ts
1379
1511
  helpers.addPoint(map, {
1380
1512
  data: "public-schools.geojson",
1381
- })
1513
+ });
1382
1514
  ```
1515
+
1383
1516
  if no color is specified, a random color is used and the default radius is ramped over the zoom level:
1384
1517
  ![](images/screenshots/points.png)
1385
1518
 
1386
- Here is the same dataset, but with *point clustering* enabled:
1519
+ Here is the same dataset, but with _point clustering_ enabled:
1520
+
1387
1521
  ```ts
1388
1522
  helpers.addPoint(map, {
1389
1523
  data: "public-schools.geojson",
1390
1524
  cluster: true,
1391
1525
  });
1392
1526
  ```
1527
+
1393
1528
  On the other hand, if clusters are enabled, the default color is fueled by the color ramp `TURBO` scaled from `10` to `10000` non-linearly resampled with the method `"ease-out-square"`. The size also varies from `minPointradius` (default: `10`) to `maxPointRadius` (default: `50`):
1394
1529
  ![](images/screenshots/points-clustered.png)
1395
1530
 
1396
1531
  With the point helper, it's also possible to adapt the color and the radius based on a property. In the following example, we display a point for each public school, with the scaling factor being the number of students:
1532
+
1397
1533
  ```ts
1398
1534
  helpers.addPoint(map, {
1399
1535
  data: "public-schools.geojson",
@@ -1404,39 +1540,44 @@ helpers.addPoint(map, {
1404
1540
  maxPointRadius: 30,
1405
1541
  showLabel: true,
1406
1542
  zoomCompensation: false,
1407
- })
1543
+ });
1408
1544
  ```
1545
+
1409
1546
  ![](images/screenshots/nyc-schools.png)
1410
1547
 
1411
1548
  Here, the`PORTLAND` color ramp is going to be used so that schools with `200` students or less will have the colors at the very beginning of the color ramp and schools with `2000` or more will have the color defined at the very end. Schools in between will be attributed a color in a non-linear fashion, following the `"ease-out-sqrt"` method (read **Color Ramps** section above for more info).
1412
1549
 
1413
1550
  All the other options are documented on [our reference page](https://docs.maptiler.com/sdk-js/api/helpers/#point) and more examples are available [here](https://docs.maptiler.com/sdk-js/examples/?q=point+helper).
1414
1551
 
1415
- ## Heatmap Layer Helper
1552
+ #### Heatmap Layer Helper
1553
+
1416
1554
  The heatmap layer is a great alternative for visualizing a collection of sparse data, but it can be challenging to use, especially when one has to come up with their own color ramp from scratch. **The helper makes this much easier!**
1417
1555
 
1418
1556
  Here is a minimalist example, using the default built-in `TURBO` color ramp:
1557
+
1419
1558
  ```ts
1420
1559
  helpers.addHeatmap(map, {
1421
1560
  data: "public-schools.geojson",
1422
1561
  });
1423
1562
  ```
1563
+
1424
1564
  ![](images/screenshots/heatmap-schools.png)
1425
1565
 
1426
- Some visualizations are created with a fixed geographic extent or zoom level in mind, whether it's a survey at the scale of a single neighborhood or statistics at a country scale. In this case, we want to tailor the color, radius, weight and intensity of the heatmap blobs exactly for these precise settings. In the following example, we disable the *zoom compensation* to make sure radio and intensity are never zoom-dependant:
1566
+ Some visualizations are created with a fixed geographic extent or zoom level in mind, whether it's a survey at the scale of a single neighborhood or statistics at a country scale. In this case, we want to tailor the color, radius, weight and intensity of the heatmap blobs exactly for these precise settings. In the following example, we disable the _zoom compensation_ to make sure radio and intensity are never zoom-dependant:
1567
+
1427
1568
  ```ts
1428
1569
  helpers.addHeatmap(map, {
1429
1570
  data: "public-schools.geojson",
1430
1571
  property: "students",
1431
1572
  // radius: how wide are the blobs
1432
1573
  radius: [
1433
- {propertyValue: 100, value: 15},
1434
- {propertyValue: 800, value: 50},
1574
+ { propertyValue: 100, value: 15 },
1575
+ { propertyValue: 800, value: 50 },
1435
1576
  ],
1436
1577
  // weight: how intense are the blob, as fueled by a property
1437
1578
  weight: [
1438
- {propertyValue: 100, value: 0.1},
1439
- {propertyValue: 800, value: 1},
1579
+ { propertyValue: 100, value: 0.1 },
1580
+ { propertyValue: 800, value: 1 },
1440
1581
  ],
1441
1582
  // A custom color ramp, must be used with its default interval of [0, 1]
1442
1583
  colorRamp: ColorRampCollection.MAGMA,
@@ -1446,13 +1587,16 @@ helpers.addHeatmap(map, {
1446
1587
  intensity: 1.2,
1447
1588
  });
1448
1589
  ```
1590
+
1449
1591
  ![](images/screenshots/heatmap-colorramp.png)
1450
- Turning off *zoom compensation* allows for more accurate adjustments to the visualization at a specific zoom level, but it may not adapt as smoothly when zooming in or out.
1592
+ Turning off _zoom compensation_ allows for more accurate adjustments to the visualization at a specific zoom level, but it may not adapt as smoothly when zooming in or out.
1451
1593
 
1452
1594
  All the other options are documented on [our reference page](https://docs.maptiler.com/sdk-js/api/helpers/#heatmap) and more examples are available [here](https://docs.maptiler.com/sdk-js/examples/?q=heatmap+helper).
1453
1595
 
1454
- # Other helpers
1455
- ## Convert GPX and KML to GeoJSON
1596
+ ### Other helpers
1597
+
1598
+ #### Convert GPX and KML to GeoJSON
1599
+
1456
1600
  In the [Polyline helper section](#polyline-layer-helper) above, we have seen that one can feed the helper directly with a path to a GPX or KML file, that is then converted under the hood client-side into a GeoJSON `FeatureCollection` object. This conversion feature is also exposed and can be used as such:
1457
1601
 
1458
1602
  ```ts
@@ -1470,6 +1614,7 @@ const features = maptilersdk.gpx(gpxStr);
1470
1614
  ```
1471
1615
 
1472
1616
  And for KML files:
1617
+
1473
1618
  ```ts
1474
1619
  import { kml } from "@maptiler/sdk";
1475
1620
 
@@ -1484,11 +1629,12 @@ const kmlStr = await res.text();
1484
1629
  const features = maptilersdk.gpx(kmlStr);
1485
1630
  ```
1486
1631
 
1632
+ #### Take Screenshots, programmatically
1487
1633
 
1488
- ## Take Screenshots, programmatically
1489
- There are two different ways to create screenshot, corresponding to two very different usecases. Note that screenshots will not contain *DOM elements* such as `Marker` and `Popup`, since those are not part of the rendering context.
1634
+ There are two different ways to create screenshot, corresponding to two very different usecases. Note that screenshots will not contain _DOM elements_ such as `Marker` and `Popup`, since those are not part of the rendering context.
1490
1635
 
1491
1636
  **1. Get a `blob` of a screenshot, PNG encoded:**
1637
+
1492
1638
  ```ts
1493
1639
  import { Map, helpers } from "@maptiler/sdk";
1494
1640
 
@@ -1497,9 +1643,11 @@ import { Map, helpers } from "@maptiler/sdk";
1497
1643
  // Inside an async function, or with using .then()
1498
1644
  const blob = await helpers.takeScreenshot(map);
1499
1645
  ```
1646
+
1500
1647
  The returned `Blob` of a PNG image file can be very handy if the goal is to programmatically further manipulate the screenshot, such as sending it to some feedback endpoint with a POST request.
1501
1648
 
1502
1649
  **2. Download a PNG file:**
1650
+
1503
1651
  ```ts
1504
1652
  import { Map, helpers } from "@maptiler/sdk";
1505
1653
 
@@ -1507,16 +1655,18 @@ import { Map, helpers } from "@maptiler/sdk";
1507
1655
 
1508
1656
  // No need to be inside an async function, the download will be triggered when the file is ready
1509
1657
  maptilersdk.helpers.takeScreenshot(map, {
1510
- download: true,
1511
- filename: "map_screenshot.png"
1658
+ download: true,
1659
+ filename: "map_screenshot.png",
1512
1660
  });
1513
1661
  ```
1662
+
1514
1663
  Getting a file directly is a nice option that can be useful to share some debugging context with colleagues, compare multiple styles, or share your creation on social media.
1515
1664
 
1516
- > ๐Ÿ“ฃ *__Note:__* Keep in mind that MapTiler Cloud data are copyrighted and their usage is restricted. This include MapTiler built-in styles and tilesets, among others. In case of doubt, do not hesitate to read our [terms](https://www.maptiler.com/terms/) or to ask our [support team](https://www.maptiler.com/contacts/).
1665
+ > ๐Ÿ“ฃ _**Note:**_ Keep in mind that MapTiler data are copyrighted and their usage is restricted. This include MapTiler built-in styles and tilesets, among others. In case of doubt, do not hesitate to read our [terms](https://www.maptiler.com/terms/) or to ask our [support team](https://www.maptiler.com/contacts/).
1517
1666
 
1518
- # Caching
1519
- Starting from v2, MapTiler SDK introduced the **caching** of tiles and fonts served by MapTiler Cloud, which can represent a large chunk of the data being fetched when browsing a map. This caching leverages modern browsers caching API so it's well-managed and there is no risk of bloating! When we update **MapTiler Planet** or our **official styles**, the caching logic will detect it and automatically invalidate older versions of the tiles that were previously cached.
1667
+ ### Caching
1668
+
1669
+ Starting from v2, MapTiler SDK introduced the **caching** of tiles and fonts served by MapTiler, which can represent a large chunk of the data being fetched when browsing a map. This caching leverages modern browsers caching API so it's well-managed and there is no risk of bloating! When we update **MapTiler Planet** or our **official styles**, the caching logic will detect it and automatically invalidate older versions of the tiles that were previously cached.
1520
1670
 
1521
1671
  Caching greatly improves the performance at load time and positively impacts the user experience, for this reason, it is **enabled by default**. If for debugging purposes or for a very specific use-case caching needs to be disabled, then it is possible:
1522
1672
 
@@ -1526,53 +1676,64 @@ import { config } from "@maptiler/sdk";
1526
1676
  config.caching = false;
1527
1677
  ```
1528
1678
 
1529
- # Easy access to MapTiler Cloud API
1679
+ ### Easy access to MapTiler API
1680
+
1530
1681
  Our map SDK is not only about maps! We also provide plenty of wrappers to our API calls!
1531
1682
 
1532
- > ๐Ÿ“ฃ *__Note:__* If you need <ins>only the API Client library</ins> to use in a headless fashion and without any map display, check out out [API Client library](https://docs.maptiler.com/client-js/) for browser and NodeJS. It's exactely what is down below and only that, in a minimalistic [TypeScript package](https://github.com/maptiler/maptiler-client-js) ๐Ÿ™.
1683
+ > ๐Ÿ“ฃ _**Note:**_ If you need <ins>only the API Client library</ins> to use in a headless fashion and without any map display, check out out [API Client library](https://docs.maptiler.com/client-js/) for browser and NodeJS. It's exactely what is down below and only that, in a minimalistic [TypeScript package](https://github.com/maptiler/maptiler-client-js) ๐Ÿ™.
1684
+
1685
+ #### ๐Ÿ” Geocoding
1533
1686
 
1687
+ > โœ… Please, use geocoding functions only from client-side (browser) and do not ๐Ÿšซ **store** or **redistribute** MapTiler API data. In case of doubt, consult the [terms](https://www.maptiler.com/cloud/terms/#explicitly-prohibited-use) โš–๏ธ
1534
1688
 
1535
- ## ๐Ÿ” Geocoding
1536
- > โœ… Please, use geocoding functions only from client-side (browser) and do not ๐Ÿšซ **store** or **redistribute** MapTiler Cloud API data. In case of doubt, consult the [terms](https://www.maptiler.com/cloud/terms/#explicitly-prohibited-use) โš–๏ธ
1689
+ ##### Forward
1537
1690
 
1538
- ### Forward
1539
1691
  You want to know the longitude and latitude of a specific place, use the forward geocoding:
1692
+
1540
1693
  ```ts
1541
1694
  // in an async function, or as a 'thenable':
1542
- const result = await maptilersdk.geocoding.forward('paris');
1695
+ const result = await maptilersdk.geocoding.forward("paris");
1543
1696
  ```
1697
+
1544
1698
  You can provide some options such as:
1699
+
1545
1700
  - the proximity, given a lon-lat position, to sort the results
1546
1701
  - one of more languages to get the results into
1547
1702
  - a bounding geo box, to restrict the search to a given window
1548
1703
 
1549
1704
  Read more about forward geocoding on our [official documentation](https://docs.maptiler.com/client-js/geocoding/#forward).
1550
1705
 
1551
- ### Reverse
1706
+ ##### Reverse
1707
+
1552
1708
  You want to know the name of a place, given a longitude-latitude? Use the reverse geocoding:
1709
+
1553
1710
  ```ts
1554
1711
  // in an async function, or as a 'thenable':
1555
1712
  const result = await maptilersdk.geocoding.reverse([6.249638, 46.402056]);
1556
1713
  ```
1714
+
1557
1715
  The same option object as the forward geocoding can be provided.
1558
1716
 
1559
1717
  Read more about reverse geocoding on our [official documentation](https://docs.maptiler.com/client-js/geocoding/#reverse).
1560
1718
 
1561
- ### Language
1562
- For both *forward* and *reverse* geocoding, this library provides a list of supported languages as shorthands to [ISO language codes](https://en.wikipedia.org/wiki/ISO_639-1). The result will be provided in multiple languages if the `language` option is an array:
1719
+ ##### Language
1720
+
1721
+ For both _forward_ and _reverse_ geocoding, this library provides a list of supported languages as shorthands to [ISO language codes](https://en.wikipedia.org/wiki/ISO_639-1). The result will be provided in multiple languages if the `language` option is an array:
1563
1722
 
1564
1723
  ```ts
1565
- const result = await maptilersdk.geocoding.forward('paris', {language: [maptilersdk.geocoding.languages.SPANISH, maptilersdk.geocoding.languages.KOREAN]})
1724
+ const result = await maptilersdk.geocoding.forward("paris", { language: [maptilersdk.geocoding.languages.SPANISH, maptilersdk.geocoding.languages.KOREAN] });
1566
1725
  ```
1567
1726
 
1568
1727
  The special language `AUTO` will detect the platform/browser preferred language.
1569
1728
 
1570
- ## ๐Ÿ•ต๏ธโ€โ™‚๏ธ Geolocation
1729
+ #### ๐Ÿ•ต๏ธโ€โ™‚๏ธ Geolocation
1730
+
1571
1731
  The geolocation service provides location information of a visitor using its IP address.
1572
1732
 
1573
1733
  The geolocation uses the IP address of a visitor to provide information about their location, such as city, region, country, timezone, etc. The precision is lower than GPS but does not require visitors to explicitly enable the location service from their web browser.
1574
1734
 
1575
1735
  There is only a single function:
1736
+
1576
1737
  ```ts
1577
1738
  // in an async function, or as a 'thenable':
1578
1739
  const result = await maptilersdk.geolocation.info();
@@ -1580,11 +1741,14 @@ const result = await maptilersdk.geolocation.info();
1580
1741
 
1581
1742
  Read more about geolocation on our [official documentation](https://docs.maptiler.com/client-js/geolocation/).
1582
1743
 
1583
- ## ๐ŸŒ Coordinates
1744
+ #### ๐ŸŒ Coordinates
1745
+
1584
1746
  If you are already familiar with [epsg.io](https://epsg.io/) (created by MapTiler), then you may find it convenient to access the details of more than 10 thousands coordinate reference systems (CRS) programmatically, as well as transform coordinates from one system to another!
1585
1747
 
1586
- ### Search
1748
+ ##### Search
1749
+
1587
1750
  The `search` lets you perform a query in a free-form fashion. Here are some examples:
1751
+
1588
1752
  ```ts
1589
1753
  // in an async function, or as a 'thenable':
1590
1754
  const resultA = await maptilersdk.coordinates.search('mercator');
@@ -1597,50 +1761,60 @@ The `transformations` options retrieve a lot more details about the CRS that Map
1597
1761
 
1598
1762
  Read more about searching coordinate systems on our [official documentation](https://docs.maptiler.com/client-js/coordinates/#search).
1599
1763
 
1600
- ### Transform
1764
+ ##### Transform
1765
+
1601
1766
  Transforming a couple of coordinates from one system to another can be challenging, for example, most countries have their own official system, yet web mapping tools are more often than not exclusive to [WGS84](https://epsg.io/4326).
1602
1767
 
1603
- If not provided, both the source (`sourceCrs`) and the destination (`targetCrs) are defaulted to **EPSG:4326**** (in other words, [WGS84](https://epsg.io/4326)). Here is how to use this feature:
1768
+ If not provided, both the source (`sourceCrs`) and the destination (`targetCrs) are defaulted to **EPSG:4326\*\*** (in other words, [WGS84](https://epsg.io/4326)). Here is how to use this feature:
1604
1769
 
1605
1770
  ```ts
1606
1771
  // in an async function, or as a 'thenable':
1607
1772
 
1608
1773
  // Providing one coordinate to transform, with a target CRS being EPSG:9793 (RGF93 v2 / Lambert-93, France official CRS)
1609
- const resultA = await maptilersdk.coordinates.transform([1, 45], {targetCrs: 9793})
1774
+ const resultA = await maptilersdk.coordinates.transform([1, 45], { targetCrs: 9793 });
1610
1775
 
1611
1776
  // Using the same logic, we can pass up to 50 coordinates to be transformed
1612
- const resultB = await maptilersdk.coordinates.transform([[10, 48], [1, 45]], {targetCrs: 9793})
1777
+ const resultB = await maptilersdk.coordinates.transform(
1778
+ [
1779
+ [10, 48],
1780
+ [1, 45],
1781
+ ],
1782
+ { targetCrs: 9793 },
1783
+ );
1613
1784
  ```
1614
1785
 
1615
1786
  Read more about transforming coordinates on our [official documentation](https://docs.maptiler.com/client-js/coordinates/#transform).
1616
1787
 
1617
- ## ๐Ÿ’ฝ Data
1618
- MapTiler Cloud gives its users the possibility to [upload and create data](https://cloud.maptiler.com/data/), manually with a user interface or by uploading a GPX, GeoJSON, KML or shp file. A unique ID is associated with each dataset so that we can later access it programmatically to retrieve a GeoJSON equivalent of it:
1788
+ #### ๐Ÿ’ฝ Data
1789
+
1790
+ MapTiler gives its users the possibility to [upload and create data](https://cloud.maptiler.com/data/), manually with a user interface or by uploading a GPX, GeoJSON, KML or shp file. A unique ID is associated with each dataset so that we can later access it programmatically to retrieve a GeoJSON equivalent of it:
1619
1791
 
1620
1792
  ```ts
1621
1793
  // in an async function, or as a 'thenable':
1622
- const result = await maptilersdk.data.get('my-dataset-unique-id')
1794
+ const result = await maptilersdk.data.get("my-dataset-unique-id");
1623
1795
  ```
1624
1796
 
1625
1797
  Since the result is a GeoJSON, it can easily be added to a `map` with `.addSource()` and `.addLayer()`.
1626
1798
 
1627
1799
  Read more about fetching your own data on our [official documentation](https://docs.maptiler.com/client-js/data/).
1628
1800
 
1629
- ## ๐Ÿ—บ๏ธ Static maps
1801
+ #### ๐Ÿ—บ๏ธ Static maps
1802
+
1630
1803
  > โœ… Please, use static maps URLs only from client side `<img>` elements, and do not ๐Ÿšซ store or redistribute the static map files. In case of doubt, consult the [terms](https://www.maptiler.com/cloud/terms/#explicitly-prohibited-use) โš–๏ธ
1631
1804
 
1632
- Maptiler Cloud provides many possibilities for creating static maps as PNG, JPEG or WebP images. They all offer the possibilities to:
1805
+ Maptiler provides many possibilities for creating static maps as PNG, JPEG or WebP images. They all offer the possibilities to:
1806
+
1633
1807
  - Choose from one of the MapTiler styles or your own
1634
1808
  - Add markers with a custom icon (or default icon with a custom color)
1635
1809
  - Add a path or polygon, with a parametric line width and color and a parametric filling color
1636
1810
 
1637
1811
  Three modes are available: `centered`, `bounded` and `automatic`.
1638
1812
 
1639
- > ๐Ÿ“ฃ *__important:__* <span style="text-decoration: underline">only image **URLs** are returned.</span>
1640
- > Contrary to the other functions of this library, the static map functions **do not** perform any query to MapTiler Cloud API, instead they build the image URL for you to use in `<img>` elements.
1813
+ > ๐Ÿ“ฃ _**important:**_ <span style="text-decoration: underline">only image **URLs** are returned.</span>
1814
+ > Contrary to the other functions of this library, the static map functions **do not** perform any query to MapTiler API, instead they build the image URL for you to use in `<img>` elements.
1641
1815
 
1816
+ ##### Map Styles
1642
1817
 
1643
- ### Map Styles
1644
1818
  In the following static map functions, the `option` object features a `style` property that can be a string or one of the built-in style shorthand. Here is the full list:
1645
1819
 
1646
1820
  - `MapStyle.STREETS`, reference style for navigation and city exploration
@@ -1669,7 +1843,7 @@ In the following static map functions, the `option` object features a `style` pr
1669
1843
  - `MapStyle.VOYAGER.DARK` (variant)
1670
1844
  - `MapStyle.VOYAGER.LIGHT` (variant)
1671
1845
  - `MapStyle.VOYAGER.VINTAGE` (variant)
1672
- - `MapStyle.TONER` reference style for very high contrast stylish maps
1846
+ - `MapStyle.TONER` reference style for very high contrast stylish maps
1673
1847
  - `MapStyle.TONER.BACKGROUND` (variant)
1674
1848
  - `MapStyle.TONER.LITE` (variant)
1675
1849
  - `MapStyle.TONER.LINES` (variant)
@@ -1678,18 +1852,19 @@ In the following static map functions, the `option` object features a `style` pr
1678
1852
  - `MapStyle.STAGE.DARK` (variant)
1679
1853
  - `MapStyle.STAGE.LIGHT` (variant)
1680
1854
 
1681
- ### Centered static maps
1855
+ ##### Centered static maps
1856
+
1682
1857
  This type of map is centered on a longitude-latitude coordinate and the zoom level must also be provided (from `0`: very zoomed out, to `22`: very zoomed in).
1683
1858
  Note that if a path or markers are provided, the framing of the map will not automatically adapt to include those (use the `automatic` mode for that).
1684
1859
 
1685
1860
  ```ts
1686
1861
  const imageLink = maptilersdk.staticMaps.centered(
1687
1862
  // center position (Boston)
1688
- [-71.06080, 42.362114],
1863
+ [-71.0608, 42.362114],
1689
1864
 
1690
1865
  // zoom level
1691
- 12.5,
1692
-
1866
+ 12.5,
1867
+
1693
1868
  // Options
1694
1869
  {
1695
1870
  // Request a hiDPI/Retina image
@@ -1701,23 +1876,24 @@ const imageLink = maptilersdk.staticMaps.centered(
1701
1876
 
1702
1877
  // Map style
1703
1878
  style: maptilersdk.MapStyle.OUTDOOR,
1704
- });
1879
+ },
1880
+ );
1705
1881
  ```
1706
1882
 
1707
1883
  Read more about centered static maps on our official [API documentation](https://docs.maptiler.com/cloud/api/static-maps/#center-based-image).
1708
1884
 
1885
+ ##### Bounded static maps
1709
1886
 
1710
- ### Bounded static maps
1711
1887
  This type of map requires a bounding box made of two points: the south-west bound and the north-east bound. The zoom level cannot be provided and is automatically deduced from the size of the bounding box.
1712
1888
 
1713
1889
  ```ts
1714
1890
  const imageLink = maptilersdk.staticMaps.bounded(
1715
1891
  // The bounding box on Europe
1716
1892
  [
1717
- -24, // west bound (min x)
1893
+ -24, // west bound (min x)
1718
1894
  34.5, // south bound (min y)
1719
- 32, // east bound (max x)
1720
- 71, // north bound (max y)
1895
+ 32, // east bound (max x)
1896
+ 71, // north bound (max y)
1721
1897
  ],
1722
1898
 
1723
1899
  // Options
@@ -1729,38 +1905,37 @@ const imageLink = maptilersdk.staticMaps.bounded(
1729
1905
 
1730
1906
  // Extra space that will add around the bounding box, in percentage
1731
1907
  // (0.1 = 10% is actually the dafault)
1732
- padding: 0.1
1733
- });
1908
+ padding: 0.1,
1909
+ },
1910
+ );
1734
1911
  ```
1735
1912
 
1736
1913
  Since the zoom level cannot be provided, the level of details is dictated by the size of the output image. here is an example:
1737
1914
 
1738
- | `2048 x 2048` | `1024 x 1024` |
1739
- | :-----------: | :-----------: |
1740
- | ![](images/screenshots/static-bounded-europe-2048.jpeg) | ![](images/screenshots/static-bounded-europe-1024.jpeg) |
1915
+ | `2048 x 2048` | `1024 x 1024` |
1916
+ | :-----------------------------------------------------: | :-----------------------------------------------------: |
1917
+ | ![](images/screenshots/static-bounded-europe-2048.jpeg) | ![](images/screenshots/static-bounded-europe-1024.jpeg) |
1741
1918
 
1742
1919
  As you may notice, the geo bounding box could have very different proportions than the output image size. In the following example, we place the very same bounding box around Portugal, which has a this particular strip looking shape. We also add a `path` that repeats exactly the same bounding box to show the difference between the provided bounding box and the final image. We kept the default padding of 10%:
1743
1920
 
1744
-
1745
- | `2048 x 2048` | `1024 x 2048` |
1746
- | :-----------: | :-----------: |
1747
- | ![](images/screenshots/static-bounded-portugal-2048x2048.jpeg) | ![](images/screenshots/static-bounded-portugal-1024x2048.jpeg) |
1748
-
1921
+ | `2048 x 2048` | `1024 x 2048` |
1922
+ | :------------------------------------------------------------: | :------------------------------------------------------------: |
1923
+ | ![](images/screenshots/static-bounded-portugal-2048x2048.jpeg) | ![](images/screenshots/static-bounded-portugal-1024x2048.jpeg) |
1749
1924
 
1750
1925
  Read more about bounded static maps on our official [API documentation](https://docs.maptiler.com/cloud/api/static-maps/#bounds-based-image).
1751
1926
 
1752
- ### Automatic static maps
1753
- As we have seen with centered and bounded maps, providing all the parameters is nice but can be cumbersome for the simplest use cases. This is why MapTiler Cloud also provides static maps that fit automatically whatever you need to place inside: path or markers.
1927
+ ##### Automatic static maps
1928
+
1929
+ As we have seen with centered and bounded maps, providing all the parameters is nice but can be cumbersome for the simplest use cases. This is why MapTiler also provides static maps that fit automatically whatever you need to place inside: path or markers.
1754
1930
 
1755
1931
  In the following example, we are going to load a cycling track recorded by one of our team members in Montreal, Canada. The track, originally a GPX file, was pushed to MapTiler Data and is now made available as a GeoJSON:
1756
1932
 
1757
1933
  ```ts
1758
1934
  // Fetching the GeoJSON
1759
- const bikeTrack = await maptilersdk.data.get('the-id-of-a-bike-track-in-montreal');
1935
+ const bikeTrack = await maptilersdk.data.get("the-id-of-a-bike-track-in-montreal");
1760
1936
 
1761
1937
  // Extracting the track points with the shape [[lng, lat], [lng, lat], ...]
1762
- const trackPoints = bikeTrack.features[0].geometry.coordinates[0]
1763
- .map(p => p.slice(0, 2));
1938
+ const trackPoints = bikeTrack.features[0].geometry.coordinates[0].map((p) => p.slice(0, 2));
1764
1939
 
1765
1940
  const imageLink = maptilersdk.staticMaps.automatic({
1766
1941
  // hiDPI/Retina precision
@@ -1768,7 +1943,7 @@ const imageLink = maptilersdk.staticMaps.automatic({
1768
1943
 
1769
1944
  // A fairly large output image
1770
1945
  width: 2048,
1771
- height: 1024 ,
1946
+ height: 1024,
1772
1947
 
1773
1948
  // A grey style on which the track will pop!
1774
1949
  style: maptilersdk.MapStyle.STREETS.LIGHT,
@@ -1777,10 +1952,10 @@ const imageLink = maptilersdk.staticMaps.automatic({
1777
1952
  path: trackPoints,
1778
1953
 
1779
1954
  // Adding a marker for the starting point, with a custom color (array of shape [lng, lat, color])
1780
- markers: [trackPoints[0][0], trackPoints[0][1], '#0a0'],
1955
+ markers: [trackPoints[0][0], trackPoints[0][1], "#0a0"],
1781
1956
 
1782
1957
  // Showing the track in red
1783
- pathStrokeColor: 'red',
1958
+ pathStrokeColor: "red",
1784
1959
  });
1785
1960
  ```
1786
1961
 
@@ -1788,20 +1963,22 @@ And voila!
1788
1963
 
1789
1964
  ![static map with bike path](images/screenshots/static-with-path.jpeg)
1790
1965
 
1791
- > ๐Ÿ“ฃ *__Note:__* The GeoJSON for this track contains 9380 couples of coordinates, which is a lot! In order to send the track to MapTiler Cloud static maps API, the client simplifies the long paths while keeping a high degree of precision using a very fast [Ramer-Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm).
1966
+ > ๐Ÿ“ฃ _**Note:**_ The GeoJSON for this track contains 9380 couples of coordinates, which is a lot! In order to send the track to MapTiler static maps API, the client simplifies the long paths while keeping a high degree of precision using a very fast [Ramer-Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm).
1792
1967
 
1793
1968
  Read more about bounded static maps on our official [API documentation](https://docs.maptiler.com/cloud/api/static-maps/#auto-fitted-image).
1794
1969
 
1795
- ## ๐Ÿ”๏ธ Elevation
1970
+ #### ๐Ÿ”๏ธ Elevation
1971
+
1796
1972
  With the elevation API, it's possible to get the elevation in meters from any location. It's possible to lookup and compute elevation for a single location, to provide a batch of points, from a GeoJSON LineString or a GeoJSON MultiLineString!
1797
1973
 
1798
- > โ„น๏ธ Under the hood, the elevation API is fueled by MapTiler Cloud's **RGB Terrain** raster tileset, which is a composite of many high-resolution DEMs from all over the world, currated and processed by our geodata team! The same dataset is also fueling our SDK's elevation (3D terrain) and the hillshading we use in many of our styles.
1974
+ > โ„น๏ธ Under the hood, the elevation API is fueled by MapTiler **RGB Terrain** raster tileset, which is a composite of many high-resolution DEMs from all over the world, currated and processed by our geodata team! The same dataset is also fueling our SDK's elevation (3D terrain) and the hillshading we use in many of our styles.
1799
1975
 
1800
- > ๐Ÿ“ฃ Note for **TypeScript** users: internaly, the elevation feature relies on some *GeoJSON* types definitions that can be found in this NPM package: `@types/geojson`. Namely `LineString`, `MultiLineString` and `Position`. It may improve your developer experience to also use these types.
1976
+ > ๐Ÿ“ฃ Note for **TypeScript** users: internaly, the elevation feature relies on some _GeoJSON_ types definitions that can be found in this NPM package: `@types/geojson`. Namely `LineString`, `MultiLineString` and `Position`. It may improve your developer experience to also use these types.
1801
1977
 
1802
1978
  Let's see how to use it:
1803
1979
 
1804
- ### At a single location
1980
+ ##### At a single location
1981
+
1805
1982
  ```ts
1806
1983
  // Not mandatory, but it's to explain where the type comes from:
1807
1984
  import { Position } from "geojson";
@@ -1809,25 +1986,27 @@ import { Position } from "geojson";
1809
1986
  const montBlancPeak: Position = [6.864884, 45.832743];
1810
1987
  const elevatedPosition = await maptilersdk.elevation.at(montBlancPeak);
1811
1988
  ```
1812
- The returned value is also a *GeoJSON* `Position` array, but with three elements: `[lng, lat, elevation]`.
1989
+
1990
+ The returned value is also a _GeoJSON_ `Position` array, but with three elements: `[lng, lat, elevation]`.
1813
1991
 
1814
1992
  Read more about elevation lookup for a single location in our [official documentation](https://docs.maptiler.com/client-js/elevation/#at).
1815
1993
 
1816
- ### Batch mode
1994
+ ##### Batch mode
1995
+
1817
1996
  ```ts
1818
1997
  // Not mandatory, but it's to explain where the type comes from:
1819
1998
  import { Position } from "geojson";
1820
1999
 
1821
2000
  const peaks: Position[] = [
1822
- [6.864884, 45.832743], // Mont Blanc, Alps
1823
- [86.9250, 27.9881], // Mount Everest, Himalayas
1824
- [-70.0109, -32.6532], // Aconcagua, Andes
1825
- [-151.0064, 63.0695], // Denali, Alaska
1826
- [37.3556, -3.0674], // Mount Kilimanjaro
1827
- [42.4453, 43.3499], // Mount Elbrus, Caucasus
1828
- [137.1595, -4.0784], // Puncak Jaya, Sudirman Range
1829
- [-140.4055, 60.5672], // Mount Logan, Saint Elias Mountains
1830
- [138.73111, 35.358055], // Mount Fuji
2001
+ [6.864884, 45.832743], // Mont Blanc, Alps
2002
+ [86.925, 27.9881], // Mount Everest, Himalayas
2003
+ [-70.0109, -32.6532], // Aconcagua, Andes
2004
+ [-151.0064, 63.0695], // Denali, Alaska
2005
+ [37.3556, -3.0674], // Mount Kilimanjaro
2006
+ [42.4453, 43.3499], // Mount Elbrus, Caucasus
2007
+ [137.1595, -4.0784], // Puncak Jaya, Sudirman Range
2008
+ [-140.4055, 60.5672], // Mount Logan, Saint Elias Mountains
2009
+ [138.73111, 35.358055], // Mount Fuji
1831
2010
  ];
1832
2011
 
1833
2012
  const elevatedPeaks = await maptilersdk.elevation.batch(peaks);
@@ -1835,17 +2014,21 @@ const elevatedPeaks = await maptilersdk.elevation.batch(peaks);
1835
2014
 
1836
2015
  Read more about elevation lookup for a batch of locations in our [official documentation](https://docs.maptiler.com/client-js/elevation/#batch).
1837
2016
 
1838
- ### From a GeoJSON LineString
1839
- In the *GeoJSON* LineString case, it clones the entire structure and the position arrays of the clone will contain three elements: `[lng, lat, elevation]`. The original LineString is not mutated nor pointed at.
2017
+ ##### From a GeoJSON LineString
2018
+
2019
+ In the _GeoJSON_ LineString case, it clones the entire structure and the position arrays of the clone will contain three elements: `[lng, lat, elevation]`. The original LineString is not mutated nor pointed at.
1840
2020
 
1841
2021
  ```ts
1842
2022
  // Not mandatory, but it's to explain where the type comes from:
1843
2023
  import { LineString } from "geojson";
1844
2024
 
1845
-
1846
2025
  const someLineString: LineString = {
1847
2026
  type: "LineString",
1848
- coordinates: [[6.864884, 45.832743], [86.9250, 27.9881], [-70.0109, -32.6532]]
2027
+ coordinates: [
2028
+ [6.864884, 45.832743],
2029
+ [86.925, 27.9881],
2030
+ [-70.0109, -32.6532],
2031
+ ],
1849
2032
  };
1850
2033
 
1851
2034
  const someElevatedLineString = await maptilersdk.elevation.fromLineString(someLineString);
@@ -1854,21 +2037,33 @@ const someElevatedLineString = await maptilersdk.elevation.fromLineString(someLi
1854
2037
 
1855
2038
  Read more about elevation lookup for a `LineString` in our [official documentation](https://docs.maptiler.com/client-js/elevation/#linestring).
1856
2039
 
1857
- ### From a GeoJSON MultiLineString
1858
- In the *GeoJSON* MultiLineString case, it clones the entire structure and the position arrays of the clone will contain three elements: `[lng, lat, elevation]`. The original MultiLineString is not mutated nor pointed at.
2040
+ ##### From a GeoJSON MultiLineString
2041
+
2042
+ In the _GeoJSON_ MultiLineString case, it clones the entire structure and the position arrays of the clone will contain three elements: `[lng, lat, elevation]`. The original MultiLineString is not mutated nor pointed at.
1859
2043
 
1860
2044
  ```ts
1861
2045
  // Not mandatory, but it's to explain where the type comes from:
1862
2046
  import { MultiLineString } from "geojson";
1863
2047
 
1864
-
1865
2048
  const someMultiLineString: MultiLineString = {
1866
2049
  type: "LineString",
1867
2050
  coordinates: [
1868
- [[6.864884, 45.832743], [86.9250, 27.9881], [-70.0109, -32.6532]],
1869
- [[-151.0064, 63.0695], [37.3556, -3.0674], [42.4453, 43.3499]],
1870
- [[137.1595, -4.0784], [-140.4055, 60.5672], [138.73111, 35.358055]],
1871
- ]
2051
+ [
2052
+ [6.864884, 45.832743],
2053
+ [86.925, 27.9881],
2054
+ [-70.0109, -32.6532],
2055
+ ],
2056
+ [
2057
+ [-151.0064, 63.0695],
2058
+ [37.3556, -3.0674],
2059
+ [42.4453, 43.3499],
2060
+ ],
2061
+ [
2062
+ [137.1595, -4.0784],
2063
+ [-140.4055, 60.5672],
2064
+ [138.73111, 35.358055],
2065
+ ],
2066
+ ],
1872
2067
  };
1873
2068
 
1874
2069
  const someElevatedMultiLineString = await maptilersdk.elevation.fromMultiLineString(someMultiLineString);
@@ -1877,13 +2072,15 @@ const someElevatedMultiLineString = await maptilersdk.elevation.fromMultiLineStr
1877
2072
 
1878
2073
  Read more about elevation lookup for a `MultiLineString` in our [official documentation](https://docs.maptiler.com/client-js/elevation/#multilinestring).
1879
2074
 
1880
- ### Caching
2075
+ ##### Caching
2076
+
1881
2077
  In order to increase performance while reducing unnecessary elevation data fetching, the elevation tiles are cached. This is particularly important for the LineString and MultiLineString lookups because GeoJSON data are likely to come from a recorded or planned route, where position points are very close to one another.
1882
2078
 
1883
- ## ๐Ÿงฎ Math
1884
- Some operations can be fairly repetitive: WGS84 to Mercator, WGS84 to *zxy* tile index, the distance between two points with the Haversine formula, etc. As a result, we have decided to expose a `math` package providing the most recurrent feature, so that, just like us at MapTiler, you no longer need to copy-paste the same function from your previous project!
2079
+ #### ๐Ÿงฎ Math
1885
2080
 
1886
- The `math` package differs from the others in the sense that it does not call the MapTiler Cloud API, instead, it operates fully on the machine it's running on.
2081
+ Some operations can be fairly repetitive: WGS84 to Mercator, WGS84 to _zxy_ tile index, the distance between two points with the Haversine formula, etc. As a result, we have decided to expose a `math` package providing the most recurrent feature, so that, just like us at MapTiler, you no longer need to copy-paste the same function from your previous project!
2082
+
2083
+ The `math` package differs from the others in the sense that it does not call the MapTiler API, instead, it operates fully on the machine it's running on.
1887
2084
 
1888
2085
  Here are some examples:
1889
2086
 
@@ -1921,10 +2118,12 @@ const tileXY = maptilersdk.math.wgs84ToTileIndex(montBlancPeakWgs84, 14);
1921
2118
 
1922
2119
  Please find out more about the math package in our [official documentation](https://docs.maptiler.com/client-js/math):
1923
2120
 
1924
- # Telemetry
2121
+ ### Telemetry
2122
+
1925
2123
  The telemetry is very valuable to the team at MapTiler because it shares information about where to add the extra effort. It also helps spotting some incompatibility issues that may arise between the SDK and a specific version of a module.
1926
2124
 
1927
2125
  It consists in sending metrics about usage of the following features:
2126
+
1928
2127
  - SDK version [string]
1929
2128
  - API key [string]
1930
2129
  - MapTiler sesion ID (if opted-in) [string]
@@ -1938,7 +2137,66 @@ In addition, each official module will be added to a list, alongside its version
1938
2137
  Telemetry is enabled by default but can be opted-out by setting `telemetry` value of `config` to `false`.
1939
2138
 
1940
2139
  ```ts
1941
- import * as maptilersdk from '@maptiler/sdk';
2140
+ import * as maptilersdk from "@maptiler/sdk";
1942
2141
 
1943
2142
  maptilersdk.config.telemetry = false;
1944
2143
  ```
2144
+
2145
+ <br>
2146
+
2147
+ ## Migration Guide
2148
+
2149
+ - [How to migrate/switch from Mapbox to MapTiler](https://docs.maptiler.com/sdk-js/examples/switch-from-mapbox/)
2150
+ - [How to migrate/switch from MapLibre to MapTiler](https://docs.maptiler.com/sdk-js/examples/switch-from-maplibre/)
2151
+
2152
+ <br>
2153
+
2154
+ ## ๐Ÿ’ฌ Support
2155
+
2156
+ - ๐Ÿ“š [Documentation](https://docs.maptiler.com/sdk-js/) - Comprehensive guides and API reference
2157
+ - โœ‰๏ธ [Contact us](https://maptiler.com/contact) - Get in touch or submit a request
2158
+ - ๐Ÿฆ [Twitter/X](https://twitter.com/maptiler) - Follow us for updates
2159
+
2160
+ <br>
2161
+
2162
+ ---
2163
+
2164
+ <br>
2165
+
2166
+ ## ๐Ÿค Contributing
2167
+
2168
+ We love contributions from the community! Whether it's bug reports, feature requests, or pull requests, all contributions are welcome:
2169
+
2170
+ - Fork the repository and create your branch fromย `main`
2171
+ - If you've added code, add tests that cover your changes
2172
+ - Ensure your code follows our style guidelines
2173
+ - Give your pull request a clear, descriptive summary
2174
+ - Open a Pull Request with a comprehensive description
2175
+
2176
+ <br>
2177
+
2178
+ ## ๐Ÿ“„ License
2179
+
2180
+ This project is licensed under the BSD 3-Clause License โ€“ see theย [LICENSE](./LICENSE)ย file for details.
2181
+
2182
+ <br>
2183
+
2184
+ ## ๐Ÿ™ Acknowledgements
2185
+
2186
+ This project is built on the shoulders of giants:
2187
+
2188
+ - [MapLibre GL JS](https://maplibre.org/)ย โ€“ The open-source mapping library
2189
+ - [OpenStreetMap](https://openstreetmap.org/)ย โ€“ The free wiki world map
2190
+
2191
+ <br>
2192
+
2193
+ <p align="center" style="margin-top:20px;margin-bottom:20px;"> <a href="https://cloud.maptiler.com/account/keys/" style="display:inline-block;padding:12px 32px;background:#F2F6FF;color:#000;font-weight:bold;border-radius:6px;text-decoration:none;"> Get Your API Key <sup style="background-color:#0000ff;color:#fff;padding:2px 6px;font-size:12px;border-radius:3px;">FREE</sup><br /> <span style="font-size:90%;font-weight:400;">Start building with 100,000 free map loads per month ใƒป No credit card required.</span> </a> </p>
2194
+
2195
+ <br>
2196
+
2197
+ <p align="center"> ๐Ÿ’œ Made with love by the <a href="https://www.maptiler.com/">MapTiler</a> team <br />
2198
+ <p align="center">
2199
+ <a href="https://www.maptiler.com/interactive-maps/">Website</a> โ€ข
2200
+ <a href="https://docs.maptiler.com/sdk-js/">Documentation</a> โ€ข
2201
+ <a href="https://github.com/maptiler/maptiler-sdk-js/">GitHub</a>
2202
+ </p>