Skip to content

Commit c1bcb0e

Browse files
lesbaaLes Moffat
andauthored
Rd 1112 projection change to mercator breaks style loading (#222)
* RD-112 Add validation to space and halo * RD-1112 Version bump for RC release * RD-1112 Add check to ensure spacebox is only created when style is loaded * RD-1112 Fix map breaking when empty object is passed to space / halo * RD-1112 Version bump for RC release. * RD-1112 Version bump and update changelog * RD-1112 Better wording for changelog * RD-1112 Fix typo * RD-1112 Remove un-need state variable * RD-1112 Better wording of explanatory comments * RD-1112 Fix Spelling in changelog --------- Co-authored-by: Les Moffat <[email protected]>
1 parent 229a6e2 commit c1bcb0e

File tree

6 files changed

+118
-23
lines changed

6 files changed

+118
-23
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# MapTiler SDK Changelog
22

3+
## 3.6.2
4+
5+
### ✨ Features and improvements
6+
- None
7+
8+
### 🐛 Bug fixes
9+
- Includes workaround where internal event is not fired correctly and causes breaking of space box.
10+
11+
### Others
12+
- None
13+
314
## 3.6.1
415

516
### ✨ Features and improvements

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@maptiler/sdk",
3-
"version": "3.6.1",
3+
"version": "3.6.2",
44
"description": "The Javascript & TypeScript map SDK tailored for MapTiler Cloud",
55
"author": "MapTiler",
66
"module": "dist/maptiler-sdk.mjs",

src/Map.ts

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import type { MinimapOptionsInput } from "./controls/Minimap";
3939
import { CACHE_API_AVAILABLE, registerLocalCacheProtocol } from "./caching";
4040
import { MaptilerProjectionControl } from "./controls/MaptilerProjectionControl";
4141
import { Telemetry } from "./Telemetry";
42-
import { CubemapDefinition, CubemapLayer, CubemapLayerConstructorOptions } from "./custom-layers/CubemapLayer";
42+
import { CubemapDefinition, CubemapLayer, CubemapLayerConstructorOptions, validateSpaceSpecification } from "./custom-layers/CubemapLayer";
4343
import { GradientDefinition, RadialGradientLayer, RadialGradientLayerConstructorOptions } from "./custom-layers/RadialGradientLayer";
4444
import { StyleSpecificationWithMetaData } from "./custom-layers/extractCustomLayerStyle";
4545

@@ -252,6 +252,14 @@ export class Map extends maplibregl.Map {
252252
return;
253253
}
254254

255+
const spaceSpecIsValid = validateSpaceSpecification(space);
256+
if (!spaceSpecIsValid) {
257+
this.setSpace({
258+
color: "transparent",
259+
});
260+
return;
261+
}
262+
255263
if (JSON.stringify(this.space?.getConfig()) === JSON.stringify(space)) {
256264
// because maplibre removes ALL layers when setting a new style, we need to add the space layer back
257265
// even if it hasn't changed
@@ -296,7 +304,7 @@ export class Map extends maplibregl.Map {
296304
[0, "transparent"],
297305
[1, "transparent"],
298306
],
299-
scale: 0,
307+
scale: 1,
300308
});
301309
return;
302310
}
@@ -1007,18 +1015,16 @@ export class Map extends maplibregl.Map {
10071015
if (styleInfo.isFallback) {
10081016
if (this.getStyle()) {
10091017
console.warn(
1010-
"Invalid style. A style must be a valid URL to a style.json, a JSON string representing a valid StyleSpecification or a valid StyleSpecification object. Keeping the curent style instead.",
1018+
"[Map.setStyle]: Invalid style. A style must be a valid URL to a style.json, a JSON string representing a valid StyleSpecification or a valid StyleSpecification object. Keeping the curent style instead.",
10111019
);
10121020
return this;
10131021
}
10141022

10151023
console.warn(
1016-
"Invalid style. A style must be a valid URL to a style.json, a JSON string representing a valid StyleSpecification or a valid StyleSpecification object. Fallback to default MapTiler style.",
1024+
"[Map.setStyle]: Invalid style. A style must be a valid URL to a style.json, a JSON string representing a valid StyleSpecification or a valid StyleSpecification object. Fallback to default MapTiler style.",
10171025
);
10181026
}
10191027

1020-
this.styleInProcess = true;
1021-
10221028
// because the style must be finished loading and parsed before we can add custom layers
10231029
// we need to check if the terrain has changed, because if it has, we also need to wait
10241030
// for the terrain to load...
@@ -1027,6 +1033,7 @@ export class Map extends maplibregl.Map {
10271033

10281034
try {
10291035
super.setStyle(styleInfo.style, options);
1036+
this.styleInProcess = true;
10301037
} catch (e) {
10311038
this.styleInProcess = false;
10321039
console.error("[Map.setStyle]: Error while setting style:", e);
@@ -1038,13 +1045,21 @@ export class Map extends maplibregl.Map {
10381045
}
10391046

10401047
const setSpaceAndHaloFromStyle = () => {
1048+
const styleSpec = styleInfo.style as StyleSpecificationWithMetaData;
1049+
if (!styleSpec.projection || styleSpec.projection.type === "mercator") {
1050+
console.warn("[Map.setStyle]: Neither space nor halo is supported for mercator projection. Ignoring...");
1051+
return;
1052+
}
1053+
10411054
this.setSpaceFromStyle({ style: styleInfo.style as StyleSpecificationWithMetaData });
1055+
10421056
this.setHaloFromStyle({ style: styleInfo.style as StyleSpecificationWithMetaData });
10431057
};
10441058

1045-
const handleStyleLoad = () => {
1059+
const handleStyleLoad = (e?: maplibregl.MapStyleDataEvent) => {
1060+
const styleSpec = (e?.target.getStyle() ?? styleInfo.style) as StyleSpecificationWithMetaData;
1061+
10461062
const targetBeforeLayer = this.getLayersOrder()[0];
1047-
const styleSpec = styleInfo.style as StyleSpecificationWithMetaData;
10481063
if (this.space) {
10491064
this.setSpaceFromStyle({ style: styleSpec });
10501065
} else {
@@ -1058,11 +1073,23 @@ export class Map extends maplibregl.Map {
10581073
}
10591074
};
10601075

1061-
if (this.styleInProcess && !this.spaceboxLoadingState.styleLoadCallbackSet) {
1076+
if (this.styleInProcess) {
10621077
// this handles setting space and halo from style on load
1063-
void this.once("style.load", handleStyleLoad);
1064-
this.spaceboxLoadingState.styleLoadCallbackSet = true;
1065-
return this;
1078+
// void this.once("idle", handleStyleLoad);
1079+
// void this.once("style.load", handleStyleLoad);
1080+
if (!this.spaceboxLoadingState.styleLoadCallbackSet) {
1081+
// unfortunately, the style.load event is not always fired correctly when
1082+
// the style is set from an object (generally when projection changes or when metadata changes)
1083+
// so, in this instance, we have to double tap with both style events.
1084+
// an issue has been raised on the maplibre github
1085+
void this.once("style.load", handleStyleLoad);
1086+
void this.once("styledata", handleStyleLoad);
1087+
1088+
this.spaceboxLoadingState.styleLoadCallbackSet = true;
1089+
return this;
1090+
}
1091+
1092+
// if these load event doesn't fire after 10 seconds, we need to reset the flag
10661093
}
10671094

10681095
// the type returned from getStyle is incorrect, it can be null
@@ -1074,13 +1101,12 @@ export class Map extends maplibregl.Map {
10741101
return this;
10751102
}
10761103

1077-
const projectionFieldDeleted = !newStyle?.projection?.type;
1078-
if (projectionFieldDeleted) {
1079-
this.styleInProcess = true;
1080-
return this;
1081-
}
1082-
1083-
handleStyleLoad();
1104+
try {
1105+
// because of the current uncertainty of the style.load event
1106+
// we have no way of knowing if the style is loaded or not
1107+
// which will fail internally if the style is not loaded correctly
1108+
handleStyleLoad();
1109+
} catch {}
10841110

10851111
return this;
10861112
}

src/custom-layers/CubemapLayer/CubemapLayer.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ const defaultConstructorOptions: CubemapLayerConstructorOptions = cubemapPresets
3838
* @throws Error if an invalid preset name is provided.
3939
*/
4040
function configureOptions(inputOptions: CubemapLayerConstructorOptions | true, defaults: CubemapLayerConstructorOptions) {
41+
if (!validateSpaceSpecification(inputOptions)) {
42+
return {
43+
color: "transparent",
44+
};
45+
}
46+
4147
if (inputOptions === true) {
4248
return defaults;
4349
}
@@ -576,6 +582,26 @@ class CubemapLayer implements CustomLayerInterface {
576582
}
577583
}
578584

585+
export function validateSpaceSpecification(space: CubemapDefinition | boolean): boolean {
586+
if (typeof space === "boolean") {
587+
return true;
588+
}
589+
590+
if (!space.path && !space.preset && !space.faces && !space.color) {
591+
return false;
592+
}
593+
594+
if (space.preset && !(space.preset in cubemapPresets)) {
595+
return false;
596+
}
597+
598+
if (space.faces && (!space.faces.pX || !space.faces.nX || !space.faces.pY || !space.faces.nY || !space.faces.pZ || !space.faces.nZ)) {
599+
return false;
600+
}
601+
602+
return true;
603+
}
604+
579605
/**
580606
* Retrieves the cubemap faces based on the provided options.
581607
* This function checks if the faces are explicitly defined, uses a preset, or constructs the faces from a path.

src/custom-layers/RadialGradientLayer/RadialGradientLayer.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,17 @@ export class RadialGradientLayer implements CustomLayerInterface {
326326
*/
327327
public async setGradient(gradient: GradientDefinition): Promise<void> {
328328
await this.animateOut();
329-
this.gradient = gradient;
329+
if (!validateHaloSpecification(gradient)) {
330+
this.gradient.scale = defaultConstructorOptions.scale;
331+
this.gradient.stops = [
332+
[0, "transparent"],
333+
[1, "transparent"],
334+
];
335+
return;
336+
}
337+
this.gradient.scale = gradient.scale ?? defaultConstructorOptions.scale;
338+
this.gradient.stops = gradient.stops ?? defaultConstructorOptions.stops;
339+
330340
await this.animateIn();
331341
}
332342

@@ -340,3 +350,25 @@ export class RadialGradientLayer implements CustomLayerInterface {
340350
this.map.setLayoutProperty(this.id, "visibility", "none");
341351
}
342352
}
353+
354+
export function validateHaloSpecification(halo: RadialGradientLayerConstructorOptions | boolean): boolean {
355+
if (typeof halo === "boolean") {
356+
return true;
357+
}
358+
359+
if (typeof halo.scale !== "number") {
360+
return false;
361+
}
362+
363+
// this is testing external data so we need to check
364+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
365+
if (!halo.stops || halo.stops.length === 0) {
366+
return false;
367+
}
368+
369+
if (halo.stops.some((stop) => typeof stop[0] !== "number" || typeof stop[1] !== "string")) {
370+
return false;
371+
}
372+
373+
return true;
374+
}

0 commit comments

Comments
 (0)