import Circle from 'ol/style/Circle.js'; import Fill from 'ol/style/Fill.js'; import Icon from 'ol/style/Icon.js'; import RenderFeature from 'ol/render/Feature.js'; import Stroke from 'ol/style/Stroke.js'; import Style from 'ol/style/Style.js'; import Text from 'ol/style/Text.js'; import { registerFont, checkedFonts } from 'ol/render/canvas.js'; import { expandUrl } from 'ol/tileurlfunction.js'; import GeoJSON from 'ol/format/GeoJSON.js'; import ImageLayer from 'ol/layer/Image.js'; import Layer from 'ol/layer/Layer.js'; import LayerGroup from 'ol/layer/Group.js'; import MVT from 'ol/format/MVT.js'; import Map from 'ol/Map.js'; import Raster from 'ol/source/Raster.js'; import Source from 'ol/source/Source.js'; import TileGrid from 'ol/tilegrid/TileGrid.js'; import TileJSON from 'ol/source/TileJSON.js'; import TileLayer from 'ol/layer/Tile.js'; import VectorLayer from 'ol/layer/Vector.js'; import VectorSource from 'ol/source/Vector.js'; import VectorTileLayer from 'ol/layer/VectorTile.js'; import VectorTileSource, { defaultLoadFunction } from 'ol/source/VectorTile.js'; import View from 'ol/View.js'; import { get as get$1, METERS_PER_UNIT, fromLonLat, equivalent, getUserProjection } from 'ol/proj.js'; import { bbox } from 'ol/loadingstrategy.js'; import { createXYZ } from 'ol/tilegrid.js'; import { getTopLeft } from 'ol/extent.js'; import { getUid } from 'ol/util.js'; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var csscolorparser = {}; var parseCSSColor_1; // (c) Dean McNamee , 2012. // // https://github.com/deanm/css-color-parser-js // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // http://www.w3.org/TR/css3-color/ var kCSSColorTable = { 'transparent': [ 0, 0, 0, 0 ], 'aliceblue': [ 240, 248, 255, 1 ], 'antiquewhite': [ 250, 235, 215, 1 ], 'aqua': [ 0, 255, 255, 1 ], 'aquamarine': [ 127, 255, 212, 1 ], 'azure': [ 240, 255, 255, 1 ], 'beige': [ 245, 245, 220, 1 ], 'bisque': [ 255, 228, 196, 1 ], 'black': [ 0, 0, 0, 1 ], 'blanchedalmond': [ 255, 235, 205, 1 ], 'blue': [ 0, 0, 255, 1 ], 'blueviolet': [ 138, 43, 226, 1 ], 'brown': [ 165, 42, 42, 1 ], 'burlywood': [ 222, 184, 135, 1 ], 'cadetblue': [ 95, 158, 160, 1 ], 'chartreuse': [ 127, 255, 0, 1 ], 'chocolate': [ 210, 105, 30, 1 ], 'coral': [ 255, 127, 80, 1 ], 'cornflowerblue': [ 100, 149, 237, 1 ], 'cornsilk': [ 255, 248, 220, 1 ], 'crimson': [ 220, 20, 60, 1 ], 'cyan': [ 0, 255, 255, 1 ], 'darkblue': [ 0, 0, 139, 1 ], 'darkcyan': [ 0, 139, 139, 1 ], 'darkgoldenrod': [ 184, 134, 11, 1 ], 'darkgray': [ 169, 169, 169, 1 ], 'darkgreen': [ 0, 100, 0, 1 ], 'darkgrey': [ 169, 169, 169, 1 ], 'darkkhaki': [ 189, 183, 107, 1 ], 'darkmagenta': [ 139, 0, 139, 1 ], 'darkolivegreen': [ 85, 107, 47, 1 ], 'darkorange': [ 255, 140, 0, 1 ], 'darkorchid': [ 153, 50, 204, 1 ], 'darkred': [ 139, 0, 0, 1 ], 'darksalmon': [ 233, 150, 122, 1 ], 'darkseagreen': [ 143, 188, 143, 1 ], 'darkslateblue': [ 72, 61, 139, 1 ], 'darkslategray': [ 47, 79, 79, 1 ], 'darkslategrey': [ 47, 79, 79, 1 ], 'darkturquoise': [ 0, 206, 209, 1 ], 'darkviolet': [ 148, 0, 211, 1 ], 'deeppink': [ 255, 20, 147, 1 ], 'deepskyblue': [ 0, 191, 255, 1 ], 'dimgray': [ 105, 105, 105, 1 ], 'dimgrey': [ 105, 105, 105, 1 ], 'dodgerblue': [ 30, 144, 255, 1 ], 'firebrick': [ 178, 34, 34, 1 ], 'floralwhite': [ 255, 250, 240, 1 ], 'forestgreen': [ 34, 139, 34, 1 ], 'fuchsia': [ 255, 0, 255, 1 ], 'gainsboro': [ 220, 220, 220, 1 ], 'ghostwhite': [ 248, 248, 255, 1 ], 'gold': [ 255, 215, 0, 1 ], 'goldenrod': [ 218, 165, 32, 1 ], 'gray': [ 128, 128, 128, 1 ], 'green': [ 0, 128, 0, 1 ], 'greenyellow': [ 173, 255, 47, 1 ], 'grey': [ 128, 128, 128, 1 ], 'honeydew': [ 240, 255, 240, 1 ], 'hotpink': [ 255, 105, 180, 1 ], 'indianred': [ 205, 92, 92, 1 ], 'indigo': [ 75, 0, 130, 1 ], 'ivory': [ 255, 255, 240, 1 ], 'khaki': [ 240, 230, 140, 1 ], 'lavender': [ 230, 230, 250, 1 ], 'lavenderblush': [ 255, 240, 245, 1 ], 'lawngreen': [ 124, 252, 0, 1 ], 'lemonchiffon': [ 255, 250, 205, 1 ], 'lightblue': [ 173, 216, 230, 1 ], 'lightcoral': [ 240, 128, 128, 1 ], 'lightcyan': [ 224, 255, 255, 1 ], 'lightgoldenrodyellow': [ 250, 250, 210, 1 ], 'lightgray': [ 211, 211, 211, 1 ], 'lightgreen': [ 144, 238, 144, 1 ], 'lightgrey': [ 211, 211, 211, 1 ], 'lightpink': [ 255, 182, 193, 1 ], 'lightsalmon': [ 255, 160, 122, 1 ], 'lightseagreen': [ 32, 178, 170, 1 ], 'lightskyblue': [ 135, 206, 250, 1 ], 'lightslategray': [ 119, 136, 153, 1 ], 'lightslategrey': [ 119, 136, 153, 1 ], 'lightsteelblue': [ 176, 196, 222, 1 ], 'lightyellow': [ 255, 255, 224, 1 ], 'lime': [ 0, 255, 0, 1 ], 'limegreen': [ 50, 205, 50, 1 ], 'linen': [ 250, 240, 230, 1 ], 'magenta': [ 255, 0, 255, 1 ], 'maroon': [ 128, 0, 0, 1 ], 'mediumaquamarine': [ 102, 205, 170, 1 ], 'mediumblue': [ 0, 0, 205, 1 ], 'mediumorchid': [ 186, 85, 211, 1 ], 'mediumpurple': [ 147, 112, 219, 1 ], 'mediumseagreen': [ 60, 179, 113, 1 ], 'mediumslateblue': [ 123, 104, 238, 1 ], 'mediumspringgreen': [ 0, 250, 154, 1 ], 'mediumturquoise': [ 72, 209, 204, 1 ], 'mediumvioletred': [ 199, 21, 133, 1 ], 'midnightblue': [ 25, 25, 112, 1 ], 'mintcream': [ 245, 255, 250, 1 ], 'mistyrose': [ 255, 228, 225, 1 ], 'moccasin': [ 255, 228, 181, 1 ], 'navajowhite': [ 255, 222, 173, 1 ], 'navy': [ 0, 0, 128, 1 ], 'oldlace': [ 253, 245, 230, 1 ], 'olive': [ 128, 128, 0, 1 ], 'olivedrab': [ 107, 142, 35, 1 ], 'orange': [ 255, 165, 0, 1 ], 'orangered': [ 255, 69, 0, 1 ], 'orchid': [ 218, 112, 214, 1 ], 'palegoldenrod': [ 238, 232, 170, 1 ], 'palegreen': [ 152, 251, 152, 1 ], 'paleturquoise': [ 175, 238, 238, 1 ], 'palevioletred': [ 219, 112, 147, 1 ], 'papayawhip': [ 255, 239, 213, 1 ], 'peachpuff': [ 255, 218, 185, 1 ], 'peru': [ 205, 133, 63, 1 ], 'pink': [ 255, 192, 203, 1 ], 'plum': [ 221, 160, 221, 1 ], 'powderblue': [ 176, 224, 230, 1 ], 'purple': [ 128, 0, 128, 1 ], 'rebeccapurple': [ 102, 51, 153, 1 ], 'red': [ 255, 0, 0, 1 ], 'rosybrown': [ 188, 143, 143, 1 ], 'royalblue': [ 65, 105, 225, 1 ], 'saddlebrown': [ 139, 69, 19, 1 ], 'salmon': [ 250, 128, 114, 1 ], 'sandybrown': [ 244, 164, 96, 1 ], 'seagreen': [ 46, 139, 87, 1 ], 'seashell': [ 255, 245, 238, 1 ], 'sienna': [ 160, 82, 45, 1 ], 'silver': [ 192, 192, 192, 1 ], 'skyblue': [ 135, 206, 235, 1 ], 'slateblue': [ 106, 90, 205, 1 ], 'slategray': [ 112, 128, 144, 1 ], 'slategrey': [ 112, 128, 144, 1 ], 'snow': [ 255, 250, 250, 1 ], 'springgreen': [ 0, 255, 127, 1 ], 'steelblue': [ 70, 130, 180, 1 ], 'tan': [ 210, 180, 140, 1 ], 'teal': [ 0, 128, 128, 1 ], 'thistle': [ 216, 191, 216, 1 ], 'tomato': [ 255, 99, 71, 1 ], 'turquoise': [ 64, 224, 208, 1 ], 'violet': [ 238, 130, 238, 1 ], 'wheat': [ 245, 222, 179, 1 ], 'white': [ 255, 255, 255, 1 ], 'whitesmoke': [ 245, 245, 245, 1 ], 'yellow': [ 255, 255, 0, 1 ], 'yellowgreen': [ 154, 205, 50, 1 ] }; function clamp_css_byte(i) { // Clamp to integer 0 .. 255. i = Math.round(i); // Seems to be what Chrome does (vs truncation). return i < 0 ? 0 : i > 255 ? 255 : i; } function clamp_css_float(f) { // Clamp to float 0.0 .. 1.0. return f < 0 ? 0 : f > 1 ? 1 : f; } function parse_css_int(str) { // int or percentage. if (str[str.length - 1] === '%') { return clamp_css_byte(parseFloat(str) / 100 * 255); } return clamp_css_byte(parseInt(str)); } function parse_css_float(str) { // float or percentage. if (str[str.length - 1] === '%') { return clamp_css_float(parseFloat(str) / 100); } return clamp_css_float(parseFloat(str)); } function css_hue_to_rgb(m1, m2, h) { if (h < 0) { h += 1; } else if (h > 1) { h -= 1; } if (h * 6 < 1) { return m1 + (m2 - m1) * h * 6; } if (h * 2 < 1) { return m2; } if (h * 3 < 2) { return m1 + (m2 - m1) * (2 / 3 - h) * 6; } return m1; } function parseCSSColor(css_str) { // Remove all whitespace, not compliant, but should just be more accepting. var str = css_str.replace(/ /g, '').toLowerCase(); // Color keywords (and transparent) lookup. if (str in kCSSColorTable) { return kCSSColorTable[str].slice(); } // dup. // #abc and #abc123 syntax. if (str[0] === '#') { if (str.length === 4) { var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. if (!(iv >= 0 && iv <= 4095)) { return null; } // Covers NaN. return [ (iv & 3840) >> 4 | (iv & 3840) >> 8, iv & 240 | (iv & 240) >> 4, iv & 15 | (iv & 15) << 4, 1 ]; } else if (str.length === 7) { var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. if (!(iv >= 0 && iv <= 16777215)) { return null; } // Covers NaN. return [ (iv & 16711680) >> 16, (iv & 65280) >> 8, iv & 255, 1 ]; } return null; } var op = str.indexOf('('), ep = str.indexOf(')'); if (op !== -1 && ep + 1 === str.length) { var fname = str.substr(0, op); var params = str.substr(op + 1, ep - (op + 1)).split(','); var alpha = 1; // To allow case fallthrough. switch (fname) { case 'rgba': if (params.length !== 4) { return null; } alpha = parse_css_float(params.pop()); // Fall through. case 'rgb': if (params.length !== 3) { return null; } return [ parse_css_int(params[0]), parse_css_int(params[1]), parse_css_int(params[2]), alpha ]; case 'hsla': if (params.length !== 4) { return null; } alpha = parse_css_float(params.pop()); // Fall through. case 'hsl': if (params.length !== 3) { return null; } var h = (parseFloat(params[0]) % 360 + 360) % 360 / 360; // 0 .. 1 // NOTE(deanm): According to the CSS spec s/l should only be // percentages, but we don't bother and let float or percentage. var s = parse_css_float(params[1]); var l = parse_css_float(params[2]); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; return [ clamp_css_byte(css_hue_to_rgb(m1, m2, h + 1 / 3) * 255), clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255), clamp_css_byte(css_hue_to_rgb(m1, m2, h - 1 / 3) * 255), alpha ]; default: return null; } } return null; } try { parseCSSColor_1 = csscolorparser.parseCSSColor = parseCSSColor; } catch (e) { } // /** * An RGBA color value. Create instances from color strings using the static * method `Color.parse`. The constructor accepts RGB channel values in the range * `[0, 1]`, premultiplied by A. * * @param {number} r The red channel. * @param {number} g The green channel. * @param {number} b The blue channel. * @param {number} a The alpha channel. * @private */ var Color = function Color(r, g, b, a) { if ( a === void 0 ) a = 1; this.r = r; this.g = g; this.b = b; this.a = a; }; /** * Parses valid CSS color strings and returns a `Color` instance. * @returns A `Color` instance, or `undefined` if the input is not a valid color string. */ Color.parse = function parse (input) { if (!input) { return undefined; } if (input instanceof Color) { return input; } if (typeof input !== 'string') { return undefined; } var rgba = parseCSSColor_1(input); if (!rgba) { return undefined; } return new Color(rgba[0] / 255 * rgba[3], rgba[1] / 255 * rgba[3], rgba[2] / 255 * rgba[3], rgba[3]); }; /** * Returns an RGBA string representing the color value. * * @returns An RGBA string. * @example * var purple = new Color.parse('purple'); * purple.toString; // = "rgba(128,0,128,1)" * var translucentGreen = new Color.parse('rgba(26, 207, 26, .73)'); * translucentGreen.toString(); // = "rgba(26,207,26,0.73)" */ Color.prototype.toString = function toString () { var ref = this.toArray(); var r = ref[0]; var g = ref[1]; var b = ref[2]; var a = ref[3]; return ("rgba(" + (Math.round(r)) + "," + (Math.round(g)) + "," + (Math.round(b)) + "," + a + ")"); }; /** * Returns an RGBA array of values representing the color, unpremultiplied by A. * * @returns An array of RGBA color values in the range [0, 255]. */ Color.prototype.toArray = function toArray () { var ref = this; var r = ref.r; var g = ref.g; var b = ref.b; var a = ref.a; return a === 0 ? [ 0, 0, 0, 0 ] : [ r * 255 / a, g * 255 / a, b * 255 / a, a ]; }; /** * Returns a RGBA array of float values representing the color, unpremultiplied by A. * * @returns An array of RGBA color values in the range [0, 1]. */ Color.prototype.toArray01 = function toArray01 () { var ref = this; var r = ref.r; var g = ref.g; var b = ref.b; var a = ref.a; return a === 0 ? [ 0, 0, 0, 0 ] : [ r / a, g / a, b / a, a ]; }; /** * Returns an RGBA array of values representing the color, premultiplied by A. * * @returns An array of RGBA color values in the range [0, 1]. */ Color.prototype.toArray01PremultipliedAlpha = function toArray01PremultipliedAlpha () { var ref = this; var r = ref.r; var g = ref.g; var b = ref.b; var a = ref.a; return [ r, g, b, a ]; }; Color.black = new Color(0, 0, 0, 1); Color.white = new Color(1, 1, 1, 1); Color.transparent = new Color(0, 0, 0, 0); Color.red = new Color(1, 0, 0, 1); Color.blue = new Color(0, 0, 1, 1); var Color$1 = Color; function convertLiteral(value) { return typeof value === 'object' ? [ 'literal', value ] : value; } function convertFunction(parameters, propertySpec) { var stops = parameters.stops; if (!stops) { // identity function return convertIdentityFunction(parameters, propertySpec); } var zoomAndFeatureDependent = stops && typeof stops[0][0] === 'object'; var featureDependent = zoomAndFeatureDependent || parameters.property !== undefined; var zoomDependent = zoomAndFeatureDependent || !featureDependent; stops = stops.map(function (stop) { if (!featureDependent && propertySpec.tokens && typeof stop[1] === 'string') { return [ stop[0], convertTokenString(stop[1]) ]; } return [ stop[0], convertLiteral(stop[1]) ]; }); if (zoomAndFeatureDependent) { return convertZoomAndPropertyFunction(parameters, propertySpec, stops); } else if (zoomDependent) { return convertZoomFunction(parameters, propertySpec, stops); } else { return convertPropertyFunction(parameters, propertySpec, stops); } } function convertIdentityFunction(parameters, propertySpec) { var get = [ 'get', parameters.property ]; if (parameters.default === undefined) { // By default, expressions for string-valued properties get coerced. To preserve // legacy function semantics, insert an explicit assertion instead. return propertySpec.type === 'string' ? [ 'string', get ] : get; } else if (propertySpec.type === 'enum') { return [ 'match', get, Object.keys(propertySpec.values), get, parameters.default ]; } else { var expression = [ propertySpec.type === 'color' ? 'to-color' : propertySpec.type, get, convertLiteral(parameters.default) ]; if (propertySpec.type === 'array') { expression.splice(1, 0, propertySpec.value, propertySpec.length || null); } return expression; } } function getInterpolateOperator(parameters) { switch (parameters.colorSpace) { case 'hcl': return 'interpolate-hcl'; case 'lab': return 'interpolate-lab'; default: return 'interpolate'; } } function convertZoomAndPropertyFunction(parameters, propertySpec, stops) { var featureFunctionParameters = {}; var featureFunctionStops = {}; var zoomStops = []; for (var s = 0; s < stops.length; s++) { var stop = stops[s]; var zoom = stop[0].zoom; if (featureFunctionParameters[zoom] === undefined) { featureFunctionParameters[zoom] = { zoom: zoom, type: parameters.type, property: parameters.property, default: parameters.default }; featureFunctionStops[zoom] = []; zoomStops.push(zoom); } featureFunctionStops[zoom].push([ stop[0].value, stop[1] ]); } // the interpolation type for the zoom dimension of a zoom-and-property // function is determined directly from the style property specification // for which it's being used: linear for interpolatable properties, step // otherwise. var functionType = getFunctionType({}, propertySpec); if (functionType === 'exponential') { var expression = [ getInterpolateOperator(parameters), ['linear'], ['zoom'] ]; for (var i = 0, list = zoomStops; i < list.length; i += 1) { var z = list[i]; var output = convertPropertyFunction(featureFunctionParameters[z], propertySpec, featureFunctionStops[z]); appendStopPair(expression, z, output, false); } return expression; } else { var expression$1 = [ 'step', ['zoom'] ]; for (var i$1 = 0, list$1 = zoomStops; i$1 < list$1.length; i$1 += 1) { var z$1 = list$1[i$1]; var output$1 = convertPropertyFunction(featureFunctionParameters[z$1], propertySpec, featureFunctionStops[z$1]); appendStopPair(expression$1, z$1, output$1, true); } fixupDegenerateStepCurve(expression$1); return expression$1; } } function coalesce(a, b) { if (a !== undefined) { return a; } if (b !== undefined) { return b; } } function getFallback(parameters, propertySpec) { var defaultValue = convertLiteral(coalesce(parameters.default, propertySpec.default)); /* * Some fields with type: resolvedImage have an undefined default. * Because undefined is an invalid value for resolvedImage, set fallback to * an empty string instead of undefined to ensure output * passes validation. */ if (defaultValue === undefined && propertySpec.type === 'resolvedImage') { return ''; } return defaultValue; } function convertPropertyFunction(parameters, propertySpec, stops) { var type = getFunctionType(parameters, propertySpec); var get = [ 'get', parameters.property ]; if (type === 'categorical' && typeof stops[0][0] === 'boolean') { var expression = ['case']; for (var i = 0, list = stops; i < list.length; i += 1) { var stop = list[i]; expression.push([ '==', get, stop[0] ], stop[1]); } expression.push(getFallback(parameters, propertySpec)); return expression; } else if (type === 'categorical') { var expression$1 = [ 'match', get ]; for (var i$1 = 0, list$1 = stops; i$1 < list$1.length; i$1 += 1) { var stop$1 = list$1[i$1]; appendStopPair(expression$1, stop$1[0], stop$1[1], false); } expression$1.push(getFallback(parameters, propertySpec)); return expression$1; } else if (type === 'interval') { var expression$2 = [ 'step', [ 'number', get ] ]; for (var i$2 = 0, list$2 = stops; i$2 < list$2.length; i$2 += 1) { var stop$2 = list$2[i$2]; appendStopPair(expression$2, stop$2[0], stop$2[1], true); } fixupDegenerateStepCurve(expression$2); return parameters.default === undefined ? expression$2 : [ 'case', [ '==', [ 'typeof', get ], 'number' ], expression$2, convertLiteral(parameters.default) ]; } else if (type === 'exponential') { var base = parameters.base !== undefined ? parameters.base : 1; var expression$3 = [ getInterpolateOperator(parameters), base === 1 ? ['linear'] : [ 'exponential', base ], [ 'number', get ] ]; for (var i$3 = 0, list$3 = stops; i$3 < list$3.length; i$3 += 1) { var stop$3 = list$3[i$3]; appendStopPair(expression$3, stop$3[0], stop$3[1], false); } return parameters.default === undefined ? expression$3 : [ 'case', [ '==', [ 'typeof', get ], 'number' ], expression$3, convertLiteral(parameters.default) ]; } else { throw new Error(("Unknown property function type " + type)); } } function convertZoomFunction(parameters, propertySpec, stops, input) { if ( input === void 0 ) input = ['zoom']; var type = getFunctionType(parameters, propertySpec); var expression; var isStep = false; if (type === 'interval') { expression = [ 'step', input ]; isStep = true; } else if (type === 'exponential') { var base = parameters.base !== undefined ? parameters.base : 1; expression = [ getInterpolateOperator(parameters), base === 1 ? ['linear'] : [ 'exponential', base ], input ]; } else { throw new Error(("Unknown zoom function type \"" + type + "\"")); } for (var i = 0, list = stops; i < list.length; i += 1) { var stop = list[i]; appendStopPair(expression, stop[0], stop[1], isStep); } fixupDegenerateStepCurve(expression); return expression; } function fixupDegenerateStepCurve(expression) { // degenerate step curve (i.e. a constant function): add a noop stop if (expression[0] === 'step' && expression.length === 3) { expression.push(0); expression.push(expression[3]); } } function appendStopPair(curve, input, output, isStep) { // Skip duplicate stop values. They were not validated for functions, but they are for expressions. // https://github.com/mapbox/mapbox-gl-js/issues/4107 if (curve.length > 3 && input === curve[curve.length - 2]) { return; } // step curves don't get the first input value, as it is redundant. if (!(isStep && curve.length === 2)) { curve.push(input); } curve.push(output); } function getFunctionType(parameters, propertySpec) { if (parameters.type) { return parameters.type; } else { return propertySpec.expression.interpolated ? 'exponential' : 'interval'; } } // "String with {name} token" => ["concat", "String with ", ["get", "name"], " token"] function convertTokenString(s) { var result = ['concat']; var re = /{([^{}]+)}/g; var pos = 0; for (var match = re.exec(s); match !== null; match = re.exec(s)) { var literal = s.slice(pos, re.lastIndex - match[0].length); pos = re.lastIndex; if (literal.length > 0) { result.push(literal); } result.push([ 'get', match[1] ]); } if (result.length === 1) { return s; } if (pos < s.length) { result.push(s.slice(pos)); } else if (result.length === 2) { return [ 'to-string', result[1] ]; } return result; } // var ParsingError = /*@__PURE__*/(function (Error) { function ParsingError(key, message) { Error.call(this, message); this.message = message; this.key = key; } if ( Error ) ParsingError.__proto__ = Error; ParsingError.prototype = Object.create( Error && Error.prototype ); ParsingError.prototype.constructor = ParsingError; return ParsingError; }(Error)); var ParsingError$1 = ParsingError; // /** * Tracks `let` bindings during expression parsing. * @private */ var Scope = function Scope(parent, bindings) { if ( bindings === void 0 ) bindings = []; this.parent = parent; this.bindings = {}; for (var i = 0, list = bindings; i < list.length; i += 1) { var ref = list[i]; var name = ref[0]; var expression = ref[1]; this.bindings[name] = expression; } }; Scope.prototype.concat = function concat (bindings) { return new Scope(this, bindings); }; Scope.prototype.get = function get (name) { if (this.bindings[name]) { return this.bindings[name]; } if (this.parent) { return this.parent.get(name); } throw new Error((name + " not found in scope.")); }; Scope.prototype.has = function has (name) { if (this.bindings[name]) { return true; } return this.parent ? this.parent.has(name) : false; }; var Scope$1 = Scope; // var NullType = { kind: 'null' }; var NumberType = { kind: 'number' }; var StringType = { kind: 'string' }; var BooleanType = { kind: 'boolean' }; var ColorType = { kind: 'color' }; var ObjectType = { kind: 'object' }; var ValueType = { kind: 'value' }; var ErrorType = { kind: 'error' }; var CollatorType = { kind: 'collator' }; var FormattedType = { kind: 'formatted' }; var ResolvedImageType = { kind: 'resolvedImage' }; function array$1(itemType, N) { return { kind: 'array', itemType: itemType, N: N }; } function toString$1(type) { if (type.kind === 'array') { var itemType = toString$1(type.itemType); return typeof type.N === 'number' ? ("array<" + itemType + ", " + (type.N) + ">") : type.itemType.kind === 'value' ? 'array' : ("array<" + itemType + ">"); } else { return type.kind; } } var valueMemberTypes = [ NullType, NumberType, StringType, BooleanType, ColorType, FormattedType, ObjectType, array$1(ValueType), ResolvedImageType ]; /** * Returns null if `t` is a subtype of `expected`; otherwise returns an * error message. * @private */ function checkSubtype(expected, t) { if (t.kind === 'error') { // Error is a subtype of every type return null; } else if (expected.kind === 'array') { if (t.kind === 'array' && (t.N === 0 && t.itemType.kind === 'value' || !checkSubtype(expected.itemType, t.itemType)) && (typeof expected.N !== 'number' || expected.N === t.N)) { return null; } } else if (expected.kind === t.kind) { return null; } else if (expected.kind === 'value') { for (var i = 0, list = valueMemberTypes; i < list.length; i += 1) { var memberType = list[i]; if (!checkSubtype(memberType, t)) { return null; } } } return ("Expected " + (toString$1(expected)) + " but found " + (toString$1(t)) + " instead."); } function isValidType(provided, allowedTypes) { return allowedTypes.some(function (t) { return t.kind === provided.kind; }); } function isValidNativeType(provided, allowedTypes) { return allowedTypes.some(function (t) { if (t === 'null') { return provided === null; } else if (t === 'array') { return Array.isArray(provided); } else if (t === 'object') { return provided && !Array.isArray(provided) && typeof provided === 'object'; } else { return t === typeof provided; } }); } // // Flow type declarations for Intl cribbed from // https://github.com/facebook/flow/issues/1270 var Collator = function Collator(caseSensitive, diacriticSensitive, locale) { if (caseSensitive) { this.sensitivity = diacriticSensitive ? 'variant' : 'case'; } else { this.sensitivity = diacriticSensitive ? 'accent' : 'base'; } this.locale = locale; this.collator = new Intl.Collator(this.locale ? this.locale : [], { sensitivity: this.sensitivity, usage: 'search' }); }; Collator.prototype.compare = function compare (lhs, rhs) { return this.collator.compare(lhs, rhs); }; Collator.prototype.resolvedLocale = function resolvedLocale () { // We create a Collator without "usage: search" because we don't want // the search options encoded in our result (e.g. "en-u-co-search") return new Intl.Collator(this.locale ? this.locale : []).resolvedOptions().locale; }; var Collator$1 = Collator; // var FormattedSection = function FormattedSection(text, image, scale, fontStack, textColor) { // combine characters so that diacritic marks are not separate code points this.text = text.normalize ? text.normalize() : text; this.image = image; this.scale = scale; this.fontStack = fontStack; this.textColor = textColor; }; var Formatted = function Formatted(sections) { this.sections = sections; }; Formatted.fromString = function fromString (unformatted) { return new Formatted([new FormattedSection(unformatted, null, null, null, null)]); }; Formatted.prototype.isEmpty = function isEmpty () { if (this.sections.length === 0) { return true; } return !this.sections.some(function (section) { return section.text.length !== 0 || section.image && section.image.name.length !== 0; }); }; Formatted.factory = function factory (text) { if (text instanceof Formatted) { return text; } else { return Formatted.fromString(text); } }; Formatted.prototype.toString = function toString () { if (this.sections.length === 0) { return ''; } return this.sections.map(function (section) { return section.text; }).join(''); }; Formatted.prototype.serialize = function serialize () { var serialized = ['format']; for (var i = 0, list = this.sections; i < list.length; i += 1) { var section = list[i]; if (section.image) { serialized.push([ 'image', section.image.name ]); continue; } serialized.push(section.text); var options = {}; if (section.fontStack) { options['text-font'] = [ 'literal', section.fontStack.split(',') ]; } if (section.scale) { options['font-scale'] = section.scale; } if (section.textColor) { options['text-color'] = ['rgba'].concat(section.textColor.toArray()); } serialized.push(options); } return serialized; }; var Formatted$1 = Formatted; // var ResolvedImage = function ResolvedImage(options) { this.name = options.name; this.available = options.available; }; ResolvedImage.prototype.toString = function toString () { return this.name; }; ResolvedImage.fromString = function fromString (name) { if (!name) { return null; } // treat empty values as no image return new ResolvedImage({ name: name, available: false }); }; ResolvedImage.prototype.serialize = function serialize () { return [ 'image', this.name ]; }; var ResolvedImage$1 = ResolvedImage; function validateRGBA(r, g, b, a) { if (!(typeof r === 'number' && r >= 0 && r <= 255 && typeof g === 'number' && g >= 0 && g <= 255 && typeof b === 'number' && b >= 0 && b <= 255)) { var value = typeof a === 'number' ? [ r, g, b, a ] : [ r, g, b ]; return ("Invalid rgba value [" + (value.join(', ')) + "]: 'r', 'g', and 'b' must be between 0 and 255."); } if (!(typeof a === 'undefined' || typeof a === 'number' && a >= 0 && a <= 1)) { return ("Invalid rgba value [" + ([ r, g, b, a ].join(', ')) + "]: 'a' must be between 0 and 1."); } return null; } function isValue(mixed) { if (mixed === null) { return true; } else if (typeof mixed === 'string') { return true; } else if (typeof mixed === 'boolean') { return true; } else if (typeof mixed === 'number') { return true; } else if (mixed instanceof Color$1) { return true; } else if (mixed instanceof Collator$1) { return true; } else if (mixed instanceof Formatted$1) { return true; } else if (mixed instanceof ResolvedImage$1) { return true; } else if (Array.isArray(mixed)) { for (var i = 0, list = mixed; i < list.length; i += 1) { var item = list[i]; if (!isValue(item)) { return false; } } return true; } else if (typeof mixed === 'object') { for (var key in mixed) { if (!isValue(mixed[key])) { return false; } } return true; } else { return false; } } function typeOf(value) { if (value === null) { return NullType; } else if (typeof value === 'string') { return StringType; } else if (typeof value === 'boolean') { return BooleanType; } else if (typeof value === 'number') { return NumberType; } else if (value instanceof Color$1) { return ColorType; } else if (value instanceof Collator$1) { return CollatorType; } else if (value instanceof Formatted$1) { return FormattedType; } else if (value instanceof ResolvedImage$1) { return ResolvedImageType; } else if (Array.isArray(value)) { var length = value.length; var itemType; for (var i = 0, list = value; i < list.length; i += 1) { var item = list[i]; var t = typeOf(item); if (!itemType) { itemType = t; } else if (itemType === t) { continue; } else { itemType = ValueType; break; } } return array$1(itemType || ValueType, length); } else { return ObjectType; } } function toString(value) { var type = typeof value; if (value === null) { return ''; } else if (type === 'string' || type === 'number' || type === 'boolean') { return String(value); } else if (value instanceof Color$1 || value instanceof Formatted$1 || value instanceof ResolvedImage$1) { return value.toString(); } else { return JSON.stringify(value); } } var Literal = function Literal(type, value) { this.type = type; this.value = value; }; Literal.parse = function parse (args, context) { if (args.length !== 2) { return context.error(("'literal' expression requires exactly one argument, but found " + (args.length - 1) + " instead.")); } if (!isValue(args[1])) { return context.error("invalid value"); } var value = args[1]; var type = typeOf(value); // special case: infer the item type if possible for zero-length arrays var expected = context.expectedType; if (type.kind === 'array' && type.N === 0 && expected && expected.kind === 'array' && (typeof expected.N !== 'number' || expected.N === 0)) { type = expected; } return new Literal(type, value); }; Literal.prototype.evaluate = function evaluate () { return this.value; }; Literal.prototype.eachChild = function eachChild () { }; Literal.prototype.outputDefined = function outputDefined () { return true; }; Literal.prototype.serialize = function serialize () { if (this.type.kind === 'array' || this.type.kind === 'object') { return [ 'literal', this.value ]; } else if (this.value instanceof Color$1) { // Constant-folding can generate Literal expressions that you // couldn't actually generate with a "literal" expression, // so we have to implement an equivalent serialization here return ['rgba'].concat(this.value.toArray()); } else if (this.value instanceof Formatted$1) { // Same as Color return this.value.serialize(); } else { return this.value; } }; var Literal$1 = Literal; // var RuntimeError = function RuntimeError(message) { this.name = 'ExpressionEvaluationError'; this.message = message; }; RuntimeError.prototype.toJSON = function toJSON () { return this.message; }; var RuntimeError$1 = RuntimeError; var types$2 = { string: StringType, number: NumberType, boolean: BooleanType, object: ObjectType }; var Assertion = function Assertion(type, args) { this.type = type; this.args = args; }; Assertion.parse = function parse (args, context) { if (args.length < 2) { return context.error("Expected at least one argument."); } var i = 1; var type; var name = args[0]; if (name === 'array') { var itemType; if (args.length > 2) { var type$1 = args[1]; if (typeof type$1 !== 'string' || !(type$1 in types$2) || type$1 === 'object') { return context.error('The item type argument of "array" must be one of string, number, boolean', 1); } itemType = types$2[type$1]; i++; } else { itemType = ValueType; } var N; if (args.length > 3) { if (args[2] !== null && (typeof args[2] !== 'number' || args[2] < 0 || args[2] !== Math.floor(args[2]))) { return context.error('The length argument to "array" must be a positive integer literal', 2); } N = args[2]; i++; } type = array$1(itemType, N); } else { type = types$2[name]; } var parsed = []; for (; i < args.length; i++) { var input = context.parse(args[i], i, ValueType); if (!input) { return null; } parsed.push(input); } return new Assertion(type, parsed); }; Assertion.prototype.evaluate = function evaluate (ctx) { for (var i = 0; i < this.args.length; i++) { var value = this.args[i].evaluate(ctx); var error = checkSubtype(this.type, typeOf(value)); if (!error) { return value; } else if (i === this.args.length - 1) { throw new RuntimeError$1(("Expected value to be of type " + (toString$1(this.type)) + ", but found " + (toString$1(typeOf(value))) + " instead.")); } } return null; }; Assertion.prototype.eachChild = function eachChild (fn) { this.args.forEach(fn); }; Assertion.prototype.outputDefined = function outputDefined () { return this.args.every(function (arg) { return arg.outputDefined(); }); }; Assertion.prototype.serialize = function serialize () { var type = this.type; var serialized = [type.kind]; if (type.kind === 'array') { var itemType = type.itemType; if (itemType.kind === 'string' || itemType.kind === 'number' || itemType.kind === 'boolean') { serialized.push(itemType.kind); var N = type.N; if (typeof N === 'number' || this.args.length > 1) { serialized.push(N); } } } return serialized.concat(this.args.map(function (arg) { return arg.serialize(); })); }; var Assertion$1 = Assertion; // var FormatExpression = function FormatExpression(sections) { this.type = FormattedType; this.sections = sections; }; FormatExpression.parse = function parse (args, context) { if (args.length < 2) { return context.error("Expected at least one argument."); } var firstArg = args[1]; if (!Array.isArray(firstArg) && typeof firstArg === 'object') { return context.error("First argument must be an image or text section."); } var sections = []; var nextTokenMayBeObject = false; for (var i = 1; i <= args.length - 1; ++i) { var arg = args[i]; if (nextTokenMayBeObject && typeof arg === 'object' && !Array.isArray(arg)) { nextTokenMayBeObject = false; var scale = null; if (arg['font-scale']) { scale = context.parse(arg['font-scale'], 1, NumberType); if (!scale) { return null; } } var font = null; if (arg['text-font']) { font = context.parse(arg['text-font'], 1, array$1(StringType)); if (!font) { return null; } } var textColor = null; if (arg['text-color']) { textColor = context.parse(arg['text-color'], 1, ColorType); if (!textColor) { return null; } } var lastExpression = sections[sections.length - 1]; lastExpression.scale = scale; lastExpression.font = font; lastExpression.textColor = textColor; } else { var content = context.parse(args[i], 1, ValueType); if (!content) { return null; } var kind = content.type.kind; if (kind !== 'string' && kind !== 'value' && kind !== 'null' && kind !== 'resolvedImage') { return context.error("Formatted text type must be 'string', 'value', 'image' or 'null'."); } nextTokenMayBeObject = true; sections.push({ content: content, scale: null, font: null, textColor: null }); } } return new FormatExpression(sections); }; FormatExpression.prototype.evaluate = function evaluate (ctx) { var evaluateSection = function (section) { var evaluatedContent = section.content.evaluate(ctx); if (typeOf(evaluatedContent) === ResolvedImageType) { return new FormattedSection('', evaluatedContent, null, null, null); } return new FormattedSection(toString(evaluatedContent), null, section.scale ? section.scale.evaluate(ctx) : null, section.font ? section.font.evaluate(ctx).join(',') : null, section.textColor ? section.textColor.evaluate(ctx) : null); }; return new Formatted$1(this.sections.map(evaluateSection)); }; FormatExpression.prototype.eachChild = function eachChild (fn) { for (var i = 0, list = this.sections; i < list.length; i += 1) { var section = list[i]; fn(section.content); if (section.scale) { fn(section.scale); } if (section.font) { fn(section.font); } if (section.textColor) { fn(section.textColor); } } }; FormatExpression.prototype.outputDefined = function outputDefined () { // Technically the combinatoric set of all children // Usually, this.text will be undefined anyway return false; }; FormatExpression.prototype.serialize = function serialize () { var serialized = ['format']; for (var i = 0, list = this.sections; i < list.length; i += 1) { var section = list[i]; serialized.push(section.content.serialize()); var options = {}; if (section.scale) { options['font-scale'] = section.scale.serialize(); } if (section.font) { options['text-font'] = section.font.serialize(); } if (section.textColor) { options['text-color'] = section.textColor.serialize(); } serialized.push(options); } return serialized; }; var FormatExpression$1 = FormatExpression; // var ImageExpression = function ImageExpression(input) { this.type = ResolvedImageType; this.input = input; }; ImageExpression.parse = function parse (args, context) { if (args.length !== 2) { return context.error("Expected two arguments."); } var name = context.parse(args[1], 1, StringType); if (!name) { return context.error("No image name provided."); } return new ImageExpression(name); }; ImageExpression.prototype.evaluate = function evaluate (ctx) { var evaluatedImageName = this.input.evaluate(ctx); var value = ResolvedImage$1.fromString(evaluatedImageName); if (value && ctx.availableImages) { value.available = ctx.availableImages.indexOf(evaluatedImageName) > -1; } return value; }; ImageExpression.prototype.eachChild = function eachChild (fn) { fn(this.input); }; ImageExpression.prototype.outputDefined = function outputDefined () { // The output of image is determined by the list of available images in the evaluation context return false; }; ImageExpression.prototype.serialize = function serialize () { return [ 'image', this.input.serialize() ]; }; var ImageExpression$1 = ImageExpression; var types$1 = { 'to-boolean': BooleanType, 'to-color': ColorType, 'to-number': NumberType, 'to-string': StringType }; /** * Special form for error-coalescing coercion expressions "to-number", * "to-color". Since these coercions can fail at runtime, they accept multiple * arguments, only evaluating one at a time until one succeeds. * * @private */ var Coercion = function Coercion(type, args) { this.type = type; this.args = args; }; Coercion.parse = function parse (args, context) { if (args.length < 2) { return context.error("Expected at least one argument."); } var name = args[0]; if ((name === 'to-boolean' || name === 'to-string') && args.length !== 2) { return context.error("Expected one argument."); } var type = types$1[name]; var parsed = []; for (var i = 1; i < args.length; i++) { var input = context.parse(args[i], i, ValueType); if (!input) { return null; } parsed.push(input); } return new Coercion(type, parsed); }; Coercion.prototype.evaluate = function evaluate (ctx) { if (this.type.kind === 'boolean') { return Boolean(this.args[0].evaluate(ctx)); } else if (this.type.kind === 'color') { var input; var error; for (var i = 0, list = this.args; i < list.length; i += 1) { var arg = list[i]; input = arg.evaluate(ctx); error = null; if (input instanceof Color$1) { return input; } else if (typeof input === 'string') { var c = ctx.parseColor(input); if (c) { return c; } } else if (Array.isArray(input)) { if (input.length < 3 || input.length > 4) { error = "Invalid rbga value " + (JSON.stringify(input)) + ": expected an array containing either three or four numeric values."; } else { error = validateRGBA(input[0], input[1], input[2], input[3]); } if (!error) { return new Color$1(input[0] / 255, input[1] / 255, input[2] / 255, input[3]); } } } throw new RuntimeError$1(error || ("Could not parse color from value '" + (typeof input === 'string' ? input : String(JSON.stringify(input))) + "'")); } else if (this.type.kind === 'number') { var value = null; for (var i$1 = 0, list$1 = this.args; i$1 < list$1.length; i$1 += 1) { var arg$1 = list$1[i$1]; value = arg$1.evaluate(ctx); if (value === null) { return 0; } var num = Number(value); if (isNaN(num)) { continue; } return num; } throw new RuntimeError$1(("Could not convert " + (JSON.stringify(value)) + " to number.")); } else if (this.type.kind === 'formatted') { // There is no explicit 'to-formatted' but this coercion can be implicitly // created by properties that expect the 'formatted' type. return Formatted$1.fromString(toString(this.args[0].evaluate(ctx))); } else if (this.type.kind === 'resolvedImage') { return ResolvedImage$1.fromString(toString(this.args[0].evaluate(ctx))); } else { return toString(this.args[0].evaluate(ctx)); } }; Coercion.prototype.eachChild = function eachChild (fn) { this.args.forEach(fn); }; Coercion.prototype.outputDefined = function outputDefined () { return this.args.every(function (arg) { return arg.outputDefined(); }); }; Coercion.prototype.serialize = function serialize () { if (this.type.kind === 'formatted') { return new FormatExpression$1([{ content: this.args[0], scale: null, font: null, textColor: null }]).serialize(); } if (this.type.kind === 'resolvedImage') { return new ImageExpression$1(this.args[0]).serialize(); } var serialized = [("to-" + (this.type.kind))]; this.eachChild(function (child) { serialized.push(child.serialize()); }); return serialized; }; var Coercion$1 = Coercion; // var geometryTypes = [ 'Unknown', 'Point', 'LineString', 'Polygon' ]; var EvaluationContext = function EvaluationContext() { this.globals = null; this.feature = null; this.featureState = null; this.formattedSection = null; this._parseColorCache = {}; this.availableImages = null; this.canonical = null; this.featureTileCoord = null; this.featureDistanceData = null; }; EvaluationContext.prototype.id = function id () { return this.feature && this.feature.id !== undefined ? this.feature.id : null; }; EvaluationContext.prototype.geometryType = function geometryType () { return this.feature ? typeof this.feature.type === 'number' ? geometryTypes[this.feature.type] : this.feature.type : null; }; EvaluationContext.prototype.geometry = function geometry () { return this.feature && 'geometry' in this.feature ? this.feature.geometry : null; }; EvaluationContext.prototype.canonicalID = function canonicalID () { return this.canonical; }; EvaluationContext.prototype.properties = function properties () { return this.feature && this.feature.properties || {}; }; EvaluationContext.prototype.distanceFromCenter = function distanceFromCenter () { if (this.featureTileCoord && this.featureDistanceData) { var c = this.featureDistanceData.center; var scale = this.featureDistanceData.scale; var ref = this.featureTileCoord; var x = ref.x; var y = ref.y; // Calculate the distance vector `d` (left handed) var dX = x * scale - c[0]; var dY = y * scale - c[1]; // The bearing vector `b` (left handed) var bX = this.featureDistanceData.bearing[0]; var bY = this.featureDistanceData.bearing[1]; // Distance is calculated as `dot(d, v)` var dist = bX * dX + bY * dY; return dist; } return 0; }; EvaluationContext.prototype.parseColor = function parseColor (input) { var cached = this._parseColorCache[input]; if (!cached) { cached = this._parseColorCache[input] = Color$1.parse(input); } return cached; }; var EvaluationContext$1 = EvaluationContext; // var CompoundExpression = function CompoundExpression(name, type, evaluate, args) { this.name = name; this.type = type; this._evaluate = evaluate; this.args = args; }; CompoundExpression.prototype.evaluate = function evaluate (ctx) { return this._evaluate(ctx, this.args); }; CompoundExpression.prototype.eachChild = function eachChild (fn) { this.args.forEach(fn); }; CompoundExpression.prototype.outputDefined = function outputDefined () { return false; }; CompoundExpression.prototype.serialize = function serialize () { return [this.name].concat(this.args.map(function (arg) { return arg.serialize(); })); }; CompoundExpression.parse = function parse (args, context) { var ref$1; var op = args[0]; var definition = CompoundExpression.definitions[op]; if (!definition) { return context.error(("Unknown expression \"" + op + "\". If you wanted a literal array, use [\"literal\", [...]]."), 0); } // Now check argument types against each signature var type = Array.isArray(definition) ? definition[0] : definition.type; var availableOverloads = Array.isArray(definition) ? [[ definition[1], definition[2] ]] : definition.overloads; var overloads = availableOverloads.filter(function (ref) { var signature = ref[0]; return !Array.isArray(signature) || // varags signature.length === args.length - 1; }// correct param count ); var signatureContext = null; for (var i$3 = 0, list = overloads; i$3 < list.length; i$3 += 1) { // Use a fresh context for each attempted signature so that, if // we eventually succeed, we haven't polluted `context.errors`. var ref = list[i$3]; var params = ref[0]; var evaluate = ref[1]; signatureContext = new ParsingContext$1(context.registry, context.path, null, context.scope); // First parse all the args, potentially coercing to the // types expected by this overload. var parsedArgs = []; var argParseFailed = false; for (var i = 1; i < args.length; i++) { var arg = args[i]; var expectedType = Array.isArray(params) ? params[i - 1] : params.type; var parsed = signatureContext.parse(arg, 1 + parsedArgs.length, expectedType); if (!parsed) { argParseFailed = true; break; } parsedArgs.push(parsed); } if (argParseFailed) { // Couldn't coerce args of this overload to expected type, move // on to next one. continue; } if (Array.isArray(params)) { if (params.length !== parsedArgs.length) { signatureContext.error(("Expected " + (params.length) + " arguments, but found " + (parsedArgs.length) + " instead.")); continue; } } for (var i$1 = 0; i$1 < parsedArgs.length; i$1++) { var expected = Array.isArray(params) ? params[i$1] : params.type; var arg$1 = parsedArgs[i$1]; signatureContext.concat(i$1 + 1).checkSubtype(expected, arg$1.type); } if (signatureContext.errors.length === 0) { return new CompoundExpression(op, type, evaluate, parsedArgs); } } if (overloads.length === 1) { (ref$1 = context.errors).push.apply(ref$1, signatureContext.errors); } else { var expected$1 = overloads.length ? overloads : availableOverloads; var signatures = expected$1.map(function (ref) { var params = ref[0]; return stringifySignature(params); }).join(' | '); var actualTypes = []; // For error message, re-parse arguments without trying to // apply any coercions for (var i$2 = 1; i$2 < args.length; i$2++) { var parsed$1 = context.parse(args[i$2], 1 + actualTypes.length); if (!parsed$1) { return null; } actualTypes.push(toString$1(parsed$1.type)); } context.error(("Expected arguments of type " + signatures + ", but found (" + (actualTypes.join(', ')) + ") instead.")); } return null; }; CompoundExpression.register = function register (registry, definitions) { CompoundExpression.definitions = definitions; for (var name in definitions) { registry[name] = CompoundExpression; } }; function stringifySignature(signature) { if (Array.isArray(signature)) { return ("(" + (signature.map(toString$1).join(', ')) + ")"); } else { return ("(" + (toString$1(signature.type)) + "...)"); } } var CompoundExpression$1 = CompoundExpression; // var CollatorExpression = function CollatorExpression(caseSensitive, diacriticSensitive, locale) { this.type = CollatorType; this.locale = locale; this.caseSensitive = caseSensitive; this.diacriticSensitive = diacriticSensitive; }; CollatorExpression.parse = function parse (args, context) { if (args.length !== 2) { return context.error("Expected one argument."); } var options = args[1]; if (typeof options !== 'object' || Array.isArray(options)) { return context.error("Collator options argument must be an object."); } var caseSensitive = context.parse(options['case-sensitive'] === undefined ? false : options['case-sensitive'], 1, BooleanType); if (!caseSensitive) { return null; } var diacriticSensitive = context.parse(options['diacritic-sensitive'] === undefined ? false : options['diacritic-sensitive'], 1, BooleanType); if (!diacriticSensitive) { return null; } var locale = null; if (options['locale']) { locale = context.parse(options['locale'], 1, StringType); if (!locale) { return null; } } return new CollatorExpression(caseSensitive, diacriticSensitive, locale); }; CollatorExpression.prototype.evaluate = function evaluate (ctx) { return new Collator$1(this.caseSensitive.evaluate(ctx), this.diacriticSensitive.evaluate(ctx), this.locale ? this.locale.evaluate(ctx) : null); }; CollatorExpression.prototype.eachChild = function eachChild (fn) { fn(this.caseSensitive); fn(this.diacriticSensitive); if (this.locale) { fn(this.locale); } }; CollatorExpression.prototype.outputDefined = function outputDefined () { // Technically the set of possible outputs is the combinatoric set of Collators produced // by all possible outputs of locale/caseSensitive/diacriticSensitive // But for the primary use of Collators in comparison operators, we ignore the Collator's // possible outputs anyway, so we can get away with leaving this false for now. return false; }; CollatorExpression.prototype.serialize = function serialize () { var options = {}; options['case-sensitive'] = this.caseSensitive.serialize(); options['diacritic-sensitive'] = this.diacriticSensitive.serialize(); if (this.locale) { options['locale'] = this.locale.serialize(); } return [ 'collator', options ]; }; var CollatorExpression$1 = CollatorExpression; // // minX, minY, maxX, maxY var EXTENT = 8192; function updateBBox(bbox, coord) { bbox[0] = Math.min(bbox[0], coord[0]); bbox[1] = Math.min(bbox[1], coord[1]); bbox[2] = Math.max(bbox[2], coord[0]); bbox[3] = Math.max(bbox[3], coord[1]); } function mercatorXfromLng(lng) { return (180 + lng) / 360; } function mercatorYfromLat(lat) { return (180 - 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360))) / 360; } function boxWithinBox(bbox1, bbox2) { if (bbox1[0] <= bbox2[0]) { return false; } if (bbox1[2] >= bbox2[2]) { return false; } if (bbox1[1] <= bbox2[1]) { return false; } if (bbox1[3] >= bbox2[3]) { return false; } return true; } function getTileCoordinates(p, canonical) { var x = mercatorXfromLng(p[0]); var y = mercatorYfromLat(p[1]); var tilesAtZoom = Math.pow(2, canonical.z); return [ Math.round(x * tilesAtZoom * EXTENT), Math.round(y * tilesAtZoom * EXTENT) ]; } function onBoundary(p, p1, p2) { var x1 = p[0] - p1[0]; var y1 = p[1] - p1[1]; var x2 = p[0] - p2[0]; var y2 = p[1] - p2[1]; return x1 * y2 - x2 * y1 === 0 && x1 * x2 <= 0 && y1 * y2 <= 0; } function rayIntersect(p, p1, p2) { return p1[1] > p[1] !== p2[1] > p[1] && p[0] < (p2[0] - p1[0]) * (p[1] - p1[1]) / (p2[1] - p1[1]) + p1[0]; } // ray casting algorithm for detecting if point is in polygon function pointWithinPolygon(point, rings) { var inside = false; for (var i = 0, len = rings.length; i < len; i++) { var ring = rings[i]; for (var j = 0, len2 = ring.length; j < len2 - 1; j++) { if (onBoundary(point, ring[j], ring[j + 1])) { return false; } if (rayIntersect(point, ring[j], ring[j + 1])) { inside = !inside; } } } return inside; } function pointWithinPolygons(point, polygons) { for (var i = 0; i < polygons.length; i++) { if (pointWithinPolygon(point, polygons[i])) { return true; } } return false; } function perp(v1, v2) { return v1[0] * v2[1] - v1[1] * v2[0]; } // check if p1 and p2 are in different sides of line segment q1->q2 function twoSided(p1, p2, q1, q2) { // q1->p1 (x1, y1), q1->p2 (x2, y2), q1->q2 (x3, y3) var x1 = p1[0] - q1[0]; var y1 = p1[1] - q1[1]; var x2 = p2[0] - q1[0]; var y2 = p2[1] - q1[1]; var x3 = q2[0] - q1[0]; var y3 = q2[1] - q1[1]; var det1 = x1 * y3 - x3 * y1; var det2 = x2 * y3 - x3 * y2; if (det1 > 0 && det2 < 0 || det1 < 0 && det2 > 0) { return true; } return false; } // a, b are end points for line segment1, c and d are end points for line segment2 function lineIntersectLine(a, b, c, d) { // check if two segments are parallel or not // precondition is end point a, b is inside polygon, if line a->b is // parallel to polygon edge c->d, then a->b won't intersect with c->d var vectorP = [ b[0] - a[0], b[1] - a[1] ]; var vectorQ = [ d[0] - c[0], d[1] - c[1] ]; if (perp(vectorQ, vectorP) === 0) { return false; } // If lines are intersecting with each other, the relative location should be: // a and b lie in different sides of segment c->d // c and d lie in different sides of segment a->b if (twoSided(a, b, c, d) && twoSided(c, d, a, b)) { return true; } return false; } function lineIntersectPolygon(p1, p2, polygon) { for (var i = 0, list = polygon; i < list.length; i += 1) { // loop through every edge of the ring var ring = list[i]; for (var j = 0; j < ring.length - 1; ++j) { if (lineIntersectLine(p1, p2, ring[j], ring[j + 1])) { return true; } } } return false; } function lineStringWithinPolygon(line, polygon) { // First, check if geometry points of line segments are all inside polygon for (var i = 0; i < line.length; ++i) { if (!pointWithinPolygon(line[i], polygon)) { return false; } } // Second, check if there is line segment intersecting polygon edge for (var i$1 = 0; i$1 < line.length - 1; ++i$1) { if (lineIntersectPolygon(line[i$1], line[i$1 + 1], polygon)) { return false; } } return true; } function lineStringWithinPolygons(line, polygons) { for (var i = 0; i < polygons.length; i++) { if (lineStringWithinPolygon(line, polygons[i])) { return true; } } return false; } function getTilePolygon(coordinates, bbox, canonical) { var polygon = []; for (var i = 0; i < coordinates.length; i++) { var ring = []; for (var j = 0; j < coordinates[i].length; j++) { var coord = getTileCoordinates(coordinates[i][j], canonical); updateBBox(bbox, coord); ring.push(coord); } polygon.push(ring); } return polygon; } function getTilePolygons(coordinates, bbox, canonical) { var polygons = []; for (var i = 0; i < coordinates.length; i++) { var polygon = getTilePolygon(coordinates[i], bbox, canonical); polygons.push(polygon); } return polygons; } function updatePoint(p, bbox, polyBBox, worldSize) { if (p[0] < polyBBox[0] || p[0] > polyBBox[2]) { var halfWorldSize = worldSize * 0.5; var shift = p[0] - polyBBox[0] > halfWorldSize ? -worldSize : polyBBox[0] - p[0] > halfWorldSize ? worldSize : 0; if (shift === 0) { shift = p[0] - polyBBox[2] > halfWorldSize ? -worldSize : polyBBox[2] - p[0] > halfWorldSize ? worldSize : 0; } p[0] += shift; } updateBBox(bbox, p); } function resetBBox(bbox) { bbox[0] = bbox[1] = Infinity; bbox[2] = bbox[3] = -Infinity; } function getTilePoints(geometry, pointBBox, polyBBox, canonical) { var worldSize = Math.pow(2, canonical.z) * EXTENT; var shifts = [ canonical.x * EXTENT, canonical.y * EXTENT ]; var tilePoints = []; if (!geometry) { return tilePoints; } for (var i$1 = 0, list$1 = geometry; i$1 < list$1.length; i$1 += 1) { var points = list$1[i$1]; for (var i = 0, list = points; i < list.length; i += 1) { var point = list[i]; var p = [ point.x + shifts[0], point.y + shifts[1] ]; updatePoint(p, pointBBox, polyBBox, worldSize); tilePoints.push(p); } } return tilePoints; } function getTileLines(geometry, lineBBox, polyBBox, canonical) { var worldSize = Math.pow(2, canonical.z) * EXTENT; var shifts = [ canonical.x * EXTENT, canonical.y * EXTENT ]; var tileLines = []; if (!geometry) { return tileLines; } for (var i$1 = 0, list$1 = geometry; i$1 < list$1.length; i$1 += 1) { var line = list$1[i$1]; var tileLine = []; for (var i = 0, list = line; i < list.length; i += 1) { var point = list[i]; var p = [ point.x + shifts[0], point.y + shifts[1] ]; updateBBox(lineBBox, p); tileLine.push(p); } tileLines.push(tileLine); } if (lineBBox[2] - lineBBox[0] <= worldSize / 2) { resetBBox(lineBBox); for (var i$3 = 0, list$3 = tileLines; i$3 < list$3.length; i$3 += 1) { var line$1 = list$3[i$3]; for (var i$2 = 0, list$2 = line$1; i$2 < list$2.length; i$2 += 1) { var p$1 = list$2[i$2]; updatePoint(p$1, lineBBox, polyBBox, worldSize); } } } return tileLines; } function pointsWithinPolygons(ctx, polygonGeometry) { var pointBBox = [ Infinity, Infinity, -Infinity, -Infinity ]; var polyBBox = [ Infinity, Infinity, -Infinity, -Infinity ]; var canonical = ctx.canonicalID(); if (!canonical) { return false; } if (polygonGeometry.type === 'Polygon') { var tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical); var tilePoints = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical); if (!boxWithinBox(pointBBox, polyBBox)) { return false; } for (var i = 0, list = tilePoints; i < list.length; i += 1) { var point = list[i]; if (!pointWithinPolygon(point, tilePolygon)) { return false; } } } if (polygonGeometry.type === 'MultiPolygon') { var tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical); var tilePoints$1 = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical); if (!boxWithinBox(pointBBox, polyBBox)) { return false; } for (var i$1 = 0, list$1 = tilePoints$1; i$1 < list$1.length; i$1 += 1) { var point$1 = list$1[i$1]; if (!pointWithinPolygons(point$1, tilePolygons)) { return false; } } } return true; } function linesWithinPolygons(ctx, polygonGeometry) { var lineBBox = [ Infinity, Infinity, -Infinity, -Infinity ]; var polyBBox = [ Infinity, Infinity, -Infinity, -Infinity ]; var canonical = ctx.canonicalID(); if (!canonical) { return false; } if (polygonGeometry.type === 'Polygon') { var tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical); var tileLines = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical); if (!boxWithinBox(lineBBox, polyBBox)) { return false; } for (var i = 0, list = tileLines; i < list.length; i += 1) { var line = list[i]; if (!lineStringWithinPolygon(line, tilePolygon)) { return false; } } } if (polygonGeometry.type === 'MultiPolygon') { var tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical); var tileLines$1 = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical); if (!boxWithinBox(lineBBox, polyBBox)) { return false; } for (var i$1 = 0, list$1 = tileLines$1; i$1 < list$1.length; i$1 += 1) { var line$1 = list$1[i$1]; if (!lineStringWithinPolygons(line$1, tilePolygons)) { return false; } } } return true; } var Within = function Within(geojson, geometries) { this.type = BooleanType; this.geojson = geojson; this.geometries = geometries; }; Within.parse = function parse (args, context) { if (args.length !== 2) { return context.error(("'within' expression requires exactly one argument, but found " + (args.length - 1) + " instead.")); } if (isValue(args[1])) { var geojson = args[1]; if (geojson.type === 'FeatureCollection') { for (var i = 0; i < geojson.features.length; ++i) { var type = geojson.features[i].geometry.type; if (type === 'Polygon' || type === 'MultiPolygon') { return new Within(geojson, geojson.features[i].geometry); } } } else if (geojson.type === 'Feature') { var type$1 = geojson.geometry.type; if (type$1 === 'Polygon' || type$1 === 'MultiPolygon') { return new Within(geojson, geojson.geometry); } } else if (geojson.type === 'Polygon' || geojson.type === 'MultiPolygon') { return new Within(geojson, geojson); } } return context.error("'within' expression requires valid geojson object that contains polygon geometry type."); }; Within.prototype.evaluate = function evaluate (ctx) { if (ctx.geometry() != null && ctx.canonicalID() != null) { if (ctx.geometryType() === 'Point') { return pointsWithinPolygons(ctx, this.geometries); } else if (ctx.geometryType() === 'LineString') { return linesWithinPolygons(ctx, this.geometries); } } return false; }; Within.prototype.eachChild = function eachChild () { }; Within.prototype.outputDefined = function outputDefined () { return true; }; Within.prototype.serialize = function serialize () { return [ 'within', this.geojson ]; }; var Within$1 = Within; // function isFeatureConstant(e) { if (e instanceof CompoundExpression$1) { if (e.name === 'get' && e.args.length === 1) { return false; } else if (e.name === 'feature-state') { return false; } else if (e.name === 'has' && e.args.length === 1) { return false; } else if (e.name === 'properties' || e.name === 'geometry-type' || e.name === 'id') { return false; } else if (/^filter-/.test(e.name)) { return false; } } if (e instanceof Within$1) { return false; } var result = true; e.eachChild(function (arg) { if (result && !isFeatureConstant(arg)) { result = false; } }); return result; } function isStateConstant(e) { if (e instanceof CompoundExpression$1) { if (e.name === 'feature-state') { return false; } } var result = true; e.eachChild(function (arg) { if (result && !isStateConstant(arg)) { result = false; } }); return result; } function isGlobalPropertyConstant(e, properties) { if (e instanceof CompoundExpression$1 && properties.indexOf(e.name) >= 0) { return false; } var result = true; e.eachChild(function (arg) { if (result && !isGlobalPropertyConstant(arg, properties)) { result = false; } }); return result; } // var Var = function Var(name, boundExpression) { this.type = boundExpression.type; this.name = name; this.boundExpression = boundExpression; }; Var.parse = function parse (args, context) { if (args.length !== 2 || typeof args[1] !== 'string') { return context.error("'var' expression requires exactly one string literal argument."); } var name = args[1]; if (!context.scope.has(name)) { return context.error(("Unknown variable \"" + name + "\". Make sure \"" + name + "\" has been bound in an enclosing \"let\" expression before using it."), 1); } return new Var(name, context.scope.get(name)); }; Var.prototype.evaluate = function evaluate (ctx) { return this.boundExpression.evaluate(ctx); }; Var.prototype.eachChild = function eachChild () { }; Var.prototype.outputDefined = function outputDefined () { return false; }; Var.prototype.serialize = function serialize () { return [ 'var', this.name ]; }; var Var$1 = Var; // /** * State associated parsing at a given point in an expression tree. * @private */ var ParsingContext = function ParsingContext(registry, path, expectedType, scope, errors) { if ( path === void 0 ) path = []; if ( scope === void 0 ) scope = new Scope$1(); if ( errors === void 0 ) errors = []; this.registry = registry; this.path = path; this.key = path.map(function (part) { return ("[" + part + "]"); }).join(''); this.scope = scope; this.errors = errors; this.expectedType = expectedType; }; /** * @param expr the JSON expression to parse * @param index the optional argument index if this expression is an argument of a parent expression that's being parsed * @param options * @param options.omitTypeAnnotations set true to omit inferred type annotations. Caller beware: with this option set, the parsed expression's type will NOT satisfy `expectedType` if it would normally be wrapped in an inferred annotation. * @private */ ParsingContext.prototype.parse = function parse (expr, index, expectedType, bindings, options) { if ( options === void 0 ) options = {}; if (index) { return this.concat(index, expectedType, bindings)._parse(expr, options); } return this._parse(expr, options); }; ParsingContext.prototype._parse = function _parse (expr, options) { if (expr === null || typeof expr === 'string' || typeof expr === 'boolean' || typeof expr === 'number') { expr = [ 'literal', expr ]; } function annotate(parsed, type, typeAnnotation) { if (typeAnnotation === 'assert') { return new Assertion$1(type, [parsed]); } else if (typeAnnotation === 'coerce') { return new Coercion$1(type, [parsed]); } else { return parsed; } } if (Array.isArray(expr)) { if (expr.length === 0) { return this.error("Expected an array with at least one element. If you wanted a literal array, use [\"literal\", []]."); } var op = expr[0]; if (typeof op !== 'string') { this.error(("Expression name must be a string, but found " + (typeof op) + " instead. If you wanted a literal array, use [\"literal\", [...]]."), 0); return null; } var Expr = this.registry[op]; if (Expr) { var parsed = Expr.parse(expr, this); if (!parsed) { return null; } if (this.expectedType) { var expected = this.expectedType; var actual = parsed.type; // When we expect a number, string, boolean, or array but have a value, wrap it in an assertion. // When we expect a color or formatted string, but have a string or value, wrap it in a coercion. // Otherwise, we do static type-checking. // // These behaviors are overridable for: // * The "coalesce" operator, which needs to omit type annotations. // * String-valued properties (e.g. `text-field`), where coercion is more convenient than assertion. // if ((expected.kind === 'string' || expected.kind === 'number' || expected.kind === 'boolean' || expected.kind === 'object' || expected.kind === 'array') && actual.kind === 'value') { parsed = annotate(parsed, expected, options.typeAnnotation || 'assert'); } else if ((expected.kind === 'color' || expected.kind === 'formatted' || expected.kind === 'resolvedImage') && (actual.kind === 'value' || actual.kind === 'string')) { parsed = annotate(parsed, expected, options.typeAnnotation || 'coerce'); } else if (this.checkSubtype(expected, actual)) { return null; } } // If an expression's arguments are all literals, we can evaluate // it immediately and replace it with a literal value in the // parsed/compiled result. Expressions that expect an image should // not be resolved here so we can later get the available images. if (!(parsed instanceof Literal$1) && parsed.type.kind !== 'resolvedImage' && isConstant(parsed)) { var ec = new EvaluationContext$1(); try { parsed = new Literal$1(parsed.type, parsed.evaluate(ec)); } catch (e) { this.error(e.message); return null; } } return parsed; } return this.error(("Unknown expression \"" + op + "\". If you wanted a literal array, use [\"literal\", [...]]."), 0); } else if (typeof expr === 'undefined') { return this.error("'undefined' value invalid. Use null instead."); } else if (typeof expr === 'object') { return this.error("Bare objects invalid. Use [\"literal\", {...}] instead."); } else { return this.error(("Expected an array, but found " + (typeof expr) + " instead.")); } }; /** * Returns a copy of this context suitable for parsing the subexpression at * index `index`, optionally appending to 'let' binding map. * * Note that `errors` property, intended for collecting errors while * parsing, is copied by reference rather than cloned. * @private */ ParsingContext.prototype.concat = function concat (index, expectedType, bindings) { var path = typeof index === 'number' ? this.path.concat(index) : this.path; var scope = bindings ? this.scope.concat(bindings) : this.scope; return new ParsingContext(this.registry, path, expectedType || null, scope, this.errors); }; /** * Push a parsing (or type checking) error into the `this.errors` * @param error The message * @param keys Optionally specify the source of the error at a child * of the current expression at `this.key`. * @private */ ParsingContext.prototype.error = function error (error$1) { var keys = [], len = arguments.length - 1; while ( len-- > 0 ) keys[ len ] = arguments[ len + 1 ]; var key = "" + (this.key) + (keys.map(function (k) { return ("[" + k + "]"); }).join('')); this.errors.push(new ParsingError$1(key, error$1)); }; /** * Returns null if `t` is a subtype of `expected`; otherwise returns an * error message and also pushes it to `this.errors`. */ ParsingContext.prototype.checkSubtype = function checkSubtype$1 (expected, t) { var error = checkSubtype(expected, t); if (error) { this.error(error); } return error; }; var ParsingContext$1 = ParsingContext; function isConstant(expression) { if (expression instanceof Var$1) { return isConstant(expression.boundExpression); } else if (expression instanceof CompoundExpression$1 && expression.name === 'error') { return false; } else if (expression instanceof CollatorExpression$1) { // Although the results of a Collator expression with fixed arguments // generally shouldn't change between executions, we can't serialize them // as constant expressions because results change based on environment. return false; } else if (expression instanceof Within$1) { return false; } var isTypeAnnotation = expression instanceof Coercion$1 || expression instanceof Assertion$1; var childrenConstant = true; expression.eachChild(function (child) { // We can _almost_ assume that if `expressions` children are constant, // they would already have been evaluated to Literal values when they // were parsed. Type annotations are the exception, because they might // have been inferred and added after a child was parsed. // So we recurse into isConstant() for the children of type annotations, // but otherwise simply check whether they are Literals. if (isTypeAnnotation) { childrenConstant = childrenConstant && isConstant(child); } else { childrenConstant = childrenConstant && child instanceof Literal$1; } }); if (!childrenConstant) { return false; } return isFeatureConstant(expression) && isGlobalPropertyConstant(expression, [ 'zoom', 'heatmap-density', 'line-progress', 'sky-radial-progress', 'accumulated', 'is-supported-script', 'pitch', 'distance-from-center' ]); } // /** * Returns the index of the last stop <= input, or 0 if it doesn't exist. * @private */ function findStopLessThanOrEqualTo(stops, input) { var lastIndex = stops.length - 1; var lowerIndex = 0; var upperIndex = lastIndex; var currentIndex = 0; var currentValue, nextValue; while (lowerIndex <= upperIndex) { currentIndex = Math.floor((lowerIndex + upperIndex) / 2); currentValue = stops[currentIndex]; nextValue = stops[currentIndex + 1]; if (currentValue <= input) { if (currentIndex === lastIndex || input < nextValue) { // Search complete return currentIndex; } lowerIndex = currentIndex + 1; } else if (currentValue > input) { upperIndex = currentIndex - 1; } else { throw new RuntimeError$1('Input is not a number.'); } } return 0; } // var Step = function Step(type, input, stops) { this.type = type; this.input = input; this.labels = []; this.outputs = []; for (var i = 0, list = stops; i < list.length; i += 1) { var ref = list[i]; var label = ref[0]; var expression = ref[1]; this.labels.push(label); this.outputs.push(expression); } }; Step.parse = function parse (args, context) { if (args.length - 1 < 4) { return context.error(("Expected at least 4 arguments, but found only " + (args.length - 1) + ".")); } if ((args.length - 1) % 2 !== 0) { return context.error("Expected an even number of arguments."); } var input = context.parse(args[1], 1, NumberType); if (!input) { return null; } var stops = []; var outputType = null; if (context.expectedType && context.expectedType.kind !== 'value') { outputType = context.expectedType; } for (var i = 1; i < args.length; i += 2) { var label = i === 1 ? -Infinity : args[i]; var value = args[i + 1]; var labelKey = i; var valueKey = i + 1; if (typeof label !== 'number') { return context.error('Input/output pairs for "step" expressions must be defined using literal numeric values (not computed expressions) for the input values.', labelKey); } if (stops.length && stops[stops.length - 1][0] >= label) { return context.error('Input/output pairs for "step" expressions must be arranged with input values in strictly ascending order.', labelKey); } var parsed = context.parse(value, valueKey, outputType); if (!parsed) { return null; } outputType = outputType || parsed.type; stops.push([ label, parsed ]); } return new Step(outputType, input, stops); }; Step.prototype.evaluate = function evaluate (ctx) { var labels = this.labels; var outputs = this.outputs; if (labels.length === 1) { return outputs[0].evaluate(ctx); } var value = this.input.evaluate(ctx); if (value <= labels[0]) { return outputs[0].evaluate(ctx); } var stopCount = labels.length; if (value >= labels[stopCount - 1]) { return outputs[stopCount - 1].evaluate(ctx); } var index = findStopLessThanOrEqualTo(labels, value); return outputs[index].evaluate(ctx); }; Step.prototype.eachChild = function eachChild (fn) { fn(this.input); for (var i = 0, list = this.outputs; i < list.length; i += 1) { var expression = list[i]; fn(expression); } }; Step.prototype.outputDefined = function outputDefined () { return this.outputs.every(function (out) { return out.outputDefined(); }); }; Step.prototype.serialize = function serialize () { var serialized = [ 'step', this.input.serialize() ]; for (var i = 0; i < this.labels.length; i++) { if (i > 0) { serialized.push(this.labels[i]); } serialized.push(this.outputs[i].serialize()); } return serialized; }; var Step$1 = Step; /* * Copyright (C) 2008 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Ported from Webkit * http://svn.webkit.org/repository/webkit/trunk/Source/WebCore/platform/graphics/UnitBezier.h */ var unitbezier = UnitBezier; function UnitBezier(p1x, p1y, p2x, p2y) { // Calculate the polynomial coefficients, implicit first and last control points are (0,0) and (1,1). 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) { // `ax t^3 + bx t^2 + cx t' expanded using Horner's rule. 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; // First try a few iterations of Newton's method -- normally very fast. 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; } // Fall back to the bisection method for reliability. 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; } // Failure. return t2; }; UnitBezier.prototype.solve = function (x, epsilon) { return this.sampleCurveY(this.solveCurveX(x, epsilon)); }; var UnitBezier$1 = /*@__PURE__*/getDefaultExportFromCjs(unitbezier); // function number(a, b, t) { return a * (1 - t) + b * t; } function color(from, to, t) { return new Color$1(number(from.r, to.r, t), number(from.g, to.g, t), number(from.b, to.b, t), number(from.a, to.a, t)); } function array(from, to, t) { return from.map(function (d, i) { return number(d, to[i], t); }); } var interpolate = /*#__PURE__*/Object.freeze({ __proto__: null, number: number, color: color, array: array }); // // Constants var Xn = 0.95047, // D65 standard referent Yn = 1, Zn = 1.08883, t0 = 4 / 29, t1 = 6 / 29, t2 = 3 * t1 * t1, t3 = t1 * t1 * t1, deg2rad$1 = Math.PI / 180, rad2deg = 180 / Math.PI; // Utilities function xyz2lab(t) { return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0; } function lab2xyz(t) { return t > t1 ? t * t * t : t2 * (t - t0); } function xyz2rgb(x) { return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055); } function rgb2xyz(x) { x /= 255; return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4); } // LAB function rgbToLab(rgbColor) { var b = rgb2xyz(rgbColor.r), a = rgb2xyz(rgbColor.g), l = rgb2xyz(rgbColor.b), x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn), y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.072175 * l) / Yn), z = xyz2lab((0.0193339 * b + 0.119192 * a + 0.9503041 * l) / Zn); return { l: 116 * y - 16, a: 500 * (x - y), b: 200 * (y - z), alpha: rgbColor.a }; } function labToRgb(labColor) { var y = (labColor.l + 16) / 116, x = isNaN(labColor.a) ? y : y + labColor.a / 500, z = isNaN(labColor.b) ? y : y - labColor.b / 200; y = Yn * lab2xyz(y); x = Xn * lab2xyz(x); z = Zn * lab2xyz(z); return new Color$1(xyz2rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB xyz2rgb(-0.969266 * x + 1.8760108 * y + 0.041556 * z), xyz2rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z), labColor.alpha); } function interpolateLab(from, to, t) { return { l: number(from.l, to.l, t), a: number(from.a, to.a, t), b: number(from.b, to.b, t), alpha: number(from.alpha, to.alpha, t) }; } // HCL function rgbToHcl(rgbColor) { var ref = rgbToLab(rgbColor); var l = ref.l; var a = ref.a; var b = ref.b; var h = Math.atan2(b, a) * rad2deg; return { h: h < 0 ? h + 360 : h, c: Math.sqrt(a * a + b * b), l: l, alpha: rgbColor.a }; } function hclToRgb(hclColor) { var h = hclColor.h * deg2rad$1, c = hclColor.c, l = hclColor.l; return labToRgb({ l: l, a: Math.cos(h) * c, b: Math.sin(h) * c, alpha: hclColor.alpha }); } function interpolateHue(a, b, t) { var d = b - a; return a + t * (d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d); } function interpolateHcl(from, to, t) { return { h: interpolateHue(from.h, to.h, t), c: number(from.c, to.c, t), l: number(from.l, to.l, t), alpha: number(from.alpha, to.alpha, t) }; } var lab = { forward: rgbToLab, reverse: labToRgb, interpolate: interpolateLab }; var hcl = { forward: rgbToHcl, reverse: hclToRgb, interpolate: interpolateHcl }; // var Interpolate = function Interpolate(type, operator, interpolation, input, stops) { this.type = type; this.operator = operator; this.interpolation = interpolation; this.input = input; this.labels = []; this.outputs = []; for (var i = 0, list = stops; i < list.length; i += 1) { var ref = list[i]; var label = ref[0]; var expression = ref[1]; this.labels.push(label); this.outputs.push(expression); } }; Interpolate.interpolationFactor = function interpolationFactor (interpolation, input, lower, upper) { var t = 0; if (interpolation.name === 'exponential') { t = exponentialInterpolation(input, interpolation.base, lower, upper); } else if (interpolation.name === 'linear') { t = exponentialInterpolation(input, 1, lower, upper); } else if (interpolation.name === 'cubic-bezier') { var c = interpolation.controlPoints; var ub = new UnitBezier$1(c[0], c[1], c[2], c[3]); t = ub.solve(exponentialInterpolation(input, 1, lower, upper)); } return t; }; Interpolate.parse = function parse (args, context) { var operator = args[0]; var interpolation = args[1]; var input = args[2]; var rest = args.slice(3); if (!Array.isArray(interpolation) || interpolation.length === 0) { return context.error("Expected an interpolation type expression.", 1); } if (interpolation[0] === 'linear') { interpolation = { name: 'linear' }; } else if (interpolation[0] === 'exponential') { var base = interpolation[1]; if (typeof base !== 'number') { return context.error("Exponential interpolation requires a numeric base.", 1, 1); } interpolation = { name: 'exponential', base: base }; } else if (interpolation[0] === 'cubic-bezier') { var controlPoints = interpolation.slice(1); if (controlPoints.length !== 4 || controlPoints.some(function (t) { return typeof t !== 'number' || t < 0 || t > 1; })) { return context.error('Cubic bezier interpolation requires four numeric arguments with values between 0 and 1.', 1); } interpolation = { name: 'cubic-bezier', controlPoints: controlPoints }; } else { return context.error(("Unknown interpolation type " + (String(interpolation[0]))), 1, 0); } if (args.length - 1 < 4) { return context.error(("Expected at least 4 arguments, but found only " + (args.length - 1) + ".")); } if ((args.length - 1) % 2 !== 0) { return context.error("Expected an even number of arguments."); } input = context.parse(input, 2, NumberType); if (!input) { return null; } var stops = []; var outputType = null; if (operator === 'interpolate-hcl' || operator === 'interpolate-lab') { outputType = ColorType; } else if (context.expectedType && context.expectedType.kind !== 'value') { outputType = context.expectedType; } for (var i = 0; i < rest.length; i += 2) { var label = rest[i]; var value = rest[i + 1]; var labelKey = i + 3; var valueKey = i + 4; if (typeof label !== 'number') { return context.error('Input/output pairs for "interpolate" expressions must be defined using literal numeric values (not computed expressions) for the input values.', labelKey); } if (stops.length && stops[stops.length - 1][0] >= label) { return context.error('Input/output pairs for "interpolate" expressions must be arranged with input values in strictly ascending order.', labelKey); } var parsed = context.parse(value, valueKey, outputType); if (!parsed) { return null; } outputType = outputType || parsed.type; stops.push([ label, parsed ]); } if (outputType.kind !== 'number' && outputType.kind !== 'color' && !(outputType.kind === 'array' && outputType.itemType.kind === 'number' && typeof outputType.N === 'number')) { return context.error(("Type " + (toString$1(outputType)) + " is not interpolatable.")); } return new Interpolate(outputType, operator, interpolation, input, stops); }; Interpolate.prototype.evaluate = function evaluate (ctx) { var labels = this.labels; var outputs = this.outputs; if (labels.length === 1) { return outputs[0].evaluate(ctx); } var value = this.input.evaluate(ctx); if (value <= labels[0]) { return outputs[0].evaluate(ctx); } var stopCount = labels.length; if (value >= labels[stopCount - 1]) { return outputs[stopCount - 1].evaluate(ctx); } var index = findStopLessThanOrEqualTo(labels, value); var lower = labels[index]; var upper = labels[index + 1]; var t = Interpolate.interpolationFactor(this.interpolation, value, lower, upper); var outputLower = outputs[index].evaluate(ctx); var outputUpper = outputs[index + 1].evaluate(ctx); if (this.operator === 'interpolate') { return interpolate[this.type.kind.toLowerCase()](outputLower, outputUpper, t);// eslint-disable-line import/namespace } else if (this.operator === 'interpolate-hcl') { return hcl.reverse(hcl.interpolate(hcl.forward(outputLower), hcl.forward(outputUpper), t)); } else { return lab.reverse(lab.interpolate(lab.forward(outputLower), lab.forward(outputUpper), t)); } }; Interpolate.prototype.eachChild = function eachChild (fn) { fn(this.input); for (var i = 0, list = this.outputs; i < list.length; i += 1) { var expression = list[i]; fn(expression); } }; Interpolate.prototype.outputDefined = function outputDefined () { return this.outputs.every(function (out) { return out.outputDefined(); }); }; Interpolate.prototype.serialize = function serialize () { var interpolation; if (this.interpolation.name === 'linear') { interpolation = ['linear']; } else if (this.interpolation.name === 'exponential') { if (this.interpolation.base === 1) { interpolation = ['linear']; } else { interpolation = [ 'exponential', this.interpolation.base ]; } } else { interpolation = ['cubic-bezier'].concat(this.interpolation.controlPoints); } var serialized = [ this.operator, interpolation, this.input.serialize() ]; for (var i = 0; i < this.labels.length; i++) { serialized.push(this.labels[i], this.outputs[i].serialize()); } return serialized; }; /** * Returns a ratio that can be used to interpolate between exponential function * stops. * How it works: Two consecutive stop values define a (scaled and shifted) exponential function `f(x) = a * base^x + b`, where `base` is the user-specified base, * and `a` and `b` are constants affording sufficient degrees of freedom to fit * the function to the given stops. * * Here's a bit of algebra that lets us compute `f(x)` directly from the stop * values without explicitly solving for `a` and `b`: * * First stop value: `f(x0) = y0 = a * base^x0 + b` * Second stop value: `f(x1) = y1 = a * base^x1 + b` * => `y1 - y0 = a(base^x1 - base^x0)` * => `a = (y1 - y0)/(base^x1 - base^x0)` * * Desired value: `f(x) = y = a * base^x + b` * => `f(x) = y0 + a * (base^x - base^x0)` * * From the above, we can replace the `a` in `a * (base^x - base^x0)` and do a * little algebra: * ``` * a * (base^x - base^x0) = (y1 - y0)/(base^x1 - base^x0) * (base^x - base^x0) * = (y1 - y0) * (base^x - base^x0) / (base^x1 - base^x0) * ``` * * If we let `(base^x - base^x0) / (base^x1 base^x0)`, then we have * `f(x) = y0 + (y1 - y0) * ratio`. In other words, `ratio` may be treated as * an interpolation factor between the two stops' output values. * * (Note: a slightly different form for `ratio`, * `(base^(x-x0) - 1) / (base^(x1-x0) - 1) `, is equivalent, but requires fewer * expensive `Math.pow()` operations.) * * @private */ function exponentialInterpolation(input, base, lowerValue, upperValue) { var difference = upperValue - lowerValue; var progress = input - lowerValue; if (difference === 0) { return 0; } else if (base === 1) { return progress / difference; } else { return (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1); } } var Interpolate$1 = Interpolate; var Coalesce = function Coalesce(type, args) { this.type = type; this.args = args; }; Coalesce.parse = function parse (args, context) { if (args.length < 2) { return context.error('Expectected at least one argument.'); } var outputType = null; var expectedType = context.expectedType; if (expectedType && expectedType.kind !== 'value') { outputType = expectedType; } var parsedArgs = []; for (var i = 0, list = args.slice(1); i < list.length; i += 1) { var arg = list[i]; var parsed = context.parse(arg, 1 + parsedArgs.length, outputType, undefined, { typeAnnotation: 'omit' }); if (!parsed) { return null; } outputType = outputType || parsed.type; parsedArgs.push(parsed); } // Above, we parse arguments without inferred type annotation so that // they don't produce a runtime error for `null` input, which would // preempt the desired null-coalescing behavior. // Thus, if any of our arguments would have needed an annotation, we // need to wrap the enclosing coalesce expression with it instead. var needsAnnotation = expectedType && parsedArgs.some(function (arg) { return checkSubtype(expectedType, arg.type); }); return needsAnnotation ? new Coalesce(ValueType, parsedArgs) : new Coalesce(outputType, parsedArgs); }; Coalesce.prototype.evaluate = function evaluate (ctx) { var result = null; var argCount = 0; var firstImage; for (var i = 0, list = this.args; i < list.length; i += 1) { var arg = list[i]; argCount++; result = arg.evaluate(ctx); // we need to keep track of the first requested image in a coalesce statement // if coalesce can't find a valid image, we return the first image so styleimagemissing can fire if (result && result instanceof ResolvedImage$1 && !result.available) { // set to first image if (!firstImage) { firstImage = result; } result = null; // if we reach the end, return the first image if (argCount === this.args.length) { return firstImage; } } if (result !== null) { break; } } return result; }; Coalesce.prototype.eachChild = function eachChild (fn) { this.args.forEach(fn); }; Coalesce.prototype.outputDefined = function outputDefined () { return this.args.every(function (arg) { return arg.outputDefined(); }); }; Coalesce.prototype.serialize = function serialize () { var serialized = ['coalesce']; this.eachChild(function (child) { serialized.push(child.serialize()); }); return serialized; }; var Coalesce$1 = Coalesce; // var Let = function Let(bindings, result) { this.type = result.type; this.bindings = [].concat(bindings); this.result = result; }; Let.prototype.evaluate = function evaluate (ctx) { return this.result.evaluate(ctx); }; Let.prototype.eachChild = function eachChild (fn) { for (var i = 0, list = this.bindings; i < list.length; i += 1) { var binding = list[i]; fn(binding[1]); } fn(this.result); }; Let.parse = function parse (args, context) { if (args.length < 4) { return context.error(("Expected at least 3 arguments, but found " + (args.length - 1) + " instead.")); } var bindings = []; for (var i = 1; i < args.length - 1; i += 2) { var name = args[i]; if (typeof name !== 'string') { return context.error(("Expected string, but found " + (typeof name) + " instead."), i); } if (/[^a-zA-Z0-9_]/.test(name)) { return context.error("Variable names must contain only alphanumeric characters or '_'.", i); } var value = context.parse(args[i + 1], i + 1); if (!value) { return null; } bindings.push([ name, value ]); } var result = context.parse(args[args.length - 1], args.length - 1, context.expectedType, bindings); if (!result) { return null; } return new Let(bindings, result); }; Let.prototype.outputDefined = function outputDefined () { return this.result.outputDefined(); }; Let.prototype.serialize = function serialize () { var serialized = ['let']; for (var i = 0, list = this.bindings; i < list.length; i += 1) { var ref = list[i]; var name = ref[0]; var expr = ref[1]; serialized.push(name, expr.serialize()); } serialized.push(this.result.serialize()); return serialized; }; var Let$1 = Let; // var At = function At(type, index, input) { this.type = type; this.index = index; this.input = input; }; At.parse = function parse (args, context) { if (args.length !== 3) { return context.error(("Expected 2 arguments, but found " + (args.length - 1) + " instead.")); } var index = context.parse(args[1], 1, NumberType); var input = context.parse(args[2], 2, array$1(context.expectedType || ValueType)); if (!index || !input) { return null; } var t = input.type; return new At(t.itemType, index, input); }; At.prototype.evaluate = function evaluate (ctx) { var index = this.index.evaluate(ctx); var array = this.input.evaluate(ctx); if (index < 0) { throw new RuntimeError$1(("Array index out of bounds: " + index + " < 0.")); } if (index >= array.length) { throw new RuntimeError$1(("Array index out of bounds: " + index + " > " + (array.length - 1) + ".")); } if (index !== Math.floor(index)) { throw new RuntimeError$1(("Array index must be an integer, but found " + index + " instead.")); } return array[index]; }; At.prototype.eachChild = function eachChild (fn) { fn(this.index); fn(this.input); }; At.prototype.outputDefined = function outputDefined () { return false; }; At.prototype.serialize = function serialize () { return [ 'at', this.index.serialize(), this.input.serialize() ]; }; var At$1 = At; // var In = function In(needle, haystack) { this.type = BooleanType; this.needle = needle; this.haystack = haystack; }; In.parse = function parse (args, context) { if (args.length !== 3) { return context.error(("Expected 2 arguments, but found " + (args.length - 1) + " instead.")); } var needle = context.parse(args[1], 1, ValueType); var haystack = context.parse(args[2], 2, ValueType); if (!needle || !haystack) { return null; } if (!isValidType(needle.type, [ BooleanType, StringType, NumberType, NullType, ValueType ])) { return context.error(("Expected first argument to be of type boolean, string, number or null, but found " + (toString$1(needle.type)) + " instead")); } return new In(needle, haystack); }; In.prototype.evaluate = function evaluate (ctx) { var needle = this.needle.evaluate(ctx); var haystack = this.haystack.evaluate(ctx); if (haystack == null) { return false; } if (!isValidNativeType(needle, [ 'boolean', 'string', 'number', 'null' ])) { throw new RuntimeError$1(("Expected first argument to be of type boolean, string, number or null, but found " + (toString$1(typeOf(needle))) + " instead.")); } if (!isValidNativeType(haystack, [ 'string', 'array' ])) { throw new RuntimeError$1(("Expected second argument to be of type array or string, but found " + (toString$1(typeOf(haystack))) + " instead.")); } return haystack.indexOf(needle) >= 0; }; In.prototype.eachChild = function eachChild (fn) { fn(this.needle); fn(this.haystack); }; In.prototype.outputDefined = function outputDefined () { return true; }; In.prototype.serialize = function serialize () { return [ 'in', this.needle.serialize(), this.haystack.serialize() ]; }; var In$1 = In; // var IndexOf = function IndexOf(needle, haystack, fromIndex) { this.type = NumberType; this.needle = needle; this.haystack = haystack; this.fromIndex = fromIndex; }; IndexOf.parse = function parse (args, context) { if (args.length <= 2 || args.length >= 5) { return context.error(("Expected 3 or 4 arguments, but found " + (args.length - 1) + " instead.")); } var needle = context.parse(args[1], 1, ValueType); var haystack = context.parse(args[2], 2, ValueType); if (!needle || !haystack) { return null; } if (!isValidType(needle.type, [ BooleanType, StringType, NumberType, NullType, ValueType ])) { return context.error(("Expected first argument to be of type boolean, string, number or null, but found " + (toString$1(needle.type)) + " instead")); } if (args.length === 4) { var fromIndex = context.parse(args[3], 3, NumberType); if (!fromIndex) { return null; } return new IndexOf(needle, haystack, fromIndex); } else { return new IndexOf(needle, haystack); } }; IndexOf.prototype.evaluate = function evaluate (ctx) { var needle = this.needle.evaluate(ctx); var haystack = this.haystack.evaluate(ctx); if (!isValidNativeType(needle, [ 'boolean', 'string', 'number', 'null' ])) { throw new RuntimeError$1(("Expected first argument to be of type boolean, string, number or null, but found " + (toString$1(typeOf(needle))) + " instead.")); } if (!isValidNativeType(haystack, [ 'string', 'array' ])) { throw new RuntimeError$1(("Expected second argument to be of type array or string, but found " + (toString$1(typeOf(haystack))) + " instead.")); } if (this.fromIndex) { var fromIndex = this.fromIndex.evaluate(ctx); return haystack.indexOf(needle, fromIndex); } return haystack.indexOf(needle); }; IndexOf.prototype.eachChild = function eachChild (fn) { fn(this.needle); fn(this.haystack); if (this.fromIndex) { fn(this.fromIndex); } }; IndexOf.prototype.outputDefined = function outputDefined () { return false; }; IndexOf.prototype.serialize = function serialize () { if (this.fromIndex != null && this.fromIndex !== undefined) { var fromIndex = this.fromIndex.serialize(); return [ 'index-of', this.needle.serialize(), this.haystack.serialize(), fromIndex ]; } return [ 'index-of', this.needle.serialize(), this.haystack.serialize() ]; }; var IndexOf$1 = IndexOf; // Map input label values to output expression index var Match = function Match(inputType, outputType, input, cases, outputs, otherwise) { this.inputType = inputType; this.type = outputType; this.input = input; this.cases = cases; this.outputs = outputs; this.otherwise = otherwise; }; Match.parse = function parse (args, context) { if (args.length < 5) { return context.error(("Expected at least 4 arguments, but found only " + (args.length - 1) + ".")); } if (args.length % 2 !== 1) { return context.error("Expected an even number of arguments."); } var inputType; var outputType; if (context.expectedType && context.expectedType.kind !== 'value') { outputType = context.expectedType; } var cases = {}; var outputs = []; for (var i = 2; i < args.length - 1; i += 2) { var labels = args[i]; var value = args[i + 1]; if (!Array.isArray(labels)) { labels = [labels]; } var labelContext = context.concat(i); if (labels.length === 0) { return labelContext.error('Expected at least one branch label.'); } for (var i$1 = 0, list = labels; i$1 < list.length; i$1 += 1) { var label = list[i$1]; if (typeof label !== 'number' && typeof label !== 'string') { return labelContext.error("Branch labels must be numbers or strings."); } else if (typeof label === 'number' && Math.abs(label) > Number.MAX_SAFE_INTEGER) { return labelContext.error(("Branch labels must be integers no larger than " + (Number.MAX_SAFE_INTEGER) + ".")); } else if (typeof label === 'number' && Math.floor(label) !== label) { return labelContext.error("Numeric branch labels must be integer values."); } else if (!inputType) { inputType = typeOf(label); } else if (labelContext.checkSubtype(inputType, typeOf(label))) { return null; } if (typeof cases[String(label)] !== 'undefined') { return labelContext.error('Branch labels must be unique.'); } cases[String(label)] = outputs.length; } var result = context.parse(value, i, outputType); if (!result) { return null; } outputType = outputType || result.type; outputs.push(result); } var input = context.parse(args[1], 1, ValueType); if (!input) { return null; } var otherwise = context.parse(args[args.length - 1], args.length - 1, outputType); if (!otherwise) { return null; } if (input.type.kind !== 'value' && context.concat(1).checkSubtype(inputType, input.type)) { return null; } return new Match(inputType, outputType, input, cases, outputs, otherwise); }; Match.prototype.evaluate = function evaluate (ctx) { var input = this.input.evaluate(ctx); var output = typeOf(input) === this.inputType && this.outputs[this.cases[input]] || this.otherwise; return output.evaluate(ctx); }; Match.prototype.eachChild = function eachChild (fn) { fn(this.input); this.outputs.forEach(fn); fn(this.otherwise); }; Match.prototype.outputDefined = function outputDefined () { return this.outputs.every(function (out) { return out.outputDefined(); }) && this.otherwise.outputDefined(); }; Match.prototype.serialize = function serialize () { var this$1$1 = this; var serialized = [ 'match', this.input.serialize() ]; // Sort so serialization has an arbitrary defined order, even though // branch order doesn't affect evaluation var sortedLabels = Object.keys(this.cases).sort(); // Group branches by unique match expression to support condensed // serializations of the form [case1, case2, ...] -> matchExpression var groupedByOutput = []; var outputLookup = {}; // lookup index into groupedByOutput for a given output expression for (var i = 0, list = sortedLabels; i < list.length; i += 1) { var label = list[i]; var outputIndex = outputLookup[this.cases[label]]; if (outputIndex === undefined) { // First time seeing this output, add it to the end of the grouped list outputLookup[this.cases[label]] = groupedByOutput.length; groupedByOutput.push([ this.cases[label], [label] ]); } else { // We've seen this expression before, add the label to that output's group groupedByOutput[outputIndex][1].push(label); } } var coerceLabel = function (label) { return this$1$1.inputType.kind === 'number' ? Number(label) : label; }; for (var i$1 = 0, list$1 = groupedByOutput; i$1 < list$1.length; i$1 += 1) { var ref = list$1[i$1]; var outputIndex = ref[0]; var labels = ref[1]; if (labels.length === 1) { // Only a single label matches this output expression serialized.push(coerceLabel(labels[0])); } else { // Array of literal labels pointing to this output expression serialized.push(labels.map(coerceLabel)); } serialized.push(this.outputs[outputIndex$1].serialize()); } serialized.push(this.otherwise.serialize()); return serialized; }; var Match$1 = Match; var Case = function Case(type, branches, otherwise) { this.type = type; this.branches = branches; this.otherwise = otherwise; }; Case.parse = function parse (args, context) { if (args.length < 4) { return context.error(("Expected at least 3 arguments, but found only " + (args.length - 1) + ".")); } if (args.length % 2 !== 0) { return context.error("Expected an odd number of arguments."); } var outputType; if (context.expectedType && context.expectedType.kind !== 'value') { outputType = context.expectedType; } var branches = []; for (var i = 1; i < args.length - 1; i += 2) { var test = context.parse(args[i], i, BooleanType); if (!test) { return null; } var result = context.parse(args[i + 1], i + 1, outputType); if (!result) { return null; } branches.push([ test, result ]); outputType = outputType || result.type; } var otherwise = context.parse(args[args.length - 1], args.length - 1, outputType); if (!otherwise) { return null; } return new Case(outputType, branches, otherwise); }; Case.prototype.evaluate = function evaluate (ctx) { for (var i = 0, list = this.branches; i < list.length; i += 1) { var ref = list[i]; var test = ref[0]; var expression = ref[1]; if (test.evaluate(ctx)) { return expression.evaluate(ctx); } } return this.otherwise.evaluate(ctx); }; Case.prototype.eachChild = function eachChild (fn) { for (var i = 0, list = this.branches; i < list.length; i += 1) { var ref = list[i]; var test = ref[0]; var expression = ref[1]; fn(test); fn(expression); } fn(this.otherwise); }; Case.prototype.outputDefined = function outputDefined () { return this.branches.every(function (ref) { ref[0]; var out = ref[1]; return out.outputDefined(); }) && this.otherwise.outputDefined(); }; Case.prototype.serialize = function serialize () { var serialized = ['case']; this.eachChild(function (child) { serialized.push(child.serialize()); }); return serialized; }; var Case$1 = Case; // var Slice = function Slice(type, input, beginIndex, endIndex) { this.type = type; this.input = input; this.beginIndex = beginIndex; this.endIndex = endIndex; }; Slice.parse = function parse (args, context) { if (args.length <= 2 || args.length >= 5) { return context.error(("Expected 3 or 4 arguments, but found " + (args.length - 1) + " instead.")); } var input = context.parse(args[1], 1, ValueType); var beginIndex = context.parse(args[2], 2, NumberType); if (!input || !beginIndex) { return null; } if (!isValidType(input.type, [ array$1(ValueType), StringType, ValueType ])) { return context.error(("Expected first argument to be of type array or string, but found " + (toString$1(input.type)) + " instead")); } if (args.length === 4) { var endIndex = context.parse(args[3], 3, NumberType); if (!endIndex) { return null; } return new Slice(input.type, input, beginIndex, endIndex); } else { return new Slice(input.type, input, beginIndex); } }; Slice.prototype.evaluate = function evaluate (ctx) { var input = this.input.evaluate(ctx); var beginIndex = this.beginIndex.evaluate(ctx); if (!isValidNativeType(input, [ 'string', 'array' ])) { throw new RuntimeError$1(("Expected first argument to be of type array or string, but found " + (toString$1(typeOf(input))) + " instead.")); } if (this.endIndex) { var endIndex = this.endIndex.evaluate(ctx); return input.slice(beginIndex, endIndex); } return input.slice(beginIndex); }; Slice.prototype.eachChild = function eachChild (fn) { fn(this.input); fn(this.beginIndex); if (this.endIndex) { fn(this.endIndex); } }; Slice.prototype.outputDefined = function outputDefined () { return false; }; Slice.prototype.serialize = function serialize () { if (this.endIndex != null && this.endIndex !== undefined) { var endIndex = this.endIndex.serialize(); return [ 'slice', this.input.serialize(), this.beginIndex.serialize(), endIndex ]; } return [ 'slice', this.input.serialize(), this.beginIndex.serialize() ]; }; var Slice$1 = Slice; // function isComparableType(op, type) { if (op === '==' || op === '!=') { // equality operator return type.kind === 'boolean' || type.kind === 'string' || type.kind === 'number' || type.kind === 'null' || type.kind === 'value'; } else { // ordering operator return type.kind === 'string' || type.kind === 'number' || type.kind === 'value'; } } function eq(ctx, a, b) { return a === b; } function neq(ctx, a, b) { return a !== b; } function lt(ctx, a, b) { return a < b; } function gt(ctx, a, b) { return a > b; } function lteq(ctx, a, b) { return a <= b; } function gteq(ctx, a, b) { return a >= b; } function eqCollate(ctx, a, b, c) { return c.compare(a, b) === 0; } function neqCollate(ctx, a, b, c) { return !eqCollate(ctx, a, b, c); } function ltCollate(ctx, a, b, c) { return c.compare(a, b) < 0; } function gtCollate(ctx, a, b, c) { return c.compare(a, b) > 0; } function lteqCollate(ctx, a, b, c) { return c.compare(a, b) <= 0; } function gteqCollate(ctx, a, b, c) { return c.compare(a, b) >= 0; } /** * Special form for comparison operators, implementing the signatures: * - (T, T, ?Collator) => boolean * - (T, value, ?Collator) => boolean * - (value, T, ?Collator) => boolean * * For inequalities, T must be either value, string, or number. For ==/!=, it * can also be boolean or null. * * Equality semantics are equivalent to Javascript's strict equality (===/!==) * -- i.e., when the arguments' types don't match, == evaluates to false, != to * true. * * When types don't match in an ordering comparison, a runtime error is thrown. * * @private */ function makeComparison(op, compareBasic, compareWithCollator) { var isOrderComparison = op !== '==' && op !== '!='; return /*@__PURE__*/(function () { function Comparison(lhs, rhs, collator) { this.type = BooleanType; this.lhs = lhs; this.rhs = rhs; this.collator = collator; this.hasUntypedArgument = lhs.type.kind === 'value' || rhs.type.kind === 'value'; } Comparison.parse = function parse (args, context) { if (args.length !== 3 && args.length !== 4) { return context.error("Expected two or three arguments."); } var op = args[0]; var lhs = context.parse(args[1], 1, ValueType); if (!lhs) { return null; } if (!isComparableType(op, lhs.type)) { return context.concat(1).error(("\"" + op + "\" comparisons are not supported for type '" + (toString$1(lhs.type)) + "'.")); } var rhs = context.parse(args[2], 2, ValueType); if (!rhs) { return null; } if (!isComparableType(op, rhs.type)) { return context.concat(2).error(("\"" + op + "\" comparisons are not supported for type '" + (toString$1(rhs.type)) + "'.")); } if (lhs.type.kind !== rhs.type.kind && lhs.type.kind !== 'value' && rhs.type.kind !== 'value') { return context.error(("Cannot compare types '" + (toString$1(lhs.type)) + "' and '" + (toString$1(rhs.type)) + "'.")); } if (isOrderComparison) { // typing rules specific to less/greater than operators if (lhs.type.kind === 'value' && rhs.type.kind !== 'value') { // (value, T) lhs = new Assertion$1(rhs.type, [lhs]); } else if (lhs.type.kind !== 'value' && rhs.type.kind === 'value') { // (T, value) rhs = new Assertion$1(lhs.type, [rhs]); } } var collator = null; if (args.length === 4) { if (lhs.type.kind !== 'string' && rhs.type.kind !== 'string' && lhs.type.kind !== 'value' && rhs.type.kind !== 'value') { return context.error("Cannot use collator to compare non-string types."); } collator = context.parse(args[3], 3, CollatorType); if (!collator) { return null; } } return new Comparison(lhs, rhs, collator); }; Comparison.prototype.evaluate = function evaluate (ctx) { var lhs = this.lhs.evaluate(ctx); var rhs = this.rhs.evaluate(ctx); if (isOrderComparison && this.hasUntypedArgument) { var lt = typeOf(lhs); var rt = typeOf(rhs); // check that type is string or number, and equal if (lt.kind !== rt.kind || !(lt.kind === 'string' || lt.kind === 'number')) { throw new RuntimeError$1(("Expected arguments for \"" + op + "\" to be (string, string) or (number, number), but found (" + (lt.kind) + ", " + (rt.kind) + ") instead.")); } } if (this.collator && !isOrderComparison && this.hasUntypedArgument) { var lt$1 = typeOf(lhs); var rt$1 = typeOf(rhs); if (lt$1.kind !== 'string' || rt$1.kind !== 'string') { return compareBasic(ctx, lhs, rhs); } } return this.collator ? compareWithCollator(ctx, lhs, rhs, this.collator.evaluate(ctx)) : compareBasic(ctx, lhs, rhs); }; Comparison.prototype.eachChild = function eachChild (fn) { fn(this.lhs); fn(this.rhs); if (this.collator) { fn(this.collator); } }; Comparison.prototype.outputDefined = function outputDefined () { return true; }; Comparison.prototype.serialize = function serialize () { var serialized = [op]; this.eachChild(function (child) { serialized.push(child.serialize()); }); return serialized; }; return Comparison; }()); } var Equals = makeComparison('==', eq, eqCollate); var NotEquals = makeComparison('!=', neq, neqCollate); var LessThan = makeComparison('<', lt, ltCollate); var GreaterThan = makeComparison('>', gt, gtCollate); var LessThanOrEqual = makeComparison('<=', lteq, lteqCollate); var GreaterThanOrEqual = makeComparison('>=', gteq, gteqCollate); // var NumberFormat = function NumberFormat(number, locale, currency, unit, minFractionDigits, maxFractionDigits) { this.type = StringType; this.number = number; this.locale = locale; this.currency = currency; this.unit = unit; this.minFractionDigits = minFractionDigits; this.maxFractionDigits = maxFractionDigits; }; NumberFormat.parse = function parse (args, context) { if (args.length !== 3) { return context.error("Expected two arguments."); } var number = context.parse(args[1], 1, NumberType); if (!number) { return null; } var options = args[2]; if (typeof options !== 'object' || Array.isArray(options)) { return context.error("NumberFormat options argument must be an object."); } var locale = null; if (options['locale']) { locale = context.parse(options['locale'], 1, StringType); if (!locale) { return null; } } var currency = null; if (options['currency']) { currency = context.parse(options['currency'], 1, StringType); if (!currency) { return null; } } var unit = null; if (options['unit']) { unit = context.parse(options['unit'], 1, StringType); if (!unit) { return null; } } var minFractionDigits = null; if (options['min-fraction-digits']) { minFractionDigits = context.parse(options['min-fraction-digits'], 1, NumberType); if (!minFractionDigits) { return null; } } var maxFractionDigits = null; if (options['max-fraction-digits']) { maxFractionDigits = context.parse(options['max-fraction-digits'], 1, NumberType); if (!maxFractionDigits) { return null; } } return new NumberFormat(number, locale, currency, unit, minFractionDigits, maxFractionDigits); }; NumberFormat.prototype.evaluate = function evaluate (ctx) { return new Intl.NumberFormat(this.locale ? this.locale.evaluate(ctx) : [], { style: this.currency && 'currency' || this.unit && 'unit' || 'decimal', currency: this.currency ? this.currency.evaluate(ctx) : undefined, unit: this.unit ? this.unit.evaluate(ctx) : undefined, minimumFractionDigits: this.minFractionDigits ? this.minFractionDigits.evaluate(ctx) : undefined, maximumFractionDigits: this.maxFractionDigits ? this.maxFractionDigits.evaluate(ctx) : undefined }).format(this.number.evaluate(ctx)); }; NumberFormat.prototype.eachChild = function eachChild (fn) { fn(this.number); if (this.locale) { fn(this.locale); } if (this.currency) { fn(this.currency); } if (this.unit) { fn(this.unit); } if (this.minFractionDigits) { fn(this.minFractionDigits); } if (this.maxFractionDigits) { fn(this.maxFractionDigits); } }; NumberFormat.prototype.outputDefined = function outputDefined () { return false; }; NumberFormat.prototype.serialize = function serialize () { var options = {}; if (this.locale) { options['locale'] = this.locale.serialize(); } if (this.currency) { options['currency'] = this.currency.serialize(); } if (this.unit) { options['unit'] = this.unit.serialize(); } if (this.minFractionDigits) { options['min-fraction-digits'] = this.minFractionDigits.serialize(); } if (this.maxFractionDigits) { options['max-fraction-digits'] = this.maxFractionDigits.serialize(); } return [ 'number-format', this.number.serialize(), options ]; }; var NumberFormat$1 = NumberFormat; // var Length = function Length(input) { this.type = NumberType; this.input = input; }; Length.parse = function parse (args, context) { if (args.length !== 2) { return context.error(("Expected 1 argument, but found " + (args.length - 1) + " instead.")); } var input = context.parse(args[1], 1); if (!input) { return null; } if (input.type.kind !== 'array' && input.type.kind !== 'string' && input.type.kind !== 'value') { return context.error(("Expected argument of type string or array, but found " + (toString$1(input.type)) + " instead.")); } return new Length(input); }; Length.prototype.evaluate = function evaluate (ctx) { var input = this.input.evaluate(ctx); if (typeof input === 'string') { return input.length; } else if (Array.isArray(input)) { return input.length; } else { throw new RuntimeError$1(("Expected value to be of type string or array, but found " + (toString$1(typeOf(input))) + " instead.")); } }; Length.prototype.eachChild = function eachChild (fn) { fn(this.input); }; Length.prototype.outputDefined = function outputDefined () { return false; }; Length.prototype.serialize = function serialize () { var serialized = ['length']; this.eachChild(function (child) { serialized.push(child.serialize()); }); return serialized; }; var Length$1 = Length; // var expressions = { // special forms '==': Equals, '!=': NotEquals, '>': GreaterThan, '<': LessThan, '>=': GreaterThanOrEqual, '<=': LessThanOrEqual, 'array': Assertion$1, 'at': At$1, 'boolean': Assertion$1, 'case': Case$1, 'coalesce': Coalesce$1, 'collator': CollatorExpression$1, 'format': FormatExpression$1, 'image': ImageExpression$1, 'in': In$1, 'index-of': IndexOf$1, 'interpolate': Interpolate$1, 'interpolate-hcl': Interpolate$1, 'interpolate-lab': Interpolate$1, 'length': Length$1, 'let': Let$1, 'literal': Literal$1, 'match': Match$1, 'number': Assertion$1, 'number-format': NumberFormat$1, 'object': Assertion$1, 'slice': Slice$1, 'step': Step$1, 'string': Assertion$1, 'to-boolean': Coercion$1, 'to-color': Coercion$1, 'to-number': Coercion$1, 'to-string': Coercion$1, 'var': Var$1, 'within': Within$1 }; function rgba(ctx, ref) { var r = ref[0]; var g = ref[1]; var b = ref[2]; var a = ref[3]; r = r.evaluate(ctx); g = g.evaluate(ctx); b = b.evaluate(ctx); var alpha = a ? a.evaluate(ctx) : 1; var error = validateRGBA(r, g, b, alpha); if (error) { throw new RuntimeError$1(error); } return new Color$1(r / 255 * alpha, g / 255 * alpha, b / 255 * alpha, alpha); } function has(key, obj) { return key in obj; } function get(key, obj) { var v = obj[key]; return typeof v === 'undefined' ? null : v; } function binarySearch(v, a, i, j) { while (i <= j) { var m = i + j >> 1; if (a[m] === v) { return true; } if (a[m] > v) { j = m - 1; } else { i = m + 1; } } return false; } function varargs(type) { return { type: type }; } CompoundExpression$1.register(expressions, { 'error': [ ErrorType, [StringType], function (ctx, ref) { var v = ref[0]; throw new RuntimeError$1(v.evaluate(ctx)); } ], 'typeof': [ StringType, [ValueType], function (ctx, ref) { var v = ref[0]; return toString$1(typeOf(v.evaluate(ctx))); } ], 'to-rgba': [ array$1(NumberType, 4), [ColorType], function (ctx, ref) { var v = ref[0]; return v.evaluate(ctx).toArray(); } ], 'rgb': [ ColorType, [ NumberType, NumberType, NumberType ], rgba ], 'rgba': [ ColorType, [ NumberType, NumberType, NumberType, NumberType ], rgba ], 'has': { type: BooleanType, overloads: [ [ [StringType], function (ctx, ref) { var key = ref[0]; return has(key.evaluate(ctx), ctx.properties()); } ], [ [ StringType, ObjectType ], function (ctx, ref) { var key = ref[0]; var obj = ref[1]; return has(key.evaluate(ctx), obj.evaluate(ctx)); } ] ] }, 'get': { type: ValueType, overloads: [ [ [StringType], function (ctx, ref) { var key = ref[0]; return get(key.evaluate(ctx), ctx.properties()); } ], [ [ StringType, ObjectType ], function (ctx, ref) { var key = ref[0]; var obj = ref[1]; return get(key.evaluate(ctx), obj.evaluate(ctx)); } ] ] }, 'feature-state': [ ValueType, [StringType], function (ctx, ref) { var key = ref[0]; return get(key.evaluate(ctx), ctx.featureState || {}); } ], 'properties': [ ObjectType, [], function (ctx) { return ctx.properties(); } ], 'geometry-type': [ StringType, [], function (ctx) { return ctx.geometryType(); } ], 'id': [ ValueType, [], function (ctx) { return ctx.id(); } ], 'zoom': [ NumberType, [], function (ctx) { return ctx.globals.zoom; } ], 'pitch': [ NumberType, [], function (ctx) { return ctx.globals.pitch || 0; } ], 'distance-from-center': [ NumberType, [], function (ctx) { return ctx.distanceFromCenter(); } ], 'heatmap-density': [ NumberType, [], function (ctx) { return ctx.globals.heatmapDensity || 0; } ], 'line-progress': [ NumberType, [], function (ctx) { return ctx.globals.lineProgress || 0; } ], 'sky-radial-progress': [ NumberType, [], function (ctx) { return ctx.globals.skyRadialProgress || 0; } ], 'accumulated': [ ValueType, [], function (ctx) { return ctx.globals.accumulated === undefined ? null : ctx.globals.accumulated; } ], '+': [ NumberType, varargs(NumberType), function (ctx, args) { var result = 0; for (var i = 0, list = args; i < list.length; i += 1) { var arg = list[i]; result += arg.evaluate(ctx); } return result; } ], '*': [ NumberType, varargs(NumberType), function (ctx, args) { var result = 1; for (var i = 0, list = args; i < list.length; i += 1) { var arg = list[i]; result *= arg.evaluate(ctx); } return result; } ], '-': { type: NumberType, overloads: [ [ [ NumberType, NumberType ], function (ctx, ref) { var a = ref[0]; var b = ref[1]; return a.evaluate(ctx) - b.evaluate(ctx); } ], [ [NumberType], function (ctx, ref) { var a = ref[0]; return -a.evaluate(ctx); } ] ] }, '/': [ NumberType, [ NumberType, NumberType ], function (ctx, ref) { var a = ref[0]; var b = ref[1]; return a.evaluate(ctx) / b.evaluate(ctx); } ], '%': [ NumberType, [ NumberType, NumberType ], function (ctx, ref) { var a = ref[0]; var b = ref[1]; return a.evaluate(ctx) % b.evaluate(ctx); } ], 'ln2': [ NumberType, [], function () { return Math.LN2; } ], 'pi': [ NumberType, [], function () { return Math.PI; } ], 'e': [ NumberType, [], function () { return Math.E; } ], '^': [ NumberType, [ NumberType, NumberType ], function (ctx, ref) { var b = ref[0]; var e = ref[1]; return Math.pow(b.evaluate(ctx), e.evaluate(ctx)); } ], 'sqrt': [ NumberType, [NumberType], function (ctx, ref) { var x = ref[0]; return Math.sqrt(x.evaluate(ctx)); } ], 'log10': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.log(n.evaluate(ctx)) / Math.LN10; } ], 'ln': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.log(n.evaluate(ctx)); } ], 'log2': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.log(n.evaluate(ctx)) / Math.LN2; } ], 'sin': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.sin(n.evaluate(ctx)); } ], 'cos': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.cos(n.evaluate(ctx)); } ], 'tan': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.tan(n.evaluate(ctx)); } ], 'asin': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.asin(n.evaluate(ctx)); } ], 'acos': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.acos(n.evaluate(ctx)); } ], 'atan': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.atan(n.evaluate(ctx)); } ], 'min': [ NumberType, varargs(NumberType), function (ctx, args) { return Math.min.apply(Math, args.map(function (arg) { return arg.evaluate(ctx); })); } ], 'max': [ NumberType, varargs(NumberType), function (ctx, args) { return Math.max.apply(Math, args.map(function (arg) { return arg.evaluate(ctx); })); } ], 'abs': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.abs(n.evaluate(ctx)); } ], 'round': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; var v = n.evaluate(ctx); // Javascript's Math.round() rounds towards +Infinity for halfway // values, even when they're negative. It's more common to round // away from 0 (e.g., this is what python and C++ do) return v < 0 ? -Math.round(-v) : Math.round(v); } ], 'floor': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.floor(n.evaluate(ctx)); } ], 'ceil': [ NumberType, [NumberType], function (ctx, ref) { var n = ref[0]; return Math.ceil(n.evaluate(ctx)); } ], 'filter-==': [ BooleanType, [ StringType, ValueType ], function (ctx, ref) { var k = ref[0]; var v = ref[1]; return ctx.properties()[k.value] === v.value; } ], 'filter-id-==': [ BooleanType, [ValueType], function (ctx, ref) { var v = ref[0]; return ctx.id() === v.value; } ], 'filter-type-==': [ BooleanType, [StringType], function (ctx, ref) { var v = ref[0]; return ctx.geometryType() === v.value; } ], 'filter-<': [ BooleanType, [ StringType, ValueType ], function (ctx, ref) { var k = ref[0]; var v = ref[1]; var a = ctx.properties()[k.value]; var b = v.value; return typeof a === typeof b && a < b; } ], 'filter-id-<': [ BooleanType, [ValueType], function (ctx, ref) { var v = ref[0]; var a = ctx.id(); var b = v.value; return typeof a === typeof b && a < b; } ], 'filter->': [ BooleanType, [ StringType, ValueType ], function (ctx, ref) { var k = ref[0]; var v = ref[1]; var a = ctx.properties()[k.value]; var b = v.value; return typeof a === typeof b && a > b; } ], 'filter-id->': [ BooleanType, [ValueType], function (ctx, ref) { var v = ref[0]; var a = ctx.id(); var b = v.value; return typeof a === typeof b && a > b; } ], 'filter-<=': [ BooleanType, [ StringType, ValueType ], function (ctx, ref) { var k = ref[0]; var v = ref[1]; var a = ctx.properties()[k.value]; var b = v.value; return typeof a === typeof b && a <= b; } ], 'filter-id-<=': [ BooleanType, [ValueType], function (ctx, ref) { var v = ref[0]; var a = ctx.id(); var b = v.value; return typeof a === typeof b && a <= b; } ], 'filter->=': [ BooleanType, [ StringType, ValueType ], function (ctx, ref) { var k = ref[0]; var v = ref[1]; var a = ctx.properties()[k.value]; var b = v.value; return typeof a === typeof b && a >= b; } ], 'filter-id->=': [ BooleanType, [ValueType], function (ctx, ref) { var v = ref[0]; var a = ctx.id(); var b = v.value; return typeof a === typeof b && a >= b; } ], 'filter-has': [ BooleanType, [ValueType], function (ctx, ref) { var k = ref[0]; return k.value in ctx.properties(); } ], 'filter-has-id': [ BooleanType, [], function (ctx) { return ctx.id() !== null && ctx.id() !== undefined; } ], 'filter-type-in': [ BooleanType, [array$1(StringType)], function (ctx, ref) { var v = ref[0]; return v.value.indexOf(ctx.geometryType()) >= 0; } ], 'filter-id-in': [ BooleanType, [array$1(ValueType)], function (ctx, ref) { var v = ref[0]; return v.value.indexOf(ctx.id()) >= 0; } ], 'filter-in-small': [ BooleanType, [ StringType, array$1(ValueType) ], // assumes v is an array literal function (ctx, ref) { var k = ref[0]; var v = ref[1]; return v.value.indexOf(ctx.properties()[k.value]) >= 0; } ], 'filter-in-large': [ BooleanType, [ StringType, array$1(ValueType) ], // assumes v is a array literal with values sorted in ascending order and of a single type function (ctx, ref) { var k = ref[0]; var v = ref[1]; return binarySearch(ctx.properties()[k.value], v.value, 0, v.value.length - 1); } ], 'all': { type: BooleanType, overloads: [ [ [ BooleanType, BooleanType ], function (ctx, ref) { var a = ref[0]; var b = ref[1]; return a.evaluate(ctx) && b.evaluate(ctx); } ], [ varargs(BooleanType), function (ctx, args) { for (var i = 0, list = args; i < list.length; i += 1) { var arg = list[i]; if (!arg.evaluate(ctx)) { return false; } } return true; } ] ] }, 'any': { type: BooleanType, overloads: [ [ [ BooleanType, BooleanType ], function (ctx, ref) { var a = ref[0]; var b = ref[1]; return a.evaluate(ctx) || b.evaluate(ctx); } ], [ varargs(BooleanType), function (ctx, args) { for (var i = 0, list = args; i < list.length; i += 1) { var arg = list[i]; if (arg.evaluate(ctx)) { return true; } } return false; } ] ] }, '!': [ BooleanType, [BooleanType], function (ctx, ref) { var b = ref[0]; return !b.evaluate(ctx); } ], 'is-supported-script': [ BooleanType, [StringType], // At parse time this will always return true, so we need to exclude this expression with isGlobalPropertyConstant function (ctx, ref) { var s = ref[0]; var isSupportedScript = ctx.globals && ctx.globals.isSupportedScript; if (isSupportedScript) { return isSupportedScript(s.evaluate(ctx)); } return true; } ], 'upcase': [ StringType, [StringType], function (ctx, ref) { var s = ref[0]; return s.evaluate(ctx).toUpperCase(); } ], 'downcase': [ StringType, [StringType], function (ctx, ref) { var s = ref[0]; return s.evaluate(ctx).toLowerCase(); } ], 'concat': [ StringType, varargs(ValueType), function (ctx, args) { return args.map(function (arg) { return toString(arg.evaluate(ctx)); }).join(''); } ], 'resolved-locale': [ StringType, [CollatorType], function (ctx, ref) { var collator = ref[0]; return collator.evaluate(ctx).resolvedLocale(); } ] }); var definitions = expressions; // /** * A type used for returning and propagating errors. The first element of the union * represents success and contains a value, and the second represents an error and * contains an error value. * @private */ function success(value) { return { result: 'success', value: value }; } function error(value) { return { result: 'error', value: value }; } // function supportsPropertyExpression(spec) { return spec['property-type'] === 'data-driven'; } function supportsZoomExpression(spec) { return !!spec.expression && spec.expression.parameters.indexOf('zoom') > -1; } function supportsInterpolation(spec) { return !!spec.expression && spec.expression.interpolated; } function isFunction(value) { return typeof value === 'object' && value !== null && !Array.isArray(value); } var StyleExpression = function StyleExpression(expression, propertySpec) { this.expression = expression; this._warningHistory = {}; this._evaluator = new EvaluationContext$1(); this._defaultValue = propertySpec ? getDefaultValue(propertySpec) : null; this._enumValues = propertySpec && propertySpec.type === 'enum' ? propertySpec.values : null; }; StyleExpression.prototype.evaluateWithoutErrorHandling = function evaluateWithoutErrorHandling (globals, feature, featureState, canonical, availableImages, formattedSection, featureTileCoord, featureDistanceData) { this._evaluator.globals = globals; this._evaluator.feature = feature; this._evaluator.featureState = featureState; this._evaluator.canonical = canonical || null; this._evaluator.availableImages = availableImages || null; this._evaluator.formattedSection = formattedSection; this._evaluator.featureTileCoord = featureTileCoord || null; this._evaluator.featureDistanceData = featureDistanceData || null; return this.expression.evaluate(this._evaluator); }; StyleExpression.prototype.evaluate = function evaluate (globals, feature, featureState, canonical, availableImages, formattedSection, featureTileCoord, featureDistanceData) { this._evaluator.globals = globals; this._evaluator.feature = feature || null; this._evaluator.featureState = featureState || null; this._evaluator.canonical = canonical || null; this._evaluator.availableImages = availableImages || null; this._evaluator.formattedSection = formattedSection || null; this._evaluator.featureTileCoord = featureTileCoord || null; this._evaluator.featureDistanceData = featureDistanceData || null; try { var val = this.expression.evaluate(this._evaluator); // eslint-disable-next-line no-self-compare if (val === null || val === undefined || typeof val === 'number' && val !== val) { return this._defaultValue; } if (this._enumValues && !(val in this._enumValues)) { throw new RuntimeError$1(("Expected value to be one of " + (Object.keys(this._enumValues).map(function (v) { return JSON.stringify(v); }).join(', ')) + ", but found " + (JSON.stringify(val)) + " instead.")); } return val; } catch (e) { if (!this._warningHistory[e.message]) { this._warningHistory[e.message] = true; if (typeof console !== 'undefined') { console.warn(e.message); } } return this._defaultValue; } }; function isExpression(expression) { return Array.isArray(expression) && expression.length > 0 && typeof expression[0] === 'string' && expression[0] in definitions; } /** * Parse and typecheck the given style spec JSON expression. If * options.defaultValue is provided, then the resulting StyleExpression's * `evaluate()` method will handle errors by logging a warning (once per * message) and returning the default value. Otherwise, it will throw * evaluation errors. * * @private */ function createExpression(expression, propertySpec) { var parser = new ParsingContext$1(definitions, [], propertySpec ? getExpectedType(propertySpec) : undefined); // For string-valued properties, coerce to string at the top level rather than asserting. var parsed = parser.parse(expression, undefined, undefined, undefined, propertySpec && propertySpec.type === 'string' ? { typeAnnotation: 'coerce' } : undefined); if (!parsed) { return error(parser.errors); } return success(new StyleExpression(parsed, propertySpec)); } var ZoomConstantExpression = function ZoomConstantExpression(kind, expression) { this.kind = kind; this._styleExpression = expression; this.isStateDependent = kind !== 'constant' && !isStateConstant(expression.expression); }; ZoomConstantExpression.prototype.evaluateWithoutErrorHandling = function evaluateWithoutErrorHandling (globals, feature, featureState, canonical, availableImages, formattedSection) { return this._styleExpression.evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection); }; ZoomConstantExpression.prototype.evaluate = function evaluate (globals, feature, featureState, canonical, availableImages, formattedSection) { return this._styleExpression.evaluate(globals, feature, featureState, canonical, availableImages, formattedSection); }; var ZoomDependentExpression = function ZoomDependentExpression(kind, expression, zoomStops, interpolationType) { this.kind = kind; this.zoomStops = zoomStops; this._styleExpression = expression; this.isStateDependent = kind !== 'camera' && !isStateConstant(expression.expression); this.interpolationType = interpolationType; }; ZoomDependentExpression.prototype.evaluateWithoutErrorHandling = function evaluateWithoutErrorHandling (globals, feature, featureState, canonical, availableImages, formattedSection) { return this._styleExpression.evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection); }; ZoomDependentExpression.prototype.evaluate = function evaluate (globals, feature, featureState, canonical, availableImages, formattedSection) { return this._styleExpression.evaluate(globals, feature, featureState, canonical, availableImages, formattedSection); }; ZoomDependentExpression.prototype.interpolationFactor = function interpolationFactor (input, lower, upper) { if (this.interpolationType) { return Interpolate$1.interpolationFactor(this.interpolationType, input, lower, upper); } else { return 0; } }; function createPropertyExpression(expression, propertySpec) { expression = createExpression(expression, propertySpec); if (expression.result === 'error') { return expression; } var parsed = expression.value.expression; var isFeatureConstant$1 = isFeatureConstant(parsed); if (!isFeatureConstant$1 && !supportsPropertyExpression(propertySpec)) { return error([new ParsingError$1('', 'data expressions not supported')]); } var isZoomConstant = isGlobalPropertyConstant(parsed, [ 'zoom', 'pitch', 'distance-from-center' ]); if (!isZoomConstant && !supportsZoomExpression(propertySpec)) { return error([new ParsingError$1('', 'zoom expressions not supported')]); } var zoomCurve = findZoomCurve(parsed); if (!zoomCurve && !isZoomConstant) { return error([new ParsingError$1('', '"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.')]); } else if (zoomCurve instanceof ParsingError$1) { return error([zoomCurve]); } else if (zoomCurve instanceof Interpolate$1 && !supportsInterpolation(propertySpec)) { return error([new ParsingError$1('', '"interpolate" expressions cannot be used with this property')]); } if (!zoomCurve) { return success(isFeatureConstant$1 ? new ZoomConstantExpression('constant', expression.value) : new ZoomConstantExpression('source', expression.value)); } var interpolationType = zoomCurve instanceof Interpolate$1 ? zoomCurve.interpolation : undefined; return success(isFeatureConstant$1 ? new ZoomDependentExpression('camera', expression.value, zoomCurve.labels, interpolationType) : new ZoomDependentExpression('composite', expression.value, zoomCurve.labels, interpolationType)); } // Zoom-dependent expressions may only use ["zoom"] as the input to a top-level "step" or "interpolate" // expression (collectively referred to as a "curve"). The curve may be wrapped in one or more "let" or // "coalesce" expressions. function findZoomCurve(expression) { var result = null; if (expression instanceof Let$1) { result = findZoomCurve(expression.result); } else if (expression instanceof Coalesce$1) { for (var i = 0, list = expression.args; i < list.length; i += 1) { var arg = list[i]; result = findZoomCurve(arg); if (result) { break; } } } else if ((expression instanceof Step$1 || expression instanceof Interpolate$1) && expression.input instanceof CompoundExpression$1 && expression.input.name === 'zoom') { result = expression; } if (result instanceof ParsingError$1) { return result; } expression.eachChild(function (child) { var childResult = findZoomCurve(child); if (childResult instanceof ParsingError$1) { result = childResult; } else if (!result && childResult) { result = new ParsingError$1('', '"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.'); } else if (result && childResult && result !== childResult) { result = new ParsingError$1('', 'Only one zoom-based "step" or "interpolate" subexpression may be used in an expression.'); } }); return result; } function getExpectedType(spec) { var types = { color: ColorType, string: StringType, number: NumberType, enum: StringType, boolean: BooleanType, formatted: FormattedType, resolvedImage: ResolvedImageType }; if (spec.type === 'array') { return array$1(types[spec.value] || ValueType, spec.length); } return types[spec.type]; } function getDefaultValue(spec) { if (spec.type === 'color' && (isFunction(spec.default) || Array.isArray(spec.default))) { // Special case for heatmap-color: it uses the 'default:' to define a // default color ramp, but createExpression expects a simple value to fall // back to in case of runtime errors return new Color$1(0, 0, 0, 0); } else if (spec.type === 'color') { return Color$1.parse(spec.default) || null; } else if (spec.default === undefined) { return null; } else { return spec.default; } } // // Turn jsonlint-lines-primitives objects into primitive objects function unbundle(value) { if (value instanceof Number || value instanceof String || value instanceof Boolean) { return value.valueOf(); } else { return value; } } function deepUnbundle(value) { if (Array.isArray(value)) { return value.map(deepUnbundle); } else if (value instanceof Object && !(value instanceof Number || value instanceof String || value instanceof Boolean)) { var unbundledValue = {}; for (var key in value) { unbundledValue[key] = deepUnbundle(value[key]); } return unbundledValue; } return unbundle(value); } var spec = {"$version":8,"$root":{"version":{"required":true,"type":"enum","values":[8]},"name":{"type":"string"},"metadata":{"type":"*"},"center":{"type":"array","value":"number"},"zoom":{"type":"number"},"bearing":{"type":"number","default":0,"period":360,"units":"degrees"},"pitch":{"type":"number","default":0,"units":"degrees"},"light":{"type":"light"},"terrain":{"type":"terrain"},"fog":{"type":"fog"},"sources":{"required":true,"type":"sources"},"sprite":{"type":"string"},"glyphs":{"type":"string"},"transition":{"type":"transition"},"projection":{"type":"projection"},"layers":{"required":true,"type":"array","value":"layer"}},"sources":{"*":{"type":"source"}},"source":["source_vector","source_raster","source_raster_dem","source_geojson","source_video","source_image"],"source_vector":{"type":{"required":true,"type":"enum","values":{"vector":{}}},"url":{"type":"string"},"tiles":{"type":"array","value":"string"},"bounds":{"type":"array","value":"number","length":4,"default":[-180,-85.051129,180,85.051129]},"scheme":{"type":"enum","values":{"xyz":{},"tms":{}},"default":"xyz"},"minzoom":{"type":"number","default":0},"maxzoom":{"type":"number","default":22},"attribution":{"type":"string"},"promoteId":{"type":"promoteId"},"volatile":{"type":"boolean","default":false},"*":{"type":"*"}},"source_raster":{"type":{"required":true,"type":"enum","values":{"raster":{}}},"url":{"type":"string"},"tiles":{"type":"array","value":"string"},"bounds":{"type":"array","value":"number","length":4,"default":[-180,-85.051129,180,85.051129]},"minzoom":{"type":"number","default":0},"maxzoom":{"type":"number","default":22},"tileSize":{"type":"number","default":512,"units":"pixels"},"scheme":{"type":"enum","values":{"xyz":{},"tms":{}},"default":"xyz"},"attribution":{"type":"string"},"volatile":{"type":"boolean","default":false},"*":{"type":"*"}},"source_raster_dem":{"type":{"required":true,"type":"enum","values":{"raster-dem":{}}},"url":{"type":"string"},"tiles":{"type":"array","value":"string"},"bounds":{"type":"array","value":"number","length":4,"default":[-180,-85.051129,180,85.051129]},"minzoom":{"type":"number","default":0},"maxzoom":{"type":"number","default":22},"tileSize":{"type":"number","default":512,"units":"pixels"},"attribution":{"type":"string"},"encoding":{"type":"enum","values":{"terrarium":{},"mapbox":{}},"default":"mapbox"},"volatile":{"type":"boolean","default":false},"*":{"type":"*"}},"source_geojson":{"type":{"required":true,"type":"enum","values":{"geojson":{}}},"data":{"type":"*"},"maxzoom":{"type":"number","default":18},"attribution":{"type":"string"},"buffer":{"type":"number","default":128,"maximum":512,"minimum":0},"filter":{"type":"*"},"tolerance":{"type":"number","default":0.375},"cluster":{"type":"boolean","default":false},"clusterRadius":{"type":"number","default":50,"minimum":0},"clusterMaxZoom":{"type":"number"},"clusterMinPoints":{"type":"number"},"clusterProperties":{"type":"*"},"lineMetrics":{"type":"boolean","default":false},"generateId":{"type":"boolean","default":false},"promoteId":{"type":"promoteId"}},"source_video":{"type":{"required":true,"type":"enum","values":{"video":{}}},"urls":{"required":true,"type":"array","value":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"source_image":{"type":{"required":true,"type":"enum","values":{"image":{}}},"url":{"required":true,"type":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"layer":{"id":{"type":"string","required":true},"type":{"type":"enum","values":{"fill":{},"line":{},"symbol":{},"circle":{},"heatmap":{},"fill-extrusion":{},"raster":{},"hillshade":{},"background":{},"sky":{}},"required":true},"metadata":{"type":"*"},"source":{"type":"string"},"source-layer":{"type":"string"},"minzoom":{"type":"number","minimum":0,"maximum":24},"maxzoom":{"type":"number","minimum":0,"maximum":24},"filter":{"type":"filter"},"layout":{"type":"layout"},"paint":{"type":"paint"}},"layout":["layout_fill","layout_line","layout_circle","layout_heatmap","layout_fill-extrusion","layout_symbol","layout_raster","layout_hillshade","layout_background","layout_sky"],"layout_background":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_sky":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_fill":{"fill-sort-key":{"type":"number","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_circle":{"circle-sort-key":{"type":"number","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_heatmap":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_fill-extrusion":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"},"fill-extrusion-edge-radius":{"type":"number","private":true,"default":0,"minimum":0,"maximum":1,"property-type":"constant"}},"layout_line":{"line-cap":{"type":"enum","values":{"butt":{},"round":{},"square":{}},"default":"butt","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"line-join":{"type":"enum","values":{"bevel":{},"round":{},"miter":{}},"default":"miter","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"line-miter-limit":{"type":"number","default":2,"requires":[{"line-join":"miter"}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"line-round-limit":{"type":"number","default":1.05,"requires":[{"line-join":"round"}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"line-sort-key":{"type":"number","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_symbol":{"symbol-placement":{"type":"enum","values":{"point":{},"line":{},"line-center":{}},"default":"point","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"symbol-spacing":{"type":"number","default":250,"minimum":1,"units":"pixels","requires":[{"symbol-placement":"line"}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"symbol-avoid-edges":{"type":"boolean","default":false,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"symbol-sort-key":{"type":"number","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"symbol-z-order":{"type":"enum","values":{"auto":{},"viewport-y":{},"source":{}},"default":"auto","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-allow-overlap":{"type":"boolean","default":false,"requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-ignore-placement":{"type":"boolean","default":false,"requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-optional":{"type":"boolean","default":false,"requires":["icon-image","text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-rotation-alignment":{"type":"enum","values":{"map":{},"viewport":{},"auto":{}},"default":"auto","requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-size":{"type":"number","default":1,"minimum":0,"units":"factor of the original icon size","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-text-fit":{"type":"enum","values":{"none":{},"width":{},"height":{},"both":{}},"default":"none","requires":["icon-image","text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-text-fit-padding":{"type":"array","value":"number","length":4,"default":[0,0,0,0],"units":"pixels","requires":["icon-image","text-field",{"icon-text-fit":["both","width","height"]}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"icon-image":{"type":"resolvedImage","tokens":true,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-rotate":{"type":"number","default":0,"period":360,"units":"degrees","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-padding":{"type":"number","default":2,"minimum":0,"units":"pixels","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"icon-keep-upright":{"type":"boolean","default":false,"requires":["icon-image",{"icon-rotation-alignment":"map"},{"symbol-placement":["line","line-center"]}],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-offset":{"type":"array","value":"number","length":2,"default":[0,0],"requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-anchor":{"type":"enum","values":{"center":{},"left":{},"right":{},"top":{},"bottom":{},"top-left":{},"top-right":{},"bottom-left":{},"bottom-right":{}},"default":"center","requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-pitch-alignment":{"type":"enum","values":{"map":{},"viewport":{},"auto":{}},"default":"auto","requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-pitch-alignment":{"type":"enum","values":{"map":{},"viewport":{},"auto":{}},"default":"auto","requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-rotation-alignment":{"type":"enum","values":{"map":{},"viewport":{},"auto":{}},"default":"auto","requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-field":{"type":"formatted","default":"","tokens":true,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-font":{"type":"array","value":"string","default":["Open Sans Regular","Arial Unicode MS Regular"],"requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-size":{"type":"number","default":16,"minimum":0,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-max-width":{"type":"number","default":10,"minimum":0,"units":"ems","requires":["text-field",{"symbol-placement":["point"]}],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-line-height":{"type":"number","default":1.2,"units":"ems","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-letter-spacing":{"type":"number","default":0,"units":"ems","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-justify":{"type":"enum","values":{"auto":{},"left":{},"center":{},"right":{}},"default":"center","requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-radial-offset":{"type":"number","units":"ems","default":0,"requires":["text-field"],"property-type":"data-driven","expression":{"interpolated":true,"parameters":["zoom","feature"]}},"text-variable-anchor":{"type":"array","value":"enum","values":{"center":{},"left":{},"right":{},"top":{},"bottom":{},"top-left":{},"top-right":{},"bottom-left":{},"bottom-right":{}},"requires":["text-field",{"symbol-placement":["point"]}],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-anchor":{"type":"enum","values":{"center":{},"left":{},"right":{},"top":{},"bottom":{},"top-left":{},"top-right":{},"bottom-left":{},"bottom-right":{}},"default":"center","requires":["text-field",{"!":"text-variable-anchor"}],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-max-angle":{"type":"number","default":45,"units":"degrees","requires":["text-field",{"symbol-placement":["line","line-center"]}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"text-writing-mode":{"type":"array","value":"enum","values":{"horizontal":{},"vertical":{}},"requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-rotate":{"type":"number","default":0,"period":360,"units":"degrees","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-padding":{"type":"number","default":2,"minimum":0,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"text-keep-upright":{"type":"boolean","default":true,"requires":["text-field",{"text-rotation-alignment":"map"},{"symbol-placement":["line","line-center"]}],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-transform":{"type":"enum","values":{"none":{},"uppercase":{},"lowercase":{}},"default":"none","requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-offset":{"type":"array","value":"number","units":"ems","length":2,"default":[0,0],"requires":["text-field",{"!":"text-radial-offset"}],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-allow-overlap":{"type":"boolean","default":false,"requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-ignore-placement":{"type":"boolean","default":false,"requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-optional":{"type":"boolean","default":false,"requires":["text-field","icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_raster":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_hillshade":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"filter":{"type":"array","value":"*"},"filter_symbol":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature","pitch","distance-from-center"]}},"filter_fill":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_line":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_circle":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_fill-extrusion":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_heatmap":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_operator":{"type":"enum","values":{"==":{},"!=":{},">":{},">=":{},"<":{},"<=":{},"in":{},"!in":{},"all":{},"any":{},"none":{},"has":{},"!has":{},"within":{}}},"geometry_type":{"type":"enum","values":{"Point":{},"LineString":{},"Polygon":{}}},"function":{"expression":{"type":"expression"},"stops":{"type":"array","value":"function_stop"},"base":{"type":"number","default":1,"minimum":0},"property":{"type":"string","default":"$zoom"},"type":{"type":"enum","values":{"identity":{},"exponential":{},"interval":{},"categorical":{}},"default":"exponential"},"colorSpace":{"type":"enum","values":{"rgb":{},"lab":{},"hcl":{}},"default":"rgb"},"default":{"type":"*","required":false}},"function_stop":{"type":"array","minimum":0,"maximum":24,"value":["number","color"],"length":2},"expression":{"type":"array","value":"*","minimum":1},"expression_name":{"type":"enum","values":{"let":{"group":"Variable binding"},"var":{"group":"Variable binding"},"literal":{"group":"Types"},"array":{"group":"Types"},"at":{"group":"Lookup"},"in":{"group":"Lookup"},"index-of":{"group":"Lookup"},"slice":{"group":"Lookup"},"case":{"group":"Decision"},"match":{"group":"Decision"},"coalesce":{"group":"Decision"},"step":{"group":"Ramps, scales, curves"},"interpolate":{"group":"Ramps, scales, curves"},"interpolate-hcl":{"group":"Ramps, scales, curves"},"interpolate-lab":{"group":"Ramps, scales, curves"},"ln2":{"group":"Math"},"pi":{"group":"Math"},"e":{"group":"Math"},"typeof":{"group":"Types"},"string":{"group":"Types"},"number":{"group":"Types"},"boolean":{"group":"Types"},"object":{"group":"Types"},"collator":{"group":"Types"},"format":{"group":"Types"},"image":{"group":"Types"},"number-format":{"group":"Types"},"to-string":{"group":"Types"},"to-number":{"group":"Types"},"to-boolean":{"group":"Types"},"to-rgba":{"group":"Color"},"to-color":{"group":"Types"},"rgb":{"group":"Color"},"rgba":{"group":"Color"},"get":{"group":"Lookup"},"has":{"group":"Lookup"},"length":{"group":"Lookup"},"properties":{"group":"Feature data"},"feature-state":{"group":"Feature data"},"geometry-type":{"group":"Feature data"},"id":{"group":"Feature data"},"zoom":{"group":"Camera"},"pitch":{"group":"Camera"},"distance-from-center":{"group":"Camera"},"heatmap-density":{"group":"Heatmap"},"line-progress":{"group":"Feature data"},"sky-radial-progress":{"group":"sky"},"accumulated":{"group":"Feature data"},"+":{"group":"Math"},"*":{"group":"Math"},"-":{"group":"Math"},"/":{"group":"Math"},"%":{"group":"Math"},"^":{"group":"Math"},"sqrt":{"group":"Math"},"log10":{"group":"Math"},"ln":{"group":"Math"},"log2":{"group":"Math"},"sin":{"group":"Math"},"cos":{"group":"Math"},"tan":{"group":"Math"},"asin":{"group":"Math"},"acos":{"group":"Math"},"atan":{"group":"Math"},"min":{"group":"Math"},"max":{"group":"Math"},"round":{"group":"Math"},"abs":{"group":"Math"},"ceil":{"group":"Math"},"floor":{"group":"Math"},"distance":{"group":"Math"},"==":{"group":"Decision"},"!=":{"group":"Decision"},">":{"group":"Decision"},"<":{"group":"Decision"},">=":{"group":"Decision"},"<=":{"group":"Decision"},"all":{"group":"Decision"},"any":{"group":"Decision"},"!":{"group":"Decision"},"within":{"group":"Decision"},"is-supported-script":{"group":"String"},"upcase":{"group":"String"},"downcase":{"group":"String"},"concat":{"group":"String"},"resolved-locale":{"group":"String"}}},"fog":{"range":{"type":"array","default":[0.5,10],"minimum":-20,"maximum":20,"length":2,"value":"number","property-type":"data-constant","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]}},"color":{"type":"color","property-type":"data-constant","default":"#ffffff","expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"high-color":{"type":"color","property-type":"data-constant","default":"#245cdf","expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"space-color":{"type":"color","property-type":"data-constant","default":["interpolate",["linear"],["zoom"],4,"#010b19",7,"#367ab9"],"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"horizon-blend":{"type":"number","property-type":"data-constant","default":["interpolate",["linear"],["zoom"],4,0.2,7,0.1],"minimum":0,"maximum":1,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"star-intensity":{"type":"number","property-type":"data-constant","default":["interpolate",["linear"],["zoom"],5,0.35,6,0],"minimum":0,"maximum":1,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true}},"light":{"anchor":{"type":"enum","default":"viewport","values":{"map":{},"viewport":{}},"property-type":"data-constant","transition":false,"expression":{"interpolated":false,"parameters":["zoom"]}},"position":{"type":"array","default":[1.15,210,30],"length":3,"value":"number","property-type":"data-constant","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]}},"color":{"type":"color","property-type":"data-constant","default":"#ffffff","expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"intensity":{"type":"number","property-type":"data-constant","default":0.5,"minimum":0,"maximum":1,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true}},"projection":{"name":{"type":"enum","values":{"albers":{},"equalEarth":{},"equirectangular":{},"lambertConformalConic":{},"mercator":{},"naturalEarth":{},"winkelTripel":{},"globe":{}},"default":"mercator","required":true},"center":{"type":"array","length":2,"value":"number","property-type":"data-constant","minimum":[-180,-90],"maximum":[180,90],"transition":false,"requires":[{"name":["albers","lambertConformalConic"]}]},"parallels":{"type":"array","length":2,"value":"number","property-type":"data-constant","minimum":[-90,-90],"maximum":[90,90],"transition":false,"requires":[{"name":["albers","lambertConformalConic"]}]}},"terrain":{"source":{"type":"string","required":true},"exaggeration":{"type":"number","property-type":"data-constant","default":1,"minimum":0,"maximum":1000,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true,"requires":["source"]}},"paint":["paint_fill","paint_line","paint_circle","paint_heatmap","paint_fill-extrusion","paint_symbol","paint_raster","paint_hillshade","paint_background","paint_sky"],"paint_fill":{"fill-antialias":{"type":"boolean","default":true,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"fill-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-color":{"type":"color","default":"#000000","transition":true,"requires":[{"!":"fill-pattern"}],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-outline-color":{"type":"color","transition":true,"requires":[{"!":"fill-pattern"},{"fill-antialias":true}],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"fill-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["fill-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"fill-pattern":{"type":"resolvedImage","transition":false,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"}},"paint_fill-extrusion":{"fill-extrusion-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"fill-extrusion-color":{"type":"color","default":"#000000","transition":true,"requires":[{"!":"fill-extrusion-pattern"}],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-extrusion-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"fill-extrusion-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["fill-extrusion-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"fill-extrusion-pattern":{"type":"resolvedImage","transition":false,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"fill-extrusion-height":{"type":"number","default":0,"minimum":0,"units":"meters","transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-extrusion-base":{"type":"number","default":0,"minimum":0,"units":"meters","transition":true,"requires":["fill-extrusion-height"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-extrusion-vertical-gradient":{"type":"boolean","default":true,"transition":false,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"fill-extrusion-ambient-occlusion-intensity":{"property-type":"data-constant","type":"number","private":true,"default":0,"minimum":0,"maximum":1,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"fill-extrusion-ambient-occlusion-radius":{"property-type":"data-constant","type":"number","private":true,"default":3,"minimum":0,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true,"requires":["fill-extrusion-edge-radius"]}},"paint_line":{"line-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-color":{"type":"color","default":"#000000","transition":true,"requires":[{"!":"line-pattern"}],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"line-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["line-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"line-width":{"type":"number","default":1,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-gap-width":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-offset":{"type":"number","default":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-blur":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-dasharray":{"type":"array","value":"number","minimum":0,"transition":false,"units":"line widths","requires":[{"!":"line-pattern"}],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"line-pattern":{"type":"resolvedImage","transition":false,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"line-gradient":{"type":"color","transition":false,"requires":[{"!":"line-pattern"},{"source":"geojson","has":{"lineMetrics":true}}],"expression":{"interpolated":true,"parameters":["line-progress"]},"property-type":"color-ramp"},"line-trim-offset":{"type":"array","value":"number","length":2,"default":[0,0],"minimum":[0,0],"maximum":[1,1],"transition":false,"requires":[{"source":"geojson","has":{"lineMetrics":true}}],"property-type":"constant"}},"paint_circle":{"circle-radius":{"type":"number","default":5,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-color":{"type":"color","default":"#000000","transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-blur":{"type":"number","default":0,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"circle-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["circle-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"circle-pitch-scale":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"circle-pitch-alignment":{"type":"enum","values":{"map":{},"viewport":{}},"default":"viewport","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"circle-stroke-width":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-stroke-color":{"type":"color","default":"#000000","transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-stroke-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"}},"paint_heatmap":{"heatmap-radius":{"type":"number","default":30,"minimum":1,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"heatmap-weight":{"type":"number","default":1,"minimum":0,"transition":false,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"heatmap-intensity":{"type":"number","default":1,"minimum":0,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"heatmap-color":{"type":"color","default":["interpolate",["linear"],["heatmap-density"],0,"rgba(0, 0, 255, 0)",0.1,"royalblue",0.3,"cyan",0.5,"lime",0.7,"yellow",1,"red"],"transition":false,"expression":{"interpolated":true,"parameters":["heatmap-density"]},"property-type":"color-ramp"},"heatmap-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_symbol":{"icon-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-color":{"type":"color","default":"#000000","transition":true,"requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","transition":true,"requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-halo-width":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-halo-blur":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"icon-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["icon-image","icon-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-color":{"type":"color","default":"#000000","transition":true,"overridable":true,"requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","transition":true,"requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-halo-width":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-halo-blur":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"text-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["text-field","text-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_raster":{"raster-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-hue-rotate":{"type":"number","default":0,"period":360,"transition":true,"units":"degrees","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-brightness-min":{"type":"number","default":0,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-brightness-max":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-saturation":{"type":"number","default":0,"minimum":-1,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-contrast":{"type":"number","default":0,"minimum":-1,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-resampling":{"type":"enum","values":{"linear":{},"nearest":{}},"default":"linear","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"raster-fade-duration":{"type":"number","default":300,"minimum":0,"transition":false,"units":"milliseconds","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_hillshade":{"hillshade-illumination-direction":{"type":"number","default":335,"minimum":0,"maximum":359,"transition":false,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-illumination-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"viewport","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-exaggeration":{"type":"number","default":0.5,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-shadow-color":{"type":"color","default":"#000000","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-highlight-color":{"type":"color","default":"#FFFFFF","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-accent-color":{"type":"color","default":"#000000","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_background":{"background-color":{"type":"color","default":"#000000","transition":true,"requires":[{"!":"background-pattern"}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"background-pattern":{"type":"resolvedImage","transition":false,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"background-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_sky":{"sky-type":{"type":"enum","values":{"gradient":{},"atmosphere":{}},"default":"atmosphere","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"sky-atmosphere-sun":{"type":"array","value":"number","length":2,"units":"degrees","minimum":[0,0],"maximum":[360,180],"transition":false,"requires":[{"sky-type":"atmosphere"}],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"sky-atmosphere-sun-intensity":{"type":"number","requires":[{"sky-type":"atmosphere"}],"default":10,"minimum":0,"maximum":100,"transition":false,"property-type":"data-constant"},"sky-gradient-center":{"type":"array","requires":[{"sky-type":"gradient"}],"value":"number","default":[0,0],"length":2,"units":"degrees","minimum":[0,0],"maximum":[360,180],"transition":false,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"sky-gradient-radius":{"type":"number","requires":[{"sky-type":"gradient"}],"default":90,"minimum":0,"maximum":180,"transition":false,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"sky-gradient":{"type":"color","default":["interpolate",["linear"],["sky-radial-progress"],0.8,"#87ceeb",1,"white"],"transition":false,"requires":[{"sky-type":"gradient"}],"expression":{"interpolated":true,"parameters":["sky-radial-progress"]},"property-type":"color-ramp"},"sky-atmosphere-halo-color":{"type":"color","default":"white","transition":false,"requires":[{"sky-type":"atmosphere"}],"property-type":"data-constant"},"sky-atmosphere-color":{"type":"color","default":"white","transition":false,"requires":[{"sky-type":"atmosphere"}],"property-type":"data-constant"},"sky-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"transition":{"duration":{"type":"number","default":300,"minimum":0,"units":"milliseconds"},"delay":{"type":"number","default":0,"minimum":0,"units":"milliseconds"}},"property-type":{"data-driven":{"type":"property-type"},"color-ramp":{"type":"property-type"},"data-constant":{"type":"property-type"},"constant":{"type":"property-type"}},"promoteId":{"*":{"type":"string"}}}; // function isExpressionFilter(filter) { if (filter === true || filter === false) { return true; } if (!Array.isArray(filter) || filter.length === 0) { return false; } switch (filter[0]) { case 'has': return filter.length >= 2 && filter[1] !== '$id' && filter[1] !== '$type'; case 'in': return filter.length >= 3 && (typeof filter[1] !== 'string' || Array.isArray(filter[2])); case '!in': case '!has': case 'none': return false; case '==': case '!=': case '>': case '>=': case '<': case '<=': return filter.length !== 3 || (Array.isArray(filter[1]) || Array.isArray(filter[2])); case 'any': case 'all': for (var i = 0, list = filter.slice(1); i < list.length; i += 1) { var f = list[i]; if (!isExpressionFilter(f) && typeof f !== 'boolean') { return false; } } return true; default: return true; } } /** * Given a filter expressed as nested arrays, return a new function * that evaluates whether a given feature (with a .properties or .tags property) * passes its test. * * @private * @param {Array} filter mapbox gl filter * @param {string} layerType the type of the layer this filter will be applied to. * @returns {Function} filter-evaluating function */ function createFilter(filter, layerType) { if ( layerType === void 0 ) layerType = 'fill'; if (filter === null || filter === undefined) { return { filter: function () { return true; }, needGeometry: false, needFeature: false }; } if (!isExpressionFilter(filter)) { filter = convertFilter(filter); } var filterExp = filter; var staticFilter = true; try { staticFilter = extractStaticFilter(filterExp); } catch (e) { console.warn(("Failed to extract static filter. Filter will continue working, but at higher memory usage and slower framerate.\nThis is most likely a bug, please report this via https://github.com/mapbox/mapbox-gl-js/issues/new?assignees=&labels=&template=Bug_report.md\nand paste the contents of this message in the report.\nThank you!\nFilter Expression:\n" + (JSON.stringify(filterExp, null, 2)) + "\n ")); } // Compile the static component of the filter var filterSpec = spec[("filter_" + layerType)]; var compiledStaticFilter = createExpression(staticFilter, filterSpec); var filterFunc = null; if (compiledStaticFilter.result === 'error') { throw new Error(compiledStaticFilter.value.map(function (err) { return ((err.key) + ": " + (err.message)); }).join(', ')); } else { filterFunc = function (globalProperties, feature, canonical) { return compiledStaticFilter.value.evaluate(globalProperties, feature, {}, canonical); }; } // If the static component is not equal to the entire filter then we have a dynamic component // Compile the dynamic component separately var dynamicFilterFunc = null; var needFeature = null; if (staticFilter !== filterExp) { var compiledDynamicFilter = createExpression(filterExp, filterSpec); if (compiledDynamicFilter.result === 'error') { throw new Error(compiledDynamicFilter.value.map(function (err) { return ((err.key) + ": " + (err.message)); }).join(', ')); } else { dynamicFilterFunc = function (globalProperties, feature, canonical, featureTileCoord, featureDistanceData) { return compiledDynamicFilter.value.evaluate(globalProperties, feature, {}, canonical, undefined, undefined, featureTileCoord, featureDistanceData); }; needFeature = !isFeatureConstant(compiledDynamicFilter.value.expression); } } filterFunc = filterFunc; var needGeometry = geometryNeeded(staticFilter); return { filter: filterFunc, dynamicFilter: dynamicFilterFunc ? dynamicFilterFunc : undefined, needGeometry: needGeometry, needFeature: !!needFeature }; } function extractStaticFilter(filter) { if (!isDynamicFilter(filter)) { return filter; } // Shallow copy so we can replace expressions in-place var result = deepUnbundle(filter); // 1. Union branches unionDynamicBranches(result); // 2. Collapse dynamic conditions to `true` result = collapseDynamicBooleanExpressions(result); return result; } function collapseDynamicBooleanExpressions(expression) { if (!Array.isArray(expression)) { return expression; } var collapsed = collapsedExpression(expression); if (collapsed === true) { return collapsed; } else { return collapsed.map(function (subExpression) { return collapseDynamicBooleanExpressions(subExpression); }); } } /** * Traverses the expression and replaces all instances of branching on a * `dynamic` conditional (such as `['pitch']` or `['distance-from-center']`) * into an `any` expression. * This ensures that all possible outcomes of a `dynamic` branch are considered * when evaluating the expression upfront during filtering. * * @param {Array} filter the filter expression mutated in-place. */ function unionDynamicBranches(filter) { var isBranchingDynamically = false; var branches = []; if (filter[0] === 'case') { for (var i = 1; i < filter.length - 1; i += 2) { isBranchingDynamically = isBranchingDynamically || isDynamicFilter(filter[i]); branches.push(filter[i + 1]); } branches.push(filter[filter.length - 1]); } else if (filter[0] === 'match') { isBranchingDynamically = isBranchingDynamically || isDynamicFilter(filter[1]); for (var i$1 = 2; i$1 < filter.length - 1; i$1 += 2) { branches.push(filter[i$1 + 1]); } branches.push(filter[filter.length - 1]); } else if (filter[0] === 'step') { isBranchingDynamically = isBranchingDynamically || isDynamicFilter(filter[1]); for (var i$2 = 1; i$2 < filter.length - 1; i$2 += 2) { branches.push(filter[i$2 + 1]); } } if (isBranchingDynamically) { filter.length = 0; filter.push.apply(filter, [ 'any' ].concat( branches )); } // traverse and recurse into children for (var i$3 = 1; i$3 < filter.length; i$3++) { unionDynamicBranches(filter[i$3]); } } function isDynamicFilter(filter) { // Base Cases if (!Array.isArray(filter)) { return false; } if (isRootExpressionDynamic(filter[0])) { return true; } for (var i = 1; i < filter.length; i++) { var child = filter[i]; if (isDynamicFilter(child)) { return true; } } return false; } function isRootExpressionDynamic(expression) { return expression === 'pitch' || expression === 'distance-from-center'; } var dynamicConditionExpressions = new Set([ 'in', '==', '!=', '>', '>=', '<', '<=', 'to-boolean' ]); function collapsedExpression(expression) { if (dynamicConditionExpressions.has(expression[0])) { for (var i = 1; i < expression.length; i++) { var param = expression[i]; if (isDynamicFilter(param)) { return true; } } } return expression; } // Comparison function to sort numbers and strings function compare(a, b) { return a < b ? -1 : a > b ? 1 : 0; } function geometryNeeded(filter) { if (!Array.isArray(filter)) { return false; } if (filter[0] === 'within') { return true; } for (var index = 1; index < filter.length; index++) { if (geometryNeeded(filter[index])) { return true; } } return false; } function convertFilter(filter) { if (!filter) { return true; } var op = filter[0]; if (filter.length <= 1) { return op !== 'any'; } var converted = op === '==' ? convertComparisonOp(filter[1], filter[2], '==') : op === '!=' ? convertNegation(convertComparisonOp(filter[1], filter[2], '==')) : op === '<' || op === '>' || op === '<=' || op === '>=' ? convertComparisonOp(filter[1], filter[2], op) : op === 'any' ? convertDisjunctionOp(filter.slice(1)) : op === 'all' ? ['all'].concat(filter.slice(1).map(convertFilter)) : op === 'none' ? ['all'].concat(filter.slice(1).map(convertFilter).map(convertNegation)) : op === 'in' ? convertInOp(filter[1], filter.slice(2)) : op === '!in' ? convertNegation(convertInOp(filter[1], filter.slice(2))) : op === 'has' ? convertHasOp(filter[1]) : op === '!has' ? convertNegation(convertHasOp(filter[1])) : op === 'within' ? filter : true; return converted; } function convertComparisonOp(property, value, op) { switch (property) { case '$type': return [ ("filter-type-" + op), value ]; case '$id': return [ ("filter-id-" + op), value ]; default: return [ ("filter-" + op), property, value ]; } } function convertDisjunctionOp(filters) { return ['any'].concat(filters.map(convertFilter)); } function convertInOp(property, values) { if (values.length === 0) { return false; } switch (property) { case '$type': return [ "filter-type-in", [ 'literal', values ] ]; case '$id': return [ "filter-id-in", [ 'literal', values ] ]; default: if (values.length > 200 && !values.some(function (v) { return typeof v !== typeof values[0]; })) { return [ 'filter-in-large', property, [ 'literal', values.sort(compare) ] ]; } else { return [ 'filter-in-small', property, [ 'literal', values ] ]; } } } function convertHasOp(property) { switch (property) { case '$type': return true; case '$id': return ["filter-has-id"]; default: return [ "filter-has", property ]; } } function convertNegation(filter) { return [ '!', filter ]; } // var refProperties = [ 'type', 'source', 'source-layer', 'minzoom', 'maxzoom', 'filter', 'layout' ]; // function deref(layer, parent) { var result = {}; for (var k in layer) { if (k !== 'ref') { result[k] = layer[k]; } } refProperties.forEach(function (k) { if (k in parent) { result[k] = parent[k]; } }); return result; } /** * Given an array of layers, some of which may contain `ref` properties * whose value is the `id` of another property, return a new array where * such layers have been augmented with the 'type', 'source', etc. properties * from the parent layer, and the `ref` property has been removed. * * The input is not modified. The output may contain references to portions * of the input. * * @private * @param {Array} layers * @returns {Array} */ function derefLayers(layers) { layers = layers.slice(); var map = Object.create(null); for (var i = 0; i < layers.length; i++) { map[layers[i].id] = layers[i]; } for (var i$1 = 0; i$1 < layers.length; i$1++) { if ('ref' in layers[i$1]) { layers[i$1] = deref(layers[i$1], map[layers[i$1].ref]); } } return layers; } var fontWeights = { thin: 100, hairline: 100, 'ultra-light': 100, 'extra-light': 100, light: 200, book: 300, regular: 400, normal: 400, plain: 400, roman: 400, standard: 400, medium: 500, 'semi-bold': 600, 'demi-bold': 600, bold: 700, heavy: 800, black: 800, 'extra-bold': 800, 'ultra-black': 900, 'extra-black': 900, 'ultra-bold': 900, 'heavy-black': 900, fat: 900, poster: 900 }; var sp = ' '; var italicRE = /(italic|oblique)$/i; var fontCache = {}; var mapboxToCssFont = function (fonts, size, lineHeight) { var cssData = fontCache[fonts]; if (!cssData) { if (!Array.isArray(fonts)) { fonts = [fonts]; } var weight = 400; var style = 'normal'; var fontFamilies = []; var haveWeight, haveStyle; for (var i = 0, ii = fonts.length; i < ii; ++i) { var font = fonts[i]; var parts = font.split(' '); var maybeWeight = parts[parts.length - 1].toLowerCase(); if (maybeWeight == 'normal' || maybeWeight == 'italic' || maybeWeight == 'oblique') { style = haveStyle ? style : maybeWeight; parts.pop(); maybeWeight = parts[parts.length - 1].toLowerCase(); } else if (italicRE.test(maybeWeight)) { maybeWeight = maybeWeight.replace(italicRE, ''); style = haveStyle ? style : parts[parts.length - 1].replace(maybeWeight, ''); } for (var w in fontWeights) { var previousPart = parts.length > 1 ? parts[parts.length - 2].toLowerCase() : ''; if (maybeWeight == w || maybeWeight == w.replace('-', '') || previousPart + '-' + maybeWeight == w) { weight = haveWeight ? weight : fontWeights[w]; parts.pop(); if (previousPart && w.startsWith(previousPart)) { parts.pop(); } break; } } if (!haveWeight && typeof maybeWeight == 'number') { weight = maybeWeight; } var fontFamily = parts.join(sp).replace('Klokantech Noto Sans', 'Noto Sans'); if (fontFamily.indexOf(sp) !== -1) { fontFamily = '"' + fontFamily + '"'; } fontFamilies.push(fontFamily); } // CSS font property: font-style font-weight font-size/line-height font-family cssData = fontCache[fonts] = [ style, weight, fontFamilies ]; } return cssData[0] + sp + cssData[1] + sp + size + 'px' + (lineHeight ? '/' + lineHeight : '') + sp + cssData[2]; }; var mb2css = /*@__PURE__*/getDefaultExportFromCjs(mapboxToCssFont); /** * Generates a shaded relief image given elevation data. Uses a 3x3 * neighborhood for determining slope and aspect. * @param {Array} inputs Array of input images. * @param {Object} data Data added in the "beforeoperations" event. * @return {ImageData} Output image. */ function hillshade(inputs, data) { var elevationImage = inputs[0]; var width = elevationImage.width; var height = elevationImage.height; var elevationData = elevationImage.data; var shadeData = new Uint8ClampedArray(elevationData.length); var dp = data.resolution * 2; var maxX = width - 1; var maxY = height - 1; var pixel = [ 0, 0, 0, 0 ]; var twoPi = 2 * Math.PI; var halfPi = Math.PI / 2; var sunEl = Math.PI * data.sunEl / 180; var sunAz = Math.PI * data.sunAz / 180; var cosSunEl = Math.cos(sunEl); var sinSunEl = Math.sin(sunEl); var highlightColor = data.highlightColor; var shadowColor = data.shadowColor; var accentColor = data.accentColor; var encoding = data.encoding; var pixelX, pixelY, x0, x1, y0, y1, offset, z0, z1, dzdx, dzdy, slope, aspect, accent, scaled, shade, scaledAccentColor, compositeShadeColor, clamp, slopeScaleBase, scaledSlope, cosIncidence; function calculateElevation(pixel, encoding) { if ( encoding === void 0 ) encoding = 'mapbox'; // The method used to extract elevations from the DEM. // // The supported methods are the Mapbox format // (red * 256 * 256 + green * 256 + blue) * 0.1 - 10000 // and the Terrarium format // (red * 256 + green + blue / 256) - 32768 // if (encoding === 'mapbox') { return (pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1 - 10000; } if (encoding === 'terrarium') { return pixel[0] * 256 + pixel[1] + pixel[2] / 256 - 32768; } } for (pixelY = 0; pixelY <= maxY; ++pixelY) { y0 = pixelY === 0 ? 0 : pixelY - 1; y1 = pixelY === maxY ? maxY : pixelY + 1; for (pixelX = 0; pixelX <= maxX; ++pixelX) { x0 = pixelX === 0 ? 0 : pixelX - 1; x1 = pixelX === maxX ? maxX : pixelX + 1; // determine elevation for (x0, pixelY) offset = (pixelY * width + x0) * 4; pixel[0] = elevationData[offset]; pixel[1] = elevationData[offset + 1]; pixel[2] = elevationData[offset + 2]; pixel[3] = elevationData[offset + 3]; z0 = data.vert * calculateElevation(pixel, encoding); // determine elevation for (x1, pixelY) offset = (pixelY * width + x1) * 4; pixel[0] = elevationData[offset]; pixel[1] = elevationData[offset + 1]; pixel[2] = elevationData[offset + 2]; pixel[3] = elevationData[offset + 3]; z1 = data.vert * calculateElevation(pixel, encoding); dzdx = (z1 - z0) / dp; // determine elevation for (pixelX, y0) offset = (y0 * width + pixelX) * 4; pixel[0] = elevationData[offset]; pixel[1] = elevationData[offset + 1]; pixel[2] = elevationData[offset + 2]; pixel[3] = elevationData[offset + 3]; z0 = data.vert * calculateElevation(pixel, encoding); // determine elevation for (pixelX, y1) offset = (y1 * width + pixelX) * 4; pixel[0] = elevationData[offset]; pixel[1] = elevationData[offset + 1]; pixel[2] = elevationData[offset + 2]; pixel[3] = elevationData[offset + 3]; z1 = data.vert * calculateElevation(pixel, encoding); dzdy = (z1 - z0) / dp; aspect = Math.atan2(dzdy, -dzdx); if (aspect < 0) { aspect = halfPi - aspect; } else if (aspect > halfPi) { aspect = twoPi - aspect + halfPi; } else { aspect = halfPi - aspect; } // Bootstrap slope and corresponding incident values slope = Math.atan(Math.sqrt(dzdx * dzdx + dzdy * dzdy)); cosIncidence = sinSunEl * Math.cos(slope) + cosSunEl * Math.sin(slope) * Math.cos(sunAz - aspect); accent = Math.cos(slope); // 255 for Hex colors scaled = 255 * cosIncidence; /* * The following is heavily inspired * by [Maplibre's equivalent WebGL shader](https://github.com/maplibre/maplibre-gl-js/blob/main/src/shaders/hillshade.fragment.glsl) */ // Forces given value to stay between two given extremes clamp = Math.min(Math.max(2 * data.sunEl, 0), 1); // Intensity basis for hillshade opacity slopeScaleBase = 1.875 - data.opacity * 1.75; // Intensity interpolation so that higher intensity values create more opaque hillshading scaledSlope = data.opacity !== 0.5 ? halfPi * ((Math.pow(slopeScaleBase, slope) - 1) / (Math.pow(slopeScaleBase, halfPi) - 1)) : slope; // Accent hillshade color with given accentColor to emphasize rougher terrain scaledAccentColor = { r: (1 - accent) * accentColor.r * clamp * 255, g: (1 - accent) * accentColor.g * clamp * 255, b: (1 - accent) * accentColor.b * clamp * 255, a: (1 - accent) * accentColor.a * clamp * 255 }; // Allows highlight vs shadow discrimination shade = Math.abs(((aspect + sunAz) / Math.PI + 0.5) % 2 - 1); // Creates a composite color mix between highlight & shadow colors to emphasize slopes compositeShadeColor = { r: (highlightColor.r * (1 - shade) + shadowColor.r * shade) * scaled, g: (highlightColor.g * (1 - shade) + shadowColor.g * shade) * scaled, b: (highlightColor.b * (1 - shade) + shadowColor.b * shade) * scaled, a: (highlightColor.a * (1 - shade) + shadowColor.a * shade) * scaled }; // Fill in result color value offset = (pixelY * width + pixelX) * 4; shadeData[offset] = scaledAccentColor.r * (1 - shade) + compositeShadeColor.r; shadeData[offset + 1] = scaledAccentColor.g * (1 - shade) + compositeShadeColor.g; shadeData[offset + 2] = scaledAccentColor.b * (1 - shade) + compositeShadeColor.b; // Key opacity on the scaledSlope to improve legibility by increasing higher elevation rates' contrast shadeData[offset + 3] = elevationData[offset + 3] * data.opacity * clamp * Math.sin(scaledSlope); } } return new ImageData(shadeData, width, height); } var mapboxBaseUrl = 'https://api.mapbox.com'; /** * Gets the path from a mapbox:// URL. * @param {string} url The Mapbox URL. * @return {string} The path. * @private */ function getMapboxPath(url) { var startsWith = 'mapbox://'; if (url.indexOf(startsWith) !== 0) { return ''; } return url.slice(startsWith.length); } /** * Turns mapbox:// sprite URLs into resolvable URLs. * @param {string} url The sprite URL. * @param {string} token The access token. * @param {string} styleUrl The style URL. * @return {string} A resolvable URL. * @private */ function normalizeSpriteUrl(url, token, styleUrl) { var mapboxPath = getMapboxPath(url); if (!mapboxPath) { return decodeURI(new URL(url, styleUrl).href); } var startsWith = 'sprites/'; if (mapboxPath.indexOf(startsWith) !== 0) { throw new Error(("unexpected sprites url: " + url)); } var sprite = mapboxPath.slice(startsWith.length); return (mapboxBaseUrl + "/styles/v1/" + sprite + "/sprite?access_token=" + token); } /** * Turns mapbox:// style URLs into resolvable URLs. * @param {string} url The style URL. * @param {string} token The access token. * @return {string} A resolvable URL. * @private */ function normalizeStyleUrl(url, token) { var mapboxPath = getMapboxPath(url); if (!mapboxPath) { return decodeURI(new URL(url, location.href).href); } var startsWith = 'styles/'; if (mapboxPath.indexOf(startsWith) !== 0) { throw new Error(("unexpected style url: " + url)); } var style = mapboxPath.slice(startsWith.length); return (mapboxBaseUrl + "/styles/v1/" + style + "?&access_token=" + token); } /** * Turns mapbox:// source URLs into vector tile URL templates. * @param {string} url The source URL. * @param {string} token The access token. * @param {string} tokenParam The access token key. * @param {string} styleUrl The style URL. * @return {string} A vector tile template. * @private */ function normalizeSourceUrl(url, token, tokenParam, styleUrl) { var urlObject = new URL(url, styleUrl); var mapboxPath = getMapboxPath(url); if (!mapboxPath) { if (!token) { return decodeURI(urlObject.href); } urlObject.searchParams.set(tokenParam, token); return decodeURI(urlObject.href); } if (mapboxPath === 'mapbox.satellite') { var sizeFactor = window.devicePixelRatio >= 1.5 ? '@2x' : ''; return ("https://api.mapbox.com/v4/" + mapboxPath + "/{z}/{x}/{y}" + sizeFactor + ".webp?access_token=" + token); } return ("https://{a-d}.tiles.mapbox.com/v4/" + mapboxPath + "/{z}/{x}/{y}.vector.pbf?access_token=" + token); } /* ol-mapbox-style - Use Mapbox Style objects with OpenLayers Copyright 2016-present ol-mapbox-style contributors License: https://raw.githubusercontent.com/openlayers/ol-mapbox-style/master/LICENSE */ /** * @typedef {Object} Options * @property {string} [accessToken] Access token for 'mapbox://' urls. * @property {function(string, ResourceType): (Request|void)} [transformRequest] * Function for controlling how `ol-mapbox-style` fetches resources. Can be used for modifying * the url, adding headers or setting credentials options. Called with the url and the resource * type as arguments, this function is supposed to return a `Request` object. Without a return value, * the original request will not be modified. For `Tiles` and `GeoJSON` resources, only the `url` of * the returned request will be respected. * @property {string} [projection='EPSG:3857'] Only useful when working with non-standard projections. * Code of a projection registered with OpenLayers. All sources of the style must be provided in this * projection. The projection must also have a valid extent defined, which will be used to determine the * origin and resolutions of the tile grid for all tiled sources of the style. When provided, the bbox * placeholder in tile and geojson urls changes: the default is `{bbox-epsg-3857}`, when projection is e.g. * set to `EPSG:4326`, the bbox placeholder will be `{bbox-epsg-4326}`. * @property {Array} [resolutions] Only useful when working with non-standard projections. * Resolutions for mapping resolution to the `zoom` used in the Mapbox style. * @property {string} [styleUrl] URL of the Mapbox GL style. Required for styles that were provided * as object, when they contain a relative sprite url, or sources referencing data by relative url. * @property {function(VectorLayer|VectorTileLayer, string):HTMLImageElement|HTMLCanvasElement|string|undefined} [getImage=undefined] * Function that returns an image for an icon name. If the result is an HTMLImageElement, it must already be * loaded. The layer can be used to call layer.changed() when the loading and processing of the image has finished. * This function be used for icons not in the sprite or to override sprite icons. * @property {string} [accessTokenParam='access_token'] Access token param. For internal use. */ /** * @typedef {Object} ApplyStyleOptions * @property {string} [source=''] Source. Default is `''`, which causes the first source in the * style to be used. * @property {Array} [layers] Layers. If no source is provided, the layers with the * provided ids will be used from the style's `layers` array. All layers need to use the same source. * @property {boolean} [updateSource=true] Update or create vector (tile) layer source with parameters * specified for the source in the mapbox style definition. */ /** @typedef {'Style'|'Source'|'Sprite'|'SpriteImage'|'Tiles'|'GeoJSON'} ResourceType */ /** * @param {import("ol/proj/Projection.js").default} projection Projection. * @param {number} [tileSize=512] Tile size. * @return {Array} Resolutions. */ function getTileResolutions(projection, tileSize) { if ( tileSize === void 0 ) tileSize = 512; return projection.getExtent() ? createXYZ({ extent: projection.getExtent(), tileSize: tileSize, maxZoom: 22 }).getResolutions() : defaultResolutions; } /** * @param {string} styleUrl Style URL. * @param {Options} options Options. * @return {Options} Completed options with accessToken and accessTokenParam. */ function completeOptions(styleUrl, options) { if (!options.accessToken) { options = Object.assign({}, options); var searchParams = new URL(styleUrl).searchParams; // The last search parameter is the access token searchParams.forEach(function (value, key) { options.accessToken = value; options.accessTokenParam = key; }); } return options; } /** * Applies a style function to an `ol/layer/VectorTile` or `ol/layer/Vector` * with an `ol/source/VectorTile` or an `ol/source/Vector`. If the layer does not have a source * yet, it will be created and populated from the information in the `glStyle` (unless `updateSource` is * set to `false`). * * **Example:** * ```js * import {applyStyle} from 'ol-mapbox-style'; * import {VectorTile} from 'ol/layer.js'; * * const layer = new VectorTile({declutter: true}); * applyStyle(layer, 'https://api.maptiler.com/maps/basic/style.json?key=YOUR_OPENMAPTILES_TOKEN'); * ``` * * The style function will render all layers from the `glStyle` object that use the source * of the first layer, the specified `source`, or a subset of layers from the same source. The * source needs to be a `"type": "vector"` or `"type": "geojson"` source. * * Two additional properties will be set on the provided layer: * * * `mapbox-source`: The `id` of the Mapbox Style document's source that the * OpenLayers layer was created from. Usually `apply()` creates one * OpenLayers layer per Mapbox Style source, unless the layer stack has * layers from different sources in between. * * `mapbox-layers`: The `id`s of the Mapbox Style document's layers that are * included in the OpenLayers layer. * * @param {VectorTileLayer|VectorLayer} layer OpenLayers layer. When the layer has a source configured, * it will be modified to use the configuration from the glStyle's `source`. Options specified on the * layer's source will override those from the glStyle's `source`, except for `url` and * `tileUrlFunction`. When the source projection is the default (`EPSG:3857`), the `tileGrid` will * also be overridden. If you'd rather not have ol-mapbox-style modify the source, configure `applyStyle()` * with the `updateSource: false` option. * @param {string|Object} glStyle Mapbox Style object. * @param {string|Array|Options&ApplyStyleOptions} [sourceOrLayersOrOptions] Options or * `source` key or an array of layer `id`s from the Mapbox Style object. When a `source` key is * provided, all layers for the specified source will be included in the style function. When layer * `id`s are provided, they must be from layers that use the same source. When not provided or a falsey * value, all layers using the first source specified in the glStyle will be rendered. * @param {Options&ApplyStyleOptions|string} [optionsOrPath] **Deprecated**. Options. Alternatively the path of the style file * (only required when a relative path is used for the `"sprite"` property of the style). * @param {Array} [resolutions] **Deprecated**. Resolutions for mapping resolution to zoom level. * Only needed when working with non-standard tile grids or projections, can also be supplied with * options. * @return {Promise} Promise which will be resolved when the style can be used * for rendering. */ function applyStyle(layer, glStyle, sourceOrLayersOrOptions, optionsOrPath, resolutions) { if ( sourceOrLayersOrOptions === void 0 ) sourceOrLayersOrOptions = ''; if ( optionsOrPath === void 0 ) optionsOrPath = {}; if ( resolutions === void 0 ) resolutions = undefined; var styleUrl, sourceId; /** @type {Options&ApplyStyleOptions} */ var options; var sourceOrLayers; var updateSource = true; if (typeof sourceOrLayersOrOptions !== 'string' && !Array.isArray(sourceOrLayersOrOptions)) { options = sourceOrLayersOrOptions; sourceOrLayers = options.source || options.layers; optionsOrPath = options; } else { sourceOrLayers = sourceOrLayersOrOptions; } if (typeof optionsOrPath === 'string') { styleUrl = optionsOrPath; options = {}; } else { styleUrl = optionsOrPath.styleUrl; options = optionsOrPath; } if (options.updateSource === false) { updateSource = false; } if (!resolutions) { resolutions = options.resolutions; } if (!styleUrl && typeof glStyle === 'string' && !glStyle.trim().startsWith('{')) { styleUrl = glStyle; } if (styleUrl) { styleUrl = styleUrl.startsWith('data:') ? location.href : normalizeStyleUrl(styleUrl, options.accessToken); options = completeOptions(styleUrl, options); } return new Promise(function (resolve, reject) { // TODO: figure out where best place to check source type is // Note that the source arg is an array of gl layer ids and each must be // dereferenced to get source type to validate getGlStyle(glStyle, options).then(function (glStyle) { if (glStyle.version != 8) { return reject(new Error('glStyle version 8 required.')); } if (!(layer instanceof VectorLayer || layer instanceof VectorTileLayer)) { return reject(new Error('Can only apply to VectorLayer or VectorTileLayer')); } var type = layer instanceof VectorTileLayer ? 'vector' : 'geojson'; if (!sourceOrLayers) { sourceId = Object.keys(glStyle.sources).find(function (key) { return glStyle.sources[key].type === type; }); sourceOrLayers = sourceId; } else if (Array.isArray(sourceOrLayers)) { sourceId = glStyle.layers.find(function (layer) { return layer.id === sourceOrLayers[0]; }).source; } else { sourceId = sourceOrLayers; } if (!sourceId) { return reject(new Error(("No " + type + " source found in the glStyle."))); } function assignSource() { if (!updateSource) { return Promise.resolve(); } if (layer instanceof VectorTileLayer) { return setupVectorSource(glStyle.sources[sourceId], styleUrl, options).then(function (source) { var targetSource = layer.getSource(); if (!targetSource) { layer.setSource(source); } else if (source !== targetSource) { targetSource.setTileUrlFunction(source.getTileUrlFunction()); if (typeof targetSource.setUrls === 'function' && typeof source.getUrls === 'function') { // to get correct keys for tile cache and queue targetSource.setUrls(source.getUrls()); } //@ts-ignore if (!targetSource.format_) { //@ts-ignore targetSource.format_ = source.format_; } if (!targetSource.getAttributions()) { targetSource.setAttributions(source.getAttributions()); } if (targetSource.getTileLoadFunction() === defaultLoadFunction) { targetSource.setTileLoadFunction(source.getTileLoadFunction()); } if (equivalent(targetSource.getProjection(), source.getProjection())) { targetSource.tileGrid = source.getTileGrid(); } } if (!isFinite(layer.getMaxResolution()) && !isFinite(layer.getMinZoom())) { var tileGrid = layer.getSource().getTileGrid(); layer.setMaxResolution(tileGrid.getResolution(tileGrid.getMinZoom())); } }); } var glSource = glStyle.sources[sourceId]; var source = layer.getSource(); if (!source || source.get('mapbox-source') !== glSource) { source = setupGeoJSONSource(glSource, styleUrl, options); } var targetSource = layer.getSource(); if (!targetSource) { layer.setSource(source); } else if (source !== targetSource) { if (!targetSource.getAttributions()) { targetSource.setAttributions(source.getAttributions()); } //@ts-ignore if (!targetSource.format_) { //@ts-ignore targetSource.format_ = source.getFormat(); } //@ts-ignore targetSource.url_ = source.getUrl(); } return Promise.resolve(); } var spriteScale, spriteData, spriteImageUrl, style; function onChange() { if (!style && (!glStyle.sprite || spriteData)) { if (options.projection && !resolutions) { var projection = get$1(options.projection); var units = projection.getUnits(); if (units !== 'm') { resolutions = defaultResolutions.map(function (resolution) { return resolution / METERS_PER_UNIT[units]; }); } } style = stylefunction(layer, glStyle, sourceOrLayers, resolutions, spriteData, spriteImageUrl, getFonts, options.getImage); if (!layer.getStyle()) { reject(new Error(("Nothing to show for source [" + sourceId + "]"))); } else { assignSource().then(resolve).catch(reject); } } else if (style) { layer.setStyle(style); assignSource().then(resolve).catch(reject); } else { reject(new Error('Something went wrong trying to apply style.')); } } if (glStyle.sprite) { var sprite = new URL(normalizeSpriteUrl(glStyle.sprite, options.accessToken, styleUrl || location.href)); spriteScale = window.devicePixelRatio >= 1.5 ? 0.5 : 1; var sizeFactor = spriteScale == 0.5 ? '@2x' : ''; var spriteUrl = sprite.origin + sprite.pathname + sizeFactor + '.json' + sprite.search; new Promise(function (resolve, reject) { fetchResource('Sprite', spriteUrl, options).then(resolve).catch(function (error) { spriteUrl = sprite.origin + sprite.pathname + '.json' + sprite.search; fetchResource('Sprite', spriteUrl, options).then(resolve).catch(reject); }); }).then(function (spritesJson) { if (spritesJson === undefined) { reject(new Error('No sprites found.')); } spriteData = spritesJson; spriteImageUrl = sprite.origin + sprite.pathname + sizeFactor + '.png' + sprite.search; if (options.transformRequest) { var transformed = options.transformRequest(spriteImageUrl, 'SpriteImage'); if (transformed instanceof Request) { spriteImageUrl = encodeURI(transformed.url); } } onChange(); }).catch(function (err) { reject(new Error(("Sprites cannot be loaded: " + spriteUrl + ": " + (err.message)))); }); } else { onChange(); } }).catch(reject); }); } var emptyObj$1 = {}; function setFirstBackground(mapOrLayer, glStyle, options) { glStyle.layers.some(function (layer) { if (layer.type === 'background') { if (mapOrLayer instanceof Layer) { mapOrLayer.setBackground(function (resolution) { return getBackgroundColor(layer, resolution, options, {}); }); return true; } if (mapOrLayer instanceof Map || mapOrLayer instanceof LayerGroup) { mapOrLayer.getLayers().push(setupBackgroundLayer(layer, options, {})); return true; } } }); } /** * Applies properties of the Mapbox Style's first `background` layer to the * provided map or layer (group). * * **Example:** * ```js * import {applyBackground} from 'ol-mapbox-style'; * import {Map} from 'ol'; * * const map = new Map({target: 'map'}); * applyBackground(map, 'https://api.maptiler.com/maps/basic/style.json?key=YOUR_OPENMAPTILES_TOKEN'); * ``` * @param {Map|import("ol/layer/Base.js").default} mapOrLayer OpenLayers Map or layer (group). * @param {Object|string} glStyle Mapbox Style object or url. * @param {Options} options Options. * @return {Promise} Promise that resolves when the background is applied. */ function applyBackground(mapOrLayer, glStyle, options) { if ( options === void 0 ) options = {}; return getGlStyle(glStyle, options).then(function (glStyle) { setFirstBackground(mapOrLayer, glStyle, options); }); } function getSourceIdByRef(layers, ref) { var sourceId; layers.some(function (layer) { if (layer.id == ref) { sourceId = layer.source; return true; } }); return sourceId; } function extentFromTileJSON(tileJSON, projection) { var bounds = tileJSON.bounds; if (bounds) { var ll = fromLonLat([ bounds[0], bounds[1] ], projection); var tr = fromLonLat([ bounds[2], bounds[3] ], projection); return [ ll[0], ll[1], tr[0], tr[1] ]; } return get$1(projection).getExtent(); } function sourceOptionsFromTileJSON(glSource, tileJSON, options) { var tileJSONSource = new TileJSON({ tileJSON: tileJSON, tileSize: glSource.tileSize || tileJSON.tileSize || 512 }); var tileJSONDoc = tileJSONSource.getTileJSON(); var tileGrid = tileJSONSource.getTileGrid(); var projection = get$1(options.projection || 'EPSG:3857'); var extent = extentFromTileJSON(tileJSONDoc, projection); var projectionExtent = projection.getExtent(); var minZoom = tileJSONDoc.minzoom || 0; var maxZoom = tileJSONDoc.maxzoom || 22; /** @type {import("ol/source/VectorTile.js").Options} */ var sourceOptions = { attributions: tileJSONSource.getAttributions(), projection: projection, tileGrid: new TileGrid({ origin: projectionExtent ? getTopLeft(projectionExtent) : tileGrid.getOrigin(0), extent: extent || tileGrid.getExtent(), minZoom: minZoom, resolutions: getTileResolutions(projection, tileJSON.tileSize).slice(0, maxZoom + 1), tileSize: tileGrid.getTileSize(0) }) }; if (Array.isArray(tileJSONDoc.tiles)) { sourceOptions.urls = tileJSONDoc.tiles; } else { sourceOptions.url = tileJSONDoc.tiles; } return sourceOptions; } function getBackgroundColor(glLayer, resolution, options, functionCache) { var background = { id: glLayer.id, type: glLayer.type }; var layout = glLayer.layout || {}; var paint = glLayer.paint || {}; background['paint'] = paint; var zoom = getZoomForResolution(resolution, options.resolutions || defaultResolutions); var bg, opacity; if (paint['background-color'] !== undefined) { bg = getValue(background, 'paint', 'background-color', zoom, emptyObj$1, functionCache); } if (paint['background-opacity'] !== undefined) { opacity = getValue(background, 'paint', 'background-opacity', zoom, emptyObj$1, functionCache); } return layout.visibility == 'none' ? undefined : colorWithOpacity(bg, opacity); } /** * @param {Object} glLayer Mapbox Style layer object. * @param {Options} options Options. * @param {Object} functionCache Cache for functions. * @return {Layer} OpenLayers layer. */ function setupBackgroundLayer(glLayer, options, functionCache) { var div = document.createElement('div'); div.className = 'ol-mapbox-style-background'; div.style.position = 'absolute'; div.style.width = '100%'; div.style.height = '100%'; return new Layer({ source: new Source({}), render: function render(frameState) { var color = getBackgroundColor(glLayer, frameState.viewState.resolution, options, functionCache); div.style.backgroundColor = color; return div; } }); } /** * Creates an OpenLayers VectorTile source for a gl source entry. * @param {Object} glSource "source" entry from a Mapbox Style object. * @param {string|undefined} styleUrl URL to use for the source. This is expected to be the complete http(s) url, * with access key applied. * @param {Options} options Options. * @return {Promise} Promise resolving to a VectorTile source. * @private */ function setupVectorSource(glSource, styleUrl, options) { return new Promise(function (resolve, reject) { getTileJson(glSource, styleUrl, options).then(function (tileJSON) { var sourceOptions = sourceOptionsFromTileJSON(glSource, tileJSON, options); sourceOptions.format = new MVT(); resolve(new VectorTileSource(sourceOptions)); }).catch(reject); }); } function setupVectorLayer(glSource, styleUrl, options) { var layer = new VectorTileLayer({ declutter: true, visible: false }); setupVectorSource(glSource, styleUrl, options).then(function (source) { source.set('mapbox-source', glSource); layer.setSource(source); }).catch(function (error) { layer.setSource(undefined); }); return layer; } function getBboxTemplate(projection) { var projCode = projection ? projection.getCode() : 'EPSG:3857'; return ("{bbox-" + (projCode.toLowerCase().replace(/[^a-z0-9]/g, '-')) + "}"); } function setupRasterLayer(glSource, styleUrl, options) { var layer = new TileLayer(); getTileJson(glSource, styleUrl, options).then(function (tileJson) { var source = new TileJSON({ interpolate: options.interpolate === undefined ? true : options.interpolate, transition: 0, crossOrigin: 'anonymous', tileJSON: tileJson }); source.tileGrid = sourceOptionsFromTileJSON(glSource, tileJson, options).tileGrid; if (options.projection) { //@ts-ignore source.projection = get$1(options.projection); } var getTileUrl = source.getTileUrlFunction(); source.setTileUrlFunction(function (tileCoord, pixelRatio, projection) { var bboxTemplate = getBboxTemplate(projection); var src = getTileUrl(tileCoord, pixelRatio, projection); if (src.indexOf(bboxTemplate) != -1) { var bbox = source.getTileGrid().getTileCoordExtent(tileCoord); src = src.replace(bboxTemplate, bbox.toString()); } return src; }); source.set('mapbox-source', glSource); layer.setSource(source); }).catch(function (error) { layer.setSource(undefined); }); return layer; } /** * * @param {Object} glSource "source" entry from a Mapbox Style object. * @param {string} styleUrl Style url * @param {Options} options ol-mapbox-style options. * @return {ImageLayer} The raster layer */ function setupHillshadeLayer(glSource, styleUrl, options) { var tileLayer = setupRasterLayer(glSource, styleUrl, options); /** @type {ImageLayer} */ var layer = new ImageLayer({ source: new Raster({ operationType: 'image', operation: hillshade, sources: [tileLayer] }) }); return layer; } /** * @param {Object} glSource glStyle source. * @param {string} styleUrl Style URL. * @param {Options} options Options. * @return {VectorSource} Configured vector source. */ function setupGeoJSONSource(glSource, styleUrl, options) { var geoJsonFormat = options.projection ? new GeoJSON({ dataProjection: options.projection }) : new GeoJSON(); var data = glSource.data; var sourceOptions = {}; if (typeof data == 'string') { var geoJsonUrl = normalizeSourceUrl(data, options.accessToken, options.accessTokenParam || 'access_token', styleUrl || location.href); if (options.transformRequest) { var transformed = options.transformRequest(geoJsonUrl, 'GeoJSON'); if (transformed instanceof Request) { geoJsonUrl = decodeURI(transformed.url); } } if (/\{bbox-[0-9a-z-]+\}/.test(geoJsonUrl)) { var extentUrl = function (extent, resolution, projection) { var bboxTemplate = getBboxTemplate(projection); return geoJsonUrl.replace(bboxTemplate, ("" + (extent.join(',')))); }; var source$1 = new VectorSource({ attributions: glSource.attribution, format: geoJsonFormat, url: extentUrl, strategy: bbox }); source$1.set('mapbox-source', glSource); return source$1; } return new VectorSource({ attributions: glSource.attribution, format: geoJsonFormat, url: geoJsonUrl }); } sourceOptions.features = geoJsonFormat.readFeatures(data, { featureProjection: getUserProjection() || 'EPSG:3857' }); var source = new VectorSource(Object.assign({ attributions: glSource.attribution, format: geoJsonFormat }, sourceOptions)); source.set('mapbox-source', glSource); return source; } function setupGeoJSONLayer(glSource, styleUrl, options) { return new VectorLayer({ declutter: true, source: setupGeoJSONSource(glSource, styleUrl, options), visible: false }); } function prerenderRasterLayer(glLayer, layer, functionCache) { var zoom = null; return function (event) { if (glLayer.paint && 'raster-opacity' in glLayer.paint && event.frameState.viewState.zoom !== zoom) { zoom = event.frameState.viewState.zoom; delete functionCache[glLayer.id]; updateRasterLayerProperties(glLayer, layer, zoom, functionCache); } }; } function updateRasterLayerProperties(glLayer, layer, zoom, functionCache) { var opacity = getValue(glLayer, 'paint', 'raster-opacity', zoom, emptyObj$1, functionCache); layer.setOpacity(opacity); } function manageVisibility(layer, mapOrGroup) { function onChange() { var glStyle = mapOrGroup.get('mapbox-style'); if (!glStyle) { return; } var mapboxLayers = derefLayers(glStyle.layers); var layerMapboxLayerids = layer.get('mapbox-layers'); var visible = mapboxLayers.filter(function (mapboxLayer) { return layerMapboxLayerids.includes(mapboxLayer.id); }).some(function (mapboxLayer) { return !mapboxLayer.layout || !mapboxLayer.layout.visibility || mapboxLayer.layout.visibility === 'visible'; }); if (layer.get('visible') !== visible) { layer.setVisible(visible); } } layer.on('change', onChange); onChange(); } function setupLayer(glStyle, styleUrl, glLayer, options) { var functionCache = getFunctionCache(glStyle); var glLayers = glStyle.layers; var type = glLayer.type; var id = glLayer.source || getSourceIdByRef(glLayers, glLayer.ref); var glSource = glStyle.sources[id]; var layer; if (type == 'background') { layer = setupBackgroundLayer(glLayer, options, functionCache); } else if (glSource.type == 'vector') { layer = setupVectorLayer(glSource, styleUrl, options); } else if (glSource.type == 'raster') { layer = setupRasterLayer(glSource, styleUrl, options); layer.setVisible(glLayer.layout ? glLayer.layout.visibility !== 'none' : true); layer.on('prerender', prerenderRasterLayer(glLayer, layer, functionCache)); } else if (glSource.type == 'geojson') { layer = setupGeoJSONLayer(glSource, styleUrl, options); } else if (glSource.type == 'raster-dem' && glLayer.type == 'hillshade') { var hillshadeLayer = setupHillshadeLayer(glSource, styleUrl, options); layer = hillshadeLayer; hillshadeLayer.getSource().on('beforeoperations', function (event) { var data = event.data; data.resolution = event.resolution; var zoom = getZoomForResolution(event.resolution, options.resolutions || defaultResolutions); data.encoding = glSource.encoding; data.vert = 5 * getValue(glLayer, 'paint', 'hillshade-exaggeration', zoom, emptyObj$1, functionCache); data.sunAz = getValue(glLayer, 'paint', 'hillshade-illumination-direction', zoom, emptyObj$1, functionCache); data.sunEl = 35; data.opacity = 0.3; data.highlightColor = getValue(glLayer, 'paint', 'hillshade-highlight-color', zoom, emptyObj$1, functionCache); data.shadowColor = getValue(glLayer, 'paint', 'hillshade-shadow-color', zoom, emptyObj$1, functionCache); data.accentColor = getValue(glLayer, 'paint', 'hillshade-accent-color', zoom, emptyObj$1, functionCache); }); layer.setVisible(glLayer.layout ? glLayer.layout.visibility !== 'none' : true); } var glSourceId = id; if (layer) { layer.set('mapbox-source', glSourceId); } return layer; } /** * @param {*} glStyle Mapbox Style. * @param {Map|LayerGroup} mapOrGroup Map or layer group. * @param {string} styleUrl Style URL. * @param {Options} options Options. * @return {Promise} Promise that resolves when the style is loaded. */ function processStyle(glStyle, mapOrGroup, styleUrl, options) { var promises = []; var view = null; if (mapOrGroup instanceof Map) { view = mapOrGroup.getView(); if (!view.isDef() && !view.getRotation() && !view.getResolutions()) { var projection = options.projection ? get$1(options.projection) : view.getProjection(); view = new View(Object.assign(view.getProperties(), { maxResolution: defaultResolutions[0] / METERS_PER_UNIT[projection.getUnits()], projection: options.projection || view.getProjection() })); mapOrGroup.setView(view); } if ('center' in glStyle && !view.getCenter()) { view.setCenter(fromLonLat(glStyle.center, view.getProjection())); } if ('zoom' in glStyle && view.getZoom() === undefined) { view.setResolution(defaultResolutions[0] / METERS_PER_UNIT[view.getProjection().getUnits()] / Math.pow(2, glStyle.zoom)); } if (!view.getCenter() || view.getZoom() === undefined) { view.fit(view.getProjection().getExtent(), { nearest: true, size: mapOrGroup.getSize() }); } } mapOrGroup.set('mapbox-style', glStyle); mapOrGroup.set('mapbox-metadata', { styleUrl: styleUrl, options: options }); var glLayers = glStyle.layers; var layerIds = []; var layer, glSourceId, id; for (var i = 0, ii = glLayers.length; i < ii; ++i) { var glLayer = glLayers[i]; var type = glLayer.type; if (type == 'heatmap') { //FIXME Unsupported layer type throw new Error((type + " layers are not supported")); } else { id = glLayer.source || getSourceIdByRef(glLayers, glLayer.ref); // this technique assumes gl layers will be in a particular order if (!id || id != glSourceId) { if (layerIds.length) { promises.push(finalizeLayer(layer, layerIds, glStyle, styleUrl, mapOrGroup, options)); layerIds = []; } layer = setupLayer(glStyle, styleUrl, glLayer, options); if (!(layer instanceof VectorLayer || layer instanceof VectorTileLayer)) { layerIds = []; } glSourceId = layer.get('mapbox-source'); } layerIds.push(glLayer.id); } } promises.push(finalizeLayer(layer, layerIds, glStyle, styleUrl, mapOrGroup, options)); return Promise.all(promises); } /** * Loads and applies a Mapbox Style object into an OpenLayers Map or LayerGroup. * This includes the map background, the layers, and for Map instances that did not * have a View defined yet also the center and the zoom. * * **Example:** * ```js * import apply from 'ol-mapbox-style'; * * apply('map', 'mapbox://styles/mapbox/bright-v9', {accessToken: 'YOUR_MAPBOX_TOKEN'}); * ``` * * The center and zoom will only be set if present in the Mapbox Style document, * and if not already set on the OpenLayers map. * * Layers will be added to the OpenLayers map, without affecting any layers that * might already be set on the map. * * Layers added by `apply()` will have two additional properties: * * * `mapbox-source`: The `id` of the Mapbox Style document's source that the * OpenLayers layer was created from. Usually `apply()` creates one * OpenLayers layer per Mapbox Style source, unless the layer stack has * layers from different sources in between. * * `mapbox-layers`: The `id`s of the Mapbox Style document's layers that are * included in the OpenLayers layer. * * This function sets an additional `mapbox-style` property on the OpenLayers * Map or LayerGroup instance, which holds the Mapbox Style object. * * @param {Map|HTMLElement|string|LayerGroup} mapOrGroupOrElement Either an existing * OpenLayers Map instance, or a HTML element, or the id of a HTML element that will be * the target of a new OpenLayers Map, or a layer group. If layer group, styles * releated to the map and view will be ignored. * @param {string|Object} style JSON style object or style url pointing to a * Mapbox Style object. When using Mapbox APIs, the url is the `styleUrl` * shown in Mapbox Studio's "share" panel. In addition, the `accessToken` option * (see below) must be set. * When passed as JSON style object, all OpenLayers layers created by `apply()` * will be immediately available, but they may not have a source yet (i.e. when * they are defined by a TileJSON url in the Mapbox Style document). When passed * as style url, layers will be added to the map when the Mapbox Style document * is loaded and parsed. * @param {Options} options Options. * @return {Promise} A promise that resolves after all layers have been added to * the OpenLayers Map instance or LayerGroup, their sources set, and their styles applied. The * `resolve` callback will be called with the OpenLayers Map instance or LayerGroup as * argument. */ function apply(mapOrGroupOrElement, style, options) { if ( options === void 0 ) options = {}; var promise; /** @type {Map|LayerGroup} */ var mapOrGroup; if (typeof mapOrGroupOrElement === 'string' || mapOrGroupOrElement instanceof HTMLElement) { mapOrGroup = new Map({ target: mapOrGroupOrElement }); } else { mapOrGroup = mapOrGroupOrElement; } if (typeof style === 'string') { var styleUrl = style.startsWith('data:') ? location.href : normalizeStyleUrl(style, options.accessToken); options = completeOptions(styleUrl, options); promise = new Promise(function (resolve, reject) { getGlStyle(style, options).then(function (glStyle) { processStyle(glStyle, mapOrGroup, styleUrl, options).then(function () { resolve(mapOrGroup); }).catch(reject); }).catch(function (err) { reject(new Error(("Could not load " + style + ": " + (err.message)))); }); }); } else { promise = new Promise(function (resolve, reject) { processStyle(style, mapOrGroup, !options.styleUrl || options.styleUrl.startsWith('data:') ? location.href : normalizeStyleUrl(options.styleUrl, options.accessToken), options).then(function () { resolve(mapOrGroup); }).catch(reject); }); } return promise; } /** * If layerIds is not empty, applies the style specified in glStyle to the layer, * and adds the layer to the map. * * The layer may not yet have a source when the function is called. If so, the style * is applied to the layer via a once listener on the 'change:source' event. * * @param {Layer} layer An OpenLayers layer instance. * @param {Array} layerIds Array containing layer ids of already-processed layers. * @param {Object} glStyle Style as a JSON object. * @param {string|undefined} styleUrl The original style URL. Only required * when a relative path is used with the `"sprite"` property of the style. * @param {Map|LayerGroup} mapOrGroup OpenLayers Map. * @param {Options} options Options. * @return {Promise} Returns a promise that resolves after the source has * been set on the specified layer, and the style has been applied. */ function finalizeLayer(layer, layerIds, glStyle, styleUrl, mapOrGroup, options) { if ( options === void 0 ) options = {}; var minZoom = 24; var maxZoom = 0; var glLayers = glStyle.layers; for (var i = 0, ii = glLayers.length; i < ii; ++i) { var glLayer = glLayers[i]; if (layerIds.indexOf(glLayer.id) !== -1) { minZoom = Math.min('minzoom' in glLayer ? glLayer.minzoom : 0, minZoom); maxZoom = Math.max('maxzoom' in glLayer ? glLayer.maxzoom : 24, maxZoom); } } return new Promise(function (resolve, reject) { var setStyle = function () { var source = layer.getSource(); if (!source || source.getState() === 'error') { reject(new Error('Error accessing data for source ' + layer.get('mapbox-source'))); return; } if ('getTileGrid' in source) { var tileGrid = /** @type {import("ol/source/Tile.js").default|import("ol/source/VectorTile.js").default} */ source.getTileGrid(); if (tileGrid) { var sourceMinZoom = tileGrid.getMinZoom(); if (minZoom > 0 || sourceMinZoom > 0) { layer.setMaxResolution(Math.min(defaultResolutions[minZoom], tileGrid.getResolution(sourceMinZoom)) + 1e-9); } if (maxZoom < 24) { layer.setMinResolution(defaultResolutions[maxZoom] + 1e-9); } } } else { if (minZoom > 0) { layer.setMaxResolution(defaultResolutions[minZoom] + 1e-9); } } if (source instanceof VectorSource || source instanceof VectorTileSource) { applyStyle(layer, glStyle, layerIds, Object.assign({ styleUrl: styleUrl }, options)).then(function () { manageVisibility(layer, mapOrGroup); resolve(); }).catch(reject); } else { resolve(); } }; layer.set('mapbox-layers', layerIds); var layers = mapOrGroup.getLayers(); if (layers.getArray().indexOf(layer) === -1) { layers.push(layer); } if (layer.getSource()) { setStyle(); } else { layer.once('change:source', setStyle); } }); } /** @typedef {import("ol").Map} Map */ /** @typedef {import("ol/layer").Layer} Layer */ /** @typedef {import("ol/layer").Group} LayerGroup */ /** @typedef {import("ol/layer").Vector} VectorLayer */ /** @typedef {import("ol/layer").VectorTile} VectorTileLayer */ /** @typedef {import("ol/source").Source} Source */ /** * @typedef {Object} FeatureIdentifier * @property {string|number} id The feature id. * @property {string} source The source id. */ var functionCacheByStyleId = {}; var filterCacheByStyleId = {}; var styleId = 0; function getStyleId(glStyle) { if (!glStyle.id) { glStyle.id = styleId++; } return glStyle.id; } function getStyleFunctionKey(glStyle, olLayer) { return getStyleId(glStyle) + '.' + getUid(olLayer); } /** * @param {Object} glStyle Mapboox style object. * @return {Object} Function cache. */ function getFunctionCache(glStyle) { var functionCache = functionCacheByStyleId[glStyle.id]; if (!functionCache) { functionCache = {}; functionCacheByStyleId[getStyleId(glStyle)] = functionCache; } return functionCache; } function clearFunctionCache() { for (var key in functionCacheByStyleId) { delete functionCacheByStyleId[key]; } } /** * @param {Object} glStyle Mapboox style object. * @return {Object} Filter cache. */ function getFilterCache(glStyle) { var filterCache = filterCacheByStyleId[glStyle.id]; if (!filterCache) { filterCache = {}; filterCacheByStyleId[getStyleId(glStyle)] = filterCache; } return filterCache; } function deg2rad(degrees) { return degrees * Math.PI / 180; } var defaultResolutions = (function () { var resolutions = []; for (var res = 78271.51696402048; resolutions.length <= 24; res /= 2) { resolutions.push(res); } return resolutions; }()); /** * @param {number} width Width of the canvas. * @param {number} height Height of the canvas. * @return {HTMLCanvasElement} Canvas. */ function createCanvas(width, height) { if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope && typeof OffscreenCanvas !== 'undefined') { // eslint-disable-line return new OffscreenCanvas(width, height); } var canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; return canvas; } function getZoomForResolution(resolution, resolutions) { var i = 0; var ii = resolutions.length; for (; i < ii; ++i) { var candidate = resolutions[i]; if (candidate < resolution && i + 1 < ii) { var zoomFactor = resolutions[i] / resolutions[i + 1]; return i + Math.log(resolutions[i] / resolution) / Math.log(zoomFactor); } } return ii - 1; } var pendingRequests = {}; /** * @param {ResourceType} resourceType Type of resource to load. * @param {string} url Url of the resource. * @param {Options} [options={}] Options. * @param {{request?: Request}} [metadata] Object to be filled with the request. * @return {Promise} Promise that resolves with the loaded resource * or rejects with the Response object. * @private */ function fetchResource(resourceType, url, options, metadata) { if ( options === void 0 ) options = {}; if (url in pendingRequests) { if (metadata) { metadata.request = pendingRequests[url][0]; } return pendingRequests[url][1]; } var request = options.transformRequest ? options.transformRequest(url, resourceType) || new Request(url) : new Request(url); if (!request.headers.get('Accept')) { request.headers.set('Accept', 'application/json'); } if (metadata) { metadata.request = request; } var pendingRequest = fetch(request).then(function (response) { delete pendingRequests[url]; return response.ok ? response.json() : Promise.reject(new Error('Error fetching source ' + url)); }).catch(function (error) { delete pendingRequests[url]; return Promise.reject(new Error('Error fetching source ' + url)); }); pendingRequests[url] = [ request, pendingRequest ]; return pendingRequest; } function getGlStyle(glStyleOrUrl, options) { if (typeof glStyleOrUrl === 'string') { if (glStyleOrUrl.trim().startsWith('{')) { try { var glStyle = JSON.parse(glStyleOrUrl); return Promise.resolve(glStyle); } catch (error) { return Promise.reject(error); } } else { glStyleOrUrl = normalizeStyleUrl(glStyleOrUrl, options.accessToken); return fetchResource('Style', glStyleOrUrl, options); } } else { return Promise.resolve(glStyleOrUrl); } } function getTransformedTilesUrl(tilesUrl, options) { if (options.transformRequest) { var transformedRequest = options.transformRequest(tilesUrl, 'Tiles'); if (transformedRequest instanceof Request) { return decodeURI(transformedRequest.url); } } return tilesUrl; } var tilejsonCache = {}; /** * @param {Object} glSource glStyle source object. * @param {string} styleUrl Style URL. * @param {Options} options Options. * @return {Object} TileJson */ function getTileJson(glSource, styleUrl, options) { if ( options === void 0 ) options = {}; var cacheKey = [ styleUrl, JSON.stringify(glSource) ].toString(); var promise = tilejsonCache[cacheKey]; if (!promise || options.transformRequest) { var url = glSource.url; if (url && !glSource.tiles) { var normalizedSourceUrl = normalizeSourceUrl(url, options.accessToken, options.accessTokenParam || 'access_token', styleUrl || location.href); if (url.startsWith('mapbox://')) { promise = Promise.resolve(Object.assign({}, glSource, { url: undefined, tiles: expandUrl(normalizedSourceUrl) })); } else { var metadata = {}; promise = fetchResource('Source', normalizedSourceUrl, options, metadata).then(function (tileJson) { tileJson.tiles = tileJson.tiles.map(function (tileUrl) { if (tileJson.scheme === 'tms') { tileUrl = tileUrl.replace('{y}', '{-y}'); } return getTransformedTilesUrl(normalizeSourceUrl(tileUrl, options.accessToken, options.accessTokenParam || 'access_token', metadata.request.url), options); }); return Promise.resolve(tileJson); }); } } else { glSource = Object.assign({}, glSource, { tiles: glSource.tiles.map(function (tileUrl) { if (glSource.scheme === 'tms') { tileUrl = tileUrl.replace('{y}', '{-y}'); } return getTransformedTilesUrl(normalizeSourceUrl(tileUrl, options.accessToken, options.accessTokenParam || 'access_token', styleUrl || location.href), options); }) }); promise = Promise.resolve(Object.assign({}, glSource)); } tilejsonCache[cacheKey] = promise; } return promise; } /** * @param {HTMLImageElement|HTMLCanvasElement} spriteImage Sprite image id. * @param {{x: number, y: number, width: number, height: number, pixelRatio: number}} spriteImageData Sprite image data. * @param {number} haloWidth Halo width. * @param {{r: number, g: number, b: number, a: number}} haloColor Halo color. * @return {HTMLCanvasElement} Canvas element with the halo. */ function drawIconHalo(spriteImage, spriteImageData, haloWidth, haloColor) { var imageCanvas = document.createElement('canvas'); var imgSize = [ 2 * haloWidth * spriteImageData.pixelRatio + spriteImageData.width, 2 * haloWidth * spriteImageData.pixelRatio + spriteImageData.height ]; imageCanvas.width = imgSize[0]; imageCanvas.height = imgSize[1]; var imageContext = imageCanvas.getContext('2d'); imageContext.drawImage(spriteImage, spriteImageData.x, spriteImageData.y, spriteImageData.width, spriteImageData.height, haloWidth * spriteImageData.pixelRatio, haloWidth * spriteImageData.pixelRatio, spriteImageData.width, spriteImageData.height); var imageData = imageContext.getImageData(0, 0, imgSize[0], imgSize[1]); imageContext.globalCompositeOperation = 'destination-over'; imageContext.fillStyle = "rgba(" + (haloColor.r * 255) + "," + (haloColor.g * 255) + "," + (haloColor.b * 255) + "," + (haloColor.a) + ")"; var data = imageData.data; for (var i = 0, ii = imageData.width; i < ii; ++i) { for (var j = 0, jj = imageData.height; j < jj; ++j) { var index = (j * ii + i) * 4; var alpha = data[index + 3]; if (alpha > 0) { imageContext.arc(i, j, haloWidth * spriteImageData.pixelRatio, 0, 2 * Math.PI); } } } imageContext.fill(); return imageCanvas; } function smoothstep(min, max, value) { var x = Math.max(0, Math.min(1, (value - min) / (max - min))); return x * x * (3 - 2 * x); } /** * @param {HTMLImageElement} image SDF image * @param {{x: number, y: number, width: number, height: number}} area Area to unSDF * @param {{r: number, g: number, b: number, a: number}} color Color to use * @return {HTMLCanvasElement} Regular image */ function drawSDF(image, area, color) { var imageCanvas = document.createElement('canvas'); imageCanvas.width = area.width; imageCanvas.height = area.height; var imageContext = imageCanvas.getContext('2d'); imageContext.drawImage(image, area.x, area.y, area.width, area.height, 0, 0, area.width, area.height); var imageData = imageContext.getImageData(0, 0, area.width, area.height); var data = imageData.data; for (var i = 0, ii = imageData.width; i < ii; ++i) { for (var j = 0, jj = imageData.height; j < jj; ++j) { var index = (j * ii + i) * 4; var dist = data[index + 3] / 255; var buffer = 0.75; var gamma = 0.1; var alpha = smoothstep(buffer - gamma, buffer + gamma, dist); if (alpha > 0) { data[index + 0] = Math.round(255 * color.r * alpha); data[index + 1] = Math.round(255 * color.g * alpha); data[index + 2] = Math.round(255 * color.b * alpha); data[index + 3] = Math.round(255 * alpha); } else { data[index + 3] = 0; } } } imageContext.putImageData(imageData, 0, 0); return imageCanvas; } /** * Get the OpenLayers layer instance that contains the provided Mapbox Style * `layer`. Note that multiple Mapbox Style layers are combined in a single * OpenLayers layer instance when they use the same Mapbox Style `source`. * @param {Map|LayerGroup} map OpenLayers Map or LayerGroup. * @param {string} layerId Mapbox Style layer id. * @return {Layer} OpenLayers layer instance. */ function getLayer(map, layerId) { var layers = map.getLayers().getArray(); for (var i = 0, ii = layers.length; i < ii; ++i) { var mapboxLayers = layers[i].get('mapbox-layers'); if (mapboxLayers && mapboxLayers.indexOf(layerId) !== -1) { return layers[i]; } } return undefined; } /** * Get the OpenLayers layer instances for the provided Mapbox Style `source`. * @param {Map|LayerGroup} map OpenLayers Map or LayerGroup. * @param {string} sourceId Mapbox Style source id. * @return {Array} OpenLayers layer instances. */ function getLayers(map, sourceId) { var result = []; var layers = map.getLayers().getArray(); for (var i = 0, ii = layers.length; i < ii; ++i) { if (layers[i].get('mapbox-source') === sourceId) { result.push(layers[i]); } } return result; } /** * Get the OpenLayers source instance for the provided Mapbox Style `source`. * @param {Map|LayerGroup} map OpenLayers Map or LayerGroup. * @param {string} sourceId Mapbox Style source id. * @return {Source} OpenLayers source instance. */ function getSource(map, sourceId) { var layers = map.getLayers().getArray(); for (var i = 0, ii = layers.length; i < ii; ++i) { var source = /** @type {Layer} */ layers[i].getSource(); if (layers[i].get('mapbox-source') === sourceId) { return source; } } return undefined; } /** * Sets or removes a feature state. The feature state is taken into account for styling, * just like the feature's properties, and can be used e.g. to conditionally render selected * features differently. * * The feature state will be stored on the OpenLayers layer matching the feature identifier, in the * `mapbox-featurestate` property. * @param {Map|VectorLayer|VectorTileLayer} mapOrLayer OpenLayers Map or layer to set the feature * state on. * @param {FeatureIdentifier} feature Feature identifier. * @param {Object|null} state Feature state. Set to `null` to remove the feature state. */ function setFeatureState(mapOrLayer, feature, state) { var layers = 'getLayers' in mapOrLayer ? getLayers(mapOrLayer, feature.source) : [mapOrLayer]; for (var i = 0, ii = layers.length; i < ii; ++i) { var featureState = layers[i].get('mapbox-featurestate'); if (featureState) { if (state) { featureState[feature.id] = state; } else { delete featureState[feature.id]; } layers[i].changed(); } else { throw new Error(("Map or layer for source \"" + (feature.source) + "\" not found.")); } } } /** * Sets or removes a feature state. The feature state is taken into account for styling, * just like the feature's properties, and can be used e.g. to conditionally render selected * features differently. * @param {Map|VectorLayer|VectorTileLayer} mapOrLayer Map or layer to set the feature state on. * @param {FeatureIdentifier} feature Feature identifier. * @return {Object|null} Feature state or `null` when no feature state is set for the given * feature identifier. */ function getFeatureState(mapOrLayer, feature) { var layers = 'getLayers' in mapOrLayer ? getLayers(mapOrLayer, feature.source) : [mapOrLayer]; for (var i = 0, ii = layers.length; i < ii; ++i) { var featureState = layers[i].get('mapbox-featurestate'); if (featureState && featureState[feature.id]) { return featureState[feature.id]; } } return undefined; } /** * Get the Mapbox Layer object for the provided `layerId`. * @param {Map|LayerGroup} mapOrGroup Map or LayerGroup. * @param {string} layerId Mapbox Layer id. * @return {Object} Mapbox Layer object. */ function getMapboxLayer(mapOrGroup, layerId) { var style = mapOrGroup.get('mapbox-style'); var layerStyle = style.layers.find(function (layer) { return layer.id === layerId; }); return layerStyle; } /** * Add a new Mapbox Layer object to the style. The map will be re-rendered. * @param {Map|LayerGroup} mapOrGroup The Map or LayerGroup `apply` was called on. * @param {Object} mapboxLayer Mapbox Layer object. * @param {string} [beforeLayerId] Optional id of the Mapbox Layer before the new layer that will be added. * @return {Promise} Resolves when the added layer is available. */ function addMapboxLayer(mapOrGroup, mapboxLayer, beforeLayerId) { var glStyle = mapOrGroup.get('mapbox-style'); var mapboxLayers = glStyle.layers; var spliceIndex; var sourceIndex = -1; if (beforeLayerId !== undefined) { var beforeMapboxLayer = getMapboxLayer(mapOrGroup, beforeLayerId); if (beforeMapboxLayer === undefined) { throw new Error(("Layer with id \"" + beforeLayerId + "\" not found.")); } spliceIndex = mapboxLayers.indexOf(beforeMapboxLayer); } else { spliceIndex = mapboxLayers.length; } var sourceOffset; if (spliceIndex > 0 && mapboxLayers[spliceIndex - 1].source === mapboxLayer.source) { sourceIndex = spliceIndex - 1; sourceOffset = -1; } else if (spliceIndex < mapboxLayers.length && mapboxLayers[spliceIndex].source === mapboxLayer.source) { sourceIndex = spliceIndex; sourceOffset = 0; } if (sourceIndex === -1) { var ref = mapOrGroup.get('mapbox-metadata'); var options = ref.options; var styleUrl = ref.styleUrl; var layer = setupLayer(glStyle, styleUrl, mapboxLayer, options); if (beforeLayerId) { var beforeLayer = getLayer(mapOrGroup, beforeLayerId); var beforeLayerIndex = mapOrGroup.getLayers().getArray().indexOf(beforeLayer); mapOrGroup.getLayers().insertAt(beforeLayerIndex, layer); } mapboxLayers.splice(spliceIndex, 0, mapboxLayer); return finalizeLayer(layer, [mapboxLayer.id], glStyle, styleUrl, mapOrGroup, options); } if (mapboxLayers.some(function (layer) { return layer.id === mapboxLayer.id; })) { throw new Error(("Layer with id \"" + (mapboxLayer.id) + "\" already exists.")); } var sourceLayerId = mapboxLayers[sourceIndex].id; var args = styleFunctionArgs[getStyleFunctionKey(mapOrGroup.get('mapbox-style'), getLayer(mapOrGroup, sourceLayerId))]; mapboxLayers.splice(spliceIndex, 0, mapboxLayer); if (args) { var olLayer = args[0]; var glStyle$1 = args[1]; var sourceOrLayers = args[2]; var resolutions = args[3]; var spriteData = args[4]; var spriteImageUrl = args[5]; var getFonts = args[6]; var getImage = args[7]; if (Array.isArray(sourceOrLayers)) { var layerIndex = sourceOrLayers.indexOf(sourceLayerId) + sourceOffset; sourceOrLayers.splice(layerIndex, 0, mapboxLayer.id); } stylefunction(olLayer, glStyle$1, sourceOrLayers, resolutions, spriteData, spriteImageUrl, getFonts, getImage); } else { getLayer(mapOrGroup, mapboxLayers[sourceIndex].id).changed(); } return Promise.resolve(); } /** * Update a Mapbox Layer object in the style. The map will be re-rendered with the new style. * @param {Map|LayerGroup} mapOrGroup The Map or LayerGroup `apply` was called on. * @param {Object} mapboxLayer Updated Mapbox Layer object. */ function updateMapboxLayer(mapOrGroup, mapboxLayer) { var glStyle = mapOrGroup.get('mapbox-style'); var mapboxLayers = glStyle.layers; var index = mapboxLayers.findIndex(function (layer) { return layer.id === mapboxLayer.id; }); if (index === -1) { throw new Error(("Layer with id \"" + (mapboxLayer.id) + "\" not found.")); } var oldLayer = mapboxLayers[index]; if (oldLayer.source !== mapboxLayer.source) { throw new Error('Updated layer and previous version must use the same source.'); } delete getFunctionCache(glStyle)[mapboxLayer.id]; delete getFilterCache(glStyle)[mapboxLayer.id]; mapboxLayers[index] = mapboxLayer; var args = styleFunctionArgs[getStyleFunctionKey(mapOrGroup.get('mapbox-style'), getLayer(mapOrGroup, mapboxLayer.id))]; if (args) { stylefunction.apply(undefined, args); } else { getLayer(mapOrGroup, mapboxLayer.id).changed(); } } /** * Remove a Mapbox Layer object from the style. The map will be re-rendered. * @param {Map|LayerGroup} mapOrGroup The Map or LayerGroup `apply` was called on. * @param {string|Object} mapboxLayerIdOrLayer Mapbox Layer id or Mapbox Layer object. */ function removeMapboxLayer(mapOrGroup, mapboxLayerIdOrLayer) { var mapboxLayerId = typeof mapboxLayerIdOrLayer === 'string' ? mapboxLayerIdOrLayer : mapboxLayerIdOrLayer.id; var layer = getLayer(mapOrGroup, mapboxLayerId); /** @type {Array} */ var layerMapboxLayers = layer.get('mapbox-layers'); if (layerMapboxLayers.length === 1) { throw new Error('Cannot remove last Mapbox layer from an OpenLayers layer.'); } layerMapboxLayers.splice(layerMapboxLayers.indexOf(mapboxLayerId), 1); var glStyle = mapOrGroup.get('mapbox-style'); var layers = glStyle.layers; layers.splice(layers.findIndex(function (layer) { return layer.id === mapboxLayerId; }), 1); var args = styleFunctionArgs[getStyleFunctionKey(glStyle, layer)]; if (args) { var olLayer = args[0]; var glStyle$1 = args[1]; var sourceOrLayers = args[2]; var resolutions = args[3]; var spriteData = args[4]; var spriteImageUrl = args[5]; var getFonts = args[6]; var getImage = args[7]; if (Array.isArray(sourceOrLayers)) { sourceOrLayers.splice(sourceOrLayers.findIndex(function (layer) { return layer === mapboxLayerId; }), 1); } stylefunction(olLayer, glStyle$1, sourceOrLayers, resolutions, spriteData, spriteImageUrl, getFonts, getImage); } else { getLayer(mapOrGroup, mapboxLayerId).changed(); } } /** * @typedef {import("./apply.js").Options} Options * @typedef {import('./apply.js').ResourceType} ResourceType * @private */ var hairSpacePool = Array(256).join('\u200A'); function applyLetterSpacing(text, letterSpacing) { if (letterSpacing >= 0.05) { var textWithLetterSpacing = ''; var lines = text.split('\n'); var joinSpaceString = hairSpacePool.slice(0, Math.round(letterSpacing / 0.1)); for (var l = 0, ll = lines.length; l < ll; ++l) { if (l > 0) { textWithLetterSpacing += '\n'; } textWithLetterSpacing += lines[l].split('').join(joinSpaceString); } return textWithLetterSpacing; } return text; } var measureContext; function getMeasureContext() { if (!measureContext) { measureContext = createCanvas(1, 1).getContext('2d'); } return measureContext; } function measureText(text, letterSpacing) { return getMeasureContext().measureText(text).width + (text.length - 1) * letterSpacing; } var measureCache = {}; function wrapText(text, font, em, letterSpacing) { if (text.indexOf('\n') !== -1) { var hardLines = text.split('\n'); var lines = []; for (var i = 0, ii = hardLines.length; i < ii; ++i) { lines.push(wrapText(hardLines[i], font, em, letterSpacing)); } return lines.join('\n'); } var key = em + ',' + font + ',' + text + ',' + letterSpacing; var wrappedText = measureCache[key]; if (!wrappedText) { var words = text.split(' '); if (words.length > 1) { var ctx = getMeasureContext(); ctx.font = font; var oneEm = ctx.measureText('M').width; var maxWidth = oneEm * em; var line = ''; var lines$1 = []; // Pass 1 - wrap lines to not exceed maxWidth for (var i$1 = 0, ii$1 = words.length; i$1 < ii$1; ++i$1) { var word = words[i$1]; var testLine = line + (line ? ' ' : '') + word; if (measureText(testLine, letterSpacing) <= maxWidth) { line = testLine; } else { if (line) { lines$1.push(line); } line = word; } } if (line) { lines$1.push(line); } // Pass 2 - add lines with a width of less than 30% of maxWidth to the previous or next line for (var i$2 = 0, ii$2 = lines$1.length; i$2 < ii$2 && ii$2 > 1; ++i$2) { var line$1 = lines$1[i$2]; if (measureText(line$1, letterSpacing) < maxWidth * 0.35) { var prevWidth = i$2 > 0 ? measureText(lines$1[i$2 - 1], letterSpacing) : Infinity; var nextWidth = i$2 < ii$2 - 1 ? measureText(lines$1[i$2 + 1], letterSpacing) : Infinity; lines$1.splice(i$2, 1); ii$2 -= 1; if (prevWidth < nextWidth) { lines$1[i$2 - 1] += ' ' + line$1; i$2 -= 1; } else { lines$1[i$2] = line$1 + ' ' + lines$1[i$2]; } } } // Pass 3 - try to fill 80% of maxWidth for each line for (var i$3 = 0, ii$3 = lines$1.length - 1; i$3 < ii$3; ++i$3) { var line$2 = lines$1[i$3]; var next = lines$1[i$3 + 1]; if (measureText(line$2, letterSpacing) > maxWidth * 0.7 && measureText(next, letterSpacing) < maxWidth * 0.6) { var lineWords = line$2.split(' '); var lastWord = lineWords.pop(); if (measureText(lastWord, letterSpacing) < maxWidth * 0.2) { lines$1[i$3] = lineWords.join(' '); lines$1[i$3 + 1] = lastWord + ' ' + next; } ii$3 -= 1; } } wrappedText = lines$1.join('\n'); } else { wrappedText = text; } wrappedText = applyLetterSpacing(wrappedText, letterSpacing); measureCache[key] = wrappedText; } return wrappedText; } var fontFamilyRegEx = /font-family: ?([^;]*);/; var stripQuotesRegEx = /("|')/g; var loadedFontFamilies; function hasFontFamily(family) { if (!loadedFontFamilies) { loadedFontFamilies = {}; var styleSheets = document.styleSheets; for (var i = 0, ii = styleSheets.length; i < ii; ++i) { var styleSheet = styleSheets[i]; try { var cssRules = styleSheet.rules || styleSheet.cssRules; if (cssRules) { for (var j = 0, jj = cssRules.length; j < jj; ++j) { var cssRule = cssRules[j]; if (cssRule.type == 5) { var match = cssRule.cssText.match(fontFamilyRegEx); loadedFontFamilies[match[1].replace(stripQuotesRegEx, '')] = true; } } } } catch (e) { } } } return family in loadedFontFamilies; } var processedFontFamilies = {}; /** * @param {Array} fonts Fonts. * @param {string} [templateUrl] Template URL. * @return {Array} Processed fonts. * @private */ function getFonts(fonts, templateUrl) { if ( templateUrl === void 0 ) templateUrl = 'https://cdn.jsdelivr.net/npm/@fontsource/{font-family}/{fontweight}{-fontstyle}.css'; var fontsKey = fonts.toString(); if (fontsKey in processedFontFamilies) { return processedFontFamilies[fontsKey]; } var fontDescriptions = []; for (var i = 0, ii = fonts.length; i < ii; ++i) { fonts[i] = fonts[i].replace('Arial Unicode MS', 'Arial'); var font = fonts[i]; var cssFont = mb2css(font, 1); registerFont(cssFont); var parts = cssFont.split(' '); fontDescriptions.push([ parts.slice(3).join(' ').replace(/"/g, ''), parts[1], parts[0] ]); } for (var i$1 = 0, ii$1 = fontDescriptions.length; i$1 < ii$1; ++i$1) { var fontDescription = fontDescriptions[i$1]; var family = fontDescription[0]; if (!hasFontFamily(family)) { if (checkedFonts.get(((fontDescription[2]) + "\n" + (fontDescription[1]) + " \n" + family)) !== 100) { var fontUrl = templateUrl.replace('{font-family}', family.replace(/ /g, '-').toLowerCase()).replace('{Font+Family}', family.replace(/ /g, '+')).replace('{fontweight}', fontDescription[1]).replace('{-fontstyle}', fontDescription[2].replace('normal', '').replace(/(.+)/, '-$1')).replace('{fontstyle}', fontDescription[2]); if (!document.querySelector('link[href="' + fontUrl + '"]')) { var markup = document.createElement('link'); markup.href = fontUrl; markup.rel = 'stylesheet'; document.head.appendChild(markup); } } } } processedFontFamilies[fontsKey] = fonts; return fonts; } /* ol-mapbox-style - Use Mapbox Style objects with OpenLayers Copyright 2016-present ol-mapbox-style contributors License: https://raw.githubusercontent.com/openlayers/ol-mapbox-style/master/LICENSE */ /** * @typedef {import("ol/layer/Vector").default} VectorLayer * @typedef {import("ol/layer/VectorTile").default} VectorTileLayer * @typedef {import("ol/style/Style").StyleFunction} StyleFunction */ var types = { 'Point': 1, 'MultiPoint': 1, 'LineString': 2, 'MultiLineString': 2, 'Polygon': 3, 'MultiPolygon': 3 }; var anchor = { 'center': [ 0.5, 0.5 ], 'left': [ 0, 0.5 ], 'right': [ 1, 0.5 ], 'top': [ 0.5, 0 ], 'bottom': [ 0.5, 1 ], 'top-left': [ 0, 0 ], 'top-right': [ 1, 0 ], 'bottom-left': [ 0, 1 ], 'bottom-right': [ 1, 1 ] }; var expressionData = function (rawExpression, propertySpec) { var compiledExpression = createPropertyExpression(rawExpression, propertySpec); if (compiledExpression.result === 'error') { throw new Error(compiledExpression.value.map(function (err) { return ((err.key) + ": " + (err.message)); }).join(', ')); } return compiledExpression.value; }; var emptyObj = {}; var zoomObj = { zoom: 0 }; var renderFeatureCoordinates, renderFeature; /** * @private * @param {Object} layer Gl object layer. * @param {string} layoutOrPaint 'layout' or 'paint'. * @param {string} property Feature property. * @param {number} zoom Zoom. * @param {Object} feature Gl feature. * @param {Object} [functionCache] Function cache. * @param {Object} [featureState] Feature state. * @return {?} Value. */ function getValue(layer, layoutOrPaint, property, zoom, feature, functionCache, featureState) { var layerId = layer.id; if (!functionCache) { functionCache = {}; console.warn('No functionCache provided to getValue()'); //eslint-disable-line no-console } if (!functionCache[layerId]) { functionCache[layerId] = {}; } var functions = functionCache[layerId]; if (!functions[property]) { var value = (layer[layoutOrPaint] || emptyObj)[property]; var propertySpec = spec[(layoutOrPaint + "_" + (layer.type))][property]; if (value === undefined) { value = propertySpec.default; } var isExpr = isExpression(value); if (!isExpr && isFunction(value)) { value = convertFunction(value, propertySpec); isExpr = true; } if (isExpr) { var compiledExpression = expressionData(value, propertySpec); functions[property] = compiledExpression.evaluate.bind(compiledExpression); } else { if (propertySpec.type == 'color') { value = Color$1.parse(value); } functions[property] = function () { return value; }; } } zoomObj.zoom = zoom; return functions[property](zoomObj, feature, featureState); } /** * @private * @param {Object} layer Gl object layer. * @param {number} zoom Zoom. * @param {Object} feature Gl feature. * @param {Object} [functionCache] Function cache. * @return {"declutter"|"obstacle"|"none"} Value. */ function getIconDeclutterMode(layer, zoom, feature, functionCache) { var allowOverlap = getValue(layer, 'layout', 'icon-allow-overlap', zoom, feature, functionCache); if (!allowOverlap) { return 'declutter'; } var ignorePlacement = getValue(layer, 'layout', 'icon-ignore-placement', zoom, feature, functionCache); if (!ignorePlacement) { return 'obstacle'; } return 'none'; } /** * @private * @param {string} layerId Layer id. * @param {?} filter Filter. * @param {Object} feature Feature. * @param {number} zoom Zoom. * @param {Object} [filterCache] Filter cache. * @return {boolean} Filter result. */ function evaluateFilter(layerId, filter, feature, zoom, filterCache) { if (!filterCache) { console.warn('No filterCache provided to evaluateFilter()'); //eslint-disable-line no-console } if (!(layerId in filterCache)) { filterCache[layerId] = createFilter(filter).filter; } zoomObj.zoom = zoom; return filterCache[layerId](zoomObj, feature); } var renderTransparentEnabled = false; /** * Configure whether features with a transparent style should be rendered. When * set to `true`, it will be possible to hit detect content that is not visible, * like transparent fills of polygons, using `ol/layer/Layer#getFeatures()` or * `ol/Map#getFeaturesAtPixel()` * @param {boolean} enabled Rendering of transparent elements is enabled. * Default is `false`. */ function renderTransparent(enabled) { if (enabled !== renderTransparentEnabled) { clearFunctionCache(); renderTransparentEnabled = enabled; } } /** * @private * @param {?} color Color. * @param {number} [opacity] Opacity. * @return {string} Color. */ function colorWithOpacity(color, opacity) { if (color) { if (!renderTransparentEnabled && (color.a === 0 || opacity === 0)) { return undefined; } var a = color.a; opacity = opacity === undefined ? 1 : opacity; return a === 0 ? 'transparent' : 'rgba(' + Math.round(color.r * 255 / a) + ',' + Math.round(color.g * 255 / a) + ',' + Math.round(color.b * 255 / a) + ',' + a * opacity + ')'; } return color; } var templateRegEx = /\{[^{}}]*\}/g; /** * @private * @param {string} text Text. * @param {Object} properties Properties. * @return {string} Text. */ function fromTemplate(text, properties) { return text.replace(templateRegEx, function (match) { return properties[match.slice(1, -1)] || ''; }); } var recordLayer = false; /** * Turns recording of the Mapbox Style's `layer` on and off. When turned on, * the layer that a rendered feature belongs to will be set as the feature's * `mapbox-layer` property. * @param {boolean} record Recording of the style layer is on. */ function recordStyleLayer(record) { if ( record === void 0 ) record = false; recordLayer = record; } var styleFunctionArgs = {}; /** * Creates a style function from the `glStyle` object for all layers that use * the specified `source`, which needs to be a `"type": "vector"` or * `"type": "geojson"` source and applies it to the specified OpenLayers layer. * * Two additional properties will be set on the provided layer: * * * `mapbox-source`: The `id` of the Mapbox Style document's source that the * OpenLayers layer was created from. Usually `apply()` creates one * OpenLayers layer per Mapbox Style source, unless the layer stack has * layers from different sources in between. * * `mapbox-layers`: The `id`s of the Mapbox Style document's layers that are * included in the OpenLayers layer. * * This function also works in a web worker. In worker mode, the main thread needs * to listen to messages from the worker and respond with another message to make * sure that sprite image loading works: * * ```js * worker.addEventListener('message', event => { * if (event.data.action === 'loadImage') { * const image = new Image(); * image.crossOrigin = 'anonymous'; * image.addEventListener('load', function() { * createImageBitmap(image, 0, 0, image.width, image.height).then(imageBitmap => { * worker.postMessage({ * action: 'imageLoaded', * image: imageBitmap, * src: event.data.src * }, [imageBitmap]); * }); * }); * image.src = event.data.src; * } * }); * ``` * * @param {VectorLayer|VectorTileLayer} olLayer OpenLayers layer to * apply the style to. In addition to the style, the layer will get two * properties: `mapbox-source` will be the `id` of the `glStyle`'s source used * for the layer, and `mapbox-layers` will be an array of the `id`s of the * `glStyle`'s layers. * @param {string|Object} glStyle Mapbox Style object. * @param {string|Array} sourceOrLayers `source` key or an array of layer `id`s * from the Mapbox Style object. When a `source` key is provided, all layers for * the specified source will be included in the style function. When layer `id`s * are provided, they must be from layers that use the same source. * @param {Array} resolutions * Resolutions for mapping resolution to zoom level. * @param {Object} spriteData Sprite data from the url specified in * the Mapbox Style object's `sprite` property. Only required if a `sprite` * property is specified in the Mapbox Style object. * @param {string} spriteImageUrl Sprite image url for the sprite * specified in the Mapbox Style object's `sprite` property. Only required if a * `sprite` property is specified in the Mapbox Style object. * @param {function(Array, string=):Array} getFonts Function that * receives a font stack and the url template from the GL style's `metadata['ol:webfonts']` * property (if set) as arguments, and returns a (modified) font stack that * is available. Font names are the names used in the Mapbox Style object. If * not provided, the font stack will be used as-is. This function can also be * used for loading web fonts. * @param {function(VectorLayer|VectorTileLayer, string):HTMLImageElement|HTMLCanvasElement|string|undefined} [getImage=undefined] * Function that returns an image or a URL for an image name. If the result is an HTMLImageElement, it must already be * loaded. The layer can be used to call layer.changed() when the loading and processing of the image has finished. * This function can be used for icons not in the sprite or to override sprite icons. * @return {StyleFunction} Style function for use in * `ol.layer.Vector` or `ol.layer.VectorTile`. */ function stylefunction(olLayer, glStyle, sourceOrLayers, resolutions, spriteData, spriteImageUrl, getFonts, getImage) { if ( resolutions === void 0 ) resolutions = defaultResolutions; if ( spriteData === void 0 ) spriteData = undefined; if ( spriteImageUrl === void 0 ) spriteImageUrl = undefined; if ( getFonts === void 0 ) getFonts = undefined; if ( getImage === void 0 ) getImage = undefined; if (typeof glStyle == 'string') { glStyle = JSON.parse(glStyle); } if (glStyle.version != 8) { throw new Error('glStyle version 8 required.'); } styleFunctionArgs[getStyleFunctionKey(glStyle, olLayer)] = Array.from(arguments); var spriteImage, spriteImageSize; var spriteImageUnSDFed; if (spriteImageUrl) { if (typeof Image !== 'undefined') { var img = new Image(); img.crossOrigin = 'anonymous'; img.onload = function () { spriteImage = img; spriteImageSize = [ img.width, img.height ]; olLayer.changed(); img.onload = null; }; img.src = spriteImageUrl; } else if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) { //eslint-disable-line var worker = self; // Main thread needs to handle 'loadImage' and dispatch 'imageLoaded' worker.postMessage({ action: 'loadImage', src: spriteImageUrl }); worker.addEventListener('message', function handler(event) { if (event.data.action === 'imageLoaded' && event.data.src === spriteImageUrl) { spriteImage = event.data.image; spriteImageSize = [ spriteImage.width, spriteImage.height ]; } }); } } var allLayers = derefLayers(glStyle.layers); var layersBySourceLayer = {}; var mapboxLayers = []; var iconImageCache = {}; var patternCache = {}; var functionCache = getFunctionCache(glStyle); var filterCache = getFilterCache(glStyle); var mapboxSource; for (var i = 0, ii = allLayers.length; i < ii; ++i) { var layer = allLayers[i]; var layerId = layer.id; if (typeof sourceOrLayers == 'string' && layer.source == sourceOrLayers || sourceOrLayers.indexOf(layerId) !== -1) { var sourceLayer = layer['source-layer']; if (!mapboxSource) { mapboxSource = layer.source; var source = glStyle.sources[mapboxSource]; if (!source) { throw new Error(("Source \"" + mapboxSource + "\" is not defined")); } var type = source.type; if (type !== 'vector' && type !== 'geojson') { throw new Error(("Source \"" + mapboxSource + "\" is not of type \"vector\" or \"geojson\", but \"" + type + "\"")); } } else if (layer.source !== mapboxSource) { throw new Error(("Layer \"" + layerId + "\" does not use source \"" + mapboxSource)); } var layers = layersBySourceLayer[sourceLayer]; if (!layers) { layers = []; layersBySourceLayer[sourceLayer] = layers; } layers.push({ layer: layer, index: i }); mapboxLayers.push(layerId); } } var textHalo = new Stroke(); var textColor = new Fill(); var styles = []; /** * @param {import("ol/Feature").default|import("ol/render/Feature").default} feature Feature. * @param {number} resolution Resolution. * @param {string} [onlyLayer] Calculate style for this layer only. * @return {Array} Style. */ var styleFunction = function (feature, resolution, onlyLayer) { var properties = feature.getProperties(); var layers = layersBySourceLayer[properties.layer]; if (!layers) { return undefined; } var zoom = resolutions.indexOf(resolution); if (zoom == -1) { zoom = getZoomForResolution(resolution, resolutions); } var type = types[feature.getGeometry().getType()]; var f = { id: feature.getId(), properties: properties, type: type }; var featureState = olLayer.get('mapbox-featurestate')[feature.getId()]; var stylesLength = -1; var featureBelongsToLayer; for (var i = 0, ii = layers.length; i < ii; ++i) { var layerData = layers[i]; var layer = layerData.layer; var layerId = layer.id; if (onlyLayer !== undefined && onlyLayer !== layerId) { continue; } var layout = layer.layout || emptyObj; var paint = layer.paint || emptyObj; if (layout.visibility === 'none' || 'minzoom' in layer && zoom < layer.minzoom || 'maxzoom' in layer && zoom >= layer.maxzoom) { continue; } var filter = layer.filter; if (!filter || evaluateFilter(layerId, filter, f, zoom, filterCache)) { featureBelongsToLayer = layer; var color = (void 0), opacity = (void 0), fill = (void 0), stroke = (void 0), strokeColor = (void 0), style = (void 0); var index = layerData.index; if (type == 3 && (layer.type == 'fill' || layer.type == 'fill-extrusion')) { opacity = getValue(layer, 'paint', layer.type + '-opacity', zoom, f, functionCache, featureState); if (layer.type + '-pattern' in paint) { var fillIcon = getValue(layer, 'paint', layer.type + '-pattern', zoom, f, functionCache, featureState); if (fillIcon) { var icon = typeof fillIcon === 'string' ? fromTemplate(fillIcon, properties) : fillIcon.toString(); if (spriteImage && spriteData && spriteData[icon]) { ++stylesLength; style = styles[stylesLength]; if (!style || !style.getFill() || style.getStroke() || style.getText()) { style = new Style({ fill: new Fill() }); styles[stylesLength] = style; } fill = style.getFill(); style.setZIndex(index); var icon_cache_key = icon + '.' + opacity; var pattern = patternCache[icon_cache_key]; if (!pattern) { var spriteImageData = spriteData[icon]; var canvas = createCanvas(spriteImageData.width, spriteImageData.height); var ctx = canvas.getContext('2d'); ctx.globalAlpha = opacity; ctx.drawImage(spriteImage, spriteImageData.x, spriteImageData.y, spriteImageData.width, spriteImageData.height, 0, 0, spriteImageData.width, spriteImageData.height); pattern = ctx.createPattern(canvas, 'repeat'); patternCache[icon_cache_key] = pattern; } fill.setColor(pattern); } } } else { color = colorWithOpacity(getValue(layer, 'paint', layer.type + '-color', zoom, f, functionCache, featureState), opacity); if (layer.type + '-outline-color' in paint) { strokeColor = colorWithOpacity(getValue(layer, 'paint', layer.type + '-outline-color', zoom, f, functionCache, featureState), opacity); } if (!strokeColor) { strokeColor = color; } if (color || strokeColor) { ++stylesLength; style = styles[stylesLength]; if (!style || color && !style.getFill() || !color && style.getFill() || strokeColor && !style.getStroke() || !strokeColor && style.getStroke() || style.getText()) { style = new Style({ fill: color ? new Fill() : undefined, stroke: strokeColor ? new Stroke() : undefined }); styles[stylesLength] = style; } if (color) { fill = style.getFill(); fill.setColor(color); } if (strokeColor) { stroke = style.getStroke(); stroke.setColor(strokeColor); stroke.setWidth(0.5); } style.setZIndex(index); } } } if (type != 1 && layer.type == 'line') { color = !('line-pattern' in paint) && 'line-color' in paint ? colorWithOpacity(getValue(layer, 'paint', 'line-color', zoom, f, functionCache, featureState), getValue(layer, 'paint', 'line-opacity', zoom, f, functionCache, featureState)) : undefined; var width = getValue(layer, 'paint', 'line-width', zoom, f, functionCache, featureState); if (color && width > 0) { ++stylesLength; style = styles[stylesLength]; if (!style || !style.getStroke() || style.getFill() || style.getText()) { style = new Style({ stroke: new Stroke() }); styles[stylesLength] = style; } stroke = style.getStroke(); stroke.setLineCap(getValue(layer, 'layout', 'line-cap', zoom, f, functionCache, featureState)); stroke.setLineJoin(getValue(layer, 'layout', 'line-join', zoom, f, functionCache, featureState)); stroke.setMiterLimit(getValue(layer, 'layout', 'line-miter-limit', zoom, f, functionCache, featureState)); stroke.setColor(color); stroke.setWidth(width); stroke.setLineDash(paint['line-dasharray'] ? getValue(layer, 'paint', 'line-dasharray', zoom, f, functionCache, featureState).map(function (x) { return x * width; }) : null); style.setZIndex(index); } } var hasImage = false; var text = null; var placementAngle = 0; var icon$1 = (void 0), iconImg = (void 0), skipLabel = (void 0); if ((type == 1 || type == 2) && 'icon-image' in layout) { var iconImage = getValue(layer, 'layout', 'icon-image', zoom, f, functionCache, featureState); if (iconImage) { icon$1 = typeof iconImage === 'string' ? fromTemplate(iconImage, properties) : iconImage.toString(); var styleGeom = undefined; var imageElement = getImage ? getImage(olLayer, icon$1) : undefined; if (spriteImage && spriteData && spriteData[icon$1] || imageElement) { var iconRotationAlignment = getValue(layer, 'layout', 'icon-rotation-alignment', zoom, f, functionCache, featureState); if (type == 2) { var geom = feature.getGeometry(); // ol package and ol-debug.js only if (geom.getFlatMidpoint || geom.getFlatMidpoints) { var extent = geom.getExtent(); var size = Math.sqrt(Math.max(Math.pow((extent[2] - extent[0]) / resolution, 2), Math.pow((extent[3] - extent[1]) / resolution, 2))); if (size > 150) { //FIXME Do not hard-code a size of 150 var midpoint = geom.getType() === 'MultiLineString' ? geom.getFlatMidpoints() : geom.getFlatMidpoint(); if (!renderFeature) { renderFeatureCoordinates = [ NaN, NaN ]; renderFeature = new RenderFeature('Point', renderFeatureCoordinates, [], {}, null); } styleGeom = renderFeature; renderFeatureCoordinates[0] = midpoint[0]; renderFeatureCoordinates[1] = midpoint[1]; var placement = getValue(layer, 'layout', 'symbol-placement', zoom, f, functionCache, featureState); if (placement === 'line' && iconRotationAlignment === 'map') { var stride = geom.getStride(); var coordinates = geom.getFlatCoordinates(); for (var i$1 = 0, ii$1 = coordinates.length - stride; i$1 < ii$1; i$1 += stride) { var x1 = coordinates[i$1]; var y1 = coordinates[i$1 + 1]; var x2 = coordinates[i$1 + stride]; var y2 = coordinates[i$1 + stride + 1]; var minX = Math.min(x1, x2); var minY = Math.min(y1, y2); var maxX = Math.max(x1, x2); var maxY = Math.max(y1, y2); if (midpoint[0] >= minX && midpoint[0] <= maxX && midpoint[1] >= minY && midpoint[1] <= maxY) { placementAngle = Math.atan2(y1 - y2, x2 - x1); break; } } } } } } if (type !== 2 || styleGeom) { var iconSize = getValue(layer, 'layout', 'icon-size', zoom, f, functionCache, featureState); var iconColor = paint['icon-color'] !== undefined ? getValue(layer, 'paint', 'icon-color', zoom, f, functionCache, featureState) : null; if (!iconColor || iconColor.a !== 0) { var haloColor = getValue(layer, 'paint', 'icon-halo-color', zoom, f, functionCache, featureState); var haloWidth = getValue(layer, 'paint', 'icon-halo-width', zoom, f, functionCache, featureState); var iconCacheKey = icon$1 + "." + iconSize + "." + haloWidth + "." + haloColor; if (iconColor !== null) { iconCacheKey += "." + iconColor; } iconImg = iconImageCache[iconCacheKey]; if (!iconImg) { var declutterMode = getIconDeclutterMode(layer, zoom, f, functionCache); var displacement = (void 0); if ('icon-offset' in layout) { displacement = getValue(layer, 'layout', 'icon-offset', zoom, f, functionCache, featureState).slice(0); displacement[1] *= -1; } var color$1 = iconColor ? [ iconColor.r * 255, iconColor.g * 255, iconColor.b * 255, iconColor.a ] : undefined; if (imageElement) { var iconOptions = { color: color$1, rotateWithView: iconRotationAlignment === 'map', displacement: displacement, declutterMode: declutterMode }; if (typeof imageElement === 'string') { // it is a src URL iconOptions.src = imageElement; } else { iconOptions.img = imageElement; iconOptions.imgSize = [ imageElement.width, imageElement.height ]; } iconImg = new Icon(iconOptions); } else { var spriteImageData$1 = spriteData[icon$1]; var img = (void 0), imgSize = (void 0), size$1 = (void 0), offset = (void 0); if (haloWidth) { if (spriteImageData$1.sdf) { img = drawIconHalo(drawSDF(spriteImage, spriteImageData$1, iconColor), { x: 0, y: 0, width: spriteImageData$1.width, height: spriteImageData$1.height, pixelRatio: spriteImageData$1.pixelRatio }, haloWidth, haloColor); color$1 = undefined; // do not tint haloed icons } else { img = drawIconHalo(spriteImage, spriteImageData$1, haloWidth, haloColor); } imgSize = [ img.width, img.height ]; } else { if (spriteImageData$1.sdf) { if (!spriteImageUnSDFed) { spriteImageUnSDFed = drawSDF(spriteImage, { x: 0, y: 0, width: spriteImageSize[0], height: spriteImageSize[1] }, { r: 1, g: 1, b: 1, a: 1 }); } img = spriteImageUnSDFed; } else { img = spriteImage; } imgSize = spriteImageSize; size$1 = [ spriteImageData$1.width, spriteImageData$1.height ]; offset = [ spriteImageData$1.x, spriteImageData$1.y ]; } iconImg = new Icon({ color: color$1, img: img, imgSize: imgSize, size: size$1, offset: offset, rotateWithView: iconRotationAlignment === 'map', scale: iconSize / spriteImageData$1.pixelRatio, displacement: displacement, declutterMode: declutterMode }); } iconImageCache[iconCacheKey] = iconImg; } } if (iconImg) { ++stylesLength; style = styles[stylesLength]; if (!style || !style.getImage() || style.getFill() || style.getStroke()) { style = new Style(); styles[stylesLength] = style; } style.setGeometry(styleGeom); iconImg.setRotation(placementAngle + deg2rad(getValue(layer, 'layout', 'icon-rotate', zoom, f, functionCache, featureState))); iconImg.setOpacity(getValue(layer, 'paint', 'icon-opacity', zoom, f, functionCache, featureState)); iconImg.setAnchor(anchor[getValue(layer, 'layout', 'icon-anchor', zoom, f, functionCache, featureState)]); style.setImage(iconImg); text = style.getText(); style.setText(undefined); style.setZIndex(index); hasImage = true; skipLabel = false; } } else { skipLabel = true; } } } } if (type == 1 && layer.type === 'circle') { ++stylesLength; style = styles[stylesLength]; if (!style || !style.getImage() || style.getFill() || style.getStroke()) { style = new Style(); styles[stylesLength] = style; } var circleRadius = 'circle-radius' in paint ? getValue(layer, 'paint', 'circle-radius', zoom, f, functionCache, featureState) : 5; var circleStrokeColor = colorWithOpacity(getValue(layer, 'paint', 'circle-stroke-color', zoom, f, functionCache, featureState), getValue(layer, 'paint', 'circle-stroke-opacity', zoom, f, functionCache, featureState)); var circleColor = colorWithOpacity(getValue(layer, 'paint', 'circle-color', zoom, f, functionCache, featureState), getValue(layer, 'paint', 'circle-opacity', zoom, f, functionCache, featureState)); var circleStrokeWidth = getValue(layer, 'paint', 'circle-stroke-width', zoom, f, functionCache, featureState); var cache_key = circleRadius + '.' + circleStrokeColor + '.' + circleColor + '.' + circleStrokeWidth; iconImg = iconImageCache[cache_key]; if (!iconImg) { iconImg = new Circle({ radius: circleRadius, stroke: circleStrokeColor && circleStrokeWidth > 0 ? new Stroke({ width: circleStrokeWidth, color: circleStrokeColor }) : undefined, fill: circleColor ? new Fill({ color: circleColor }) : undefined, declutterMode: 'none' }); iconImageCache[cache_key] = iconImg; } style.setImage(iconImg); text = style.getText(); style.setText(undefined); style.setGeometry(undefined); style.setZIndex(index); hasImage = true; } var label = (void 0), font = (void 0), textLineHeight = (void 0), textSize = (void 0), letterSpacing = (void 0), maxTextWidth = (void 0); if ('text-field' in layout) { textSize = Math.round(getValue(layer, 'layout', 'text-size', zoom, f, functionCache, featureState)); var fontArray = getValue(layer, 'layout', 'text-font', zoom, f, functionCache, featureState); textLineHeight = getValue(layer, 'layout', 'text-line-height', zoom, f, functionCache, featureState); font = mb2css(getFonts ? getFonts(fontArray, glStyle.metadata ? glStyle.metadata['ol:webfonts'] : undefined) : fontArray, textSize, textLineHeight); if (!font.includes('sans-serif')) { font += ',sans-serif'; } letterSpacing = getValue(layer, 'layout', 'text-letter-spacing', zoom, f, functionCache, featureState); maxTextWidth = getValue(layer, 'layout', 'text-max-width', zoom, f, functionCache, featureState); var textField = getValue(layer, 'layout', 'text-field', zoom, f, functionCache, featureState); if (typeof textField === 'object' && textField.sections) { if (textField.sections.length === 1) { label = textField.toString(); } else { label = textField.sections.reduce(function (acc, chunk, i) { var fonts = chunk.fontStack ? chunk.fontStack.split(',') : fontArray; var chunkFont = mb2css(getFonts ? getFonts(fonts) : fonts, textSize * (chunk.scale || 1), textLineHeight); var text = chunk.text; if (text === '\n') { acc.push('\n', ''); return acc; } if (type == 2) { acc.push(applyLetterSpacing(text, letterSpacing), chunkFont); return; } text = wrapText(text, chunkFont, maxTextWidth, letterSpacing).split('\n'); for (var i$1 = 0, ii = text.length; i$1 < ii; ++i$1) { if (i$1 > 0) { acc.push('\n', ''); } acc.push(text[i$1], chunkFont); } return acc; }, []); } } else { label = fromTemplate(textField, properties).trim(); } opacity = getValue(layer, 'paint', 'text-opacity', zoom, f, functionCache, featureState); } if (label && opacity && !skipLabel) { if (!hasImage) { ++stylesLength; style = styles[stylesLength]; if (!style || !style.getText() || style.getFill() || style.getStroke()) { style = new Style(); styles[stylesLength] = style; } style.setImage(undefined); style.setGeometry(undefined); } if (!style.getText()) { style.setText(text || new Text({ padding: [ 2, 2, 2, 2 ] })); } text = style.getText(); var textTransform = layout['text-transform']; if (textTransform == 'uppercase') { label = Array.isArray(label) ? label.map(function (t, i) { return i % 2 ? t : t.toUpperCase(); }) : label.toUpperCase(); } else if (textTransform == 'lowercase') { label = Array.isArray(label) ? label.map(function (t, i) { return i % 2 ? t : t.toLowerCase(); }) : label.toLowerCase(); } var wrappedLabel = Array.isArray(label) ? label : type == 2 ? applyLetterSpacing(label, letterSpacing) : wrapText(label, font, maxTextWidth, letterSpacing); text.setText(wrappedLabel); text.setFont(font); text.setRotation(deg2rad(getValue(layer, 'layout', 'text-rotate', zoom, f, functionCache, featureState))); var textAnchor = getValue(layer, 'layout', 'text-anchor', zoom, f, functionCache, featureState); var placement$1 = hasImage || type == 1 ? 'point' : getValue(layer, 'layout', 'symbol-placement', zoom, f, functionCache, featureState); var textAlign = (void 0); if (placement$1 === 'line-center') { text.setPlacement('line'); textAlign = 'center'; } else { text.setPlacement(placement$1); } if (placement$1 === 'line' && typeof text.setRepeat === 'function') { var symbolSpacing = getValue(layer, 'layout', 'symbol-spacing', zoom, f, functionCache, featureState); text.setRepeat(symbolSpacing * 2); } text.setOverflow(placement$1 === 'point'); var textHaloWidth = getValue(layer, 'paint', 'text-halo-width', zoom, f, functionCache, featureState); var textOffset = getValue(layer, 'layout', 'text-offset', zoom, f, functionCache, featureState); var textTranslate = getValue(layer, 'paint', 'text-translate', zoom, f, functionCache, featureState); // Text offset has to take halo width and line height into account var vOffset = 0; var hOffset = 0; if (placement$1 == 'point') { textAlign = 'center'; if (textAnchor.indexOf('left') !== -1) { textAlign = 'left'; hOffset = textHaloWidth; } else if (textAnchor.indexOf('right') !== -1) { textAlign = 'right'; hOffset = -textHaloWidth; } var textRotationAlignment = getValue(layer, 'layout', 'text-rotation-alignment', zoom, f, functionCache, featureState); text.setRotateWithView(textRotationAlignment == 'map'); } else { text.setMaxAngle(deg2rad(getValue(layer, 'layout', 'text-max-angle', zoom, f, functionCache, featureState)) * label.length / wrappedLabel.length); text.setRotateWithView(false); } text.setTextAlign(textAlign); var textBaseline = 'middle'; if (textAnchor.indexOf('bottom') == 0) { textBaseline = 'bottom'; vOffset = -textHaloWidth - 0.5 * (textLineHeight - 1) * textSize; } else if (textAnchor.indexOf('top') == 0) { textBaseline = 'top'; vOffset = textHaloWidth + 0.5 * (textLineHeight - 1) * textSize; } text.setTextBaseline(textBaseline); var textJustify = getValue(layer, 'layout', 'text-justify', zoom, f, functionCache, featureState); text.setJustify(textJustify === 'auto' ? undefined : textJustify); text.setOffsetX(textOffset[0] * textSize + hOffset + textTranslate[0]); text.setOffsetY(textOffset[1] * textSize + vOffset + textTranslate[1]); textColor.setColor(colorWithOpacity(getValue(layer, 'paint', 'text-color', zoom, f, functionCache, featureState), opacity)); text.setFill(textColor); var haloColor$1 = colorWithOpacity(getValue(layer, 'paint', 'text-halo-color', zoom, f, functionCache, featureState), opacity); if (haloColor$1) { textHalo.setColor(haloColor$1); // spec here : https://docs.mapbox.com/mapbox-gl-js/style-spec/#paint-symbol-text-halo-width // Halo width must be doubled because it is applied around the center of the text outline textHaloWidth *= 2; // 1/4 of text size (spec) x 2 var halfTextSize = 0.5 * textSize; textHalo.setWidth(textHaloWidth <= halfTextSize ? textHaloWidth : halfTextSize); text.setStroke(textHalo); } else { text.setStroke(undefined); } var textPadding = getValue(layer, 'layout', 'text-padding', zoom, f, functionCache, featureState); var padding = text.getPadding(); if (textPadding !== padding[0]) { padding[0] = textPadding; padding[1] = textPadding; padding[2] = textPadding; padding[3] = textPadding; } style.setZIndex(index); } } } if (stylesLength > -1) { styles.length = stylesLength + 1; if (recordLayer) { if ('set' in feature) { // ol/Feature feature.set('mapbox-layer', featureBelongsToLayer); } else { // ol/render/Feature feature.getProperties()['mapbox-layer'] = featureBelongsToLayer; } } return styles; } return undefined; }; olLayer.setStyle(styleFunction); olLayer.set('mapbox-source', mapboxSource); olLayer.set('mapbox-layers', mapboxLayers); olLayer.set('mapbox-featurestate', olLayer.get('mapbox-featurestate') || {}); return styleFunction; } /** * Get the the style for a specific Mapbox layer only. This can be useful for creating a legend. * @param {import("ol/Feature").default|import("ol/render/Feature").default} feature OpenLayers feature. * @param {number} resolution View resolution. * @param {import("ol/layer").Vector|import("ol/layer").VectorTile} olLayer OpenLayers layer. * @param {string} layerId Id of the Mapbox layer to get the style for * @return {Array} Styles for the provided Mapbox layer. */ function getStyleForLayer(feature, resolution, olLayer, layerId) { var evaluateStyle = olLayer.getStyleFunction(); if (evaluateStyle.length === 3) { // @ts-ignore return evaluateStyle(feature, resolution, layerId); } return undefined; } export { addMapboxLayer, apply, applyBackground, applyStyle, apply as default, getFeatureState, getLayer, getLayers, getMapboxLayer, getSource, getStyleForLayer, recordStyleLayer, removeMapboxLayer, renderTransparent, setFeatureState, stylefunction, updateMapboxLayer }; //# sourceMappingURL=index.js.map