mapbox-gl
Version:
A WebGL interactive maps library
1,505 lines (1,487 loc) • 1.75 MB
JavaScript
/* Mapbox GL JS is Copyright © 2020 Mapbox and subject to the Mapbox Terms of Service ((https://www.mapbox.com/legal/tos/). */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.mapboxgl = factory());
}(this, (function () { 'use strict';
/* eslint-disable */
var shared, worker, mapboxgl;
// define gets called three times: one for each chunk. we rely on the order
// they're imported to know which is which
function define(_, chunk) {
if (!shared) {
shared = chunk;
} else if (!worker) {
worker = chunk;
} else {
var workerBundleString = "self.onerror = function() { console.error('An error occurred while parsing the WebWorker bundle. This is most likely due to improper transpilation by Babel; please see https://docs.mapbox.com/mapbox-gl-js/api/#transpiling-v2'); }; var sharedChunk = {}; (" + shared + ")(sharedChunk); (" + worker + ")(sharedChunk); self.onerror = null;"
var sharedChunk = {};
shared(sharedChunk);
mapboxgl = chunk(sharedChunk);
if (typeof window !== 'undefined') {
mapboxgl.workerUrl = window.URL.createObjectURL(new Blob([workerBundleString], { type: 'text/javascript' }));
}
}
}
define(['exports'], function (exports) { 'use strict';
var version = "2.3.1";
var unitbezier = UnitBezier;
function UnitBezier(p1x, p1y, p2x, p2y) {
this.cx = 3 * p1x;
this.bx = 3 * (p2x - p1x) - this.cx;
this.ax = 1 - this.cx - this.bx;
this.cy = 3 * p1y;
this.by = 3 * (p2y - p1y) - this.cy;
this.ay = 1 - this.cy - this.by;
this.p1x = p1x;
this.p1y = p2y;
this.p2x = p2x;
this.p2y = p2y;
}
UnitBezier.prototype.sampleCurveX = function (t) {
return ((this.ax * t + this.bx) * t + this.cx) * t;
};
UnitBezier.prototype.sampleCurveY = function (t) {
return ((this.ay * t + this.by) * t + this.cy) * t;
};
UnitBezier.prototype.sampleCurveDerivativeX = function (t) {
return (3 * this.ax * t + 2 * this.bx) * t + this.cx;
};
UnitBezier.prototype.solveCurveX = function (x, epsilon) {
if (typeof epsilon === 'undefined')
epsilon = 0.000001;
var t0, t1, t2, x2, i;
for (t2 = x, i = 0; i < 8; i++) {
x2 = this.sampleCurveX(t2) - x;
if (Math.abs(x2) < epsilon)
return t2;
var d2 = this.sampleCurveDerivativeX(t2);
if (Math.abs(d2) < 0.000001)
break;
t2 = t2 - x2 / d2;
}
t0 = 0;
t1 = 1;
t2 = x;
if (t2 < t0)
return t0;
if (t2 > t1)
return t1;
while (t0 < t1) {
x2 = this.sampleCurveX(t2);
if (Math.abs(x2 - x) < epsilon)
return t2;
if (x > x2) {
t0 = t2;
} else {
t1 = t2;
}
t2 = (t1 - t0) * 0.5 + t0;
}
return t2;
};
UnitBezier.prototype.solve = function (x, epsilon) {
return this.sampleCurveY(this.solveCurveX(x, epsilon));
};
var pointGeometry = Point;
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype = {
clone: function () {
return new Point(this.x, this.y);
},
add: function (p) {
return this.clone()._add(p);
},
sub: function (p) {
return this.clone()._sub(p);
},
multByPoint: function (p) {
return this.clone()._multByPoint(p);
},
divByPoint: function (p) {
return this.clone()._divByPoint(p);
},
mult: function (k) {
return this.clone()._mult(k);
},
div: function (k) {
return this.clone()._div(k);
},
rotate: function (a) {
return this.clone()._rotate(a);
},
rotateAround: function (a, p) {
return this.clone()._rotateAround(a, p);
},
matMult: function (m) {
return this.clone()._matMult(m);
},
unit: function () {
return this.clone()._unit();
},
perp: function () {
return this.clone()._perp();
},
round: function () {
return this.clone()._round();
},
mag: function () {
return Math.sqrt(this.x * this.x + this.y * this.y);
},
equals: function (other) {
return this.x === other.x && this.y === other.y;
},
dist: function (p) {
return Math.sqrt(this.distSqr(p));
},
distSqr: function (p) {
var dx = p.x - this.x, dy = p.y - this.y;
return dx * dx + dy * dy;
},
angle: function () {
return Math.atan2(this.y, this.x);
},
angleTo: function (b) {
return Math.atan2(this.y - b.y, this.x - b.x);
},
angleWith: function (b) {
return this.angleWithSep(b.x, b.y);
},
angleWithSep: function (x, y) {
return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
},
_matMult: function (m) {
var x = m[0] * this.x + m[1] * this.y, y = m[2] * this.x + m[3] * this.y;
this.x = x;
this.y = y;
return this;
},
_add: function (p) {
this.x += p.x;
this.y += p.y;
return this;
},
_sub: function (p) {
this.x -= p.x;
this.y -= p.y;
return this;
},
_mult: function (k) {
this.x *= k;
this.y *= k;
return this;
},
_div: function (k) {
this.x /= k;
this.y /= k;
return this;
},
_multByPoint: function (p) {
this.x *= p.x;
this.y *= p.y;
return this;
},
_divByPoint: function (p) {
this.x /= p.x;
this.y /= p.y;
return this;
},
_unit: function () {
this._div(this.mag());
return this;
},
_perp: function () {
var y = this.y;
this.y = this.x;
this.x = -y;
return this;
},
_rotate: function (angle) {
var cos = Math.cos(angle), sin = Math.sin(angle), x = cos * this.x - sin * this.y, y = sin * this.x + cos * this.y;
this.x = x;
this.y = y;
return this;
},
_rotateAround: function (angle, p) {
var cos = Math.cos(angle), sin = Math.sin(angle), x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y), y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
this.x = x;
this.y = y;
return this;
},
_round: function () {
this.x = Math.round(this.x);
this.y = Math.round(this.y);
return this;
}
};
Point.convert = function (a) {
if (a instanceof Point) {
return a;
}
if (Array.isArray(a)) {
return new Point(a[0], a[1]);
}
return a;
};
var window$1 = typeof self !== 'undefined' ? self : {};
const MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
const DEG_TO_RAD = Math.PI / 180;
const RAD_TO_DEG = 180 / Math.PI;
function degToRad(a) {
return a * DEG_TO_RAD;
}
function radToDeg(a) {
return a * RAD_TO_DEG;
}
const TILE_CORNERS = [
[
0,
0
],
[
1,
0
],
[
1,
1
],
[
0,
1
]
];
function furthestTileCorner(bearing) {
const alignedBearing = (bearing + 45 + 360) % 360;
const cornerIdx = Math.round(alignedBearing / 90) % 4;
return TILE_CORNERS[cornerIdx];
}
function easeCubicInOut(t) {
if (t <= 0)
return 0;
if (t >= 1)
return 1;
const t2 = t * t, t3 = t2 * t;
return 4 * (t < 0.5 ? t3 : 3 * (t - t2) + t3 - 0.75);
}
function getBounds(points) {
let minX = Infinity;
let minY = Infinity;
let maxX = -Infinity;
let maxY = -Infinity;
for (const p of points) {
minX = Math.min(minX, p.x);
minY = Math.min(minY, p.y);
maxX = Math.max(maxX, p.x);
maxY = Math.max(maxY, p.y);
}
return {
min: new pointGeometry(minX, minY),
max: new pointGeometry(maxX, maxY)
};
}
function getAABBPointSquareDist(min, max, point) {
let sqDist = 0;
for (let i = 0; i < 2; ++i) {
const v = point ? point[i] : 0;
if (min[i] > v)
sqDist += (min[i] - v) * (min[i] - v);
if (max[i] < v)
sqDist += (v - max[i]) * (v - max[i]);
}
return sqDist;
}
function polygonizeBounds(min, max, buffer = 0, close = true) {
const offset = new pointGeometry(buffer, buffer);
const minBuf = min.sub(offset);
const maxBuf = max.add(offset);
const polygon = [
minBuf,
new pointGeometry(maxBuf.x, minBuf.y),
maxBuf,
new pointGeometry(minBuf.x, maxBuf.y)
];
if (close) {
polygon.push(minBuf);
}
return polygon;
}
function bufferConvexPolygon(ring, buffer) {
const output = [];
for (let currIdx = 0; currIdx < ring.length; currIdx++) {
const prevIdx = wrap(currIdx - 1, -1, ring.length - 1);
const nextIdx = wrap(currIdx + 1, -1, ring.length - 1);
const prev = ring[prevIdx];
const curr = ring[currIdx];
const next = ring[nextIdx];
const p1 = prev.sub(curr).unit();
const p2 = next.sub(curr).unit();
const interiorAngle = p2.angleWithSep(p1.x, p1.y);
const offset = p1.add(p2).unit().mult(-1 * buffer / Math.sin(interiorAngle / 2));
output.push(curr.add(offset));
}
return output;
}
function bezier(p1x, p1y, p2x, p2y) {
const bezier = new unitbezier(p1x, p1y, p2x, p2y);
return function (t) {
return bezier.solve(t);
};
}
const ease = bezier(0.25, 0.1, 0.25, 1);
function clamp(n, min, max) {
return Math.min(max, Math.max(min, n));
}
function smoothstep(e0, e1, x) {
x = clamp((x - e0) / (e1 - e0), 0, 1);
return x * x * (3 - 2 * x);
}
function wrap(n, min, max) {
const d = max - min;
const w = ((n - min) % d + d) % d + min;
return w === min ? max : w;
}
function asyncAll(array, fn, callback) {
if (!array.length) {
return callback(null, []);
}
let remaining = array.length;
const results = new Array(array.length);
let error = null;
array.forEach((item, i) => {
fn(item, (err, result) => {
if (err)
error = err;
results[i] = result;
if (--remaining === 0)
callback(error, results);
});
});
}
function values(obj) {
const result = [];
for (const k in obj) {
result.push(obj[k]);
}
return result;
}
function keysDifference(obj, other) {
const difference = [];
for (const i in obj) {
if (!(i in other)) {
difference.push(i);
}
}
return difference;
}
function extend(dest, ...sources) {
for (const src of sources) {
for (const k in src) {
dest[k] = src[k];
}
}
return dest;
}
function pick(src, properties) {
const result = {};
for (let i = 0; i < properties.length; i++) {
const k = properties[i];
if (k in src) {
result[k] = src[k];
}
}
return result;
}
let id = 1;
function uniqueId() {
return id++;
}
function uuid() {
function b(a) {
return a ? (a ^ Math.random() * 16 >> a / 4).toString(16) : ([10000000] + -[1000] + -4000 + -8000 + -100000000000).replace(/[018]/g, b);
}
return b();
}
function nextPowerOfTwo(value) {
if (value <= 1)
return 1;
return Math.pow(2, Math.ceil(Math.log(value) / Math.LN2));
}
function prevPowerOfTwo(value) {
if (value <= 1)
return 1;
return Math.pow(2, Math.floor(Math.log(value) / Math.LN2));
}
function validateUuid(str) {
return str ? /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str) : false;
}
function bindAll(fns, context) {
fns.forEach(fn => {
if (!context[fn]) {
return;
}
context[fn] = context[fn].bind(context);
});
}
function endsWith(string, suffix) {
return string.indexOf(suffix, string.length - suffix.length) !== -1;
}
function mapObject(input, iterator, context) {
const output = {};
for (const key in input) {
output[key] = iterator.call(context || this, input[key], key, input);
}
return output;
}
function filterObject(input, iterator, context) {
const output = {};
for (const key in input) {
if (iterator.call(context || this, input[key], key, input)) {
output[key] = input[key];
}
}
return output;
}
function clone(input) {
if (Array.isArray(input)) {
return input.map(clone);
} else if (typeof input === 'object' && input) {
return mapObject(input, clone);
} else {
return input;
}
}
function arraysIntersect(a, b) {
for (let l = 0; l < a.length; l++) {
if (b.indexOf(a[l]) >= 0)
return true;
}
return false;
}
const warnOnceHistory = {};
function warnOnce(message) {
if (!warnOnceHistory[message]) {
if (typeof console !== 'undefined')
console.warn(message);
warnOnceHistory[message] = true;
}
}
function isCounterClockwise(a, b, c) {
return (c.y - a.y) * (b.x - a.x) > (b.y - a.y) * (c.x - a.x);
}
function calculateSignedArea(ring) {
let sum = 0;
for (let i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
p1 = ring[i];
p2 = ring[j];
sum += (p2.x - p1.x) * (p1.y + p2.y);
}
return sum;
}
function isWorker() {
return typeof WorkerGlobalScope !== 'undefined' && typeof self !== 'undefined' && self instanceof WorkerGlobalScope;
}
function parseCacheControl(cacheControl) {
const re = /(?:^|(?:\s*\,\s*))([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\]|\\.)*)\")))?/g;
const header = {};
cacheControl.replace(re, ($0, $1, $2, $3) => {
const value = $2 || $3;
header[$1] = value ? value.toLowerCase() : true;
return '';
});
if (header['max-age']) {
const maxAge = parseInt(header['max-age'], 10);
if (isNaN(maxAge))
delete header['max-age'];
else
header['max-age'] = maxAge;
}
return header;
}
let _isSafari = null;
function isSafari(scope) {
if (_isSafari == null) {
const userAgent = scope.navigator ? scope.navigator.userAgent : null;
_isSafari = !!scope.safari || !!(userAgent && (/\b(iPad|iPhone|iPod)\b/.test(userAgent) || !!userAgent.match('Safari') && !userAgent.match('Chrome')));
}
return _isSafari;
}
function storageAvailable(type) {
try {
const storage = window$1[type];
storage.setItem('_mapbox_test_', 1);
storage.removeItem('_mapbox_test_');
return true;
} catch (e) {
return false;
}
}
function b64EncodeUnicode(str) {
return window$1.btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => {
return String.fromCharCode(Number('0x' + p1));
}));
}
function b64DecodeUnicode(str) {
return decodeURIComponent(window$1.atob(str).split('').map(c => {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
let linkEl;
let reducedMotionQuery;
let stubTime;
const exported = {
now() {
if (stubTime !== undefined) {
return stubTime;
}
return window$1.performance.now();
},
setNow(time) {
stubTime = time;
},
restoreNow() {
stubTime = undefined;
},
frame(fn) {
const frame = window$1.requestAnimationFrame(fn);
return { cancel: () => window$1.cancelAnimationFrame(frame) };
},
getImageData(img, padding = 0) {
const canvas = window$1.document.createElement('canvas');
const context = canvas.getContext('2d');
if (!context) {
throw new Error('failed to create canvas 2d context');
}
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0, img.width, img.height);
return context.getImageData(-padding, -padding, img.width + 2 * padding, img.height + 2 * padding);
},
resolveURL(path) {
if (!linkEl)
linkEl = window$1.document.createElement('a');
linkEl.href = path;
return linkEl.href;
},
get devicePixelRatio() {
return window$1.devicePixelRatio;
},
get prefersReducedMotion() {
if (!window$1.matchMedia)
return false;
if (reducedMotionQuery == null) {
reducedMotionQuery = window$1.matchMedia('(prefers-reduced-motion: reduce)');
}
return reducedMotionQuery.matches;
}
};
let mapboxHTTPURLRegex;
const config = {
API_URL: 'https://api.mapbox.com',
get API_URL_REGEX() {
if (mapboxHTTPURLRegex == null) {
const prodMapboxHTTPURLRegex = /^((https?:)?\/\/)?([^\/]+\.)?mapbox\.c(n|om)(\/|\?|$)/i;
try {
mapboxHTTPURLRegex = process.env.API_URL_REGEX != null ? new RegExp(process.env.API_URL_REGEX) : prodMapboxHTTPURLRegex;
} catch (e) {
mapboxHTTPURLRegex = prodMapboxHTTPURLRegex;
}
}
return mapboxHTTPURLRegex;
},
get EVENTS_URL() {
if (!this.API_URL) {
return null;
}
if (this.API_URL.indexOf('https://api.mapbox.cn') === 0) {
return 'https://events.mapbox.cn/events/v2';
} else if (this.API_URL.indexOf('https://api.mapbox.com') === 0) {
return 'https://events.mapbox.com/events/v2';
} else {
return null;
}
},
SESSION_PATH: '/map-sessions/v1',
FEEDBACK_URL: 'https://apps.mapbox.com/feedback',
TILE_URL_VERSION: 'v4',
RASTER_URL_PREFIX: 'raster/v1',
REQUIRE_ACCESS_TOKEN: true,
ACCESS_TOKEN: null,
MAX_PARALLEL_IMAGE_REQUESTS: 16
};
const exported$1 = {
supported: false,
testSupport
};
let glForTesting;
let webpCheckComplete = false;
let webpImgTest;
let webpImgTestOnloadComplete = false;
if (window$1.document) {
webpImgTest = window$1.document.createElement('img');
webpImgTest.onload = function () {
if (glForTesting)
testWebpTextureUpload(glForTesting);
glForTesting = null;
webpImgTestOnloadComplete = true;
};
webpImgTest.onerror = function () {
webpCheckComplete = true;
glForTesting = null;
};
webpImgTest.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA=';
}
function testSupport(gl) {
if (webpCheckComplete || !webpImgTest)
return;
if (webpImgTestOnloadComplete) {
testWebpTextureUpload(gl);
} else {
glForTesting = gl;
}
}
function testWebpTextureUpload(gl) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
try {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, webpImgTest);
if (gl.isContextLost())
return;
exported$1.supported = true;
} catch (e) {
}
gl.deleteTexture(texture);
webpCheckComplete = true;
}
const SKU_ID = '01';
function createSkuToken() {
const TOKEN_VERSION = '1';
const base62chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
let sessionRandomizer = '';
for (let i = 0; i < 10; i++) {
sessionRandomizer += base62chars[Math.floor(Math.random() * 62)];
}
const expiration = 12 * 60 * 60 * 1000;
const token = [
TOKEN_VERSION,
SKU_ID,
sessionRandomizer
].join('');
const tokenExpiresAt = Date.now() + expiration;
return {
token,
tokenExpiresAt
};
}
const AUTH_ERR_MSG = 'NO_ACCESS_TOKEN';
class RequestManager {
constructor(transformRequestFn, customAccessToken, silenceAuthErrors) {
this._transformRequestFn = transformRequestFn;
this._customAccessToken = customAccessToken;
this._silenceAuthErrors = !!silenceAuthErrors;
this._createSkuToken();
}
_createSkuToken() {
const skuToken = createSkuToken();
this._skuToken = skuToken.token;
this._skuTokenExpiresAt = skuToken.tokenExpiresAt;
}
_isSkuTokenExpired() {
return Date.now() > this._skuTokenExpiresAt;
}
transformRequest(url, type) {
if (this._transformRequestFn) {
return this._transformRequestFn(url, type) || { url };
}
return { url };
}
normalizeStyleURL(url, accessToken) {
if (!isMapboxURL(url))
return url;
const urlObject = parseUrl(url);
urlObject.path = `/styles/v1${ urlObject.path }`;
return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
}
normalizeGlyphsURL(url, accessToken) {
if (!isMapboxURL(url))
return url;
const urlObject = parseUrl(url);
urlObject.path = `/fonts/v1${ urlObject.path }`;
return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
}
normalizeSourceURL(url, accessToken) {
if (!isMapboxURL(url))
return url;
const urlObject = parseUrl(url);
urlObject.path = `/v4/${ urlObject.authority }.json`;
urlObject.params.push('secure');
return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
}
normalizeSpriteURL(url, format, extension, accessToken) {
const urlObject = parseUrl(url);
if (!isMapboxURL(url)) {
urlObject.path += `${ format }${ extension }`;
return formatUrl(urlObject);
}
urlObject.path = `/styles/v1${ urlObject.path }/sprite${ format }${ extension }`;
return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
}
normalizeTileURL(tileURL, use2x, rasterTileSize) {
if (this._isSkuTokenExpired()) {
this._createSkuToken();
}
if (tileURL && !isMapboxURL(tileURL))
return tileURL;
const urlObject = parseUrl(tileURL);
const imageExtensionRe = /(\.(png|jpg)\d*)(?=$)/;
const extension = exported$1.supported ? '.webp' : '$1';
const use2xAs512 = rasterTileSize && urlObject.authority !== 'raster' && rasterTileSize === 512;
const suffix = use2x || use2xAs512 ? '@2x' : '';
urlObject.path = urlObject.path.replace(imageExtensionRe, `${ suffix }${ extension }`);
if (urlObject.authority === 'raster') {
urlObject.path = `/${ config.RASTER_URL_PREFIX }${ urlObject.path }`;
} else {
const tileURLAPIPrefixRe = /^.+\/v4\//;
urlObject.path = urlObject.path.replace(tileURLAPIPrefixRe, '/');
urlObject.path = `/${ config.TILE_URL_VERSION }${ urlObject.path }`;
}
const accessToken = this._customAccessToken || getAccessToken(urlObject.params) || config.ACCESS_TOKEN;
if (config.REQUIRE_ACCESS_TOKEN && accessToken && this._skuToken) {
urlObject.params.push(`sku=${ this._skuToken }`);
}
return this._makeAPIURL(urlObject, accessToken);
}
canonicalizeTileURL(url, removeAccessToken) {
const extensionRe = /\.[\w]+$/;
const urlObject = parseUrl(url);
if (!urlObject.path.match(/^(\/v4\/|\/raster\/v1\/)/) || !urlObject.path.match(extensionRe)) {
return url;
}
let result = 'mapbox://';
if (urlObject.path.match(/^\/raster\/v1\//)) {
const rasterPrefix = `/${ config.RASTER_URL_PREFIX }/`;
result += `raster/${ urlObject.path.replace(rasterPrefix, '') }`;
} else {
const tilesPrefix = `/${ config.TILE_URL_VERSION }/`;
result += `tiles/${ urlObject.path.replace(tilesPrefix, '') }`;
}
let params = urlObject.params;
if (removeAccessToken) {
params = params.filter(p => !p.match(/^access_token=/));
}
if (params.length)
result += `?${ params.join('&') }`;
return result;
}
canonicalizeTileset(tileJSON, sourceURL) {
const removeAccessToken = sourceURL ? isMapboxURL(sourceURL) : false;
const canonical = [];
for (const url of tileJSON.tiles || []) {
if (isMapboxHTTPURL(url)) {
canonical.push(this.canonicalizeTileURL(url, removeAccessToken));
} else {
canonical.push(url);
}
}
return canonical;
}
_makeAPIURL(urlObject, accessToken) {
const help = 'See https://www.mapbox.com/api-documentation/#access-tokens-and-token-scopes';
const apiUrlObject = parseUrl(config.API_URL);
urlObject.protocol = apiUrlObject.protocol;
urlObject.authority = apiUrlObject.authority;
if (urlObject.protocol === 'http') {
const i = urlObject.params.indexOf('secure');
if (i >= 0)
urlObject.params.splice(i, 1);
}
if (apiUrlObject.path !== '/') {
urlObject.path = `${ apiUrlObject.path }${ urlObject.path }`;
}
if (!config.REQUIRE_ACCESS_TOKEN)
return formatUrl(urlObject);
accessToken = accessToken || config.ACCESS_TOKEN;
if (!this._silenceAuthErrors) {
if (!accessToken)
throw new Error(`An API access token is required to use Mapbox GL. ${ help }`);
if (accessToken[0] === 's')
throw new Error(`Use a public access token (pk.*) with Mapbox GL, not a secret access token (sk.*). ${ help }`);
}
urlObject.params = urlObject.params.filter(d => d.indexOf('access_token') === -1);
urlObject.params.push(`access_token=${ accessToken || '' }`);
return formatUrl(urlObject);
}
}
function isMapboxURL(url) {
return url.indexOf('mapbox:') === 0;
}
function isMapboxHTTPURL(url) {
return config.API_URL_REGEX.test(url);
}
function hasCacheDefeatingSku(url) {
return url.indexOf('sku=') > 0 && isMapboxHTTPURL(url);
}
function getAccessToken(params) {
for (const param of params) {
const match = param.match(/^access_token=(.*)$/);
if (match) {
return match[1];
}
}
return null;
}
const urlRe = /^(\w+):\/\/([^/?]*)(\/[^?]+)?\??(.+)?/;
function parseUrl(url) {
const parts = url.match(urlRe);
if (!parts) {
throw new Error('Unable to parse URL object');
}
return {
protocol: parts[1],
authority: parts[2],
path: parts[3] || '/',
params: parts[4] ? parts[4].split('&') : []
};
}
function formatUrl(obj) {
const params = obj.params.length ? `?${ obj.params.join('&') }` : '';
return `${ obj.protocol }://${ obj.authority }${ obj.path }${ params }`;
}
const telemEventKey = 'mapbox.eventData';
function parseAccessToken(accessToken) {
if (!accessToken) {
return null;
}
const parts = accessToken.split('.');
if (!parts || parts.length !== 3) {
return null;
}
try {
const jsonData = JSON.parse(b64DecodeUnicode(parts[1]));
return jsonData;
} catch (e) {
return null;
}
}
class TelemetryEvent {
constructor(type) {
this.type = type;
this.anonId = null;
this.eventData = {};
this.queue = [];
this.pendingRequest = null;
}
getStorageKey(domain) {
const tokenData = parseAccessToken(config.ACCESS_TOKEN);
let u = '';
if (tokenData && tokenData['u']) {
u = b64EncodeUnicode(tokenData['u']);
} else {
u = config.ACCESS_TOKEN || '';
}
return domain ? `${ telemEventKey }.${ domain }:${ u }` : `${ telemEventKey }:${ u }`;
}
fetchEventData() {
const isLocalStorageAvailable = storageAvailable('localStorage');
const storageKey = this.getStorageKey();
const uuidKey = this.getStorageKey('uuid');
if (isLocalStorageAvailable) {
try {
const data = window$1.localStorage.getItem(storageKey);
if (data) {
this.eventData = JSON.parse(data);
}
const uuid = window$1.localStorage.getItem(uuidKey);
if (uuid)
this.anonId = uuid;
} catch (e) {
warnOnce('Unable to read from LocalStorage');
}
}
}
saveEventData() {
const isLocalStorageAvailable = storageAvailable('localStorage');
const storageKey = this.getStorageKey();
const uuidKey = this.getStorageKey('uuid');
if (isLocalStorageAvailable) {
try {
window$1.localStorage.setItem(uuidKey, this.anonId);
if (Object.keys(this.eventData).length >= 1) {
window$1.localStorage.setItem(storageKey, JSON.stringify(this.eventData));
}
} catch (e) {
warnOnce('Unable to write to LocalStorage');
}
}
}
processRequests(_) {
}
postEvent(timestamp, additionalPayload, callback, customAccessToken) {
if (!config.EVENTS_URL)
return;
const eventsUrlObject = parseUrl(config.EVENTS_URL);
eventsUrlObject.params.push(`access_token=${ customAccessToken || config.ACCESS_TOKEN || '' }`);
const payload = {
event: this.type,
created: new Date(timestamp).toISOString(),
sdkIdentifier: 'mapbox-gl-js',
sdkVersion: version,
skuId: SKU_ID,
userId: this.anonId
};
const finalPayload = additionalPayload ? extend(payload, additionalPayload) : payload;
const request = {
url: formatUrl(eventsUrlObject),
headers: { 'Content-Type': 'text/plain' },
body: JSON.stringify([finalPayload])
};
this.pendingRequest = postData(request, error => {
this.pendingRequest = null;
callback(error);
this.saveEventData();
this.processRequests(customAccessToken);
});
}
queueRequest(event, customAccessToken) {
this.queue.push(event);
this.processRequests(customAccessToken);
}
}
class MapLoadEvent extends TelemetryEvent {
constructor() {
super('map.load');
this.success = {};
this.skuToken = '';
}
postMapLoadEvent(mapId, skuToken, customAccessToken, callback) {
this.skuToken = skuToken;
this.errorCb = callback;
if (config.EVENTS_URL) {
if (customAccessToken || config.ACCESS_TOKEN) {
this.queueRequest({
id: mapId,
timestamp: Date.now()
}, customAccessToken);
} else {
this.errorCb(new Error(AUTH_ERR_MSG));
}
}
}
processRequests(customAccessToken) {
if (this.pendingRequest || this.queue.length === 0)
return;
const {id, timestamp} = this.queue.shift();
if (id && this.success[id])
return;
if (!this.anonId) {
this.fetchEventData();
}
if (!validateUuid(this.anonId)) {
this.anonId = uuid();
}
this.postEvent(timestamp, { skuToken: this.skuToken }, err => {
if (err) {
this.errorCb(err);
} else {
if (id)
this.success[id] = true;
}
}, customAccessToken);
}
}
class MapSessionAPI extends TelemetryEvent {
constructor() {
super('map.auth');
this.success = {};
this.skuToken = '';
}
getSession(timestamp, token, callback, customAccessToken) {
if (!config.API_URL || !config.SESSION_PATH)
return;
const authUrlObject = parseUrl(config.API_URL + config.SESSION_PATH);
authUrlObject.params.push(`sku=${ token || '' }`);
authUrlObject.params.push(`access_token=${ customAccessToken || config.ACCESS_TOKEN || '' }`);
const request = {
url: formatUrl(authUrlObject),
headers: { 'Content-Type': 'text/plain' }
};
this.pendingRequest = getData(request, error => {
this.pendingRequest = null;
callback(error);
this.saveEventData();
this.processRequests(customAccessToken);
});
}
getSessionAPI(mapId, skuToken, customAccessToken, callback) {
this.skuToken = skuToken;
this.errorCb = callback;
if (config.SESSION_PATH && config.API_URL) {
if (customAccessToken || config.ACCESS_TOKEN) {
this.queueRequest({
id: mapId,
timestamp: Date.now()
}, customAccessToken);
} else {
this.errorCb(new Error(AUTH_ERR_MSG));
}
}
}
processRequests(customAccessToken) {
if (this.pendingRequest || this.queue.length === 0)
return;
const {id, timestamp} = this.queue.shift();
if (id && this.success[id])
return;
this.getSession(timestamp, this.skuToken, err => {
if (err) {
this.errorCb(err);
} else {
if (id)
this.success[id] = true;
}
}, customAccessToken);
}
}
class TurnstileEvent extends TelemetryEvent {
constructor(customAccessToken) {
super('appUserTurnstile');
this._customAccessToken = customAccessToken;
}
postTurnstileEvent(tileUrls, customAccessToken) {
if (config.EVENTS_URL && config.ACCESS_TOKEN && Array.isArray(tileUrls) && tileUrls.some(url => isMapboxURL(url) || isMapboxHTTPURL(url))) {
this.queueRequest(Date.now(), customAccessToken);
}
}
processRequests(customAccessToken) {
if (this.pendingRequest || this.queue.length === 0) {
return;
}
if (!this.anonId || !this.eventData.lastSuccess || !this.eventData.tokenU) {
this.fetchEventData();
}
const tokenData = parseAccessToken(config.ACCESS_TOKEN);
const tokenU = tokenData ? tokenData['u'] : config.ACCESS_TOKEN;
let dueForEvent = tokenU !== this.eventData.tokenU;
if (!validateUuid(this.anonId)) {
this.anonId = uuid();
dueForEvent = true;
}
const nextUpdate = this.queue.shift();
if (this.eventData.lastSuccess) {
const lastUpdate = new Date(this.eventData.lastSuccess);
const nextDate = new Date(nextUpdate);
const daysElapsed = (nextUpdate - this.eventData.lastSuccess) / (24 * 60 * 60 * 1000);
dueForEvent = dueForEvent || daysElapsed >= 1 || daysElapsed < -1 || lastUpdate.getDate() !== nextDate.getDate();
} else {
dueForEvent = true;
}
if (!dueForEvent) {
return this.processRequests();
}
this.postEvent(nextUpdate, { 'enabled.telemetry': false }, err => {
if (!err) {
this.eventData.lastSuccess = nextUpdate;
this.eventData.tokenU = tokenU;
}
}, customAccessToken);
}
}
const turnstileEvent_ = new TurnstileEvent();
const postTurnstileEvent = turnstileEvent_.postTurnstileEvent.bind(turnstileEvent_);
const mapLoadEvent_ = new MapLoadEvent();
const postMapLoadEvent = mapLoadEvent_.postMapLoadEvent.bind(mapLoadEvent_);
const mapSessionAPI_ = new MapSessionAPI();
const getMapSessionAPI = mapSessionAPI_.getSessionAPI.bind(mapSessionAPI_);
const authenticatedMaps = new Set();
function storeAuthState(gl, state) {
if (state) {
authenticatedMaps.add(gl);
} else {
authenticatedMaps.delete(gl);
}
}
function isMapAuthenticated(gl) {
return authenticatedMaps.has(gl);
}
function removeAuthState(gl) {
authenticatedMaps.delete(gl);
}
const CACHE_NAME = 'mapbox-tiles';
let cacheLimit = 500;
let cacheCheckThreshold = 50;
const MIN_TIME_UNTIL_EXPIRY = 1000 * 60 * 7;
let sharedCache;
function cacheOpen() {
if (window$1.caches && !sharedCache) {
sharedCache = window$1.caches.open(CACHE_NAME);
}
}
let responseConstructorSupportsReadableStream;
function prepareBody(response, callback) {
if (responseConstructorSupportsReadableStream === undefined) {
try {
new Response(new ReadableStream());
responseConstructorSupportsReadableStream = true;
} catch (e) {
responseConstructorSupportsReadableStream = false;
}
}
if (responseConstructorSupportsReadableStream) {
callback(response.body);
} else {
response.blob().then(callback);
}
}
function cachePut(request, response, requestTime) {
cacheOpen();
if (!sharedCache)
return;
const options = {
status: response.status,
statusText: response.statusText,
headers: new window$1.Headers()
};
response.headers.forEach((v, k) => options.headers.set(k, v));
const cacheControl = parseCacheControl(response.headers.get('Cache-Control') || '');
if (cacheControl['no-store']) {
return;
}
if (cacheControl['max-age']) {
options.headers.set('Expires', new Date(requestTime + cacheControl['max-age'] * 1000).toUTCString());
}
const timeUntilExpiry = new Date(options.headers.get('Expires')).getTime() - requestTime;
if (timeUntilExpiry < MIN_TIME_UNTIL_EXPIRY)
return;
prepareBody(response, body => {
const clonedResponse = new window$1.Response(body, options);
cacheOpen();
if (!sharedCache)
return;
sharedCache.then(cache => cache.put(stripQueryParameters(request.url), clonedResponse)).catch(e => warnOnce(e.message));
});
}
function stripQueryParameters(url) {
const start = url.indexOf('?');
return start < 0 ? url : url.slice(0, start);
}
function cacheGet(request, callback) {
cacheOpen();
if (!sharedCache)
return callback(null);
const strippedURL = stripQueryParameters(request.url);
sharedCache.then(cache => {
cache.match(strippedURL).then(response => {
const fresh = isFresh(response);
cache.delete(strippedURL);
if (fresh) {
cache.put(strippedURL, response.clone());
}
callback(null, response, fresh);
}).catch(callback);
}).catch(callback);
}
function isFresh(response) {
if (!response)
return false;
const expires = new Date(response.headers.get('Expires') || 0);
const cacheControl = parseCacheControl(response.headers.get('Cache-Control') || '');
return expires > Date.now() && !cacheControl['no-cache'];
}
let globalEntryCounter = Infinity;
function cacheEntryPossiblyAdded(dispatcher) {
globalEntryCounter++;
if (globalEntryCounter > cacheCheckThreshold) {
dispatcher.getActor().send('enforceCacheSizeLimit', cacheLimit);
globalEntryCounter = 0;
}
}
function enforceCacheSizeLimit(limit) {
cacheOpen();
if (!sharedCache)
return;
sharedCache.then(cache => {
cache.keys().then(keys => {
for (let i = 0; i < keys.length - limit; i++) {
cache.delete(keys[i]);
}
});
});
}
function clearTileCache(callback) {
const promise = window$1.caches.delete(CACHE_NAME);
if (callback) {
promise.catch(callback).then(() => callback());
}
}
function setCacheLimits(limit, checkThreshold) {
cacheLimit = limit;
cacheCheckThreshold = checkThreshold;
}
const ResourceType = {
Unknown: 'Unknown',
Style: 'Style',
Source: 'Source',
Tile: 'Tile',
Glyphs: 'Glyphs',
SpriteImage: 'SpriteImage',
SpriteJSON: 'SpriteJSON',
Image: 'Image'
};
if (typeof Object.freeze == 'function') {
Object.freeze(ResourceType);
}
class AJAXError extends Error {
constructor(message, status, url) {
if (status === 401 && isMapboxHTTPURL(url)) {
message += ': you may have provided an invalid Mapbox access token. See https://www.mapbox.com/api-documentation/#access-tokens-and-token-scopes';
}
super(message);
this.status = status;
this.url = url;
}
toString() {
return `${ this.name }: ${ this.message } (${ this.status }): ${ this.url }`;
}
}
const getReferrer = isWorker() ? () => self.worker && self.worker.referrer : () => (window$1.location.protocol === 'blob:' ? window$1.parent : window$1).location.href;
const isFileURL = url => /^file:/.test(url) || /^file:/.test(getReferrer()) && !/^\w+:/.test(url);
function makeFetchRequest(requestParameters, callback) {
const controller = new window$1.AbortController();
const request = new window$1.Request(requestParameters.url, {
method: requestParameters.method || 'GET',
body: requestParameters.body,
credentials: requestParameters.credentials,
headers: requestParameters.headers,
referrer: getReferrer(),
signal: controller.signal
});
let complete = false;
let aborted = false;
const cacheIgnoringSearch = hasCacheDefeatingSku(request.url);
if (requestParameters.type === 'json') {
request.headers.set('Accept', 'application/json');
}
const validateOrFetch = (err, cachedResponse, responseIsFresh) => {
if (aborted)
return;
if (err) {
if (err.message !== 'SecurityError') {
warnOnce(err);
}
}
if (cachedResponse && responseIsFresh) {
return finishRequest(cachedResponse);
}
const requestTime = Date.now();
window$1.fetch(request).then(response => {
if (response.ok) {
const cacheableResponse = cacheIgnoringSearch ? response.clone() : null;
return finishRequest(response, cacheableResponse, requestTime);
} else {
return callback(new AJAXError(response.statusText, response.status, requestParameters.url));
}
}).catch(error => {
if (error.code === 20) {
return;
}
callback(new Error(error.message));
});
};
const finishRequest = (response, cacheableResponse, requestTime) => {
(requestParameters.type === 'arrayBuffer' ? response.arrayBuffer() : requestParameters.type === 'json' ? response.json() : response.text()).then(result => {
if (aborted)
return;
if (cacheableResponse && requestTime) {
cachePut(request, cacheableResponse, requestTime);
}
complete = true;
callback(null, result, response.headers.get('Cache-Control'), response.headers.get('Expires'));
}).catch(err => {
if (!aborted)
callback(new Error(err.message));
});
};
if (cacheIgnoringSearch) {
cacheGet(request, validateOrFetch);
} else {
validateOrFetch(null, null);
}
return {
cancel: () => {
aborted = true;
if (!complete)
controller.abort();
}
};
}
function makeXMLHttpRequest(requestParameters, callback) {
const xhr = new window$1.XMLHttpRequest();
xhr.open(requestParameters.method || 'GET', requestParameters.url, true);
if (requestParameters.type === 'arrayBuffer') {
xhr.responseType = 'arraybuffer';
}
for (const k in requestParameters.headers) {
xhr.setRequestHeader(k, requestParameters.headers[k]);
}
if (requestParameters.type === 'json') {
xhr.responseType = 'text';
xhr.setRequestHeader('Accept', 'application/json');
}
xhr.withCredentials = requestParameters.credentials === 'include';
xhr.onerror = () => {
callback(new Error(xhr.statusText));
};
xhr.onload = () => {
if ((xhr.status >= 200 && xhr.status < 300 || xhr.status === 0) && xhr.response !== null) {
let data = xhr.response;
if (requestParameters.type === 'json') {
try {
data = JSON.parse(xhr.response);
} catch (err) {
return callback(err);
}
}
callback(null, data, xhr.getResponseHeader('Cache-Control'), xhr.getResponseHeader('Expires'));
} else {
callback(new AJAXError(xhr.statusText, xhr.status, requestParameters.url));
}
};
xhr.send(requestParameters.body);
return { cancel: () => xhr.abort() };
}
const makeRequest = function (requestParameters, callback) {
if (!isFileURL(requestParameters.url)) {
if (window$1.fetch && window$1.Request && window$1.AbortController && window$1.Request.prototype.hasOwnProperty('signal')) {
return makeFetchRequest(requestParameters, callback);
}
if (isWorker() && self.worker && self.worker.actor) {
const queueOnMainThread = true;
return self.worker.actor.send('getResource', requestParameters, callback, undefined, queueOnMainThread);
}
}
return makeXMLHttpRequest(requestParameters, callback);
};
const getJSON = function (requestParameters, callback) {
return makeRequest(extend(requestParameters, { type: 'json' }), callback);
};
const getArrayBuffer = function (requestParameters, callback) {
return makeRequest(extend(requestParameters, { type: 'arrayBuffer' }), callback);
};
const postData = function (requestParameters, callback) {
return makeRequest(extend(requestParameters, { method: 'POST' }), callback);
};
const getData = function (requestParameters, callback) {
return makeRequest(extend(requestParameters, { method: 'GET' }), callback);
};
function sameOrigin(url) {
const a = window$1.document.createElement('a');
a.href = url;
return a.protocol === window$1.document.location.protocol && a.host === window$1.document.location.host;
}
const transparentPngUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII=';
function arrayBufferToImage(data, callback) {
const img = new window$1.Image();
const URL = window$1.URL;
img.onload = () => {
callback(null, img);
URL.revokeObjectURL(img.src);
img.onload = null;
window$1.requestAnimationFrame(() => {
img.src = transparentPngUrl;
});
};
img.onerror = () => callback(new Error('Could not load image. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.'));
const blob = new window$1.Blob([new Uint8Array(data)], { type: 'image/png' });
img.src = data.byteLength ? URL.createObjectURL(blob) : transparentPngUrl;
}
function arrayBufferToImageBitmap(data, callback) {
const blob = new window$1.Blob([new Uint8Array(data)], { type: 'image/png' });
window$1.createImageBitmap(blob).then(imgBitmap => {
callback(null, imgBitmap);
}).catch(e => {
callback(new Error(`Could not load image because of ${ e.message }. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`));
});
}
let imageQueue, numImageRequests;
const resetImageRequestQueue = () => {
imageQueue = [];
numImageRequests = 0;
};
resetImageRequestQueue();
const getImage = function (requestParameters, callback) {
if (exported$1.supported) {
if (!requestParameters.headers) {
requestParameters.headers = {};
}
requestParameters.headers.accept = 'image/webp,*/*';
}
if (numImageRequests >= config.MAX_PARALLEL_IMAGE_REQUESTS) {
const queued = {
requestParameters,
callback,
cancelled: false,
cancel() {
this.cancelled = true;
}
};
imageQueue.push(queued);
return queued;
}
numImageRequests++;
let advanced = false;
const advanceImageRequestQueue = () => {
if (advanced)
return;
advanced = true;
numImageRequests--;
while (imageQueue.length && numImageRequests < config.MAX_PARALLEL_IMAGE_REQUESTS) {
const request = imageQueue.shift();
const {requestParameters, callback, cancelled} = request;
if (!cancelled) {
request.cancel = getImage(requestParameters, callback).cancel;
}
}
};
const request = getArrayBuffer(requestParameters, (err, data, cacheControl, expires) => {
advanceImageRequestQueue();
if (err) {
callback(err);
} else if (data) {
if (window$1.createImageBitmap) {
arrayBufferToImageBitmap(data, (err, imgBitmap) => callback(err, imgBitmap, cacheControl, expires));
} else {
arrayBufferToImage(data, (err, img) => callback(err, img, cacheControl, expires));
}
}
});
return {
cancel: () => {
request.cancel();
advanceImageRequestQueue();
}
};
};
const getVideo = function (urls, callback) {
const video = window$1.document.createElement('video');
video.muted = true;
video.onloadstart = function () {
callback(null, video);
};
for (let i = 0; i < urls.length; i++) {
const s = window$1.document.createElement('source');
if (!sameOrigin(urls[i])) {
video.crossOrigin = 'Anonymous';
}
s.src = urls[i];
video.appendChild(s);
}
return {
cancel: () => {
}
};
};
function _addEventListener(type, listener, listenerList) {
const listenerExists = listenerList[type] && listenerList[type].indexOf(lis