@maptiler/sdk 1.1.1 → 1.2.0
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 +94 -51
- package/colorramp.md +93 -0
- package/dist/maptiler-sdk.d.ts +1207 -123
- package/dist/maptiler-sdk.min.mjs +3 -1
- package/dist/maptiler-sdk.mjs +3561 -485
- package/dist/maptiler-sdk.mjs.map +1 -1
- package/dist/maptiler-sdk.umd.js +3825 -869
- 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 +298 -0
- package/rollup.config.js +2 -16
- package/src/Map.ts +489 -357
- 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 +10 -0
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LngLatLike } from "maplibre-gl";
|
|
1
|
+
import type { LngLatLike, MapLibreEvent } from "maplibre-gl";
|
|
2
2
|
import maplibregl from "maplibre-gl";
|
|
3
3
|
import { GeolocateControl } from "./GeolocateControl";
|
|
4
4
|
import { DOMcreate } from "./tools";
|
|
@@ -7,6 +7,10 @@ const Marker = maplibregl.Marker;
|
|
|
7
7
|
const LngLat = maplibregl.LngLat;
|
|
8
8
|
const LngLatBounds = maplibregl.LngLatBounds;
|
|
9
9
|
|
|
10
|
+
type MoveEndEvent = MapLibreEvent<
|
|
11
|
+
MouseEvent | TouchEvent | WheelEvent | undefined
|
|
12
|
+
> & { geolocateSource?: boolean };
|
|
13
|
+
|
|
10
14
|
/**
|
|
11
15
|
* The MaptilerGeolocateControl is an extension of the original GeolocateControl
|
|
12
16
|
* with a few changes. In this version, the active mode persists as long as the
|
|
@@ -22,10 +26,10 @@ export class MaptilerGeolocateControl extends GeolocateControl {
|
|
|
22
26
|
* @param {Position} position the Geolocation API Position
|
|
23
27
|
* @private
|
|
24
28
|
*/
|
|
25
|
-
_updateCamera(position: GeolocationPosition) {
|
|
29
|
+
_updateCamera = (position: GeolocationPosition) => {
|
|
26
30
|
const center = new LngLat(
|
|
27
31
|
position.coords.longitude,
|
|
28
|
-
position.coords.latitude
|
|
32
|
+
position.coords.latitude,
|
|
29
33
|
);
|
|
30
34
|
const radius = position.coords.accuracy;
|
|
31
35
|
const bearing = this._map.getBearing();
|
|
@@ -37,7 +41,7 @@ export class MaptilerGeolocateControl extends GeolocateControl {
|
|
|
37
41
|
|
|
38
42
|
const currentMapZoom = this._map.getZoom();
|
|
39
43
|
|
|
40
|
-
if (currentMapZoom > this.options
|
|
44
|
+
if (currentMapZoom > (this.options?.fitBoundsOptions?.maxZoom ?? 30)) {
|
|
41
45
|
options.zoom = currentMapZoom;
|
|
42
46
|
}
|
|
43
47
|
|
|
@@ -73,30 +77,30 @@ export class MaptilerGeolocateControl extends GeolocateControl {
|
|
|
73
77
|
|
|
74
78
|
this.lastUpdatedCenter = this._map.getCenter();
|
|
75
79
|
});
|
|
76
|
-
}
|
|
80
|
+
};
|
|
77
81
|
|
|
78
|
-
_setupUI(supported: boolean) {
|
|
82
|
+
_setupUI = (supported: boolean) => {
|
|
79
83
|
this.lastUpdatedCenter = this._map.getCenter();
|
|
80
84
|
|
|
81
85
|
this._container.addEventListener("contextmenu", (e: MouseEvent) =>
|
|
82
|
-
e.preventDefault()
|
|
86
|
+
e.preventDefault(),
|
|
83
87
|
);
|
|
84
88
|
this._geolocateButton = DOMcreate(
|
|
85
89
|
"button",
|
|
86
90
|
"maplibregl-ctrl-geolocate",
|
|
87
|
-
this._container
|
|
91
|
+
this._container,
|
|
88
92
|
);
|
|
89
93
|
DOMcreate(
|
|
90
94
|
"span",
|
|
91
95
|
"maplibregl-ctrl-icon",
|
|
92
|
-
this._geolocateButton
|
|
96
|
+
this._geolocateButton,
|
|
93
97
|
).setAttribute("aria-hidden", "true");
|
|
94
98
|
this._geolocateButton.type = "button";
|
|
95
99
|
|
|
96
100
|
if (supported === false) {
|
|
97
101
|
// warnOnce('Geolocation support is not available so the GeolocateControl will be disabled.');
|
|
98
102
|
const title = this._map._getUIString(
|
|
99
|
-
"GeolocateControl.LocationNotAvailable"
|
|
103
|
+
"GeolocateControl.LocationNotAvailable",
|
|
100
104
|
);
|
|
101
105
|
this._geolocateButton.disabled = true;
|
|
102
106
|
this._geolocateButton.title = title;
|
|
@@ -115,12 +119,11 @@ export class MaptilerGeolocateControl extends GeolocateControl {
|
|
|
115
119
|
// when showUserLocation is enabled, keep the Geolocate button disabled until the device location marker is setup on the map
|
|
116
120
|
if (this.options.showUserLocation) {
|
|
117
121
|
this._dotElement = DOMcreate("div", "maplibregl-user-location-dot");
|
|
118
|
-
|
|
119
|
-
this._userLocationDotMarker = new Marker(this._dotElement);
|
|
122
|
+
this._userLocationDotMarker = new Marker({ element: this._dotElement });
|
|
120
123
|
|
|
121
124
|
this._circleElement = DOMcreate(
|
|
122
125
|
"div",
|
|
123
|
-
"maplibregl-user-location-accuracy-circle"
|
|
126
|
+
"maplibregl-user-location-accuracy-circle",
|
|
124
127
|
);
|
|
125
128
|
this._accuracyCircleMarker = new Marker({
|
|
126
129
|
element: this._circleElement,
|
|
@@ -143,11 +146,11 @@ export class MaptilerGeolocateControl extends GeolocateControl {
|
|
|
143
146
|
// is a zoom, rotation or pitch (where the center stays the same) then we can keep the ACTIVE_LOCK
|
|
144
147
|
// mode ON.
|
|
145
148
|
if (this.options.trackUserLocation) {
|
|
146
|
-
this._map.on("moveend", (event:
|
|
149
|
+
this._map.on("moveend", (event: MoveEndEvent) => {
|
|
147
150
|
const fromResize =
|
|
148
151
|
event.originalEvent && event.originalEvent.type === "resize";
|
|
149
152
|
const movingDistance = this.lastUpdatedCenter.distanceTo(
|
|
150
|
-
this._map.getCenter()
|
|
153
|
+
this._map.getCenter(),
|
|
151
154
|
);
|
|
152
155
|
|
|
153
156
|
if (
|
|
@@ -158,17 +161,17 @@ export class MaptilerGeolocateControl extends GeolocateControl {
|
|
|
158
161
|
) {
|
|
159
162
|
this._watchState = "BACKGROUND";
|
|
160
163
|
this._geolocateButton.classList.add(
|
|
161
|
-
"maplibregl-ctrl-geolocate-background"
|
|
164
|
+
"maplibregl-ctrl-geolocate-background",
|
|
162
165
|
);
|
|
163
166
|
this._geolocateButton.classList.remove(
|
|
164
|
-
"maplibregl-ctrl-geolocate-active"
|
|
167
|
+
"maplibregl-ctrl-geolocate-active",
|
|
165
168
|
);
|
|
166
169
|
|
|
167
170
|
this.fire(new Event("trackuserlocationend"));
|
|
168
171
|
}
|
|
169
172
|
});
|
|
170
173
|
}
|
|
171
|
-
}
|
|
174
|
+
};
|
|
172
175
|
|
|
173
176
|
_updateCircleRadius() {
|
|
174
177
|
if (
|
|
@@ -196,9 +199,9 @@ export class MaptilerGeolocateControl extends GeolocateControl {
|
|
|
196
199
|
this._circleElement.style.height = `${circleDiameter}px`;
|
|
197
200
|
}
|
|
198
201
|
|
|
199
|
-
_onZoom() {
|
|
202
|
+
_onZoom = () => {
|
|
200
203
|
if (this.options.showUserLocation && this.options.showAccuracyCircle) {
|
|
201
204
|
this._updateCircleRadius();
|
|
202
205
|
}
|
|
203
|
-
}
|
|
206
|
+
};
|
|
204
207
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import maplibregl from "maplibre-gl";
|
|
2
1
|
import type { LogoOptions as LogoOptionsML } from "maplibre-gl";
|
|
3
2
|
import { defaults } from "./defaults";
|
|
4
|
-
import { Map } from "./Map";
|
|
5
3
|
import { LogoControl } from "./LogoControl";
|
|
4
|
+
import type { Map } from "./Map";
|
|
6
5
|
|
|
7
6
|
type LogoOptions = LogoOptionsML & {
|
|
8
7
|
logoURL?: string;
|
|
@@ -14,6 +13,7 @@ type LogoOptions = LogoOptionsML & {
|
|
|
14
13
|
* any link URL. By default this is using MapTiler logo and URL.
|
|
15
14
|
*/
|
|
16
15
|
export class MaptilerLogoControl extends LogoControl {
|
|
16
|
+
declare _compact: boolean;
|
|
17
17
|
private logoURL = "";
|
|
18
18
|
private linkURL = "";
|
|
19
19
|
|
|
@@ -26,7 +26,7 @@ export class MaptilerLogoControl extends LogoControl {
|
|
|
26
26
|
|
|
27
27
|
onAdd(map: Map): HTMLElement {
|
|
28
28
|
this._map = map;
|
|
29
|
-
this._compact = this.options
|
|
29
|
+
this._compact = this.options.compact ?? false;
|
|
30
30
|
this._container = window.document.createElement("div");
|
|
31
31
|
this._container.className = "maplibregl-ctrl";
|
|
32
32
|
const anchor = window.document.createElement("a");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { NavigationControl } from "./NavigationControl";
|
|
2
2
|
|
|
3
3
|
type HTMLButtonElementPlus = HTMLButtonElement & {
|
|
4
|
-
clickFunction: (e?:
|
|
4
|
+
clickFunction: (e?: Event) => unknown;
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
export class MaptilerNavigationControl extends NavigationControl {
|
|
@@ -15,7 +15,7 @@ export class MaptilerNavigationControl extends NavigationControl {
|
|
|
15
15
|
// Removing the default click event
|
|
16
16
|
this._compass.removeEventListener(
|
|
17
17
|
"click",
|
|
18
|
-
(this._compass as HTMLButtonElementPlus).clickFunction
|
|
18
|
+
(this._compass as HTMLButtonElementPlus).clickFunction,
|
|
19
19
|
);
|
|
20
20
|
|
|
21
21
|
// Adding custom click event
|
|
@@ -40,7 +40,7 @@ export class MaptilerNavigationControl extends NavigationControl {
|
|
|
40
40
|
*/
|
|
41
41
|
_createButton(
|
|
42
42
|
className: string,
|
|
43
|
-
fn: (e?:
|
|
43
|
+
fn: (e?: Event) => unknown,
|
|
44
44
|
): HTMLButtonElementPlus {
|
|
45
45
|
const button = super._createButton(className, fn) as HTMLButtonElementPlus;
|
|
46
46
|
button.clickFunction = fn;
|
|
@@ -50,17 +50,20 @@ export class MaptilerNavigationControl extends NavigationControl {
|
|
|
50
50
|
/**
|
|
51
51
|
* Overloading: Limit how flat the compass icon can get
|
|
52
52
|
*/
|
|
53
|
-
_rotateCompassArrow() {
|
|
53
|
+
_rotateCompassArrow = () => {
|
|
54
54
|
const rotate = this.options.visualizePitch
|
|
55
55
|
? `scale(${Math.min(
|
|
56
56
|
1.5,
|
|
57
57
|
1 /
|
|
58
|
-
Math.pow(
|
|
58
|
+
Math.pow(
|
|
59
|
+
Math.cos(this._map.transform.pitch * (Math.PI / 180)),
|
|
60
|
+
0.5,
|
|
61
|
+
),
|
|
59
62
|
)}) rotateX(${Math.min(70, this._map.transform.pitch)}deg) rotateZ(${
|
|
60
63
|
this._map.transform.angle * (180 / Math.PI)
|
|
61
64
|
}deg)`
|
|
62
65
|
: `rotate(${this._map.transform.angle * (180 / Math.PI)}deg)`;
|
|
63
66
|
|
|
64
67
|
this._compassIcon.style.transform = rotate;
|
|
65
|
-
}
|
|
68
|
+
};
|
|
66
69
|
}
|
|
@@ -1,32 +1,32 @@
|
|
|
1
1
|
import { bindAll, DOMcreate, DOMremove } from "./tools";
|
|
2
2
|
|
|
3
|
-
import { Map } from "./Map";
|
|
4
|
-
import
|
|
3
|
+
import type { Map } from "./Map";
|
|
4
|
+
import type { IControl } from "maplibre-gl";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* A `MaptilerTerrainControl` control adds a button to turn terrain on and off
|
|
8
8
|
* by triggering the terrain logic that is already deployed in the Map object.
|
|
9
9
|
*/
|
|
10
|
-
export class MaptilerTerrainControl implements
|
|
11
|
-
_map
|
|
12
|
-
_container
|
|
13
|
-
_terrainButton
|
|
10
|
+
export class MaptilerTerrainControl implements IControl {
|
|
11
|
+
_map!: Map;
|
|
12
|
+
_container!: HTMLElement;
|
|
13
|
+
_terrainButton!: HTMLButtonElement;
|
|
14
14
|
|
|
15
15
|
constructor() {
|
|
16
16
|
bindAll(["_toggleTerrain", "_updateTerrainIcon"], this);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
onAdd(map: Map) {
|
|
19
|
+
onAdd(map: Map): HTMLElement {
|
|
20
20
|
this._map = map;
|
|
21
21
|
this._container = DOMcreate("div", "maplibregl-ctrl maplibregl-ctrl-group");
|
|
22
22
|
this._terrainButton = DOMcreate(
|
|
23
23
|
"button",
|
|
24
24
|
"maplibregl-ctrl-terrain",
|
|
25
|
-
this._container
|
|
25
|
+
this._container,
|
|
26
26
|
);
|
|
27
27
|
DOMcreate("span", "maplibregl-ctrl-icon", this._terrainButton).setAttribute(
|
|
28
28
|
"aria-hidden",
|
|
29
|
-
"true"
|
|
29
|
+
"true",
|
|
30
30
|
);
|
|
31
31
|
this._terrainButton.type = "button";
|
|
32
32
|
this._terrainButton.addEventListener("click", this._toggleTerrain);
|
|
@@ -36,13 +36,14 @@ export class MaptilerTerrainControl implements maplibregl.IControl {
|
|
|
36
36
|
return this._container;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
onRemove() {
|
|
39
|
+
onRemove(): void {
|
|
40
40
|
DOMremove(this._container);
|
|
41
41
|
this._map.off("terrain", this._updateTerrainIcon);
|
|
42
|
+
// @ts-expect-error: map will only be undefined on remove
|
|
42
43
|
this._map = undefined;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
_toggleTerrain() {
|
|
46
|
+
_toggleTerrain(): void {
|
|
46
47
|
if (this._map.hasTerrain()) {
|
|
47
48
|
this._map.disableTerrain();
|
|
48
49
|
} else {
|
|
@@ -52,19 +53,19 @@ export class MaptilerTerrainControl implements maplibregl.IControl {
|
|
|
52
53
|
this._updateTerrainIcon();
|
|
53
54
|
}
|
|
54
55
|
|
|
55
|
-
_updateTerrainIcon() {
|
|
56
|
+
_updateTerrainIcon(): void {
|
|
56
57
|
this._terrainButton.classList.remove("maplibregl-ctrl-terrain");
|
|
57
58
|
this._terrainButton.classList.remove("maplibregl-ctrl-terrain-enabled");
|
|
58
59
|
// if (this._map.terrain) {
|
|
59
60
|
if (this._map.hasTerrain()) {
|
|
60
61
|
this._terrainButton.classList.add("maplibregl-ctrl-terrain-enabled");
|
|
61
62
|
this._terrainButton.title = this._map._getUIString(
|
|
62
|
-
"TerrainControl.disableTerrain"
|
|
63
|
+
"TerrainControl.disableTerrain",
|
|
63
64
|
);
|
|
64
65
|
} else {
|
|
65
66
|
this._terrainButton.classList.add("maplibregl-ctrl-terrain");
|
|
66
67
|
this._terrainButton.title = this._map._getUIString(
|
|
67
|
-
"TerrainControl.enableTerrain"
|
|
68
|
+
"TerrainControl.enableTerrain",
|
|
68
69
|
);
|
|
69
70
|
}
|
|
70
71
|
}
|
package/src/Minimap.ts
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is an extension adds support for adding a minimap to one of the map's control containers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { Map } from "./Map";
|
|
6
|
+
import { DOMcreate, DOMremove } from "./tools";
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
ControlPosition,
|
|
10
|
+
CustomLayerInterface,
|
|
11
|
+
FillLayerSpecification,
|
|
12
|
+
FilterSpecification,
|
|
13
|
+
GeoJSONSource,
|
|
14
|
+
IControl,
|
|
15
|
+
LayerSpecification,
|
|
16
|
+
LineLayerSpecification,
|
|
17
|
+
SourceSpecification,
|
|
18
|
+
StyleOptions,
|
|
19
|
+
StyleSetterOptions,
|
|
20
|
+
StyleSpecification,
|
|
21
|
+
StyleSwapOptions,
|
|
22
|
+
} from "maplibre-gl";
|
|
23
|
+
import type { MapOptions } from "./Map";
|
|
24
|
+
import type { MapStyleVariant, ReferenceMapStyle } from "@maptiler/client";
|
|
25
|
+
|
|
26
|
+
export interface ParentRect {
|
|
27
|
+
lineLayout: LineLayerSpecification["layout"];
|
|
28
|
+
linePaint: LineLayerSpecification["paint"];
|
|
29
|
+
fillPaint: FillLayerSpecification["paint"];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface MinimapOptionsInput {
|
|
33
|
+
/**
|
|
34
|
+
* Style of the map. Can be:
|
|
35
|
+
* - a full style URL (possibly with API key)
|
|
36
|
+
* - a shorthand with only the MapTIler style name (eg. `"streets-v2"`)
|
|
37
|
+
* - a longer form with the prefix `"maptiler://"` (eg. `"maptiler://streets-v2"`)
|
|
38
|
+
*/
|
|
39
|
+
style?: ReferenceMapStyle | MapStyleVariant | StyleSpecification | string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Set the zoom difference between the parent and the minimap
|
|
43
|
+
* If the parent is zoomed to 10 and the minimap is zoomed to 8, the zoomAdjust should be 2
|
|
44
|
+
* Default: -4
|
|
45
|
+
*/
|
|
46
|
+
zoomAdjust?: number;
|
|
47
|
+
|
|
48
|
+
/** Set a zoom of the minimap and don't allow any future changes */
|
|
49
|
+
lockZoom?: number;
|
|
50
|
+
|
|
51
|
+
/** Adjust the pitch only if the user requests */
|
|
52
|
+
pitchAdjust?: boolean;
|
|
53
|
+
|
|
54
|
+
/** Set CSS properties of the container using object key-values */
|
|
55
|
+
containerStyle?: Record<string, string>;
|
|
56
|
+
|
|
57
|
+
/** Set the position of the minimap at either "top-left", "top-right", "bottom-left", or "bottom-right" */
|
|
58
|
+
position?: ControlPosition;
|
|
59
|
+
|
|
60
|
+
/** Set the parentRect fill and/or line options */
|
|
61
|
+
parentRect?: ParentRect;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface MinimapOptions extends MapOptions {
|
|
65
|
+
zoomAdjust: number;
|
|
66
|
+
pitchAdjust: boolean;
|
|
67
|
+
containerStyle: Record<string, string>;
|
|
68
|
+
parentRect?: ParentRect;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export default class Minimap implements IControl {
|
|
72
|
+
#options: MinimapOptions;
|
|
73
|
+
map!: Map;
|
|
74
|
+
#parentMap!: Map;
|
|
75
|
+
#container!: HTMLElement;
|
|
76
|
+
#canvasContainer!: HTMLElement;
|
|
77
|
+
#parentRect?: GeoJSON.Feature<GeoJSON.Polygon>;
|
|
78
|
+
#differentStyle = false;
|
|
79
|
+
#desync?: () => void;
|
|
80
|
+
constructor(options: MinimapOptionsInput, mapOptions: MapOptions) {
|
|
81
|
+
// check if the style is different
|
|
82
|
+
if (options.style !== undefined) this.#differentStyle = true;
|
|
83
|
+
// set options
|
|
84
|
+
this.#options = {
|
|
85
|
+
// set defaults
|
|
86
|
+
zoomAdjust: -4,
|
|
87
|
+
position: "top-right",
|
|
88
|
+
// inherit map options
|
|
89
|
+
...mapOptions,
|
|
90
|
+
// override any lingering control options
|
|
91
|
+
forceNoAttributionControl: true,
|
|
92
|
+
attributionControl: false,
|
|
93
|
+
navigationControl: false,
|
|
94
|
+
geolocateControl: false,
|
|
95
|
+
maptilerLogo: false,
|
|
96
|
+
minimap: false,
|
|
97
|
+
hash: false,
|
|
98
|
+
pitchAdjust: false,
|
|
99
|
+
// override map options with new user defined minimap options
|
|
100
|
+
...options,
|
|
101
|
+
containerStyle: {
|
|
102
|
+
border: "1px solid #000",
|
|
103
|
+
width: "400px",
|
|
104
|
+
height: "300px",
|
|
105
|
+
...(options.containerStyle ?? {}),
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
if (options.lockZoom !== undefined) {
|
|
109
|
+
this.#options.minZoom = options.lockZoom;
|
|
110
|
+
this.#options.maxZoom = options.lockZoom;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
setStyle(
|
|
115
|
+
style:
|
|
116
|
+
| null
|
|
117
|
+
| ReferenceMapStyle
|
|
118
|
+
| MapStyleVariant
|
|
119
|
+
| StyleSpecification
|
|
120
|
+
| string,
|
|
121
|
+
options?: StyleSwapOptions & StyleOptions,
|
|
122
|
+
): void {
|
|
123
|
+
if (!this.#differentStyle) this.map.setStyle(style, options);
|
|
124
|
+
this.#setParentBounds();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
addLayer(
|
|
128
|
+
layer:
|
|
129
|
+
| (LayerSpecification & {
|
|
130
|
+
source?: string | SourceSpecification;
|
|
131
|
+
})
|
|
132
|
+
| CustomLayerInterface,
|
|
133
|
+
beforeId?: string,
|
|
134
|
+
): Map {
|
|
135
|
+
if (!this.#differentStyle) this.map.addLayer(layer, beforeId);
|
|
136
|
+
this.#setParentBounds();
|
|
137
|
+
return this.map;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
moveLayer(id: string, beforeId?: string): Map {
|
|
141
|
+
if (!this.#differentStyle) this.map.moveLayer(id, beforeId);
|
|
142
|
+
this.#setParentBounds();
|
|
143
|
+
return this.map;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
removeLayer(id: string): this {
|
|
147
|
+
if (!this.#differentStyle) this.map.removeLayer(id);
|
|
148
|
+
this.#setParentBounds();
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
setLayerZoomRange(layerId: string, minzoom: number, maxzoom: number): this {
|
|
153
|
+
if (!this.#differentStyle)
|
|
154
|
+
this.map.setLayerZoomRange(layerId, minzoom, maxzoom);
|
|
155
|
+
this.#setParentBounds();
|
|
156
|
+
return this;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
setFilter(
|
|
160
|
+
layerId: string,
|
|
161
|
+
filter?: FilterSpecification | null,
|
|
162
|
+
options?: StyleSetterOptions,
|
|
163
|
+
): this {
|
|
164
|
+
if (!this.#differentStyle) this.map.setFilter(layerId, filter, options);
|
|
165
|
+
this.#setParentBounds();
|
|
166
|
+
return this;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
setPaintProperty(
|
|
170
|
+
layerId: string,
|
|
171
|
+
name: string,
|
|
172
|
+
// maplibre controlled types
|
|
173
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
174
|
+
value: any,
|
|
175
|
+
options?: StyleSetterOptions,
|
|
176
|
+
): this {
|
|
177
|
+
if (!this.#differentStyle)
|
|
178
|
+
this.map.setPaintProperty(layerId, name, value, options);
|
|
179
|
+
this.#setParentBounds();
|
|
180
|
+
return this;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
setLayoutProperty(
|
|
184
|
+
layerId: string,
|
|
185
|
+
name: string,
|
|
186
|
+
// maplibre controlled types
|
|
187
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
188
|
+
value: any,
|
|
189
|
+
options?: StyleSetterOptions,
|
|
190
|
+
): this {
|
|
191
|
+
if (!this.#differentStyle)
|
|
192
|
+
this.map.setLayoutProperty(layerId, name, value, options);
|
|
193
|
+
this.#setParentBounds();
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
setGlyphs(glyphsUrl: string | null, options?: StyleSetterOptions): this {
|
|
198
|
+
if (!this.#differentStyle) this.map.setGlyphs(glyphsUrl, options);
|
|
199
|
+
this.#setParentBounds();
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
onAdd(parentMap: Map): HTMLElement {
|
|
204
|
+
this.#parentMap = parentMap;
|
|
205
|
+
//prep the container
|
|
206
|
+
this.#container = DOMcreate("div", "maplibregl-ctrl maplibregl-ctrl-group");
|
|
207
|
+
// adjust styling
|
|
208
|
+
for (const [key, value] of Object.entries(this.#options.containerStyle)) {
|
|
209
|
+
this.#container.style.setProperty(key, value);
|
|
210
|
+
}
|
|
211
|
+
this.#options.container = this.#container;
|
|
212
|
+
this.#options.zoom = parentMap.getZoom() + this.#options.zoomAdjust ?? -4;
|
|
213
|
+
this.map = new Map(this.#options);
|
|
214
|
+
|
|
215
|
+
// NOTE: For some reason the DOM doesn't properly update it's size in time
|
|
216
|
+
// for the minimap to convey it's size to the canvas.
|
|
217
|
+
this.map.once("style.load", () => {
|
|
218
|
+
this.map.resize();
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// set options
|
|
222
|
+
this.map.once("load", () => {
|
|
223
|
+
this.#addParentRect(this.#options.parentRect);
|
|
224
|
+
this.#desync = this.#syncMaps();
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
return this.#container;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
onRemove(): void {
|
|
231
|
+
this.#desync?.();
|
|
232
|
+
DOMremove(this.#container);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
#addParentRect(rect?: ParentRect): void {
|
|
236
|
+
if (
|
|
237
|
+
rect === undefined ||
|
|
238
|
+
(rect.linePaint === undefined && rect.fillPaint === undefined)
|
|
239
|
+
) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
this.#parentRect = {
|
|
243
|
+
type: "Feature",
|
|
244
|
+
properties: {
|
|
245
|
+
name: "parentRect",
|
|
246
|
+
},
|
|
247
|
+
geometry: {
|
|
248
|
+
type: "Polygon",
|
|
249
|
+
coordinates: [[[], [], [], [], []]],
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
this.map.addSource("parentRect", {
|
|
254
|
+
type: "geojson",
|
|
255
|
+
data: this.#parentRect,
|
|
256
|
+
});
|
|
257
|
+
if (rect.lineLayout !== undefined || rect.linePaint !== undefined) {
|
|
258
|
+
this.map.addLayer({
|
|
259
|
+
id: "parentRectOutline",
|
|
260
|
+
type: "line",
|
|
261
|
+
source: "parentRect",
|
|
262
|
+
layout: {
|
|
263
|
+
...rect.lineLayout,
|
|
264
|
+
},
|
|
265
|
+
paint: {
|
|
266
|
+
"line-color": "#FFF",
|
|
267
|
+
"line-width": 1,
|
|
268
|
+
"line-opacity": 0.85,
|
|
269
|
+
...rect.linePaint,
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (rect.fillPaint !== undefined) {
|
|
274
|
+
this.map.addLayer({
|
|
275
|
+
id: "parentRectFill",
|
|
276
|
+
type: "fill",
|
|
277
|
+
source: "parentRect",
|
|
278
|
+
layout: {},
|
|
279
|
+
paint: {
|
|
280
|
+
"fill-color": "#08F",
|
|
281
|
+
"fill-opacity": 0.135,
|
|
282
|
+
...rect.fillPaint,
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
this.#setParentBounds();
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
#setParentBounds() {
|
|
291
|
+
if (this.#parentRect === undefined) return;
|
|
292
|
+
|
|
293
|
+
const { devicePixelRatio } = window;
|
|
294
|
+
const canvas = this.#parentMap.getCanvas();
|
|
295
|
+
const width = canvas.width / devicePixelRatio;
|
|
296
|
+
const height = canvas.height / devicePixelRatio;
|
|
297
|
+
|
|
298
|
+
// Get coordinates for all four corners
|
|
299
|
+
const unproject = this.#parentMap.unproject.bind(this.#parentMap);
|
|
300
|
+
const northWest = unproject([0, 0]);
|
|
301
|
+
const northEast = unproject([width, 0]);
|
|
302
|
+
const southWest = unproject([0, height]);
|
|
303
|
+
const southEast = unproject([width, height]);
|
|
304
|
+
|
|
305
|
+
this.#parentRect.geometry.coordinates = [
|
|
306
|
+
[
|
|
307
|
+
southWest.toArray(),
|
|
308
|
+
southEast.toArray(),
|
|
309
|
+
northEast.toArray(),
|
|
310
|
+
northWest.toArray(),
|
|
311
|
+
southWest.toArray(),
|
|
312
|
+
],
|
|
313
|
+
];
|
|
314
|
+
|
|
315
|
+
const source = this.map.getSource("parentRect") as GeoJSONSource;
|
|
316
|
+
source.setData(this.#parentRect);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
#syncMaps(): () => void {
|
|
320
|
+
const { pitchAdjust } = this.#options;
|
|
321
|
+
// syncing callbacks
|
|
322
|
+
const parentCallback = () => {
|
|
323
|
+
sync("parent");
|
|
324
|
+
};
|
|
325
|
+
const minimapCallback = () => {
|
|
326
|
+
sync("minimap");
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
// on off functions
|
|
330
|
+
const on = () => {
|
|
331
|
+
this.#parentMap.on("move", parentCallback);
|
|
332
|
+
this.map.on("move", minimapCallback);
|
|
333
|
+
};
|
|
334
|
+
const off = () => {
|
|
335
|
+
this.#parentMap.off("move", parentCallback);
|
|
336
|
+
this.map.off("move", minimapCallback);
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
// When one map moves, we turn off the movement listeners
|
|
340
|
+
// on all the maps, move it, then turn the listeners on again
|
|
341
|
+
const sync = (which: "parent" | "minimap") => {
|
|
342
|
+
// OFF
|
|
343
|
+
off();
|
|
344
|
+
|
|
345
|
+
// MOVE
|
|
346
|
+
const from = which === "parent" ? this.#parentMap : this.map;
|
|
347
|
+
const to = which === "parent" ? this.map : this.#parentMap;
|
|
348
|
+
const center = from.getCenter();
|
|
349
|
+
const zoom =
|
|
350
|
+
from.getZoom() +
|
|
351
|
+
(this.#options.zoomAdjust ?? -4) * (which === "parent" ? 1 : -1);
|
|
352
|
+
const bearing = from.getBearing();
|
|
353
|
+
const pitch = from.getPitch();
|
|
354
|
+
to.jumpTo({
|
|
355
|
+
center,
|
|
356
|
+
zoom,
|
|
357
|
+
bearing,
|
|
358
|
+
pitch: pitchAdjust ? pitch : 0,
|
|
359
|
+
});
|
|
360
|
+
// update parent rect
|
|
361
|
+
this.#setParentBounds();
|
|
362
|
+
|
|
363
|
+
// ON
|
|
364
|
+
on();
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
on();
|
|
368
|
+
// return a desync function
|
|
369
|
+
return () => {
|
|
370
|
+
off();
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
}
|
package/src/Point.ts
CHANGED
|
@@ -10,8 +10,6 @@ export type Matrix2 = [number, number, number, number];
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* a point
|
|
13
|
-
* @param x
|
|
14
|
-
* @param y
|
|
15
13
|
*/
|
|
16
14
|
export class Point {
|
|
17
15
|
public x: number;
|
|
@@ -249,7 +247,7 @@ export class Point {
|
|
|
249
247
|
* @param {Point} other the other point
|
|
250
248
|
* @return {boolean} whether the points are equal
|
|
251
249
|
*/
|
|
252
|
-
equals(other): boolean {
|
|
250
|
+
equals(other: Point): boolean {
|
|
253
251
|
return this.x === other.x && this.y === other.y;
|
|
254
252
|
}
|
|
255
253
|
|
|
@@ -258,7 +256,7 @@ export class Point {
|
|
|
258
256
|
* @param {Point} p the other point
|
|
259
257
|
* @return {Number} distance
|
|
260
258
|
*/
|
|
261
|
-
dist(p): number {
|
|
259
|
+
dist(p: Point): number {
|
|
262
260
|
return Math.sqrt(this.distSqr(p));
|
|
263
261
|
}
|
|
264
262
|
|
|
@@ -269,7 +267,7 @@ export class Point {
|
|
|
269
267
|
* @param {Point} p the other point
|
|
270
268
|
* @return {Number} distance
|
|
271
269
|
*/
|
|
272
|
-
distSqr(p): number {
|
|
270
|
+
distSqr(p: Point): number {
|
|
273
271
|
const dx = p.x - this.x;
|
|
274
272
|
const dy = p.y - this.y;
|
|
275
273
|
return dx * dx + dy * dy;
|