@maptiler/sdk 1.1.2 → 1.2.1
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/.eslintrc.cjs +15 -5
- package/.github/pull_request_template.md +11 -0
- package/.github/workflows/format-lint.yml +24 -0
- package/CHANGELOG.md +105 -51
- package/colorramp.md +93 -0
- package/dist/maptiler-sdk.d.ts +1226 -124
- package/dist/maptiler-sdk.min.mjs +3 -1
- package/dist/maptiler-sdk.mjs +3582 -483
- package/dist/maptiler-sdk.mjs.map +1 -1
- package/dist/maptiler-sdk.umd.js +4524 -863
- package/dist/maptiler-sdk.umd.js.map +1 -1
- package/dist/maptiler-sdk.umd.min.js +51 -49
- package/package.json +27 -13
- package/readme.md +493 -5
- package/rollup.config.js +2 -16
- package/src/Map.ts +515 -359
- package/src/MaptilerGeolocateControl.ts +23 -20
- package/src/MaptilerLogoControl.ts +3 -3
- package/src/MaptilerNavigationControl.ts +9 -6
- package/src/MaptilerTerrainControl.ts +15 -14
- package/src/Minimap.ts +373 -0
- package/src/Point.ts +3 -5
- package/src/colorramp.ts +1216 -0
- package/src/config.ts +4 -3
- package/src/converters/index.ts +1 -0
- package/src/converters/xml.ts +681 -0
- package/src/defaults.ts +1 -1
- package/src/helpers/index.ts +27 -0
- package/src/helpers/stylehelper.ts +395 -0
- package/src/helpers/vectorlayerhelpers.ts +1511 -0
- package/src/index.ts +90 -121
- package/src/language.ts +116 -79
- package/src/mapstyle.ts +4 -2
- package/src/tools.ts +68 -16
- package/tsconfig.json +8 -5
- package/vite.config.ts +10 -0
- package/demos/maptiler-sdk.css +0 -147
- package/demos/maptiler-sdk.umd.js +0 -4041
- package/demos/mountain.html +0 -67
- package/demos/simple.html +0 -67
- package/demos/transform-request.html +0 -81
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maptiler/sdk",
|
|
3
|
-
"version": "1.1
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "The Javascript & TypeScript map SDK tailored for MapTiler Cloud",
|
|
5
5
|
"module": "dist/maptiler-sdk.mjs",
|
|
6
6
|
"types": "dist/maptiler-sdk.d.ts",
|
|
@@ -8,10 +8,14 @@
|
|
|
8
8
|
"type": "module",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"import": "./dist/maptiler-sdk.mjs"
|
|
11
|
+
"import": "./dist/maptiler-sdk.mjs",
|
|
12
|
+
"types": "./dist/maptiler-sdk.d.ts"
|
|
12
13
|
},
|
|
13
14
|
"./dist/maptiler-sdk.css": {
|
|
14
15
|
"import": "./dist/maptiler-sdk.css"
|
|
16
|
+
},
|
|
17
|
+
"./style.css": {
|
|
18
|
+
"import": "./dist/maptiler-sdk.css"
|
|
15
19
|
}
|
|
16
20
|
},
|
|
17
21
|
"keywords": [
|
|
@@ -32,20 +36,28 @@
|
|
|
32
36
|
"scripts": {
|
|
33
37
|
"build": "rm -rf dist/* && NODE_ENV=production rollup -c",
|
|
34
38
|
"dev": "rm -rf dist/* && NODE_ENV=development rollup -c -w",
|
|
35
|
-
"format": "prettier --write \"src/**/*.{js,ts,tsx}\"",
|
|
36
|
-
"
|
|
39
|
+
"format:fix": "prettier --write \"src/**/*.{js,ts,tsx}\"",
|
|
40
|
+
"format": "prettier -c \"src/**/*.{js,ts,tsx}\"",
|
|
41
|
+
"lint:fix": "eslint --fix \"src/**/*.{js,ts}\"",
|
|
42
|
+
"lint": "eslint \"src/**/*.{js,ts}\"",
|
|
37
43
|
"doc": "rm -rf docs/* && typedoc --out docs && cp -r images docs/",
|
|
38
|
-
"prepare": "npm run format && npm run lint && npm run build && npm run
|
|
44
|
+
"prepare": "npm run format:fix && npm run lint:fix && npm run build && npm run test",
|
|
45
|
+
"test:dev": "vitest dev",
|
|
46
|
+
"test": "vitest run"
|
|
39
47
|
},
|
|
40
48
|
"author": "MapTiler",
|
|
41
49
|
"devDependencies": {
|
|
42
50
|
"@rollup/plugin-commonjs": "^24.1.0",
|
|
43
51
|
"@rollup/plugin-json": "^6.0.0",
|
|
44
52
|
"@rollup/plugin-node-resolve": "^15.0.2",
|
|
45
|
-
"@
|
|
46
|
-
"@
|
|
47
|
-
"eslint": "^
|
|
48
|
-
"
|
|
53
|
+
"@types/uuid": "^9.0.2",
|
|
54
|
+
"@types/xmldom": "^0.1.31",
|
|
55
|
+
"@typescript-eslint/eslint-plugin": "^6.9.0",
|
|
56
|
+
"@typescript-eslint/parser": "^6.9.0",
|
|
57
|
+
"eslint": "^8.52.0",
|
|
58
|
+
"eslint-config-prettier": "^9.0.0",
|
|
59
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
60
|
+
"prettier": "^3.0.3",
|
|
49
61
|
"rollup": "^3.20.6",
|
|
50
62
|
"rollup-plugin-copy-merge": "^1.0.0",
|
|
51
63
|
"rollup-plugin-dts": "^5.3.0",
|
|
@@ -56,14 +68,16 @@
|
|
|
56
68
|
"rollup-plugin-swc": "^0.2.1",
|
|
57
69
|
"serve": "^14.2.0",
|
|
58
70
|
"terser": "^5.17.1",
|
|
59
|
-
"typedoc": "^0.24.
|
|
60
|
-
"typescript": "^5.
|
|
71
|
+
"typedoc": "^0.24.8",
|
|
72
|
+
"typescript": "^5.1.6",
|
|
73
|
+
"vitest": "^0.34.2",
|
|
74
|
+
"xmldom": "^0.6.0"
|
|
61
75
|
},
|
|
62
76
|
"dependencies": {
|
|
63
|
-
"@maptiler/client": "^1.
|
|
77
|
+
"@maptiler/client": "^1.8.0",
|
|
64
78
|
"events": "^3.3.0",
|
|
65
79
|
"js-base64": "^3.7.4",
|
|
66
|
-
"maplibre-gl": "3.
|
|
80
|
+
"maplibre-gl": "3.6.2",
|
|
67
81
|
"uuid": "^9.0.0"
|
|
68
82
|
}
|
|
69
83
|
}
|
package/readme.md
CHANGED
|
@@ -392,16 +392,32 @@ Languages that are written right-to-left such as arabic and hebrew are fully sup
|
|
|
392
392
|
|
|
393
393
|
# Custom Events and Map Lifecycle
|
|
394
394
|
## Events
|
|
395
|
-
|
|
395
|
+
### The `ready` event
|
|
396
|
+
The `ready` event happens just after the `load` event but waits that all the controls managed by the `Map` constructor are dealt with, some having an asynchronous logic to set up.
|
|
397
|
+
Since the `ready` event waits that all the basic controls are nicely positioned, it is **safer** to use `ready` than `load` if you plan to add other custom comtrols with the `.addControl()` method.
|
|
396
398
|
|
|
397
|
-
|
|
399
|
+
This event works exactely the same way as `load` and you can safely replace those by `"ready"`. Here is a usage example:
|
|
400
|
+
|
|
401
|
+
```js
|
|
402
|
+
const map = new maptilersdk.Map({
|
|
403
|
+
container: "map-container",
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
map.on("ready", (evt) => {
|
|
407
|
+
const terrainControl = new maptilersdk.MaptilerTerrainControl();
|
|
408
|
+
map.addControl(terrainControl);
|
|
409
|
+
})
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### The `loadWithTerrain` event
|
|
413
|
+
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.
|
|
398
414
|
|
|
399
415
|
**Why a new event?**
|
|
400
416
|
When a map is instanciated 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.
|
|
401
|
-
Relying on the `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.
|
|
417
|
+
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.
|
|
402
418
|
|
|
403
419
|
## Lifecycle Methods
|
|
404
|
-
The events `load` 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
|
|
420
|
+
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:
|
|
405
421
|
|
|
406
422
|
- Classic: with a callback on the `load` event:
|
|
407
423
|
```ts
|
|
@@ -494,9 +510,352 @@ async function init() {
|
|
|
494
510
|
}
|
|
495
511
|
```
|
|
496
512
|
|
|
513
|
+
And finally, the lifecycle method corresponding to the `ready` event:
|
|
514
|
+
- Classic: with a callback on the `ready` event:
|
|
515
|
+
```ts
|
|
516
|
+
function init() {
|
|
517
|
+
|
|
518
|
+
const map = new Map({
|
|
519
|
+
container,
|
|
520
|
+
center: [2.34804, 48.85439], // Paris, France
|
|
521
|
+
zoom: 14,
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
// We wait for the event.
|
|
525
|
+
// Once triggered, the callback is ranin it's own scope.
|
|
526
|
+
map.on("ready", (evt) => {
|
|
527
|
+
// Adding a data source
|
|
528
|
+
map.addSource('my-gps-track-source', {
|
|
529
|
+
type: "geojson",
|
|
530
|
+
data: "https://example.com/some-gps-track.geojson",
|
|
531
|
+
});
|
|
532
|
+
})
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
- Modern: with a promise returned by the method `.onReadyAsync()`, used in an `async` function:
|
|
537
|
+
```ts
|
|
538
|
+
async function init() {
|
|
539
|
+
|
|
540
|
+
const map = new Map({
|
|
541
|
+
container,
|
|
542
|
+
center: [2.34804, 48.85439], // Paris, France
|
|
543
|
+
zoom: 14,
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// We wait for the promise to resolve.
|
|
547
|
+
// Once triggered, the rest of the init function runs
|
|
548
|
+
await map.onReadyAsync();
|
|
549
|
+
|
|
550
|
+
// Adding a data source
|
|
551
|
+
map.addSource('my-gps-track-source', {
|
|
552
|
+
type: "geojson",
|
|
553
|
+
data: "https://example.com/some-gps-track.geojson",
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
```
|
|
557
|
+
|
|
497
558
|
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.
|
|
498
559
|
|
|
499
|
-
> 📣 *__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` and `loadWithTerrain` events.
|
|
560
|
+
> 📣 *__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.
|
|
561
|
+
|
|
562
|
+
# Color Ramps
|
|
563
|
+
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 usualy additional colors within the range.
|
|
564
|
+
|
|
565
|
+
Color ramps are super useful to represent numerical data in a visual way: the temperature, the population density, the average commute time, etc.
|
|
566
|
+
|
|
567
|
+
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:
|
|
568
|
+
|
|
569
|
+

|
|
570
|
+
|
|
571
|
+
To use an already existing color ramp and access some of its values:
|
|
572
|
+
```ts
|
|
573
|
+
import { ColorRampCollection } from "@maptiler/sdk";
|
|
574
|
+
|
|
575
|
+
// The TURBO color ramp, just like all the built-ins, is defined in [0, 1],
|
|
576
|
+
// but we can rescale it to fit the range of temperature [-18, 38]°C (equivalent to [0, 100]F)
|
|
577
|
+
// and this actually creates a clone of the original TURBO
|
|
578
|
+
const temperatureTurbo = ColorRampCollection.TURBO.scale(-18, 38);
|
|
579
|
+
|
|
580
|
+
// What's the color at 0°C (or 32F) ?
|
|
581
|
+
const zeroColor = temperatureTurbo.getColor(0);
|
|
582
|
+
// The color is an array: [45, 218, 189, 255]
|
|
583
|
+
|
|
584
|
+
// Alternatively, we can ask for the hex color:
|
|
585
|
+
const zeroColorHex = temperatureTurbo.getColorHex(0);
|
|
586
|
+
// The color is a string: "#2ddabdff"
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
Creating a new one consists in 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:
|
|
590
|
+
|
|
591
|
+
```ts
|
|
592
|
+
import { ColorRamp } from "@maptiler/sdk";
|
|
593
|
+
|
|
594
|
+
const myCustomRamp = new ColorRamp({
|
|
595
|
+
stops: [
|
|
596
|
+
{ value: 0, color: [68, 1, 84] },
|
|
597
|
+
{ value: 13, color: [71, 44, 122] },
|
|
598
|
+
{ value: 25, color: [59, 81, 139] },
|
|
599
|
+
{ value: 38, color: [44, 113, 142] },
|
|
600
|
+
{ value: 5, color: [33, 144, 141] },
|
|
601
|
+
{ value: 63, color: [39, 173, 129] },
|
|
602
|
+
{ value: 75, color: [92, 200, 99] },
|
|
603
|
+
{ value: 88, color: [170, 220, 50] },
|
|
604
|
+
{ value: 100, color: [253, 231, 37] },
|
|
605
|
+
]
|
|
606
|
+
});
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
When defining a new *ramp*, the colors can be a RGB array (`[number, number, number]`) or a RGBA array (`[number, number, number, number]`).
|
|
610
|
+
|
|
611
|
+
Many methods are available on color ramps, such as getting a `<canvas>` element of it, rescale it, flip it or [resample it in a non-linear way](colorramp.md). Read more on [our reference page](https://docs.maptiler.com/sdk-js/api/map/) and have a look at our [examples](https://docs.maptiler.com/sdk-js/examples/?q=colorramp) to see how they work.
|
|
612
|
+
|
|
613
|
+
|
|
614
|
+
# Vector Layer Helpers
|
|
615
|
+
**Let's make vector layers easy!** Originaly, 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!** 🖋️
|
|
616
|
+

|
|
617
|
+
|
|
618
|
+
## Shared logic
|
|
619
|
+
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!
|
|
620
|
+
|
|
621
|
+
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.
|
|
622
|
+
|
|
623
|
+
All the helpers are made avaialable under the `helpers` object. If you are using ES Modules, this is how you access them:
|
|
624
|
+
```ts
|
|
625
|
+
import { Map, helpers } from "@maptiler/sdk";
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
If you are using the UMD bundle of the SDK, for example from our CDN, you will find the `helpers` with:
|
|
629
|
+
```js
|
|
630
|
+
maptilersdk.helpers
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
**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*.
|
|
634
|
+
|
|
635
|
+
In addition to easy styling, helper's datasource can be:
|
|
636
|
+
- a URL to a geoJSON file or its string content
|
|
637
|
+
- a URL to a GPX or KML file (only for the polyline helper) or its string content
|
|
638
|
+
- a UUID of a MapTiler Cloud dataset
|
|
639
|
+
|
|
640
|
+
### Multiple Layers
|
|
641
|
+
The key design principle of these vector layers helpers is **it's easy to make what you want**, which is very different from **making MapLibre easier to use**.
|
|
642
|
+
|
|
643
|
+
> 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.
|
|
644
|
+
|
|
645
|
+
With the polyline helper, you just say if you want an outline and specify its size (or even a zoom dependant size) and everything is handled for you. As a result, calling the method `helpers.addPolyline` will return an object with **multiple IDs**: ID of the top/main layer, ID of the outline layer (could be `null`) and the ID of the data source. This makes further layer and source manipulation possible.
|
|
646
|
+
|
|
647
|
+
### Input
|
|
648
|
+
|
|
649
|
+
The vector layer helper also share some *I/O* logic: each of them can take many options but a subset of them is common across all the helpers:
|
|
650
|
+
|
|
651
|
+
```ts
|
|
652
|
+
/**
|
|
653
|
+
* A geojson Feature collection or a URL to a geojson or the UUID of a MapTiler Cloud dataset.
|
|
654
|
+
*/
|
|
655
|
+
data: FeatureCollection | string;
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* ID to give to the layer.
|
|
659
|
+
* If not provided, an auto-generated ID of the for "maptiler-layer-xxxxxx" will be auto-generated,
|
|
660
|
+
* with "xxxxxx" being a random string.
|
|
661
|
+
*/
|
|
662
|
+
layerId?: string;
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* ID to give to the geojson source.
|
|
666
|
+
* If not provided, an auto-generated ID of the for "maptiler-source-xxxxxx" will be auto-generated,
|
|
667
|
+
* with "xxxxxx" being a random string.
|
|
668
|
+
*/
|
|
669
|
+
sourceId?: string;
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* The ID of an existing layer to insert the new layer before, resulting in the new layer appearing
|
|
673
|
+
* visually beneath the existing layer. If this argument is not specified, the layer will be appended
|
|
674
|
+
* to the end of the layers array and appear visually above all other layers.
|
|
675
|
+
*/
|
|
676
|
+
beforeId?: string;
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Zoom level at which it starts to show.
|
|
680
|
+
* Default: `0`
|
|
681
|
+
*/
|
|
682
|
+
minzoom?: number;
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Zoom level after which it no longer show.
|
|
686
|
+
* Default: `22`
|
|
687
|
+
*/
|
|
688
|
+
maxzoom?: number;
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
## Polyline Layer Helper
|
|
694
|
+
The method `helpers.addPolyline` is not only compaptible 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.
|
|
695
|
+
|
|
696
|
+
here is the minimal usage, with the default line width and a random color (withing a selected list):
|
|
697
|
+
```ts
|
|
698
|
+
helpers.addPolyline(map, {
|
|
699
|
+
// A URL, relative or absolute
|
|
700
|
+
data: "some-trace.geojson",
|
|
701
|
+
});
|
|
702
|
+
```
|
|
703
|
+

|
|
704
|
+
|
|
705
|
+
We can add many options, such a a specific color, a custom width or a dash pattern, this time sourcing the data from MapTiler Cloud, using the UUID of a dataset:
|
|
706
|
+
```ts
|
|
707
|
+
helpers.addPolyline(map, {
|
|
708
|
+
data: "74003ba7-215a-4b7e-8e26-5bbe3aa70b05",
|
|
709
|
+
lineColor: "#FF6666",
|
|
710
|
+
lineWidth: 4,
|
|
711
|
+
lineDashArray: "____ _ ",
|
|
712
|
+
lineCap: "butt",
|
|
713
|
+
});
|
|
714
|
+
```
|
|
715
|
+

|
|
716
|
+
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!
|
|
717
|
+
|
|
718
|
+
Adding an outline is also pretty straightforward:
|
|
719
|
+
```ts
|
|
720
|
+
helpers.addPolyline(map, {
|
|
721
|
+
data: "74003ba7-215a-4b7e-8e26-5bbe3aa70b05",
|
|
722
|
+
lineColor: "#880000",
|
|
723
|
+
outline: true,
|
|
724
|
+
});
|
|
725
|
+
```
|
|
726
|
+

|
|
727
|
+
|
|
728
|
+
Endless possibilities, what about a glowing wire?
|
|
729
|
+
```ts
|
|
730
|
+
helpers.addPolyline(map, {
|
|
731
|
+
data: "74003ba7-215a-4b7e-8e26-5bbe3aa70b05",
|
|
732
|
+
lineColor: "#fff",
|
|
733
|
+
lineWidth: 1,
|
|
734
|
+
outline: true,
|
|
735
|
+
outlineColor: "#ca57ff",
|
|
736
|
+
outlineWidth: 2,
|
|
737
|
+
outlineWidth: 10,
|
|
738
|
+
outlineBlur: 10,
|
|
739
|
+
outlineOpacity: 0.5,
|
|
740
|
+
});
|
|
741
|
+
```
|
|
742
|
+

|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
All the other options are documented on a [our reference page](https://docs.maptiler.com/sdk-js/api/map/) and more examples are available [here](https://docs.maptiler.com/sdk-js/examples/).
|
|
746
|
+
|
|
747
|
+
## Polygon Layer Helper
|
|
748
|
+
The polygon helper makes it easy to create vector layers that contain polygons, whether they are *multi*polylons, *holed*polygons or just simple polygons. Whenever it's possible and it makes sense, we use the same terminology across the different helpers.
|
|
749
|
+
|
|
750
|
+
Here is a minimalist example, with a half-transparent polygon of Switzerland, from a local file:
|
|
751
|
+
|
|
752
|
+
```ts
|
|
753
|
+
helpers.addPolygon(map, {
|
|
754
|
+
data: "switzerland.geojson",
|
|
755
|
+
fillOpacity: 0.5,
|
|
756
|
+
});
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
Again, if no color is specified, a random one from a list is being picked:
|
|
760
|
+

|
|
761
|
+
|
|
762
|
+
Plenty of options are available to create the interesting thematic visualizations:
|
|
763
|
+
|
|
764
|
+
```ts
|
|
765
|
+
helpers.addPolygon(map, {
|
|
766
|
+
data: "switzerland.geojson",
|
|
767
|
+
pattern: "cheese512.png",
|
|
768
|
+
outline: true,
|
|
769
|
+
outlineWidth: 3,
|
|
770
|
+
outlineColor: "white",
|
|
771
|
+
outlineDashArray: "_ ",
|
|
772
|
+
fillOpacity: 0.7,
|
|
773
|
+
});
|
|
774
|
+
```
|
|
775
|
+

|
|
776
|
+
|
|
777
|
+
All the other options are documented on a [our reference page](https://docs.maptiler.com/sdk-js/api/map/) and more examples are available [here](https://docs.maptiler.com/sdk-js/examples/).
|
|
778
|
+
|
|
779
|
+
## Point Layer Helper
|
|
780
|
+
A point visualisation may appear like the simplest of all, but we noticed this is where people get the most creative: cluster, data-drive 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.
|
|
781
|
+
|
|
782
|
+
Here is the simplest example, with a dataset loaded from a local file:
|
|
783
|
+
```ts
|
|
784
|
+
helpers.addPoint(map, {
|
|
785
|
+
data: "public-schools.geojson",
|
|
786
|
+
})
|
|
787
|
+
```
|
|
788
|
+
if no color is specified, a random color is used and the default radius is ramped over the zoom level:
|
|
789
|
+

|
|
790
|
+
|
|
791
|
+
Here is the same dataset, but with *point clustering* enabled:
|
|
792
|
+
```ts
|
|
793
|
+
helpers.addPoint(map, {
|
|
794
|
+
data: "public-schools.geojson",
|
|
795
|
+
cluster: true,
|
|
796
|
+
});
|
|
797
|
+
```
|
|
798
|
+
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`):
|
|
799
|
+

|
|
800
|
+
|
|
801
|
+
With the point helper, it's also possible to adapt the color and theradius 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:
|
|
802
|
+
```ts
|
|
803
|
+
helpers.addPoint(map, {
|
|
804
|
+
data: "public-schools.geojson",
|
|
805
|
+
property: "students",
|
|
806
|
+
pointColor: ColorRampCollection.PORTLAND.scale(200, 2000).resample("ease-out-sqrt"),
|
|
807
|
+
pointOpacity: 0.8,
|
|
808
|
+
minPointRadius: 6,
|
|
809
|
+
maxPointRadius: 30,
|
|
810
|
+
showLabel: true,
|
|
811
|
+
zoomCompensation: false,
|
|
812
|
+
})
|
|
813
|
+
```
|
|
814
|
+

|
|
815
|
+
|
|
816
|
+
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 begining 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 colors in a non-linear fashion, following the `"ease-out-sqrt"` method (read **Color Ramps** section above for more info).
|
|
817
|
+
|
|
818
|
+
All the other options are documented on a [our reference page](https://docs.maptiler.com/sdk-js/api/map/) and more examples are available [here](https://docs.maptiler.com/sdk-js/examples/).
|
|
819
|
+
|
|
820
|
+
## Heatmap Layer Helper
|
|
821
|
+
The heatmap layer is a great alternative for visualizing a collection of sparse data, but they 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!**
|
|
822
|
+
|
|
823
|
+
Here is a minimalist example, using the default built-in `TURBO` color ramp:
|
|
824
|
+
```ts
|
|
825
|
+
helpers.addHeatmap(map, {
|
|
826
|
+
data: "public-schools.geojson",
|
|
827
|
+
});
|
|
828
|
+
```
|
|
829
|
+

|
|
830
|
+
|
|
831
|
+
Some visualisations are created with a fixed geographic extent or zoom level in mind, whether it's a survey at the scale of a single neigbohood, or statitics at country scale. In this case, we want to tailor the color, radius, weight and intensity of the heatmap blobs exactely for this precise settings. In the following example, we disable the *zoom compensation* to make sure radii and intensity is never zoom-dependant:
|
|
832
|
+
```ts
|
|
833
|
+
helpers.addHeatmap(map, {
|
|
834
|
+
data: "public-schools.geojson",
|
|
835
|
+
property: "students",
|
|
836
|
+
// radius: how wide are the blobs
|
|
837
|
+
radius: [
|
|
838
|
+
{propertyValue: 100, value: 15},
|
|
839
|
+
{propertyValue: 800, value: 50},
|
|
840
|
+
],
|
|
841
|
+
// weight: how intense are the blob, as fueled by a property
|
|
842
|
+
weight: [
|
|
843
|
+
{propertyValue: 100, value: 0.1},
|
|
844
|
+
{propertyValue: 800, value: 1},
|
|
845
|
+
],
|
|
846
|
+
// A custom color ramp, must be used with its default interval of [0, 1]
|
|
847
|
+
colorRamp: ColorRampCollection.MAGMA,
|
|
848
|
+
zoomCompensation: false,
|
|
849
|
+
opacity: 0.6,
|
|
850
|
+
// a global factor applied to all the blobs, regardless of the property or zoom
|
|
851
|
+
intensity: 1.2,
|
|
852
|
+
});
|
|
853
|
+
```
|
|
854
|
+

|
|
855
|
+
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.
|
|
856
|
+
|
|
857
|
+
All the other options are documented on a [our reference page](https://docs.maptiler.com/sdk-js/api/map/) and more examples are available [here](https://docs.maptiler.com/sdk-js/examples/).
|
|
858
|
+
|
|
500
859
|
|
|
501
860
|
# Easy access to MapTiler Cloud API
|
|
502
861
|
Our map SDK is not only about maps! We also provide plenty of wrapper to our API calls!
|
|
@@ -763,3 +1122,132 @@ And voila!
|
|
|
763
1122
|
> 📣 *__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).
|
|
764
1123
|
|
|
765
1124
|
Read more about bounded static maps on our official [API documentation](https://docs.maptiler.com/cloud/api/static-maps/#auto-fitted-image).
|
|
1125
|
+
|
|
1126
|
+
## 🏔️ Elevation
|
|
1127
|
+
With the elevation API, it's possible to get the elevation in metter 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 from a GeoJSON MultiLineString!
|
|
1128
|
+
|
|
1129
|
+
> ℹ️ 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.
|
|
1130
|
+
|
|
1131
|
+
> 📣 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.
|
|
1132
|
+
|
|
1133
|
+
Let's see how to use it:
|
|
1134
|
+
|
|
1135
|
+
### At a single location
|
|
1136
|
+
```ts
|
|
1137
|
+
// Not mandatory, but it's to explain where the type comes from:
|
|
1138
|
+
import { Position } from "geojson";
|
|
1139
|
+
|
|
1140
|
+
const montBlancPeak: Position = [6.864884, 45.832743];
|
|
1141
|
+
const elevatedPosition = await maptilersdk.elevation.at(montBlancPeak);
|
|
1142
|
+
```
|
|
1143
|
+
The returned value is also a *GeoJSON* `Position` array, but with three elements: `[lng, lat, elevation]`.
|
|
1144
|
+
|
|
1145
|
+
Read more about elevation lookup for a single location in our [official documentation](https://docs.maptiler.com/client-js/elevation/#at).
|
|
1146
|
+
|
|
1147
|
+
### Batch mode
|
|
1148
|
+
```ts
|
|
1149
|
+
// Not mandatory, but it's to explain where the type comes from:
|
|
1150
|
+
import { Position } from "geojson";
|
|
1151
|
+
|
|
1152
|
+
const peaks: Position[] = [
|
|
1153
|
+
[6.864884, 45.832743], // Mont Blanc, Alps
|
|
1154
|
+
[86.9250, 27.9881], // Mount Everest, Himalayas
|
|
1155
|
+
[-70.0109, -32.6532], // Aconcagua, Andes
|
|
1156
|
+
[-151.0064, 63.0695], // Denali, Alaska
|
|
1157
|
+
[37.3556, -3.0674], // Mount Kilimanjaro
|
|
1158
|
+
[42.4453, 43.3499], // Mount Elbrus, Caucasus
|
|
1159
|
+
[137.1595, -4.0784], // Puncak Jaya, Sudirman Range
|
|
1160
|
+
[-140.4055, 60.5672], // Mount Logan, Saint Elias Mountains
|
|
1161
|
+
[138.73111, 35.358055], // Mount Fuji
|
|
1162
|
+
];
|
|
1163
|
+
|
|
1164
|
+
const elevatedPeaks = await maptilersdk.elevation.batch(peaks);
|
|
1165
|
+
```
|
|
1166
|
+
|
|
1167
|
+
Read more about elevation lookup for a batch of locations in our [official documentation](https://docs.maptiler.com/client-js/elevation/#batch).
|
|
1168
|
+
|
|
1169
|
+
### From a GeoJSON LineString
|
|
1170
|
+
In the *GeoJSON* LineString case, it clones the entire structure and the positions arrays of the clone will contain three element: `[lng, lat, elevation]`. The original LineString is not mutated nor pointed at.
|
|
1171
|
+
|
|
1172
|
+
```ts
|
|
1173
|
+
// Not mandatory, but it's to explain where the type comes from:
|
|
1174
|
+
import { LineString } from "geojson";
|
|
1175
|
+
|
|
1176
|
+
|
|
1177
|
+
const someLineString: LineString = {
|
|
1178
|
+
type: "LineString",
|
|
1179
|
+
coordinates: [[6.864884, 45.832743], [86.9250, 27.9881], [-70.0109, -32.6532]]
|
|
1180
|
+
};
|
|
1181
|
+
|
|
1182
|
+
const someElevatedLineString = await maptilersdk.elevation.fromLineString(someLineString);
|
|
1183
|
+
// someElevatedLineString is also of type LineString
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
Read more about elevation lookup for a `LineString` in our [official documentation](https://docs.maptiler.com/client-js/elevation/#linestring).
|
|
1187
|
+
|
|
1188
|
+
### From a GeoJSON MultiLineString
|
|
1189
|
+
In the *GeoJSON* MultiLineString case, it clones the entire structure and the positions arrays of the clone will contain three element: `[lng, lat, elevation]`. The original MultiLineString is not mutated nor pointed at.
|
|
1190
|
+
|
|
1191
|
+
```ts
|
|
1192
|
+
// Not mandatory, but it's to explain where the type comes from:
|
|
1193
|
+
import { MultiLineString } from "geojson";
|
|
1194
|
+
|
|
1195
|
+
|
|
1196
|
+
const someMultiLineString: MultiLineString = {
|
|
1197
|
+
type: "LineString",
|
|
1198
|
+
coordinates: [
|
|
1199
|
+
[[6.864884, 45.832743], [86.9250, 27.9881], [-70.0109, -32.6532]],
|
|
1200
|
+
[[-151.0064, 63.0695], [37.3556, -3.0674], [42.4453, 43.3499]],
|
|
1201
|
+
[[137.1595, -4.0784], [-140.4055, 60.5672], [138.73111, 35.358055]],
|
|
1202
|
+
]
|
|
1203
|
+
};
|
|
1204
|
+
|
|
1205
|
+
const someElevatedMultiLineString = await maptilersdk.elevation.fromMultiLineString(someMultiLineString);
|
|
1206
|
+
// someElevatedMultiLineString is also of type MultiLineString
|
|
1207
|
+
```
|
|
1208
|
+
|
|
1209
|
+
Read more about elevation lookup for a `MultiLineString` in our [official documentation](https://docs.maptiler.com/client-js/elevation/#multilinestring).
|
|
1210
|
+
|
|
1211
|
+
### Caching
|
|
1212
|
+
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.
|
|
1213
|
+
|
|
1214
|
+
## 🧮 Math
|
|
1215
|
+
Some operations can be fairly repetitive: WGS84 to Mercator, WGS84 to *zxy* tile index, distance between two points with Haversine formula, etc. As a result, we have decided to expose a `math` package providing the most recurent feature, so that, just like us at MapTiler, you no longer need to copy-paste the same function from your previous project!
|
|
1216
|
+
|
|
1217
|
+
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.
|
|
1218
|
+
|
|
1219
|
+
Here are some examples:
|
|
1220
|
+
|
|
1221
|
+
```ts
|
|
1222
|
+
// Not mandatory, but it's to explain where the type comes from:
|
|
1223
|
+
import { Position } from "geojson";
|
|
1224
|
+
|
|
1225
|
+
// Some constants
|
|
1226
|
+
const earthRadius = maptilersdk.math.EARTH_RADIUS;
|
|
1227
|
+
const earthCircumference = maptilersdk.math.EARTH_CIRCUMFERENCE;
|
|
1228
|
+
|
|
1229
|
+
const montBlancPeakWgs84: Position = [6.864884, 45.832743];
|
|
1230
|
+
|
|
1231
|
+
// From WGS84 to Mercator
|
|
1232
|
+
const montBlancPeakMerc = maptilersdk.math.wgs84ToMercator(montBlancPeakWgs84); // also of type Position
|
|
1233
|
+
|
|
1234
|
+
// From Mercator to WGS84
|
|
1235
|
+
const montBlancPeakWgs84Again = maptilersdk.math.mercatorToWgs84(montBlancPeakMerc);
|
|
1236
|
+
|
|
1237
|
+
// A great-circle distance in meter:
|
|
1238
|
+
const from: Position = /* ... */;
|
|
1239
|
+
const to: Position = /* ... */;
|
|
1240
|
+
const distance = maptilersdk.math.haversineDistanceWgs84(from, to);
|
|
1241
|
+
|
|
1242
|
+
// Full distance of a route made of many positions
|
|
1243
|
+
const route: Position[] = /* ... */;
|
|
1244
|
+
const totalDistance = maptilersdk.math.haversineCumulatedDistanceWgs84(route);
|
|
1245
|
+
|
|
1246
|
+
// Lon lat to tile index, given a zoom level. An [x, y] array is returned
|
|
1247
|
+
const tileXY = maptilersdk.math.wgs84ToTileIndex(montBlancPeakWgs84, 14);
|
|
1248
|
+
// Possible to have floating point tile indices with a third argument to `false`
|
|
1249
|
+
|
|
1250
|
+
// and many more!
|
|
1251
|
+
```
|
|
1252
|
+
|
|
1253
|
+
Please find out more about the math package in our [official documentation](https://docs.maptiler.com/client-js/math):
|
package/rollup.config.js
CHANGED
|
@@ -10,7 +10,7 @@ import json from '@rollup/plugin-json';
|
|
|
10
10
|
import execute from "rollup-plugin-shell";
|
|
11
11
|
|
|
12
12
|
const outputName = "maptiler-sdk";
|
|
13
|
-
const externals = ["maplibre-gl", "@maptiler/client", "@mapbox/point-geometry", "uuid", "@mapbox/unitbezier", "events", "js-base64"];
|
|
13
|
+
const externals = ["maplibre-gl", "@maptiler/client", "@mapbox/point-geometry", "uuid", "@mapbox/unitbezier", "events", "js-base64", "geojson-validation"];
|
|
14
14
|
|
|
15
15
|
const cssMaplibreFilepath = "node_modules/maplibre-gl/dist/maplibre-gl.css";
|
|
16
16
|
const cssTemplateFilepath = "src/style/style_template.css";
|
|
@@ -28,20 +28,6 @@ const copyCssPlugin = copy({
|
|
|
28
28
|
],
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
const copyUmdBundle = copy({
|
|
32
|
-
targets: [
|
|
33
|
-
{
|
|
34
|
-
src: `dist/${outputName}.umd.js`,
|
|
35
|
-
dest: "demos/",
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
src: `dist/${outputName}.css`,
|
|
39
|
-
dest: "demos/",
|
|
40
|
-
},
|
|
41
|
-
],
|
|
42
|
-
hook: "writeBundle"
|
|
43
|
-
});
|
|
44
|
-
|
|
45
31
|
|
|
46
32
|
const bundles = [
|
|
47
33
|
// ES module, not minified + sourcemap
|
|
@@ -78,7 +64,7 @@ const bundles = [
|
|
|
78
64
|
globals(),
|
|
79
65
|
json(),
|
|
80
66
|
esbuild(),
|
|
81
|
-
copyUmdBundle,
|
|
67
|
+
// copyUmdBundle,
|
|
82
68
|
],
|
|
83
69
|
output: [
|
|
84
70
|
{
|