UNPKG

mapbox-gl

Version:
1,505 lines (1,487 loc) 1.75 MB
/* 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