UNPKG

@panoramax/web-viewer

Version:

Panoramax web viewer for geolocated pictures

138 lines (122 loc) 4.32 kB
import { PanoramaxPresetsURL } from "./services"; // Iconify aliases for whole collections const ICON_COLLECTIONS_SUB = { "fas": "fa6-solid" }; // Iconify aliases for specific icons const ICON_SUBS = { "fa6-solid:directions": "fa6-solid:diamond-turn-right" }; /** * Presets Manager handle retrieval of presets against dedicated endpoint. * It allows an easily search between all presets, and handles translations. * * @class Panoramax.utils.PresetsManager * @typicalname presetsManager * @param {string} [lang] The user prefered language. Defaults to web browser preferences. * @param {boolean} [skipLoad=false] Set to true to disable automatic load of API data */ export default class PresetManager { constructor(lang = null, skipLoad = false) { this._ready = false; this._presets = null; this._translations = {}; if(!skipLoad) { this._load(lang); } } /** * Downloads various JSON file against presets API. * @private */ async _load(lang) { lang = lang || window.navigator.languages[0]?.substring(0, 2); try { const [translationsENRes, translationsLangRes, presetsRes] = await Promise.all([ fetch(`${PanoramaxPresetsURL()}/translations/en.min.json`), lang ? fetch(`${PanoramaxPresetsURL()}/translations/${lang}.min.json`) : Promise.resolve({ok: true}), fetch(`${PanoramaxPresetsURL()}/presets.min.json`), ]); if ( !translationsENRes || !translationsLangRes || !presetsRes || !translationsENRes.ok || !translationsLangRes.ok || !presetsRes.ok ) { this._ready = -1; throw new Error("Presets service is not available"); } this._presets = await presetsRes.json(); this._translations.en = (await translationsENRes.json())?.en?.presets; if(lang) { this._translations[lang] = (await translationsLangRes.json())?.[lang]?.presets; } // Post-process presets Object.entries(this._presets).forEach(([pid,p]) => { // Add labels if(this._translations[lang]?.presets?.[pid]?.name) { p.name = this._translations[lang].presets[pid].name; } else if(this._translations.en?.presets?.[pid]?.name) { p.name = this._translations.en.presets[pid].name; } // Create iconify-compatible icon if(p.icon) { const iconColl = p.icon.split("-")[0]; const iconCollSub = ICON_COLLECTIONS_SUB[iconColl]; p.iconify = iconCollSub ? p.icon.replace(iconColl+"-", iconCollSub+":") : p.icon.split("-")[0]+":"+p.icon.split("-").slice(1).join("-"); if(ICON_SUBS[p.iconify]) { p.iconify = ICON_SUBS[p.iconify]; } } }); this._ready = true; } catch (error) { console.error("Presets service throws an error:", error); this._ready = -1; } } /** * Resolves when the all necessary data was downloaded. * @memberOf Panoramax.utils.PresetsManager# * @returns {Promise} */ async onceReady() { if(!this._ready) { await new Promise(resolve => setTimeout(resolve, 250)); return this.onceReady(); } else if(this._ready === -1) { return Promise.reject(); } else { return Promise.resolve(); } } /** * Find the best matching preset for a given STAC feature. * @memberOf Panoramax.utils.PresetsManager# * @returns {Promise} * @fulfil {object|null} The preset JSON that best matches, or null if no matches */ async getPreset(f) { return this.onceReady().then(() => { const candidatePresets = Object.values(this._presets).filter(p => { if(Object.keys(p.tags).length === 0) { return false; } // Check if every tag on preset exists in feature for(let pk in p.tags) { const pv = p.tags[pk]; if(!f.semantics.find(s => s.key === pk && (pv === "*" || pv === s.value))) { return false; } } return true; }); // Find best matching preset candidatePresets.sort((a,b) => { const nbTagsA = Object.keys(a.tags).length; const nbTagsB = Object.keys(b.tags).length; if(nbTagsA > nbTagsB) { return -1; } else if(nbTagsA === nbTagsB) { const nbTagsStarA = Object.values(a.tags).filter(v => v === "*").length; const nbTagsStarB = Object.values(b.tags).filter(v => v === "*").length; if(nbTagsStarA < nbTagsStarB) { return -1; } else if(nbTagsStarA > nbTagsStarB) { return 1; } else { return 0; } } else { return 1; } }); return candidatePresets.shift(); }); } }