diff --git a/src/lib/geolonia-map.ts b/src/lib/geolonia-map.ts index 746c70c..e71d5a3 100644 --- a/src/lib/geolonia-map.ts +++ b/src/lib/geolonia-map.ts @@ -8,7 +8,7 @@ import parseAtts from './parse-atts'; import { SimpleStyle } from './simplestyle'; import SimpleStyleVector from './simplestyle-vector'; -import { getContainer, getOptions, getSessionId, getStyle, handleRestrictedMode, isScrollable, parseControlOption, parseSimpleVector } from './util'; +import { getContainer, getOptions, getSessionId, getStyle, handleRestrictedMode, isScrollable, parseControlOption, parseSimpleVector, handleErrorMode } from './util'; import type { MapOptions, PointLike, StyleOptions, StyleSpecification, StyleSwapOptions } from 'maplibre-gl'; @@ -46,10 +46,11 @@ export default class GeoloniaMap extends maplibregl.Map { private __styleExtensionLoadRequired: boolean; constructor(params: string | GeoloniaMapOptions) { + const container = getContainer(params) as Container | false; if (!container) { - if ( typeof params === 'string') { + if (typeof params === 'string') { throw new Error(`[Geolonia] No HTML elements found matching \`${params}\`. Please ensure the map container element exists.`); } else { throw new Error('[Geolonia] No HTML elements found. Please ensure the map container element exists.'); @@ -142,8 +143,14 @@ export default class GeoloniaMap extends maplibregl.Map { return request; }; - // Generate Map - super(options); + try { + // Generate Map + super(options); + } catch (error) { + handleErrorMode(container); + throw error; + } + const map = this; this.geoloniaSourcesUrl = sourcesUrl; this.__styleExtensionLoadRequired = true; @@ -151,7 +158,7 @@ export default class GeoloniaMap extends maplibregl.Map { // Note: GeoloniaControl should be placed before another controls. // Because this control should be "very" bottom-left(default) or the attributed position. const { position: geoloniaControlPosition } = parseControlOption(atts.geoloniaControl); - map.addControl(new GeoloniaControl(), geoloniaControlPosition); + map.addControl(new GeoloniaControl(), geoloniaControlPosition); map.addControl(new CustomAttributionControl(), 'bottom-right'); @@ -172,7 +179,7 @@ export default class GeoloniaMap extends maplibregl.Map { const { enabled: scaleControlEnabled, position: scaleControlPosition } = parseControlOption(atts.scaleControl); if (scaleControlEnabled) { - map.addControl(new ScaleControl({}), scaleControlPosition); + map.addControl(new ScaleControl({}), scaleControlPosition); } map.on('load', (event) => { diff --git a/src/lib/render.ts b/src/lib/render.ts index afb724c..a91a3eb 100644 --- a/src/lib/render.ts +++ b/src/lib/render.ts @@ -67,7 +67,12 @@ export const renderGeoloniaMap = () => { if (!item.isIntersecting) { return; } - renderSingleMap(item.target); + try { + renderSingleMap(item.target); + } catch (e) { + // Not throw error because, following maps will not be rendered. + console.error('[Geolonia] Failed to initialize map', e); // eslint-disable-line + } observer.unobserve(item.target); }); }); @@ -82,7 +87,12 @@ export const renderGeoloniaMap = () => { // render Map immediately for (let i = 0; i < containers.length; i++) { - renderSingleMap(containers[i]); + try { + renderSingleMap(containers[i]); + } catch (e) { + // Not throw error because, following maps will not be rendered. + console.error('[Geolonia] Failed to initialize map', e); // eslint-disable-line + } } // set intersection observer diff --git a/src/lib/util.ts b/src/lib/util.ts index 65204bf..00e0a07 100644 --- a/src/lib/util.ts +++ b/src/lib/util.ts @@ -272,6 +272,24 @@ export const handleRestrictedMode = (map) => { } }; +export const handleErrorMode = (container) => { + + const errorContainer = document.createElement('div'); + errorContainer.classList.add('geolonia__error-container'); + + const div = document.createElement('div'); + + const h1 = document.createElement('h2'); + h1.textContent = 'Geolonia Maps'; + div.appendChild(h1); + + div.classList.add('geolonia__error-message'); + div.innerHTML += '
'; + + errorContainer.appendChild(div); + container.appendChild(errorContainer); +}; + export const sanitizeDescription = async (description) => { const { default: sanitizeHtml } = await import('sanitize-html'); return sanitizeHtml(description, { @@ -281,3 +299,4 @@ export const sanitizeDescription = async (description) => { }; export const random = (max: number): number => Math.floor(Math.random() * max); + diff --git a/src/style.css b/src/style.css index 3e288fb..33554f5 100644 --- a/src/style.css +++ b/src/style.css @@ -110,6 +110,34 @@ background-size: cover; } +/* Style for error message */ +.geolonia__error-container { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + background-color: #dedede; + z-index: 9999; + position: absolute; +} + +.geolonia__error-message { + max-width: 300px; + background-color: #ffffff; + margin: 10px; + padding: 0.75rem 1.25rem; + border-radius: 6px; + position: absolute; + z-index: 99999; + word-wrap: break-word; + box-shadow: 0 4px 10px #0000001a +} + +.geolonia__error-message-description { + margin: 15px 0; +} + /* CSS for Attribution */ /* Fix: https://github.com/geolonia/embed/issues/291 */ .maplibregl-map {