Skip to content

Commit 290e626

Browse files
Ihor DykhtaIhor Dykhta
authored andcommitted
Merge branch 'master' into igr/patch-3.3.0-alpha.6
2 parents 5f8a56e + 426d605 commit 290e626

2 files changed

Lines changed: 86 additions & 11 deletions

File tree

src/utils/src/export-map-html.ts

Lines changed: 83 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,29 @@ export const exportMapToHTML = (options, version = KEPLER_GL_VERSION) => {
8686
// native loader (which fails under file://).
8787
window.esmsInitOptions = {shimMode: true};
8888
</script>
89+
<script>
90+
// Replace the loading overlay with an error message.
91+
// Safe to call at any time — once React has mounted and removed
92+
// #kepler-load-screen this becomes a no-op.
93+
window._keplerShowLoadError = function(msg) {
94+
var loadScreen = document.getElementById('kepler-load-screen');
95+
if (!loadScreen) return;
96+
var spinner = loadScreen.querySelector('.kepler-spinner');
97+
var label = loadScreen.querySelector('.kepler-load-label');
98+
if (spinner) spinner.style.display = 'none';
99+
if (label) label.style.display = 'none';
100+
var errEl = document.createElement('div');
101+
errEl.className = 'kepler-load-error';
102+
errEl.textContent = msg || 'Failed to load the map. Check your internet connection and reload the page.';
103+
loadScreen.appendChild(errEl);
104+
};
105+
// Catch unhandled promise rejections (e.g. ES module imports failing
106+
// inside the module-shim script before loadScript is ever called).
107+
window.addEventListener('unhandledrejection', function(event) {
108+
console.error('kepler.gl: unhandled rejection during map load', event.reason);
109+
window._keplerShowLoadError('Failed to load the map. Check your internet connection and reload the page.');
110+
});
111+
</script>
89112
<script src="https://unpkg.com/es-module-shims@${ES_MODULE_SHIMS_VERSION}/dist/es-module-shims.js" crossorigin="anonymous"></script>
90113
91114
<script type="importmap-shim">
@@ -155,10 +178,44 @@ export const exportMapToHTML = (options, version = KEPLER_GL_VERSION) => {
155178
})
156179
.catch(function(error) {
157180
console.error('kepler.gl: failed to load UMD bundle', error);
181+
window._keplerShowLoadError('Failed to load the map bundle. Check your internet connection and reload the page.');
158182
});
159183
</script>
160184
<style type="text/css">
161185
body {margin: 0; padding: 0; overflow: hidden;}
186+
#kepler-load-screen {
187+
position: fixed;
188+
top: 0; left: 0;
189+
width: 100%; height: 100%;
190+
background: #29323c;
191+
display: flex;
192+
flex-direction: column;
193+
align-items: center;
194+
justify-content: center;
195+
gap: 20px;
196+
z-index: 9999;
197+
font-family: ff-clan-web-pro, 'Helvetica Neue', Helvetica, sans-serif;
198+
color: #a0a7b4;
199+
}
200+
#kepler-load-screen .kepler-spinner {
201+
width: 48px; height: 48px;
202+
border: 4px solid rgba(255,255,255,0.08);
203+
border-top-color: #1fbad6;
204+
border-radius: 50%;
205+
animation: kepler-spin 0.8s linear infinite;
206+
}
207+
#kepler-load-screen .kepler-load-label {
208+
font-size: 13px;
209+
letter-spacing: 0.5px;
210+
}
211+
#kepler-load-screen .kepler-load-error {
212+
font-size: 13px;
213+
color: #f05e45;
214+
max-width: 360px;
215+
text-align: center;
216+
line-height: 1.5;
217+
}
218+
@keyframes kepler-spin { to { transform: rotate(360deg); } }
162219
</style>
163220
164221
<!--MapBox token-->
@@ -199,7 +256,10 @@ export const exportMapToHTML = (options, version = KEPLER_GL_VERSION) => {
199256
<body>
200257
<!-- We will put our React component inside this div. -->
201258
<div id="app">
202-
<!-- Kepler.gl map will be placed here-->
259+
<div id="kepler-load-screen">
260+
<div class="kepler-spinner"></div>
261+
<div class="kepler-load-label">Loading map…</div>
262+
</div>
203263
</div>
204264
205265
<!--
@@ -214,17 +274,23 @@ export const exportMapToHTML = (options, version = KEPLER_GL_VERSION) => {
214274
}
215275
216276
/** STORE **/
217-
const reducers = (function createReducers(redux, keplerGl) {
277+
// Pre-seed styleType so the correct basemap fetch starts on the very
278+
// first render, avoiding a flash of the default dark basemap.
279+
// options.config has the versioned envelope shape: { version, config: { mapStyle, ... } }
280+
const savedStyleType = ${JSON.stringify(options.config?.config?.mapStyle?.styleType ?? null)};
281+
282+
const reducers = (function createReducers(redux, keplerGl, styleType) {
218283
return redux.combineReducers({
219284
// mount keplerGl reducer
220285
keplerGl: keplerGl.keplerGlReducer.initialState({
221286
uiState: {
222287
readOnly: ${options.mode === EXPORT_HTML_MAP_MODES.READ},
223288
currentModal: null
224-
}
289+
},
290+
...(styleType ? {mapStyle: {styleType}} : {})
225291
})
226292
});
227-
}(Redux, KeplerGl));
293+
}(Redux, KeplerGl, savedStyleType));
228294
229295
const middleWares = (function createMiddlewares(keplerGl) {
230296
return keplerGl.enhanceReduxMiddleware([
@@ -237,11 +303,9 @@ export const exportMapToHTML = (options, version = KEPLER_GL_VERSION) => {
237303
}(Redux, middleWares));
238304
239305
const store = (function createStore(redux, enhancers) {
240-
const initialState = {};
241-
242306
return redux.createStore(
243307
reducers,
244-
initialState,
308+
{},
245309
redux.compose(enhancers)
246310
);
247311
}(Redux, enhancers));
@@ -359,6 +423,13 @@ export const exportMapToHTML = (options, version = KEPLER_GL_VERSION) => {
359423
window.addEventListener('resize', handleResize);
360424
return function() {window.removeEventListener('resize', handleResize);};
361425
}, []);
426+
// Remove the loading overlay after the first render is painted.
427+
// useEffect fires post-commit, so this is safe under React 19's
428+
// concurrent renderer — the map is visible before the overlay goes away.
429+
react.useEffect(function removeLoadScreen() {
430+
var loadScreen = document.getElementById('kepler-load-screen');
431+
if (loadScreen) loadScreen.remove();
432+
}, []);
362433
return react.createElement(
363434
'div',
364435
{style: {position: 'absolute', left: 0, width: '100vw', height: '100vh'}},
@@ -403,7 +474,11 @@ export const exportMapToHTML = (options, version = KEPLER_GL_VERSION) => {
403474
config
404475
);
405476
406-
// For some reason Kepler overwrites the config without extra wait time
477+
// The 500 ms delay is a historical workaround for a race where
478+
// keplerGl re-initialises and overwrites config applied synchronously.
479+
// The pre-seeded styleType above removes the basemap flash on first
480+
// render; this dispatch still applies the full saved config (layers,
481+
// viewport, layer groups, etc.) once the component has settled.
407482
window.setTimeout(() => {
408483
store.dispatch(
409484
keplerGl.addDataToMap({

website/yarn.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4620,9 +4620,9 @@ __metadata:
46204620
linkType: hard
46214621

46224622
"fast-uri@npm:^3.0.1":
4623-
version: 3.1.4
4624-
resolution: "fast-uri@npm:3.1.4"
4625-
checksum: 10c0/f90948821ceb49980f64f89b8216ba498f5957f26035be813526a55b6145d26cbd63ef5618d5205a3292b31edc9c08589749350cd72bd86c7095eb434dceb757
4623+
version: 3.1.5
4624+
resolution: "fast-uri@npm:3.1.5"
4625+
checksum: 10c0/2bf60eb800dd610c65e17be436425dcb21c92aff3a87d442a8bccab0b7b071e88cf1a5d7d1ea946370b937e6fc0375c405c0296c10587e57de4f78be4646d1d0
46264626
languageName: node
46274627
linkType: hard
46284628

0 commit comments

Comments
 (0)