@maptiler/client
Version:
Javascript & Typescript wrapper to MapTiler Cloud API
2,206 lines (2,194 loc) • 69.7 kB
JavaScript
'use strict';
function tryGettingFetch() {
if (typeof self !== "undefined") {
return fetch.bind(self);
}
if (typeof global !== "undefined" && global.fetch) {
return global.fetch;
}
return null;
}
class ClientConfig {
constructor() {
/**
* MapTiler Cloud API key
*/
this._apiKey = "";
/**
* The fetch function. To be set if in Node < 18, otherwise
* will be automatically resolved.
*/
this._fetch = tryGettingFetch();
/**
* Number of tiles to keep in cache
*/
this.tileCacheSize = 200;
}
/**
* Set the MapTiler Cloud API key
*/
set apiKey(k) {
this._apiKey = k;
}
/**
* Get the MapTiler Cloud API key
*/
get apiKey() {
return this._apiKey;
}
/**
* Set a the custom fetch function to replace the default one
*/
set fetch(f) {
this._fetch = f;
}
/**
* Get the fetch fucntion
*/
get fetch() {
return this._fetch;
}
}
const config = new ClientConfig();
const NonISOLanguage = {
/**
* Language mode to display the labels in the end user's device language.
*/
AUTO: {
code: null,
flag: "auto",
name: "Auto",
latin: false,
isMode: true,
geocoding: true
},
/**
* The OSM language using latin script. MapTiler discourages its use as a primary language setting due to the lack of actual linguistic specificity,
* though it can be an handy fallback. This is not to be confused with the "Classical Latin" language, which is available under the tag `.CLASSICAL_LATIN`.
*/
LATIN: {
code: "latin",
flag: "name:latin",
name: "Latin",
latin: true,
isMode: false,
geocoding: false
},
/**
* The OSM language using non-latin script. MapTiler discourages its use as a primary language setting due to the lack of actual linguistic specificity,
* though it can be an handy fallback.
*/
NON_LATIN: {
code: "nonlatin",
flag: "name:nonlatin",
name: "Non Latin",
latin: false,
isMode: false,
geocoding: false
},
/**
* Using the local language generaly (but not always) means that every labels of a given region will use the dominant local language.
*/
LOCAL: {
code: null,
flag: "name",
name: "Local",
latin: true,
isMode: false,
geocoding: false
}
};
const ISOLanguage = {
/**
* Albanian language
*/
ALBANIAN: {
code: "sq",
flag: "name:sq",
name: "Albanian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Amharic language
*/
AMHARIC: {
code: "am",
flag: "name:am",
name: "Amharic",
latin: false,
isMode: false,
geocoding: true
},
/**
* Arabic language (right-to-left script)
*/
ARABIC: {
code: "ar",
flag: "name:ar",
name: "Arabic",
latin: false,
isMode: false,
geocoding: true
},
/**
* Armenian language
*/
ARMENIAN: {
code: "hy",
flag: "name:hy",
name: "Armenian",
latin: false,
isMode: false,
geocoding: true
},
/**
* Azerbaijani language
*/
AZERBAIJANI: {
code: "az",
flag: "name:az",
name: "Azerbaijani",
latin: true,
isMode: false,
geocoding: true
},
/**
* Basque language
*/
BASQUE: {
code: "eu",
flag: "name:eu",
name: "Basque",
latin: true,
isMode: false,
geocoding: true
},
/**
* Belarusian langauge
*/
BELARUSIAN: {
code: "be",
flag: "name:be",
name: "Belarusian",
latin: false,
isMode: false,
geocoding: true
},
/**
* Bengali language
*/
BENGALI: {
code: "bn",
flag: "name:bn",
name: "Bengali",
latin: true,
isMode: false,
geocoding: true
},
/**
* Bosnian language
*/
BOSNIAN: {
code: "bs",
flag: "name:bs",
name: "Bosnian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Breton language
*/
BRETON: {
code: "br",
flag: "name:br",
name: "Breton",
latin: true,
isMode: false,
geocoding: true
},
/**
* Bulgarian language
*/
BULGARIAN: {
code: "bg",
flag: "bg",
name: "Bulgarian",
latin: false,
isMode: false,
geocoding: true
},
/**
* Catalan language
*/
CATALAN: {
code: "ca",
flag: "name:ca",
name: "Catalan",
latin: true,
isMode: false,
geocoding: true
},
/**
* Chinese language
*/
CHINESE: {
code: "zh",
flag: "name:zh",
name: "Chinese",
latin: false,
isMode: false,
geocoding: true
},
/**
* Traditional Chinese language
*/
TRADITIONAL_CHINESE: {
code: "zh-Hant",
flag: "name:zh-Hant",
name: "Chinese (traditional)",
latin: false,
isMode: false,
geocoding: false
},
/**
* Simplified Chinese language
*/
SIMPLIFIED_CHINESE: {
code: "zh-Hans",
flag: "name:zh-Hans",
name: "Chinese (simplified)",
latin: false,
isMode: false,
geocoding: false
},
/**
* Corsican language
*/
CORSICAN: {
code: "co",
flag: "name:co",
name: "Corsican",
latin: true,
isMode: false,
geocoding: true
},
/**
* Croatian language
*/
CROATIAN: {
code: "hr",
flag: "name:hr",
name: "Croatian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Czech language
*/
CZECH: {
code: "cs",
flag: "name:cs",
name: "Czech",
latin: true,
isMode: false,
geocoding: true
},
/**
* Danish language
*/
DANISH: {
code: "da",
flag: "name:da",
name: "Danish",
latin: true,
isMode: false,
geocoding: true
},
/**
* Dutch language
*/
DUTCH: {
code: "nl",
flag: "name:nl",
name: "Dutch",
latin: true,
isMode: false,
geocoding: true
},
/**
* German language
*/
GERMAN: {
code: "de",
flag: "name:de",
name: "German",
latin: true,
isMode: false,
geocoding: true
},
/**
* Greek language
*/
GREEK: {
code: "el",
flag: "name:el",
name: "Greek",
latin: false,
isMode: false,
geocoding: true
},
/**
* English language
*/
ENGLISH: {
code: "en",
flag: "name:en",
name: "English",
latin: true,
isMode: false,
geocoding: true
},
/**
* Esperanto language
*/
ESPERANTO: {
code: "eo",
flag: "name:eo",
name: "Esperanto",
latin: true,
isMode: false,
geocoding: true
},
/**
* Estonian language
*/
ESTONIAN: {
code: "et",
flag: "name:et",
name: "Estonian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Finnish language
*/
FINNISH: {
code: "fi",
flag: "name:fi",
name: "Finnish",
latin: true,
isMode: false,
geocoding: true
},
/**
* French language
*/
FRENCH: {
code: "fr",
flag: "name:fr",
name: "French",
latin: true,
isMode: false,
geocoding: true
},
/**
* Frisian language
*/
FRISIAN: {
code: "fy",
flag: "name:fy",
name: "Frisian (West)",
latin: true,
isMode: false,
geocoding: true
},
/**
* Georgian language
*/
GEORGIAN: {
code: "ka",
flag: "name:ka",
name: "Georgian",
latin: false,
isMode: false,
geocoding: true
},
/**
* Hebrew language (right-to-left non-latin script)
*/
HEBREW: {
code: "he",
flag: "name:he",
name: "Hebrew",
latin: false,
isMode: false,
geocoding: true
},
/**
* Hindi language
*/
HINDI: {
code: "hi",
flag: "name:hi",
name: "Hindi",
latin: false,
isMode: false,
geocoding: true
},
/**
* Hungarian language
*/
HUNGARIAN: {
code: "hu",
flag: "name:hu",
name: "Hungarian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Icelandic language
*/
ICELANDIC: {
code: "is",
flag: "name:is",
name: "Icelandic",
latin: true,
isMode: false,
geocoding: true
},
/**
* Indonesian language
*/
INDONESIAN: {
code: "id",
flag: "name:id",
name: "Indonesian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Irish language
*/
IRISH: {
code: "ga",
flag: "name:ga",
name: "Irish",
latin: true,
isMode: false,
geocoding: true
},
/**
* Italian language
*/
ITALIAN: {
code: "it",
flag: "name:it",
name: "Italian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Japanese language
*/
JAPANESE: {
code: "ja",
flag: "name:ja",
name: "Japanese",
latin: false,
isMode: false,
geocoding: true
},
/**
* Japanese language in Hiragana form
*/
JAPANESE_HIRAGANA: {
code: "ja-Hira",
flag: "name:ja-Hira",
name: "Japanese Hiragana form",
latin: false,
isMode: false,
geocoding: false
},
/**
* Japanese language (latin script)
*/
JAPANESE_2018: {
code: "ja-Latn",
flag: "name:ja-Latn",
name: "Japanese (Latin 2018)",
latin: true,
isMode: false,
geocoding: false
},
/**
* Japanese language in Kana form (non-latin script)
*/
JAPANESE_KANA: {
code: "ja_kana",
flag: "name:ja_kana",
name: "Japanese (Kana)",
latin: false,
isMode: false,
geocoding: false
},
/**
* Japanse language, romanized (latin script)
*/
JAPANESE_LATIN: {
code: "ja_rm",
flag: "name:ja_rm",
name: "Japanese (Latin script)",
latin: true,
isMode: false,
geocoding: false
},
/**
* Kannada language
*/
KANNADA: {
code: "kn",
flag: "name:kn",
name: "Kannada",
latin: true,
isMode: false,
geocoding: true
},
/**
* Kazakh language
*/
KAZAKH: {
code: "kk",
flag: "name:kk",
name: "Kazakh",
latin: false,
isMode: false,
geocoding: true
},
/**
* Korean language
*/
KOREAN: {
code: "ko",
flag: "name:ko",
name: "Korean",
latin: false,
isMode: false,
geocoding: true
},
/**
* Korean language (latin script)
*/
KOREAN_LATIN: {
code: "ko-Latn",
flag: "name:ko-Latn",
name: "Korean (Latin script)",
latin: true,
isMode: false,
geocoding: false
},
/**
* Kurdish language
*/
KURDISH: {
code: "ku",
flag: "name:ku",
name: "Kurdish",
latin: true,
isMode: false,
geocoding: true
},
/**
* Classical Latin language
*/
CLASSICAL_LATIN: {
code: "la",
flag: "name:la",
name: "Latin",
latin: true,
isMode: false,
geocoding: true
},
/**
* Latvian language
*/
LATVIAN: {
code: "lv",
flag: "name:lv",
name: "Latvian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Lithuanian language
*/
LITHUANIAN: {
code: "lt",
flag: "name:lt",
name: "Lithuanian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Luxembourgish language
*/
LUXEMBOURGISH: {
code: "lb",
flag: "name:lb",
name: "Luxembourgish",
latin: true,
isMode: false,
geocoding: true
},
/**
* Macedonian language
*/
MACEDONIAN: {
code: "mk",
flag: "name:mk",
name: "Macedonian",
latin: false,
isMode: false,
geocoding: true
},
/**
* Malayalm language
*/
MALAYALAM: {
code: "ml",
flag: "name:ml",
name: "Malayalam",
latin: false,
isMode: false,
geocoding: true
},
/**
* Maltese language
*/
MALTESE: {
code: "mt",
flag: "name:mt",
name: "Maltese",
latin: true,
isMode: false,
geocoding: true
},
/**
* Norwegian language
*/
NORWEGIAN: {
code: "no",
flag: "name:no",
name: "Norwegian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Occitan language
*/
OCCITAN: {
code: "oc",
flag: "name:oc",
name: "Occitan",
latin: true,
isMode: false,
geocoding: true
},
/**
* Persian language
*/
PERSIAN: {
code: "fa",
flag: "name:fa",
name: "Persian",
latin: false,
isMode: false,
geocoding: true
},
/**
* Polish language
*/
POLISH: {
code: "pl",
flag: "name:pl",
name: "Polish",
latin: true,
isMode: false,
geocoding: true
},
/**
* Portuguese language
*/
PORTUGUESE: {
code: "pt",
flag: "name:pt",
name: "Portuguese",
latin: true,
isMode: false,
geocoding: true
},
/**
* Punjabi language
*/
PUNJABI: {
code: "pa",
flag: "name:pa",
name: "Punjabi",
latin: false,
isMode: false,
geocoding: true
},
/**
* Western Punjabi language
*/
WESTERN_PUNJABI: {
code: "pnb",
flag: "name:pnb",
name: "Western Punjabi",
latin: false,
isMode: false,
geocoding: false
},
/**
* Romanian language
*/
ROMANIAN: {
code: "ro",
flag: "name:ro",
name: "Romanian",
latin: true,
isMode: false,
geocoding: true
},
/**
* Romansh language
*/
ROMANSH: {
code: "rm",
flag: "name:rm",
name: "Romansh",
latin: true,
isMode: false,
geocoding: true
},
/**
* Russian language
*/
RUSSIAN: {
code: "ru",
flag: "name:ru",
name: "Russian",
latin: false,
isMode: false,
geocoding: true
},
/**
* Serbian language (cyrillic script)
*/
SERBIAN_CYRILLIC: {
code: "sr",
flag: "name:sr",
name: "Serbian (Cyrillic script)",
latin: false,
isMode: false,
geocoding: true
},
/**
* Serbian language (latin script)
*/
SERBIAN_LATIN: {
code: "sr-Latn",
flag: "name:sr-Latn",
name: "Serbian (Latin script)",
latin: true,
isMode: false,
geocoding: false
},
/**
* Scottish Gaelic language
*/
SCOTTISH_GAELIC: {
code: "gd",
flag: "name:gd",
name: "Scottish Gaelic",
latin: true,
isMode: false,
geocoding: true
},
/**
* Slovak language
*/
SLOVAK: {
code: "sk",
flag: "name:sk",
name: "Slovak",
latin: true,
isMode: false,
geocoding: true
},
/**
* Slovene language
*/
SLOVENE: {
code: "sl",
flag: "name:sl",
name: "Slovene",
latin: true,
isMode: false,
geocoding: true
},
/**
* Spanish language
*/
SPANISH: {
code: "es",
flag: "name:es",
name: "Spanish",
latin: true,
isMode: false,
geocoding: true
},
/**
* Swedish language
*/
SWEDISH: {
code: "sv",
flag: "name:sv",
name: "Swedish",
latin: true,
isMode: false,
geocoding: true
},
/**
* Tamil language
*/
TAMIL: {
code: "ta",
flag: "name:ta",
name: "Tamil",
latin: false,
isMode: false,
geocoding: true
},
/**
* Telugu language
*/
TELUGU: {
code: "te",
flag: "name:te",
name: "Telugu",
latin: false,
isMode: false,
geocoding: true
},
/**
* Thai language
*/
THAI: {
code: "th",
flag: "name:th",
name: "Thai",
latin: false,
isMode: false,
geocoding: true
},
/**
* Turkish language
*/
TURKISH: {
code: "tr",
flag: "name:tr",
name: "Turkish",
latin: true,
isMode: false,
geocoding: true
},
/**
* Ukrainian language
*/
UKRAINIAN: {
code: "uk",
flag: "name:uk",
name: "Ukrainian",
latin: false,
isMode: false,
geocoding: true
},
/**
* Vietnamese language (latin script)
*/
VIETNAMESE: {
code: "vi",
flag: "name:vi",
name: "Vietnamese (Latin script)",
latin: true,
isMode: false,
geocoding: true
},
/**
* Welsh language
*/
WELSH: {
code: "cy",
flag: "name:cy",
name: "Welsh",
latin: true,
isMode: false,
geocoding: true
}
};
const Language = {
...NonISOLanguage,
...ISOLanguage
};
function getLanguageInfoFromKey(languageKey, languageDictionary = Language) {
if (languageKey in languageDictionary) {
return languageKey[languageKey];
}
return null;
}
function getLanguageInfoFromCode(languageCode, languageDictionary = Language) {
for (const lang of Object.values(languageDictionary)) {
if (lang.code === languageCode) {
return lang;
}
}
return null;
}
function getLanguageInfoFromFlag(languageFlag, languageDictionary = Language) {
for (const lang of Object.values(languageDictionary)) {
if (lang.flag === languageFlag) {
return lang;
}
}
return null;
}
function getAutoLanguage() {
if (typeof navigator === "undefined") {
const code = Intl.DateTimeFormat().resolvedOptions().locale.split("-")[0];
const langInfo = getLanguageInfoFromCode(code);
return langInfo ?? Language.ENGLISH;
}
const canditatelangs = Array.from(
new Set(navigator.languages.map((l) => l.split("-")[0]))
).map((code) => getLanguageInfoFromCode(code)).filter((li) => li);
return canditatelangs[0] ?? Language.ENGLISH;
}
function isLanguageInfo(obj) {
return obj !== null && typeof obj === "object" && "code" in obj && "flag" in obj && "name" in obj && "latin" in obj && "isMode" in obj && "geocoding" in obj && (typeof obj.code === "string" || obj.code === null) && typeof obj.flag === "string" && typeof obj.name === "string" && typeof obj.latin === "boolean" && typeof obj.isMode === "boolean" && typeof obj.geocoding === "boolean";
}
function toLanguageInfo(lang, languageDictionary = Language) {
if (isLanguageInfo(lang)) {
return getLanguageInfoFromFlag(lang.flag, languageDictionary);
}
if (typeof lang !== "string") {
return null;
}
return getLanguageInfoFromKey(lang, languageDictionary) || getLanguageInfoFromCode(lang, languageDictionary) || getLanguageInfoFromFlag(lang, languageDictionary) || null;
}
function areSameLanguages(langA, langB, languageDictionary = Language) {
const langAObj = toLanguageInfo(langA, languageDictionary);
const langBObj = toLanguageInfo(langB, languageDictionary);
return langAObj && langBObj && langAObj.flag === langBObj.flag;
}
async function callFetch(resource, options = {}) {
if (config.fetch === null) {
throw new Error(
"The fetch function was not found. If on NodeJS < 18 please specify the fetch function with config.fetch"
);
}
if (new URL(resource).searchParams.get("key").trim() === "") {
throw new Error(
"The MapTiler Cloud API key is missing. Set it in `config.apiKey` or get one for free at https://maptiler.com"
);
}
return config.fetch(resource, options);
}
const defaults = {
maptilerApiURL: "https://api.maptiler.com/",
mapStyle: "streets-v2"
};
Object.freeze(defaults);
class ServiceError extends Error {
constructor(res, customMessage = "") {
super(
`Call to enpoint ${res.url} failed with the status code ${res.status}. ${customMessage}`
);
this.res = res;
}
}
const customMessages$4 = {
400: "Query too long / Invalid parameters",
403: "Key is missing, invalid or restricted"
};
function addLanguageGeocodingOptions(searchParams, options) {
const { language } = options;
if (language === void 0) {
return;
}
const languageCodes = (Array.isArray(language) ? language : [language]).map((elem) => toValidGeocodingLanguageCode(elem)).filter((elem) => elem);
const languages = Array.from(new Set(languageCodes)).join(",");
searchParams.set("language", languages);
}
function toValidGeocodingLanguageCode(lang) {
const langInfo = lang === Language.AUTO.flag ? getAutoLanguage() : typeof lang === "string" ? getLanguageInfoFromCode(lang) : isLanguageInfo(lang) ? lang.flag === Language.AUTO.flag ? getAutoLanguage() : getLanguageInfoFromFlag(lang.flag) : null;
return langInfo?.geocoding ? langInfo.code : null;
}
function addCommonForwardAndReverseGeocodingOptions(searchParams, options) {
const { apiKey, limit, types, excludeTypes } = options;
searchParams.set("key", apiKey ?? config.apiKey);
if (limit !== void 0) {
searchParams.set("limit", String(limit));
}
if (types !== void 0) {
searchParams.set("types", types.join(","));
}
if (excludeTypes !== void 0) {
searchParams.set("excludeTypes", String(excludeTypes));
}
addLanguageGeocodingOptions(searchParams, options);
}
function addForwardGeocodingOptions(searchParams, options) {
addCommonForwardAndReverseGeocodingOptions(searchParams, options);
const { bbox, proximity, country, fuzzyMatch, autocomplete } = options;
if (bbox !== void 0) {
searchParams.set("bbox", bbox.join(","));
}
if (proximity !== void 0) {
searchParams.set(
"proximity",
proximity === "ip" ? proximity : proximity.join(",")
);
}
if (country !== void 0) {
searchParams.set("country", country.join(","));
}
if (fuzzyMatch !== void 0) {
searchParams.set("fuzzyMatch", fuzzyMatch ? "true" : "false");
}
if (autocomplete !== void 0) {
searchParams.set("autocomplete", autocomplete ? "true" : "false");
}
}
async function forward(query, options = {}) {
if (typeof query !== "string" || query.trim().length === 0) {
throw new Error("The query must be a non-empty string");
}
const endpoint = new URL(
`geocoding/${encodeURIComponent(query)}.json`,
defaults.maptilerApiURL
);
addForwardGeocodingOptions(endpoint.searchParams, options);
const res = await callFetch(endpoint.toString());
if (!res.ok) {
throw new ServiceError(res, customMessages$4[res.status] ?? "");
}
return await res.json();
}
async function reverse(position, options = {}) {
if (!Array.isArray(position) || position.length < 2) {
throw new Error("The position must be an array of form [lng, lat].");
}
const endpoint = new URL(
`geocoding/${position[0]},${position[1]}.json`,
defaults.maptilerApiURL
);
addCommonForwardAndReverseGeocodingOptions(endpoint.searchParams, options);
const res = await callFetch(endpoint.toString());
if (!res.ok) {
throw new ServiceError(res, customMessages$4[res.status] ?? "");
}
return await res.json();
}
async function byId(id, options = {}) {
const endpoint = new URL(`geocoding/${id}.json`, defaults.maptilerApiURL);
endpoint.searchParams.set("key", options.apiKey ?? config.apiKey);
addLanguageGeocodingOptions(endpoint.searchParams, options);
const res = await callFetch(endpoint.toString());
if (!res.ok) {
throw new ServiceError(res, customMessages$4[res.status] ?? "");
}
return await res.json();
}
async function batch$1(queries, options = {}) {
if (!queries.length) {
return [];
}
const joinedQuery = queries.map((query) => encodeURIComponent(query)).join(";");
const endpoint = new URL(
`geocoding/${joinedQuery}.json`,
defaults.maptilerApiURL
);
addForwardGeocodingOptions(endpoint.searchParams, options);
const res = await callFetch(endpoint.toString());
if (!res.ok) {
throw new ServiceError(res, customMessages$4[res.status] ?? "");
}
const obj = await res.json();
return queries.length === 1 ? [obj] : obj;
}
const geocoding = {
forward,
reverse,
byId,
batch: batch$1
};
const customMessages$3 = {
403: "Key is missing, invalid or restricted"
};
async function info(options = {}) {
const endpoint = new URL(`geolocation/ip.json`, defaults.maptilerApiURL);
endpoint.searchParams.set("key", options.apiKey ?? config.apiKey);
if ("elevation" in options) {
endpoint.searchParams.set(
"elevation",
options.elevation ? "true" : "false"
);
}
const urlWithParams = endpoint.toString();
const res = await callFetch(urlWithParams);
if (!res.ok) {
throw new ServiceError(
res,
res.status in customMessages$3 ? customMessages$3[res.status] : ""
);
}
const obj = await res.json();
return obj;
}
const geolocation = {
info
};
const customMessages$2 = {
403: "Key is missing, invalid or restricted"
};
async function search(query, options = {}) {
if (typeof query !== "string" || query.trim().length === 0) {
throw new Error("The query must be a non-empty string");
}
const endpoint = new URL(
`coordinates/search/${query}.json`,
defaults.maptilerApiURL
);
endpoint.searchParams.set("key", options.apiKey ?? config.apiKey);
if ("limit" in options) {
endpoint.searchParams.set("limit", options.limit.toString());
}
if ("transformations" in options) {
endpoint.searchParams.set(
"transformations",
options.transformations.toString()
);
}
if ("exports" in options) {
endpoint.searchParams.set("exports", options.exports.toString());
}
const urlWithParams = endpoint.toString();
const res = await callFetch(urlWithParams);
if (!res.ok) {
throw new ServiceError(
res,
res.status in customMessages$2 ? customMessages$2[res.status] : ""
);
}
const obj = await res.json();
return obj;
}
async function transform(positions, options = {}) {
const coordinatesStr = (Array.isArray(positions[0]) ? positions : [positions]).map((coord) => `${coord[0]},${coord[1]}`).join(";");
const endpoint = new URL(
`coordinates/transform/${coordinatesStr}.json`,
defaults.maptilerApiURL
);
endpoint.searchParams.set("key", options.apiKey ?? config.apiKey);
if ("sourceCrs" in options) {
endpoint.searchParams.set("s_srs", options.sourceCrs.toString());
}
if ("targetCrs" in options) {
endpoint.searchParams.set("t_srs", options.targetCrs.toString());
}
if ("operations" in options) {
endpoint.searchParams.set(
"ops",
(Array.isArray(options.operations) ? options.operations : [options.operations]).join("|")
);
}
const urlWithParams = endpoint.toString();
const res = await callFetch(urlWithParams);
if (!res.ok) {
throw new ServiceError(
res,
res.status in customMessages$2 ? customMessages$2[res.status] : ""
);
}
const obj = await res.json();
return obj;
}
const coordinates = {
search,
transform
};
const customMessages$1 = {
403: "Key is missing, invalid or restricted"
};
async function get(dataId, options = {}) {
if (typeof dataId !== "string" || dataId.trim().length === 0) {
throw new Error("The data ID must be a non-empty string");
}
const endpoint = new URL(
`data/${encodeURIComponent(dataId)}/features.json`,
defaults.maptilerApiURL
);
endpoint.searchParams.set("key", options.apiKey ?? config.apiKey);
const urlWithParams = endpoint.toString();
const res = await callFetch(urlWithParams);
if (!res.ok) {
throw new ServiceError(
res,
res.status in customMessages$1 ? customMessages$1[res.status] : ""
);
}
const obj = await res.json();
return obj;
}
const data = {
get
};
function expandMapStyle(style) {
const maptilerDomainRegex = /^maptiler:\/\/(.*)/;
let match;
const trimmed = style.trim();
let expandedStyle;
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) {
expandedStyle = trimmed;
} else if ((match = maptilerDomainRegex.exec(trimmed)) !== null) {
expandedStyle = `https://api.maptiler.com/maps/${match[1]}/style.json`;
} else {
expandedStyle = `https://api.maptiler.com/maps/${trimmed}/style.json`;
}
return expandedStyle;
}
class MapStyleVariant {
constructor(name, variantType, id, referenceStyle, description, imageURL, deprecated = false) {
this.name = name;
this.variantType = variantType;
this.id = id;
this.referenceStyle = referenceStyle;
this.description = description;
this.imageURL = imageURL;
this.deprecated = deprecated;
}
/**
* Get the human-friendly name
* @returns
*/
getName() {
return this.name;
}
getFullName() {
return `${this.referenceStyle.getName()} ${this.name}`;
}
/**
* Get the variant type (eg. "DEFAULT", "DARK", "PASTEL", etc.)
* @returns
*/
getType() {
return this.variantType;
}
/**
* Get the MapTiler Cloud id
* @returns
*/
getId() {
return this.id;
}
/**
* Get the human-friendly description
*/
getDescription() {
return this.description;
}
/**
* Get the reference style this variant belongs to
* @returns
*/
getReferenceStyle() {
return this.referenceStyle;
}
/**
* Check if a variant of a given type exists for _this_ variants
* (eg. if this is a "DARK", then we can check if there is a "LIGHT" variant of it)
* @param variantType
* @returns
*/
hasVariant(variantType) {
return this.referenceStyle.hasVariant(variantType);
}
/**
* Retrieve the variant of a given type. If not found, will return the "DEFAULT" variant.
* (eg. _this_ "DARK" variant does not have any "PASTEL" variant, then the "DEFAULT" is returned)
* @param variantType
* @returns
*/
getVariant(variantType) {
const variant = this.referenceStyle.getVariant(variantType);
this.warnIfDeprecated(variant);
return variant;
}
/**
* Get all the variants for _this_ variants, except _this_ current one
* @returns
*/
getVariants() {
return this.referenceStyle.getVariants().filter((v) => v !== this).map((v) => {
this.warnIfDeprecated(v);
return v;
});
}
/**
* Get the image URL that represent _this_ variant
* @returns
*/
getImageURL() {
return this.imageURL;
}
/**
* Get the style as usable by MapLibre, a string (URL) or a plain style description (StyleSpecification)
* @returns
*/
getExpandedStyleURL() {
return expandMapStyle(this.getId());
}
warnIfDeprecated(variant = this) {
if (!variant.deprecated)
return variant;
const name = variant.getFullName();
console.warn(
`Style "${name}" is deprecated and will be removed in a future version.`
);
return variant;
}
}
class ReferenceMapStyle {
constructor(name, id) {
this.name = name;
this.id = id;
/**
* Variants that belong to this reference style, key being the reference type
*/
this.variants = {};
/**
* Variants that belong to this reference style, ordered by relevance
*/
this.orderedVariants = [];
}
/**
* Get the human-friendly name of this reference style
* @returns
*/
getName() {
return this.name;
}
/**
* Get the id of _this_ reference style
* @returns
*/
getId() {
return this.id;
}
/**
* Add a variant to _this_ reference style
* @param v
*/
addVariant(v) {
this.variants[v.getType()] = v;
this.orderedVariants.push(v);
}
/**
* Check if a given variant type exists for this reference style
* @param variantType
* @returns
*/
hasVariant(variantType) {
return variantType in this.variants;
}
/**
* Get a given variant. If the given type of variant does not exist for this reference style,
* then the most relevant default variant is returned instead
* @param variantType
* @returns
*/
getVariant(variantType) {
return variantType in this.variants ? this.variants[variantType] : this.orderedVariants[0];
}
/**
* Get the list of variants for this reference style
* @returns
*/
getVariants() {
return Object.values(this.variants);
}
/**
* Get the defualt variant for this reference style
* @returns
*/
getDefaultVariant() {
return this.orderedVariants[0].warnIfDeprecated();
}
}
const mapStylePresetList = [
{
referenceStyleID: "STREETS",
name: "Streets",
description: "",
variants: [
{
id: "streets-v2",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "streets-v2-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
},
{
id: "streets-v2-light",
name: "Light",
variantType: "LIGHT",
description: "",
imageURL: ""
},
{
id: "streets-v2-night",
name: "Night",
variantType: "NIGHT",
description: "",
imageURL: ""
},
{
id: "streets-v2-pastel",
name: "Pastel",
variantType: "PASTEL",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "OUTDOOR",
name: "Outdoor",
description: "",
variants: [
{
id: "outdoor-v2",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "outdoor-v2-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "WINTER",
name: "Winter",
description: "",
variants: [
{
id: "winter-v2",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "winter-v2-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "SATELLITE",
name: "Satellite",
description: "",
variants: [
{
id: "satellite",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "HYBRID",
name: "Hybrid",
description: "",
variants: [
{
id: "hybrid",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "BASIC",
name: "Basic",
description: "",
variants: [
{
id: "basic-v2",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "basic-v2-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
},
{
id: "basic-v2-light",
name: "Light",
variantType: "LIGHT",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "BRIGHT",
name: "Bright",
description: "",
variants: [
{
id: "bright-v2",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "bright-v2-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
},
{
id: "bright-v2-light",
name: "Light",
variantType: "LIGHT",
description: "",
imageURL: ""
},
{
id: "bright-v2-pastel",
name: "Pastel",
variantType: "PASTEL",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "OPENSTREETMAP",
name: "OpenStreetMap",
description: "",
variants: [
{
id: "openstreetmap",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "TOPO",
name: "Topo",
description: "",
variants: [
{
id: "topo-v2",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "topo-v2-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
},
{
id: "topo-v2-shiny",
name: "Shiny",
deprecated: true,
variantType: "SHINY",
description: "",
imageURL: ""
},
{
id: "topo-v2-pastel",
name: "Pastel",
variantType: "PASTEL",
description: "",
imageURL: ""
},
{
id: "topo-v2-topographique",
name: "Topographique",
variantType: "TOPOGRAPHIQUE",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "VOYAGER",
name: "Voyager",
description: "",
variants: [
{
id: "voyager-v2",
name: "Default",
deprecated: true,
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "voyager-v2-darkmatter",
name: "Darkmatter",
deprecated: true,
variantType: "DARK",
description: "",
imageURL: ""
},
{
id: "voyager-v2-positron",
name: "Positron",
deprecated: true,
variantType: "LIGHT",
description: "",
imageURL: ""
},
{
id: "voyager-v2-vintage",
name: "Vintage",
deprecated: true,
variantType: "VINTAGE",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "TONER",
name: "Toner",
description: "",
variants: [
{
id: "toner-v2",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "toner-v2-background",
name: "Background",
variantType: "BACKGROUND",
deprecated: true,
description: "",
imageURL: ""
},
{
id: "toner-v2-lite",
name: "Lite",
variantType: "LITE",
description: "",
imageURL: ""
},
{
id: "toner-v2-lines",
name: "Lines",
variantType: "LINES",
deprecated: true,
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "DATAVIZ",
name: "Dataviz",
description: "",
variants: [
{
id: "dataviz",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "dataviz-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
},
{
id: "dataviz-light",
name: "Light",
variantType: "LIGHT",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "BACKDROP",
name: "Backdrop",
description: "",
variants: [
{
id: "backdrop",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "backdrop-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
},
{
id: "backdrop-light",
name: "Light",
variantType: "LIGHT",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "OCEAN",
name: "Ocean",
description: "",
variants: [
{
id: "ocean",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "AQUARELLE",
name: "Aquarelle",
description: "Watercolor map for creative use",
variants: [
{
id: "aquarelle",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "aquarelle-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
},
{
id: "aquarelle-vivid",
name: "Vivid",
variantType: "VIVID",
description: "",
imageURL: ""
}
]
},
{
referenceStyleID: "LANDSCAPE",
name: "Landscape",
description: "Terrain map for data overlays and visualisations",
variants: [
{
id: "landscape",
name: "Default",
variantType: "DEFAULT",
description: "",
imageURL: ""
},
{
id: "landscape-dark",
name: "Dark",
variantType: "DARK",
description: "",
imageURL: ""
},
{
id: "landscape-vivid",
name: "Vivid",
variantType: "VIVID",
description: "",
imageURL: ""
}
]
}
];
function makeReferenceStyleProxy(referenceStyle) {
return new Proxy(referenceStyle, {
get(target, prop, receiver) {
if (target.hasVariant(prop)) {
return target.getVariant(prop);
}
if (prop.toString().toUpperCase() === prop) {
return referenceStyle.getDefaultVariant();
}
const style = Reflect.get(target, prop, receiver);
return style;
}
});
}
function buildMapStyles() {
const mapStyle = {};
for (let i = 0; i < mapStylePresetList.length; i += 1) {
const refStyleInfo = mapStylePresetList[i];
const refStyle = makeReferenceStyleProxy(
new ReferenceMapStyle(refStyleInfo.name, refStyleInfo.referenceStyleID)
);
for (let j = 0; j < refStyleInfo.variants.length; j += 1) {
const variantInfo = refStyleInfo.variants[j];
const variant = new MapStyleVariant(
variantInfo.name,
// name
variantInfo.variantType,
// variantType
variantInfo.id,
// id
refStyle,
// referenceStyle
variantInfo.description,
variantInfo.imageURL,
// imageURL
variantInfo.deprecated
// deprecated
);
refStyle.addVariant(variant);
}
mapStyle[refStyleInfo.referenceStyleID] = refStyle;
}
return mapStyle;
}
function styleToStyle(style) {
if (!style) {
return MapStyle[mapStylePresetList[0].referenceStyleID].getDefaultVariant().getId();
}
if (typeof style === "string" || style instanceof String) {
return style.trim().toLowerCase();
}
if (style instanceof MapStyleVariant) {
return style.getId();
}
if (style instanceof ReferenceMapStyle) {
return style.getDefaultVariant().getId();
}
}
const MapStyle = buildMapStyles();
function extractLineStrings(geoJson) {
const lineStrings = [];
function extractFromGeometry(geometry) {
if (geometry.type === "LineString" || geometry.type === "MultiLineString") {
lineStrings.push(geometry);
}
}
function extractFromFeature(feature) {
if (feature.geometry) {
extractFromGeometry(feature.geometry);
}
}
function extractFromFeatureCollection(collection) {
for (const feature of collection.features) {
if (feature.type === "Feature") {
extractFromFeature(feature);
} else if (feature.type === "FeatureCollection") {
extractFromFeatureCollection(feature);
}
}
}
if (geoJson.type === "Feature") {
extractFromFeature(geoJson);
} else if (geoJson.type === "FeatureCollection") {
extractFromFeatureCollection(geoJson);
} else {
extractFromGeometry(geoJson);
}
return lineStrings;
}
function getSqSegDist(p, p1, p2) {
let x = p1[0], y = p1[1], dx = p2[0] - x, dy = p2[1] - y;
if (dx !== 0 || dy !== 0) {
const t = ((p[0] - x) * dx + (p[1] - y) * dy) / (dx * dx + dy * dy);
if (t > 1) {
x = p2[0];
y = p2[1];
} else if (t > 0) {
x += dx * t;
y += dy * t;
}
}
dx = p[0] - x;
dy = p[1] - y;
return dx * dx + dy * dy;
}
function simplifyDPStep(points, first, last, sqTolerance, simplified) {
let maxSqDist = sqTolerance, index;
for (let i = first + 1; i < last; i++) {
const sqDist = getSqSegDist(points[i], points[first], points[last]);
if (sqDist > maxSqDist) {
index = i;
maxSqDist = sqDist;
}
}
if (maxSqDist > sqTolerance) {
if (index - first > 1) {
simplifyDPStep(points, first, index, sqTolerance, simplified);
}
simplified.push(points[index]);
if (last - index > 1) {
simplifyDPStep(points, index, last, sqTolerance, simplified);
}
}
}
function simplifyDouglasPeucker(points, sqTolerance) {
const last = points.length - 1;
const simplified = [points[0]];
simplifyDPStep(points, 0, last, sqTolerance, simplified);
simplified.push(points[last]);
return simplified;
}
function simplify(points, tolerance) {
if (points.length <= 2) {
return points;
}
const sqTolerance = tolerance !== void 0 ? tolerance * tolerance : 1;
const simplePoints = simplifyDouglasPeucker(points, sqTolerance);
return simplePoints;
}
const misc = {
extractLineStrings,
simplify
};
function staticMapMarkerToString(marker, includeColor = true) {
let str = `${marker[0]},${marker[1]}`;
if (marker.length === 3 && includeColor) {
str += `,${marker[2]}`;
}
return str;
}
function simplifyAndStringify(path, maxNbChar = 3e3) {
let str = path.map((point) => point.join(",")).join("|");
let tolerance = 5e-6;
const toleranceStep = 1e-5;
while (str.length > maxNbChar) {
const simplerPath = misc.simplify(path, tolerance);
str = simplerPath.map((point) => `${point[0]},${point[1]}`).join("|");
tolerance += toleranceStep;
}
return str;
}
function centered(center, zoom, options = {}) {
const style = styleToStyle(options.style);
const scale = options.hiDPI ? "@2x" : "";
const format = options.format ?? "png";
let width = ~~(options.width ?? 1024);
let height = ~~(options.height ?? 1024);
if (options.hiDPI) {
width = ~~(width / 2);
height = ~~(height / 2);
}
const endpoint = new URL(
`maps/${encodeURIComponent(style)}/static/${center[0]},${center[1]},${zoom}/${width}x${height}${scale}.${format}`,
defaults.maptilerApiURL
);
if ("attribution" in options) {
endpoint.searchParams.set("attribution", options.attribution.toString());
}
if ("markers" in options) {
let markerStr = "";
const hasIcon = "markerIcon" in options;
if (hasIcon) {
markerStr += `icon:${options.markerIcon}|`;
}
if (hasIcon && "markerAnchor" in options) {
markerStr += `anchor:${options.markerAnchor}|`;
}
if (hasIcon && options.hiDPI) {
markerStr += `scale:2|`;
}
const markerList = Array.isArray(options.markers[0]) ? options.markers : [options.markers];
markerStr += markerList.map((m) => staticMapMarkerToString(m, !hasIcon)).join("|");
endpoint.searchParams.set("markers", markerStr);
}
if ("path" in options) {
let pathStr = "";
pathStr += `fill:${options.pathFillColor ?? "none"}|`;
if ("pathStrokeColor" in options) {
pathStr += `stroke:${options.pathStrokeColor}|`;
}
if ("pathWidth" in options) {
const pathWidth = options.pathWidth / (options.hiDPI ? 2 : 1);
pathStr += `width:${pathWidth.toString()}|`;
}
pathStr += simplifyAndStringify(options.path);
endpoint.searchParams.set("path", pathStr);
}
endpoint.searchParams.set("key", options.apiKey ?? config.apiKey);
return endpoint.toString();
}
function bounded(boundingBox, options = {}) {
const style = styleToStyle(options.style);
const scale = options.hiDPI ? "@2x" : "";
const format = options.format ?? "png";
let width = ~~(options.width ?? 1024);
let height = ~~(options.height ?? 1024);
if (options.hiDPI) {
width = ~~(width / 2);
height = ~~(height / 2);
}
const endpoint = new URL(
`maps/${encodeURIComponent(style)}/static/${boundingBox[0]},${boundingBox[1]},${boundingBox[2]},${boundingBox[3]}/${width}x${height}${scale}.${format}`,
defaults.maptilerApiURL
);
if ("attribution" in options) {
endpoint.searchParams.set("attribution", options.attribution.toString());
}
if ("padding" in options) {
endpoint.searchParams.set("padding", options.padding.toString());
}
if ("markers" in options) {
let markerStr = "";
const hasIcon = "markerIcon" in options;
if (hasIcon) {
markerStr += `icon:${options.markerIcon}|`;
}
if (hasIcon && "markerAnchor" in options) {
markerStr += `anchor:${options.markerAnchor}|`;
}
if (hasIcon && options.hiDPI) {
markerStr += `scale:2|`;
}
const markerList = Array.isArray(options.markers[0]) ? options.markers : [options.markers];
markerStr += markerList.map((m) => staticMapMarkerToString(m, !hasIcon)).join("|");
endpoint.searchParams.set("markers", markerStr);
}
if ("path" in options) {
let pathStr = "";
pathStr += `fill:${options.pathFillColor ?? "none"}|`;
if ("pathStrokeColor" in options) {
pathStr += `stroke:${options.pathStrokeColor}|`;
}
if ("pathWidth" in options) {
const pathWidth = options.pathWidth / (options.hiDPI ? 2 : 1);
pathStr += `width:${pathWidth.toString()}|`;
}
pathStr += simplifyAndStringify(options.path);
endpoint.searchParams.set("path", pathStr);
}
endpoint.searchParams.set("key", options.apiKey ?? config.apiKey);
return endpoint.toString();
}
function automatic(options = {}) {
if (!("markers" in options) && !("path" in options)) {
throw new Error(
"Automatic static maps require markers and/or path to be created."
);
}
const style = styleToStyle(options.style);
const scale = options.hiDPI ? "@2x" : "";
const format = options.format ?? "png";
let width = ~~(options.width ?? 1024);
let height = ~~(options.height ?? 1024);
if (options.hiDPI) {
width = ~~(width / 2);
height = ~~(height / 2);
}
const endpoint = new URL(
`maps/${encodeURIComponent(
style
)}/static/auto/${width}x${height}${scale}.${format}`,
defaults.maptilerApiURL
);
if ("attribution" in options) {
endpoint.searchParams.set("attribution", options.attribution.toString());
}
if ("padding" in options) {
endpoint.searchParams.set("padding", options.padding.toString());
}
if ("markers" in options) {
let markerStr = "";
const hasIcon = "markerIcon" in options;
if (hasIcon) {
markerStr += `icon:${options.markerIcon}|`;
}
if (hasIcon && "markerAnchor" in options) {
markerStr += `anchor:${options.markerAnchor}|`;
}
if (hasIcon && options.hiDPI) {
markerStr += `scale:2|`;
}
const markerList = Array.isArray(options.markers[0]) ? options.markers : [options.markers];
markerStr += markerList.map((m) => staticMapMarkerToString(m, !hasIcon)).join("|");
endpoint.searchParams.set("markers", markerStr);
}
if ("path" in options) {
let pathStr = "";
pathStr += `fill:${options.pathFillColor ?? "none"}|`;
if ("pathStrokeColor" in options) {
pathStr += `str