diff options
Diffstat (limited to 'themes/CodeIT/assets/lib/mapbox-gl/mapbox-gl-language.js')
-rw-r--r-- | themes/CodeIT/assets/lib/mapbox-gl/mapbox-gl-language.js | 305 |
1 files changed, 305 insertions, 0 deletions
diff --git a/themes/CodeIT/assets/lib/mapbox-gl/mapbox-gl-language.js b/themes/CodeIT/assets/lib/mapbox-gl/mapbox-gl-language.js new file mode 100644 index 0000000..023772e --- /dev/null +++ b/themes/CodeIT/assets/lib/mapbox-gl/mapbox-gl-language.js @@ -0,0 +1,305 @@ +/** + * Create a new [Mapbox GL JS plugin](https://www.mapbox.com/blog/build-mapbox-gl-js-plugins/) that + * modifies the layers of the map style to use the 'text-field' that matches the browser language. + * @constructor + * @param {object} options - Options to configure the plugin. + * @param {string[]} [options.supportedLanguages] - List of supported languages + * @param {Function} [options.languageTransform] - Custom style transformation to apply + * @param {RegExp} [options.languageField=/^\{name/] - RegExp to match if a text-field is a language field + * @param {Function} [options.getLanguageField] - Given a language choose the field in the vector tiles + * @param {string} [options.languageSource] - Name of the source that contains the different languages. + * @param {string} [options.defaultLanguage] - Name of the default language to initialize style after loading. + * @param {string[]} [options.excludedLayerIds] - Name of the layers that should be excluded from translation. + */ +function MapboxLanguage(options) { + options = Object.assign({}, options); + if (!(this instanceof MapboxLanguage)) { + throw new Error("MapboxLanguage needs to be called with the new keyword"); + } + + this.setLanguage = this.setLanguage.bind(this); + this._initialStyleUpdate = this._initialStyleUpdate.bind(this); + + this._defaultLanguage = options.defaultLanguage; + this._isLanguageField = options.languageField || /^\{name/; + this._getLanguageField = + options.getLanguageField || + function nameField(language) { + return language === "mul" ? "{name}" : "{name_" + language + "}"; + }; + this._languageSource = options.languageSource || null; + this._languageTransform = + options.languageTransform || + function (style, language) { + if (language === "ar") { + return noSpacing(style); + } else { + return standardSpacing(style); + } + }; + this._excludedLayerIds = options.excludedLayerIds || []; + this.supportedLanguages = options.supportedLanguages || [ + "ar", + "en", + "es", + "fr", + "de", + "ja", + "ko", + "mul", + "pt", + "ru", + "zh", + ]; +} + +function standardSpacing(style) { + var changedLayers = style.layers.map(function (layer) { + if (!(layer.layout || {})["text-field"]) return layer; + var spacing = 0; + if (layer["source-layer"] === "state_label") { + spacing = 0.15; + } + if (layer["source-layer"] === "marine_label") { + if (/-lg/.test(layer.id)) { + spacing = 0.25; + } + if (/-md/.test(layer.id)) { + spacing = 0.15; + } + if (/-sm/.test(layer.id)) { + spacing = 0.1; + } + } + if (layer["source-layer"] === "place_label") { + if (/-suburb/.test(layer.id)) { + spacing = 0.15; + } + if (/-neighbour/.test(layer.id)) { + spacing = 0.1; + } + if (/-islet/.test(layer.id)) { + spacing = 0.01; + } + } + if (layer["source-layer"] === "airport_label") { + spacing = 0.01; + } + if (layer["source-layer"] === "rail_station_label") { + spacing = 0.01; + } + if (layer["source-layer"] === "poi_label") { + if (/-scalerank/.test(layer.id)) { + spacing = 0.01; + } + } + if (layer["source-layer"] === "road_label") { + if (/-label-/.test(layer.id)) { + spacing = 0.01; + } + if (/-shields/.test(layer.id)) { + spacing = 0.05; + } + } + return Object.assign({}, layer, { + layout: Object.assign({}, layer.layout, { + "text-letter-spacing": spacing, + }), + }); + }); + + return Object.assign({}, style, { + layers: changedLayers, + }); +} + +function noSpacing(style) { + var changedLayers = style.layers.map(function (layer) { + if (!(layer.layout || {})["text-field"]) return layer; + var spacing = 0; + return Object.assign({}, layer, { + layout: Object.assign({}, layer.layout, { + "text-letter-spacing": spacing, + }), + }); + }); + + return Object.assign({}, style, { + layers: changedLayers, + }); +} + +function isNameStringField(isLangField, property) { + return typeof property === "string" && isLangField.test(property); +} + +function isNameFunctionField(isLangField, property) { + return ( + property.stops && + property.stops.filter(function (stop) { + return isLangField.test(stop[1]); + }).length > 0 + ); +} + +function adaptPropertyLanguage(isLangField, property, languageFieldName) { + if (isNameStringField(isLangField, property)) return languageFieldName; + if (isNameFunctionField(isLangField, property)) { + var newStops = property.stops.map(function (stop) { + if (isLangField.test(stop[1])) { + return [stop[0], languageFieldName]; + } + return stop; + }); + return Object.assign({}, property, { + stops: newStops, + }); + } + return property; +} + +function changeLayerTextProperty( + isLangField, + layer, + languageFieldName, + excludedLayerIds +) { + if ( + layer.layout && + layer.layout["text-field"] && + excludedLayerIds.indexOf(layer.id) === -1 + ) { + return Object.assign({}, layer, { + layout: Object.assign({}, layer.layout, { + "text-field": adaptPropertyLanguage( + isLangField, + layer.layout["text-field"], + languageFieldName + ), + }), + }); + } + return layer; +} + +function findStreetsSource(style) { + var sources = Object.keys(style.sources).filter(function (sourceName) { + var source = style.sources[sourceName]; + return /mapbox-streets-v\d/.test(source.url); + }); + return sources[0]; +} + +/** + * Explicitly change the language for a style. + * @param {object} style - Mapbox GL style to modify + * @param {string} language - The language iso code + * @returns {object} the modified style + */ +MapboxLanguage.prototype.setLanguage = function (style, language) { + if (this.supportedLanguages.indexOf(language) < 0) + throw new Error("Language " + language + " is not supported"); + var streetsSource = this._languageSource || findStreetsSource(style); + if (!streetsSource) return style; + + var field = this._getLanguageField(language); + var isLangField = this._isLanguageField; + var excludedLayerIds = this._excludedLayerIds; + var changedLayers = style.layers.map(function (layer) { + if (layer.source === streetsSource) + return changeLayerTextProperty( + isLangField, + layer, + field, + excludedLayerIds + ); + return layer; + }); + + var languageStyle = Object.assign({}, style, { + layers: changedLayers, + }); + + return this._languageTransform(languageStyle, language); +}; + +MapboxLanguage.prototype._initialStyleUpdate = function () { + var style = this._map.getStyle(); + var language = + this._defaultLanguage || browserLanguage(this.supportedLanguages); + + // We only update the style once + this._map.off("styledata", this._initialStyleUpdate); + this._map.setStyle(this.setLanguage(style, language)); +}; + +function browserLanguage(supportedLanguages) { + var language = navigator.languages + ? navigator.languages[0] + : navigator.language || navigator.userLanguage; + var parts = language.split("-"); + var languageCode = language; + if (parts.length > 1) { + languageCode = parts[0]; + } + if (supportedLanguages.indexOf(languageCode) > -1) { + return languageCode; + } + return null; +} + +MapboxLanguage.prototype.onAdd = function (map) { + this._map = map; + this._map.on("styledata", this._initialStyleUpdate); + this._container = document.createElement("div"); + return this._container; +}; + +MapboxLanguage.prototype.onRemove = function () { + this._map.off("styledata", this._initialStyleUpdate); + this._map = undefined; +}; + +function ie11Polyfill() { + if (typeof Object.assign != "function") { + // Must be writable: true, enumerable: false, configurable: true + Object.defineProperty(Object, "assign", { + // eslint-disable-next-line no-unused-vars + value: function assign(target, varArgs) { + // .length of function is 2 + // eslint-disable-next-line strict + "use strict"; + if (target === null) { + // TypeError if undefined or null + throw new TypeError("Cannot convert undefined or null to object"); + } + + var to = Object(target); + + for (var index = 1; index < arguments.length; index++) { + var nextSource = arguments[index]; + + if (nextSource !== null) { + // Skip over if undefined or null + for (var nextKey in nextSource) { + // Avoid bugs when hasOwnProperty is shadowed + if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) { + to[nextKey] = nextSource[nextKey]; + } + } + } + } + return to; + }, + writable: true, + configurable: true, + }); + } +} + +if (typeof module !== "undefined" && typeof module.exports !== "undefined") { + module.exports = MapboxLanguage; +} else { + ie11Polyfill(); + window.MapboxLanguage = MapboxLanguage; +} |