Skip to content

Commit 09ce2a3

Browse files
lesbaaLes Moffat
andauthored
RD-901 Misc Spacebox fixes: (#207)
* RD-901 Misc Spacebox fixes: - fix to account for layers being removed when setStyle is called - adds "milyway-colored" preset - exposes `getConfig` method to retrive - update demos to show new method * RD-901 Fix ts annotation in cubemaplayer.ts * RD-901 Reduce some logging to dev only * RD-901 Appease linter --------- Co-authored-by: Les Moffat <[email protected]>
1 parent d764aa8 commit 09ce2a3

File tree

5 files changed

+109
-31
lines changed

5 files changed

+109
-31
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,7 @@ Alternatively, you can provide a cubemap for a space backround using one of the
616616
- `milkyway`: Black half-transparent background with standard milkyway and stars. Space color changes the stars and milkyway color, background always stays black.
617617
- `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.
618618
- `milkyway-bright`: Black half-transparent background with bright milkyway and more stars. Space color changes the stars and milkyway color, background always stays black.
619+
- `milkyway-colored`: Full background image with natural space colors. Space color doesn’t change anything (non transparent image).
619620

620621
```ts
621622
const map = new maptilersdk.Map({

demos/src/07-spacebox.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@ function main() {
2828
const color = input.value;
2929
console.log("Setting background color to:", color);
3030
map.setSpace({
31+
...map.getSpace()?.getConfig(),
3132
color, // or any other color
3233
});
34+
console.log("Config: ", map.getSpace()?.getConfig());
3335
});
3436

3537
const stopsSelection: { stops: [number, string][]; scale: number }[] = [
@@ -123,13 +125,17 @@ function main() {
123125

124126
presetSelect.addEventListener("change", (e: Event) => {
125127
const select = e.target as HTMLSelectElement;
126-
const { value, textContent } = select;
128+
const { value } = select;
127129
const config = configs.find((c) => c.name === value);
128130
if (config) {
129131
console.log("Setting spacebox config:", config);
130-
map.setSpace(config);
132+
const currentConfig = map.getSpace()?.getConfig();
133+
map.setSpace({
134+
...config,
135+
color: currentConfig?.color,
136+
} as CubemapDefinition);
131137
}
132-
console.log("Selected preset:", textContent);
138+
console.log("Current config:", map.getSpace()?.getConfig());
133139
});
134140
}
135141

src/Map.ts

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -216,15 +216,22 @@ export class Map extends maplibregl.Map {
216216
return this.space;
217217
}
218218

219+
/**
220+
* Sets the space for the map.
221+
* @param {CubemapDefinition} space the `CubemapDefinition` options to set.
222+
* @remarks This method, at present, ** overwrites ** the current config.
223+
* If an option is not set it will internally revert to the default option
224+
* unless explicitly set when calling.
225+
*/
219226
public setSpace(space: CubemapDefinition) {
220227
if (this.space) {
221-
this.space.setCubemap(space);
228+
void this.space.setCubemap(space);
222229
return;
223230
}
224231

225232
this.space = new CubemapLayer(space);
226233

227-
this.once("load", () => {
234+
void this.once("load", () => {
228235
const firstLayer = this.getLayersOrder()[0];
229236
if (this.space) {
230237
this.addLayer(this.space, firstLayer);
@@ -236,14 +243,50 @@ export class Map extends maplibregl.Map {
236243
if (!style.metadata?.maptiler?.space) {
237244
return;
238245
}
239-
this.space?.setCubemap(style.metadata.maptiler.space);
246+
const space = style.metadata.maptiler.space;
247+
248+
const updateSpace = () => {
249+
if (this.space) {
250+
const before = this.getLayersOrder()[0];
251+
this.addLayer(this.space, before);
252+
void this.space.setCubemap(space);
253+
}
254+
};
255+
256+
if (!this.styleInProcess) {
257+
updateSpace();
258+
return;
259+
}
260+
261+
void this.once("style.load", () => {
262+
updateSpace();
263+
});
240264
}
241265

242266
private setHaloFromStyle({ style }: { style: StyleSpecificationWithMetaData }) {
243-
if (!style.metadata?.maptiler?.halo) {
267+
const maptiler = style.metadata?.maptiler;
268+
269+
if (!maptiler?.halo) {
244270
return;
245271
}
246-
void this.halo?.setGradient(style.metadata.maptiler.halo);
272+
273+
const updateHalo = () => {
274+
if (this.halo) {
275+
const beforeIndex = this.getLayersOrder().indexOf(this.space?.id ?? "") + 1;
276+
const before = this.getLayersOrder()[beforeIndex];
277+
this.addLayer(this.halo, before);
278+
void this.halo.setGradient(maptiler.halo);
279+
}
280+
};
281+
282+
if (!this.styleInProcess) {
283+
updateHalo();
284+
return;
285+
}
286+
287+
void this.once("style.load", () => {
288+
updateHalo();
289+
});
247290
}
248291

249292
private setSpaceFromCurrentStyle() {
@@ -482,7 +525,6 @@ export class Map extends maplibregl.Map {
482525
this.setProjection({ type: "globe" });
483526
}
484527
});
485-
486528
// Map centering and geolocation
487529
this.once("styledata", async () => {
488530
// Not using geolocation centering if...
@@ -963,18 +1005,18 @@ export class Map extends maplibregl.Map {
9631005
const before = this.getLayersOrder()[0];
9641006

9651007
if (typeof styleInfo.style !== "string" && !styleInfo.requiresUrlMonitoring) {
966-
if (this.space) {
1008+
if (this.halo) {
9671009
const styleWithMetaData = styleInfo.style as StyleSpecificationWithMetaData;
968-
this.setSpaceFromStyle({ style: styleWithMetaData });
1010+
this.setHaloFromStyle({ style: styleWithMetaData });
9691011
} else {
970-
this.initSpace({ before });
1012+
this.initHalo({ before });
9711013
}
9721014

973-
if (this.halo) {
1015+
if (this.space) {
9741016
const styleWithMetaData = styleInfo.style as StyleSpecificationWithMetaData;
975-
this.setHaloFromStyle({ style: styleWithMetaData });
1017+
this.setSpaceFromStyle({ style: styleWithMetaData });
9761018
} else {
977-
this.initHalo({ before });
1019+
this.initSpace({ before });
9781020
}
9791021

9801022
return this;

src/custom-layers/CubemapLayer/CubemapLayer.ts

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,19 @@ function configureOptions(inputOptions: CubemapLayerConstructorOptions | true, d
6464

6565
const presetName = inputOptions.preset!;
6666

67-
if (!(presetName in cubemapPresets)) {
67+
// "Unnecessary conditional"
68+
// It _should_ be defined but we need to check anyway as the preset can come from an outside source
69+
const presetIsUndefined = presetName === undefined;
70+
71+
if (!presetIsUndefined && !(presetName in cubemapPresets)) {
6872
throw new Error(`[CubemapLayer]: Invalid preset "${presetName}". Available presets: ${Object.keys(cubemapPresets).join(", ")}`);
6973
}
7074

7175
// path / faces will not be defined at this point
7276
// so we don't need to delete them
7377
return {
7478
...outputOptions,
79+
// this _could_ be nullish_
7580
color: outputOptions.color ?? cubemapPresets[presetName].color ?? "hsl(233,100%,92%)",
7681
} as CubemapLayerConstructorOptions;
7782
}
@@ -171,6 +176,13 @@ class CubemapLayer implements CustomLayerInterface {
171176
*/
172177
public currentFacesDefinitionKey: string = "";
173178

179+
/**
180+
* The configuration options for the cubemap layer.
181+
* @type {CubemapLayerConstructorOptions}
182+
* @private
183+
*/
184+
private options: CubemapLayerConstructorOptions;
185+
174186
/**
175187
* Creates a new instance of CubemapLayer
176188
*
@@ -185,7 +197,7 @@ class CubemapLayer implements CustomLayerInterface {
185197
*/
186198
constructor(cubemapConfig: CubemapLayerConstructorOptions | true) {
187199
const options = configureOptions(cubemapConfig, defaultConstructorOptions);
188-
200+
this.options = options;
189201
this.currentFacesDefinitionKey = JSON.stringify(options.faces ?? options.preset ?? options.path);
190202

191203
this.bgColor = [0, 0, 0, 0];
@@ -240,6 +252,7 @@ class CubemapLayer implements CustomLayerInterface {
240252
*/
241253
public onAdd(map: MapSDK, gl: WebGLRenderingContext | WebGL2RenderingContext): void {
242254
this.map = map;
255+
243256
this.gl = gl;
244257
this.updateCubemap();
245258
}
@@ -251,7 +264,7 @@ class CubemapLayer implements CustomLayerInterface {
251264
* @param {MapSDK} _map - The map instance from which this layer is removed.
252265
* @param {WebGLRenderingContext | WebGL2RenderingContext} gl - The WebGL context used for rendering.
253266
*/
254-
public onRemove(_map: MapSDK, gl: WebGLRenderingContext | WebGL2RenderingContext): void {
267+
public onRemove(_map: MapSDK, gl: WebGLRenderingContext | WebGL2RenderingContext) {
255268
if (this.cubemap) {
256269
gl.deleteProgram(this.cubemap.shaderProgram);
257270
gl.deleteBuffer(this.cubemap.positionBuffer);
@@ -290,7 +303,7 @@ class CubemapLayer implements CustomLayerInterface {
290303
* @param {CustomRenderMethodInput} _options - Additional options for the render method.
291304
*/
292305
public prerender(gl: WebGLContext, _options: CustomRenderMethodInput): void {
293-
this.updateTexture(gl, this.faces!);
306+
if (this.faces) this.updateTexture(gl, this.faces!);
294307
}
295308

296309
/**
@@ -303,9 +316,9 @@ class CubemapLayer implements CustomLayerInterface {
303316
const animateColorChange = () => {
304317
if (this.transitionDelta < 1.0) {
305318
requestAnimationFrame(animateColorChange);
306-
307319
this.bgColor = lerpVec4(this.previousBgColor, this.targetBgColor, this.transitionDelta);
308320
this.transitionDelta += 0.075;
321+
309322
this.map.triggerRepaint();
310323
}
311324
};
@@ -370,7 +383,6 @@ class CubemapLayer implements CustomLayerInterface {
370383
this.imageFadeInDelta = Math.min(this.imageFadeInDelta + 0.05, 1.0);
371384
this.currentFadeOpacity = lerp(1.0, 0.0, this.imageFadeInDelta);
372385
this.map.triggerRepaint();
373-
374386
if (this.imageFadeInDelta >= 1.0) {
375387
this.imageIsAnimating = false;
376388
this.imageFadeInDelta = 0.0;
@@ -401,8 +413,8 @@ class CubemapLayer implements CustomLayerInterface {
401413
throw new Error("[CubemapLayer]: Cubemap is undefined");
402414
}
403415

404-
if (this.texture === undefined) {
405-
console.warn("[CubemapLayer]: Texture is undefined, no teture will be rendered to cubemap");
416+
if (this.texture === undefined && process.env.NODE_ENV === "development") {
417+
console.warn("[CubemapLayer]: Texture is undefined, no texture will be rendered to cubemap");
406418
}
407419

408420
gl.disable(gl.DEPTH_TEST);
@@ -447,15 +459,9 @@ class CubemapLayer implements CustomLayerInterface {
447459
*/
448460
gl.uniform4fv(this.cubemap.programInfo.uniformsLocations.bgColor, new Float32Array(this.bgColor));
449461

450-
/**
451-
* Texture
452-
*/
453-
if (this.texture === undefined) {
454-
console.warn("[CubemapLayer]: Texture is undefined, no texture will be rendered to cubemap");
455-
}
462+
gl.uniform1f(this.cubemap.programInfo.uniformsLocations.fadeOpacity, this.currentFadeOpacity);
456463

457464
if (this.useCubemapTexture && this.texture) {
458-
gl.uniform1f(this.cubemap.programInfo.uniformsLocations.fadeOpacity, this.currentFadeOpacity);
459465
gl.activeTexture(gl.TEXTURE0);
460466
gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.texture);
461467
gl.uniform1i(this.cubemap.programInfo.uniformsLocations.cubeSampler, 0);
@@ -484,9 +490,25 @@ class CubemapLayer implements CustomLayerInterface {
484490
this.transitionDelta = 0.0;
485491
}
486492

493+
/**
494+
* Returns the current configuration options for the cubemap layer.
495+
* @returns {CubemapLayerConstructorOptions} The current configuration options.
496+
*/
497+
public getConfig() {
498+
return this.options;
499+
}
500+
487501
private async setCubemapFaces(cubemap: CubemapDefinition): Promise<void> {
488502
await this.animateOut();
489503

504+
if (!cubemap.faces && !cubemap.preset && !cubemap.path) {
505+
this.faces = null;
506+
this.useCubemapTexture = false;
507+
this.currentFacesDefinitionKey = "";
508+
this.animateIn();
509+
return;
510+
}
511+
490512
this.faces = getCubemapFaces(cubemap);
491513
this.currentFacesDefinitionKey = JSON.stringify(cubemap.faces ?? cubemap.preset ?? cubemap.path);
492514
}
@@ -504,13 +526,16 @@ class CubemapLayer implements CustomLayerInterface {
504526
* Finally, it calls `updateCubemap` to apply the changes and trigger a repaint of the map.
505527
*/
506528
public async setCubemap(cubemap: CubemapDefinition): Promise<void> {
529+
this.options = cubemap;
530+
507531
const facesKey = JSON.stringify(cubemap.faces ?? cubemap.preset ?? cubemap.path);
508532

509-
if (facesKey && this.currentFacesDefinitionKey !== facesKey) {
533+
if (this.currentFacesDefinitionKey !== facesKey) {
510534
await this.setCubemapFaces(cubemap);
511535
}
512536

513537
const color = parseColorStringToVec4(cubemap.color);
538+
514539
if (cubemap.color && this.targetBgColor.toString() !== color.toString()) {
515540
this.setBgColor(color);
516541
} else if (cubemap.preset && cubemap.preset in cubemapPresets) {

src/custom-layers/CubemapLayer/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ export const cubemapPresets: Record<string, CubemapDefinition> = {
2929
color: "hsl(233,100%,92%)",
3030
preset: "milkyway-bright",
3131
},
32+
"milkyway-colored": {
33+
color: "black",
34+
preset: "milkyway-colored",
35+
},
3236
};
3337

3438
// This is not the most elegant but it's more readable than some of the alternatives.

0 commit comments

Comments
 (0)