Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Socket
Sign inDemoInstall

ol-mapbox-style

Package Overview
Dependencies
Maintainers
3
Versions
170
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ol-mapbox-style - npm Package Compare versions

Comparing version 7.1.1 to 8.0.0

dist/apply.d.ts

19

CHANGELOG.md
# Changelog
## 8.0.0
### Breaking changes
* The package now provides two separate bundles for umd and ejs. `dist/olms.js` is the umd bundle, `dist/index.js` the ejs bundle. No other JavaScript files are provided in the `dist/` folder any more.
* Imports from the `dist/` folder are no longer supported. They need to be replaced with imports from the package, e.g. `import {stylefunction} from "ol-mapbox-style"` instead of `import stylefunction from "ol-mapbox-style/dist/stylefunction"`.
* The `apply()` function has been replaced with an alias of the default export. This means that `apply()` now returns a `Promise<Map>` instead of a `Map`.
* The auto-generated types are now stricter, because they reference OpenLayers types correctly, instead of using `any`.
### Other changes
* `apply()`, `applyStyle()` and `applyBackground()` now take an `options` argument, which can contain a `transformRequest` option. With that function, urls and requests for styles, sprites, tiles and data can be modified. This can be useful e.g. to fix relative urls or to add credentials.
* Another available option is `accessToken`. In combination with the new support for `mapbox://` urls, it has become much easier to use maps and styles from Mapbox.
* Finally, a set of resolutions can be configured in the `options`. This makes it much easier to work with layers or maps in projections other than Web Mercator.
* The `applyStyle()` function has become more powerful and can now create and populate the source of the provided layer.
* [`feature-state`](https://docs.mapbox.com/mapbox-gl-js/style-spec/expressions/#feature-state) is now supported. The new functions `setFeatureState()` and `getFeatureState()` can be used to set and get the feature state.
* The build size is now at least 80 kB smaller because of pre-processing of the style specification from the `@mapbox/mapbox-gl-style-spec` package. The umd bundle no longer contains the OpenLayers code that has been there by accident for a few releases, which had unnecessarily increased the build size by almost 400 kB.
* The API docs are now generated with typedoc instead of documentation.js
## 7.1.1

@@ -4,0 +23,0 @@

2

dist/examples/common.js.LICENSE.txt

@@ -1,3 +0,1 @@

/*! https://mths.be/punycode v1.3.2 by @mathias */
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */

@@ -10,3 +10,3 @@ {

"type": "geojson",
"data": "./states.geojson"
"data": "/data/states.geojson"
}

@@ -13,0 +13,0 @@ },

@@ -1,2 +0,2 @@

"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[223],{2044:(s,e,n)=>{n(9789),(0,n(2697).nn)("map","data/geojson-inline.json")}},s=>{s(s.s=2044)}]);
"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[223],{6065:(s,e,n)=>{n(9789),(0,n(5955).nn)("map","data/geojson-inline.json")}},s=>{s(s.s=6065)}]);
//# sourceMappingURL=geojson-inline.js.map

@@ -1,2 +0,2 @@

"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[346],{3370:(s,e,a)=>{a(9789),(0,a(2697).nn)("map","data/geojson.json")}},s=>{s(s.s=3370)}]);
"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[346],{4783:(s,e,a)=>{a(9789),(0,a(5955).nn)("map","data/geojson.json")}},s=>{s(s.s=4783)}]);
//# sourceMappingURL=geojson.js.map

@@ -1,2 +0,2 @@

"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[862],{3863:(e,o,s)=>{s(9789);var c=s(2697),a=document.cookie.replace(/(?:(?:^|.*;\s*)mapbox_access_token\s*\=\s*([^;]*).*$)|^.*$/,"$1");a||(a=window.prompt("Enter your Mapbox API access token:"),document.cookie="mapbox_access_token="+a+"; expires=Fri, 31 Dec 9999 23:59:59 GMT"),(0,c.ZP)("map","https://api.mapbox.com/styles/v1/mapbox/bright-v9?access_token="+a)}},e=>{e(e.s=3863)}]);
"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[862],{7018:(e,o,s)=>{s(9789);var c=s(5955),a=document.cookie.replace(/(?:(?:^|.*;\s*)mapbox_access_token\s*\=\s*([^;]*).*$)|^.*$/,"$1");a||(a=window.prompt("Enter your Mapbox API access token:"),document.cookie="mapbox_access_token="+a+"; expires=Fri, 31 Dec 9999 23:59:59 GMT"),(0,c.ZP)("map","mapbox://styles/mapbox/bright-v9",{accessToken:a})}},e=>{e(e.s=7018)}]);
//# sourceMappingURL=mapbox.js.map

@@ -1,2 +0,2 @@

"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[347],{9312:(e,s,o)=>{o(9789);var t=o(2697),c=document.cookie.replace(/(?:(?:^|.*;\s*)tilehosting_access_token\s*\=\s*([^;]*).*$)|^.*$/,"$1");c||(c=window.prompt("Enter your tilehosting API access token:"),document.cookie="tilehosting_access_token="+c+"; expires=Fri, 31 Dec 9999 23:59:59 GMT"),(0,t.ZP)("map","https://api.maptiler.com/maps/basic/style.json?key="+c)}},e=>{e(e.s=9312)}]);
"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[347],{3563:(e,s,o)=>{o(9789);var t=o(5955),c=document.cookie.replace(/(?:(?:^|.*;\s*)tilehosting_access_token\s*\=\s*([^;]*).*$)|^.*$/,"$1");c||(c=window.prompt("Enter your tilehosting API access token:"),document.cookie="tilehosting_access_token="+c+"; expires=Fri, 31 Dec 9999 23:59:59 GMT"),(0,t.ZP)("map","https://api.maptiler.com/maps/basic/style.json?key="+c)}},e=>{e(e.s=3563)}]);
//# sourceMappingURL=openmaptiles.js.map

@@ -1,2 +0,2 @@

"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[890],{635:(e,t,a)=>{a(9789);var n=a(5812),s=a(5206),o=a(518),r=a(4486),u=a(4286),c=a(9799),l=new o.Z({declutter:!0,source:new r.Z({format:new n.Z,url:"data/states.geojson"})}),w=new s.Z({target:"map",view:new u.ZP({center:[-13603186.115192635,6785744.563386],zoom:2})});fetch("data/states.json").then((function(e){return e.json()})).then((function(e){(0,c.ZP)(l,e,"states"),-1===w.getLayers().getArray().indexOf(l)&&w.addLayer(l)}))}},e=>{e(e.s=635)}]);
"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[890],{4468:(e,t,a)=>{a(9789);var n=a(8833),s=a(6219),o=a(5218),r=a(8275),u=a(8615),c=a(5955),l=new o.Z({declutter:!0,source:new r.Z({format:new n.Z,url:"data/states.geojson"})}),w=new s.Z({target:"map",view:new u.ZP({center:[-13603186.115192635,6785744.563386],zoom:2})});fetch("data/states.json").then((function(e){return e.json()})).then((function(e){(0,c.uX)(l,e,"states"),-1===w.getLayers().getArray().indexOf(l)&&w.addLayer(l)}))}},e=>{e(e.s=4468)}]);
//# sourceMappingURL=stylefunction.js.map

@@ -1,2 +0,2 @@

"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[366],{7521:(s,e,o)=>{o(9789),(0,o(2697).nn)("map"," https://demo.tegola.io/styles/hot-osm.json")}},s=>{s(s.s=7521)}]);
"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[366],{3327:(s,e,o)=>{o(9789),(0,o(5955).nn)("map"," https://demo.tegola.io/styles/hot-osm.json")}},s=>{s(s.s=3327)}]);
//# sourceMappingURL=tilejson-vectortile.js.map

@@ -1,2 +0,2 @@

"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[177],{7090:(s,e,a)=>{a(9789),(0,a(2697).nn)("map","data/tilejson.json")}},s=>{s(s.s=7090)}]);
"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[177],{8492:(s,e,a)=>{a(9789),(0,a(5955).nn)("map","data/tilejson.json")}},s=>{s(s.s=8492)}]);
//# sourceMappingURL=tilejson.js.map

@@ -1,2 +0,2 @@

"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[840],{2522:(s,a,e)=>{e(9789),(0,e(2697).ZP)("map","data/wms.json")}},s=>{s(s.s=2522)}]);
"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[840],{2516:(s,a,e)=>{e(9789),(0,e(5955).ZP)("map","data/wms.json")}},s=>{s(s.s=2516)}]);
//# sourceMappingURL=wms.js.map

@@ -1,179 +0,2 @@

/**
* ```js
* import {applyStyle} from 'ol-mapbox-style';
* ```
*
* Applies a style function to an `ol.layer.VectorTile` or `ol.layer.Vector`
* with an `ol.source.VectorTile` or an `ol.source.Vector`. The style function
* will render all layers from the `glStyle` object that use 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.
* @param {string|Object} glStyle Mapbox Style object.
* @param {string|Array<string>} source `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 {string} [path=undefined] Path of the style file. Only required when
* a relative path is used with the `"sprite"` property of the style.
* @param {Array<number>} [resolutions=undefined] Resolutions for mapping resolution to zoom level.
* @return {Promise} Promise which will be resolved when the style can be used
* for rendering.
*/
export function applyStyle(layer: VectorTileLayer | VectorLayer, glStyle: string | any, source: string | Array<string>, path?: string, resolutions?: Array<number>): Promise<any>;
/**
* ```js
* import {applyBackground} from 'ol-mapbox-style';
* ```
* Applies properties of the Mapbox Style's first `background` layer to the
* provided map or VectorTile layer.
* @param {PluggableMap|VectorTileLayer} mapOrLayer OpenLayers Map or VectorTile layer.
* @param {Object} glStyle Mapbox Style object.
*/
export function applyBackground(mapOrLayer: PluggableMap | VectorTileLayer, glStyle: any): void;
/**
* Creates an OpenLayers VectorTile source for a gl source entry.
* @param {Object} glSource "source" entry from a Mapbox Style object.
* @param {string|undefined} url URL to use for the source. This is expected to be the complete http(s) url,
* with access key applied.When not provided, `glSource.tiles` has to be set.
* @return {Promise<import("ol/source/VectorTile").default>} Promise resolving to a VectorTile source.
* @private
*/
export function setupVectorSource(glSource: any, url: string | undefined): Promise<any>;
/**
* ```js
* import olms from 'ol-mapbox-style';
* ```
*
* Loads and applies a Mapbox Style object to an OpenLayers Map. This includes
* the map background, the layers, the center and the zoom.
*
* 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 instance, which holds the Mapbox Style object.
*
* @param {PluggableMap|HTMLElement|string} map 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.
* @param {string|Object} style JSON style object or style url pointing to a
* Mapbox Style object. When using Mapbox APIs, the url must contain an access
* token and look like
* `https://api.mapbox.com/styles/v1/mapbox/bright-v9?access_token=[your_access_token_here]`.
* 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.
* @return {Promise} A promise that resolves after all layers have been added to
* the OpenLayers Map instance, their sources set, and their styles applied. the
* `resolve` callback will be called with the OpenLayers Map instance as
* argument.
*/
export default function olms(map: PluggableMap | HTMLElement | string, style: string | any): Promise<any>;
/**
* ```js
* import {apply} from 'ol-mapbox-style';
* ```
* Like `olms`, but returns an `ol/Map` instance instead of a `Promise`.
*
* @param {PluggableMap|HTMLElement|string} map 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.
* @param {string|Object} style JSON style object or style url pointing to a
* Mapbox Style object. When using Mapbox APIs, the url must contain an access
* token and look like
* `https://api.mapbox.com/styles/v1/mapbox/bright-v9?access_token=[your_access_token_here]`.
* 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.
* @return {PluggableMap} The OpenLayers Map instance that will be populated with the
* contents described in the Mapbox Style object.
*/
export function apply(map: PluggableMap | HTMLElement | string, style: string | any): any;
/**
* ```js
* import {getLayer} from 'ol-mapbox-style';
* ```
* 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 {PluggableMap} map OpenLayers Map.
* @param {string} layerId Mapbox Style layer id.
* @return {Layer} OpenLayers layer instance.
*/
export function getLayer(map: any, layerId: string): any;
/**
* ```js
* import {getLayers} from 'ol-mapbox-style';
* ```
* Get the OpenLayers layer instances for the provided Mapbox Style `source`.
* @param {PluggableMap} map OpenLayers Map.
* @param {string} sourceId Mapbox Style source id.
* @return {Array<Layer>} OpenLayers layer instances.
*/
export function getLayers(map: any, sourceId: string): Array<Layer>;
/**
* ```js
* import {getSource} from 'ol-mapbox-style';
* ```
* Get the OpenLayers source instance for the provided Mapbox Style `source`.
* @param {PluggableMap} map OpenLayers Map.
* @param {string} sourceId Mapbox Style source id.
* @return {Source} OpenLayers source instance.
*/
export function getSource(map: any, sourceId: string): any;
export type PluggableMap = any;
export type Layer = any;
export type Source = any;
/**
* 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<string>} layerIds Array containing layer ids of already-processed layers.
* @param {Object} glStyle Style as a JSON object.
* @param {string|undefined} path The path part of the style URL. Only required
* when a relative path is used with the `"sprite"` property of the style.
* @param {PluggableMap} map OpenLayers Map.
* @return {Promise} Returns a promise that resolves after the source has
* been set on the specified layer, and the style has been applied.
* @private
*/
declare function finalizeLayer(layer: any, layerIds: Array<string>, glStyle: any, path: string | undefined, map: any): Promise<any>;
/**
* @private
* @param {Array} fonts Fonts.
* @return {Array} Processed fonts.
*/
declare function getFonts(fonts: any[]): any[];
export { finalizeLayer as _finalizeLayer, getFonts as _getFonts };
//# sourceMappingURL=index.d.ts.map
export { stylefunction, recordStyleLayer, renderTransparent } from "./stylefunction.js";
export { apply as default, apply, applyBackground, applyStyle, getFeatureState, setFeatureState, getLayer, getLayers, getSource } from "./apply.js";

@@ -9,9 +9,7 @@ /**

* @param {Object} [functionCache] Function cache.
* @param {Object} [featureState] Feature state.
* @return {?} Value.
*/
export function getValue(layer: any, layoutOrPaint: string, property: string, zoom: number, feature: any, functionCache?: any): unknown;
export function getValue(layer: any, layoutOrPaint: string, property: string, zoom: number, feature: any, functionCache?: any, featureState?: any): unknown;
/**
* ```js
* import {renderTransparent} from 'ol-mapbox-style/dist/stylefunction';
* ```
* Configure whether features with a transparent style should be rendered. When

@@ -26,5 +24,2 @@ * set to `true`, it will be possible to hit detect content that is not visible,

/**
* ```js
* import {recordStyleLayer} from 'ol-mapbox-style/dist/stylefunction';
* ```
* Turns recording of the Mapbox Style's `layer` on and off. When turned on,

@@ -35,7 +30,4 @@ * the layer that a rendered feature belongs to will be set as the feature's

*/
export function recordStyleLayer(record?: boolean): void;
export function recordStyleLayer(record?: boolean | undefined): void;
/**
* ```js
* import stylefunction from 'ol-mapbox-style/dist/stylefunction';
* ```
* Creates a style function from the `glStyle` object for all layers that use

@@ -83,3 +75,3 @@ * the specified `source`, which needs to be a `"type": "vector"` or

* @param {string|Object} glStyle Mapbox Style object.
* @param {string|Array<string>} source `source` key or an array of layer `id`s
* @param {string|Array<string>} sourceOrLayers `source` key or an array of layer `id`s
* from the Mapbox Style object. When a `source` key is provided, all layers for

@@ -104,13 +96,13 @@ * the specified source will be included in the style function. When layer `id`s

*/
export default function _default(olLayer: VectorLayer | VectorTileLayer, glStyle: string | any, source: string | Array<string>, resolutions?: Array<number>, spriteData?: any, spriteImageUrl?: string, getFonts?: (arg0: Array<string>) => Array<string>): any;
export type VectorLayer = any;
export type VectorTileLayer = any;
export type StyleFunction = any;
export function stylefunction(olLayer: import("ol/layer/Vector").default<any> | VectorTileLayer, glStyle: string | any, sourceOrLayers: string | Array<string>, resolutions?: number[] | undefined, spriteData?: any, spriteImageUrl?: string | undefined, getFonts?: ((arg0: Array<string>) => Array<string>) | undefined): StyleFunction;
export type VectorLayer = import("ol/layer/Vector").default<any>;
export type VectorTileLayer = import("ol/layer/VectorTile").default;
export type StyleFunction = import("ol/style/Style").StyleFunction;
/**
* @private
* @param {?} color Color.
* @param {number} opacity Opacity.
* @param {number} [opacity] Opacity.
* @return {string} Color.
*/
declare function colorWithOpacity(color: unknown, opacity: number): string;
declare function colorWithOpacity(color: unknown, opacity?: number | undefined): string;
/**

@@ -134,2 +126,1 @@ * @private

export { colorWithOpacity as _colorWithOpacity, evaluateFilter as _evaluateFilter, fromTemplate as _fromTemplate, getValue as _getValue };
//# sourceMappingURL=stylefunction.d.ts.map

@@ -9,6 +9,21 @@ export function deg2rad(degrees: any): number;

export function getZoomForResolution(resolution: any, resolutions: any): number;
export function applyLetterSpacing(text: any, letterSpacing: any): any;
export function wrapText(text: any, font: any, em: any, letterSpacing: any): any;
export function assign(target: any, var_sources: any, ...args: any[]): any;
/**
* @param {ResourceType} resourceType Type of resource to load.
* @param {string} url Url of the resource.
* @param {Options} [options={}] Options.
* @return {Promise<Object|Response>} Promise that resolves with the loaded resource
* or rejects with the Response object.
* @private
*/
export function fetchResource(resourceType: ResourceType, url: string, options?: import("./apply.js").Options | undefined): Promise<any | Response>;
export function getGlStyle(glStyleOrUrl: any, options: any): Promise<any>;
/**
* @param {Object} glSource glStyle source object.
* @param {string} styleUrl Style URL.
* @param {Options} options Options.
* @return {Object} TileJson
*/
export function getTileJson(glSource: any, styleUrl: string, options?: Options): any;
export const defaultResolutions: number[];
//# sourceMappingURL=util.d.ts.map
export type Options = import("./apply.js").Options;
export type ResourceType = import('./apply.js').ResourceType;
{
"name": "ol-mapbox-style",
"version": "7.1.1",
"version": "8.0.0",
"description": "Create OpenLayers maps from Mapbox Style objects",
"main": "dist/index.js",
"type": "module",
"main": "dist/olms.js",
"module": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"module": "./dist/index.js",
"require": "./dist/olms.js"
}
},
"repository": {

@@ -24,3 +32,3 @@ "type": "git",

"build": "tsc --project tsconfig-build.json && webpack-cli --mode=production --config ./webpack.config.olms.cjs && webpack-cli --mode=production --config ./webpack.config.examples.cjs",
"doc": "documentation readme -s API src/index.js src/stylefunction.js --document-exported true",
"doc": "typedoc --plugin typedoc-plugin-markdown --plugin typedoc-plugin-missing-exports src/index.js --readme none --excludeExternals --internalNamespace 'types' --tsconfig tsconfig-typecheck.json",
"karma": "karma start test/karma.conf.cjs",

@@ -33,3 +41,3 @@ "lint": "eslint test examples src",

"dependencies": {
"@mapbox/mapbox-gl-style-spec": "^13.20.1",
"@mapbox/mapbox-gl-style-spec": "^13.23.1",
"mapbox-to-css-font": "^2.4.1",

@@ -40,4 +48,3 @@ "webfont-matcher": "^1.1.0"

"@types/arcgis-rest-api": "^10.4.4",
"@types/geojson": "^7946.0.7",
"@types/node": "^17.0.1",
"@types/mocha": "^9.1.0",
"@types/offscreencanvas": "^2019.6.4",

@@ -52,3 +59,2 @@ "@types/topojson-specification": "^1.0.1",

"deep-freeze": "0.0.1",
"documentation": "^13.2.5",
"eslint": "^8.2.0",

@@ -58,2 +64,3 @@ "eslint-config-openlayers": "^16.0.1",

"html-webpack-plugin": "^5.5.0",
"json-strip-loader": "^1.0.5",
"karma": "^6.3.4",

@@ -68,7 +75,12 @@ "karma-chrome-launcher": "^3.1.0",

"mocha": "^9.1.3",
"ol": "^6.12.1-dev.1645634577440",
"nanoassert": "^2.0.0",
"ol": "^6.14.1",
"puppeteer": "^13.0.0",
"remove-flow-types-loader": "^1.1.0",
"should": "^13.2.3",
"sinon": "^13.0.0",
"style-loader": "^3.3.1",
"typedoc": "^0.22.14",
"typedoc-plugin-markdown": "^3.11.14",
"typedoc-plugin-missing-exports": "^0.22.6",
"typescript": "^4.6.0-beta",

@@ -75,0 +87,0 @@ "webpack": "^5.62.1",

@@ -21,13 +21,2 @@ To create and publish a release, perform the following steps:

### Update README when API docs changed
To build the docs, run
npm run doc
When the above results in changes to README.md, commit these changes to master:
git add README.md
git commit -m "Update API docs in README"
### Merge the release branch

@@ -43,4 +32,4 @@

git add -f dist
git commit -m "Add dist for v2.11.0"
git add -f dist docs
git commit -m "Add dist and docs for v2.11.0"

@@ -47,0 +36,0 @@ ### Create and push a tag

@@ -13,33 +13,39 @@ # ol-mapbox-style

When installed this way, just import the ol-mapbox-style module, like in the usage example below. To use a standalone build of ol-mapbox-style, just include 'dist/olms.js' on your HTML page, and access the global `olms` object.
When installed this way, just import the ol-mapbox-style module, like in the usage example below. To use a standalone build of ol-mapbox-style, just include 'dist/olms.js' on your HTML page, and access the exported functions from the global `olms` object (e.g. `olms.apply()`, `olms.applyBackground()`). Note that the standalone build depends on the legacy build of OpenLayers.
**ol-mapbox-style requires [OpenLayers](https://npmjs.com/package/ol) version >= 6.13.0 < 7**.
### Usage example
### Usage examples
The code below creates an OpenLayers map from Mapbox's Bright v9 style:
The code below creates an OpenLayers map from Mapbox's Bright v9 style, using a `https://` url:
```js
import olms from 'ol-mapbox-style';
import apply from 'ol-mapbox-style';
var key = 'Your Mapbox Access Token here';
olms('map', 'https://api.mapbox.com/styles/v1/mapbox/bright-v9?access_token=' + key);
apply('map', 'https://api.mapbox.com/styles/v1/mapbox/bright-v9?access_token=YOUR_MAPBOX_TOKEN');
```
To assign style and source to a layer only, use `applyStyle()`. `mapbox://` urls are also supported:
```js
import {applyStyle} from 'ol-mapbox-style';
import VectorTileLayer from 'ol/layer/VectorTile.js'
const layer = new VectorTileLayer({declutter: true});
applyStyle(layer, 'mapbox://styles/mapbox/bright-v9', {accessToken: 'YOUR_MAPBOX_TOKEN'});
```
Only commonly available system fonts and [Google Fonts](https://developers.google.com/fonts/) will automatically be available for any `text-font` defined in the Mapbox Style object. It is the responsibility of the application to load other fonts. Because `ol-mapbox-style` uses system and web fonts instead of PBF/SDF glyphs, the [font stack](https://www.mapbox.com/help/manage-fontstacks/) is treated a little different: style and weight are taken from the primary font (i.e. the first one in the font stack). Subsequent fonts in the font stack are only used if the primary font is not available/loaded, and they will be used with the style and weight of the primary font.
To apply a subset of the layers defined in the Mapbox Style layer to a custom OpenLayers layer, use the `applyStyle()` function.
To apply the properties of the Mapbox Style's `background` layer to the map or a `VectorTile` layer, use the `applyBackground()` function.
To create a style function for individual OpenLayers vector or vector tile layers, use the `stylefunction` module:
There is also a low-level API available. To create a style function for individual OpenLayers vector or vector tile layers, use the `stylefunction` module:
```js
import stylefunction from 'ol-mapbox-style/dist/stylefunction';
// OpenLayers imports from https://npmjs.com/package/ol
import VectorLayer from 'ol/layer/Vector';
import VectorSource from 'ol/source/Vector';
import GeoJSON from 'ol/format/GeoJSON';
import {stylefunction} from 'ol-mapbox-style';
import VectorLayer from 'ol/layer/Vector.js';
import VectorSource from 'ol/source/Vector.js';
import GeoJSON from 'ol/format/GeoJSON.js';
var layer = new VectorLayer({
const layer = new VectorLayer({
source: new VectorSource({

@@ -58,2 +64,4 @@ format: new GeoJSON(),

Note that this low-level API does not create a source for the layer, and extra work is required to set up sprite handling for styles that use icons.
## Compatibility notes

@@ -69,297 +77,4 @@

<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
Consult the [documentation](./docs/README.md) for the full API.
#### Table of Contents
* [applyStyle](#applystyle)
* [Parameters](#parameters)
* [renderTransparent](#rendertransparent)
* [Parameters](#parameters-1)
* [recordStyleLayer](#recordstylelayer)
* [Parameters](#parameters-2)
* [stylefunction](#stylefunction)
* [Parameters](#parameters-3)
* [applyBackground](#applybackground)
* [Parameters](#parameters-4)
* [olms](#olms)
* [Parameters](#parameters-5)
* [apply](#apply)
* [Parameters](#parameters-6)
* [getLayer](#getlayer)
* [Parameters](#parameters-7)
* [getLayers](#getlayers)
* [Parameters](#parameters-8)
* [getSource](#getsource)
* [Parameters](#parameters-9)
### applyStyle
```js
import {applyStyle} from 'ol-mapbox-style';
```
Applies a style function to an `ol.layer.VectorTile` or `ol.layer.Vector`
with an `ol.source.VectorTile` or an `ol.source.Vector`. The style function
will render all layers from the `glStyle` object that use 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.
#### Parameters
* `layer` **(VectorTileLayer | VectorLayer)** OpenLayers layer.
* `glStyle` **([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) | [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** Mapbox Style object.
* `source` **([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) | [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>)** `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.
* `path` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Path of the style file. Only required when
a relative path is used with the `"sprite"` property of the style. (optional, default `undefined`)
* `resolutions` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)>** Resolutions for mapping resolution to zoom level. (optional, default `undefined`)
Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** Promise which will be resolved when the style can be used
for rendering.
### renderTransparent
```js
import {renderTransparent} from 'ol-mapbox-style/dist/stylefunction';
```
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()`
#### Parameters
* `enabled` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Rendering of transparent elements is enabled.
Default is `false`.
### recordStyleLayer
```js
import {recordStyleLayer} from 'ol-mapbox-style/dist/stylefunction';
```
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.
#### Parameters
* `record` **[boolean](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean)** Recording of the style layer is on. (optional, default `false`)
### stylefunction
```js
import stylefunction from 'ol-mapbox-style/dist/stylefunction';
```
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;
}
});
```
#### Parameters
* `olLayer` **(VectorLayer | VectorTileLayer)** 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.
* `glStyle` **([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) | [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** Mapbox Style object.
* `source` **([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) | [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>)** `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.
* `resolutions` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[number](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number)>** Resolutions for mapping resolution to zoom level. (optional, default `[78271.51696402048,39135.75848201024,19567.87924100512,9783.93962050256,4891.96981025128,2445.98490512564,1222.99245256282,611.49622628141,305.748113140705,152.8740565703525,76.43702828517625,38.21851414258813,19.109257071294063,9.554628535647032,4.777314267823516,2.388657133911758,1.194328566955879,0.5971642834779395,0.29858214173896974,0.14929107086948487,0.07464553543474244]`)
* `spriteData` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** 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. (optional, default `undefined`)
* `spriteImageUrl` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** 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. (optional, default `undefined`)
* `getFonts` **function ([Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>): [Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>** Function that
receives a font stack 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. (optional, default `undefined`)
Returns **StyleFunction** Style function for use in
`ol.layer.Vector` or `ol.layer.VectorTile`.
### applyBackground
```js
import {applyBackground} from 'ol-mapbox-style';
```
Applies properties of the Mapbox Style's first `background` layer to the
provided map or VectorTile layer.
#### Parameters
* `mapOrLayer` **(PluggableMap | VectorTileLayer)** OpenLayers Map or VectorTile layer.
* `glStyle` **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** Mapbox Style object.
### olms
```js
import olms from 'ol-mapbox-style';
```
Loads and applies a Mapbox Style object to an OpenLayers Map. This includes
the map background, the layers, the center and the zoom.
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 instance, which holds the Mapbox Style object.
#### Parameters
* `map` **(PluggableMap | [HTMLElement](https://developer.mozilla.org/docs/Web/HTML/Element) | [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String))** 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.
* `style` **([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) | [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** JSON style object or style url pointing to a
Mapbox Style object. When using Mapbox APIs, the url must contain an access
token and look like
`https://api.mapbox.com/styles/v1/mapbox/bright-v9?access_token=[your_access_token_here]`.
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.
Returns **[Promise](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise)** A promise that resolves after all layers have been added to
the OpenLayers Map instance, their sources set, and their styles applied. the
`resolve` callback will be called with the OpenLayers Map instance as
argument.
### apply
```js
import {apply} from 'ol-mapbox-style';
```
Like `olms`, but returns an `ol/Map` instance instead of a `Promise`.
#### Parameters
* `map` **(PluggableMap | [HTMLElement](https://developer.mozilla.org/docs/Web/HTML/Element) | [string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String))** 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.
* `style` **([string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String) | [Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object))** JSON style object or style url pointing to a
Mapbox Style object. When using Mapbox APIs, the url must contain an access
token and look like
`https://api.mapbox.com/styles/v1/mapbox/bright-v9?access_token=[your_access_token_here]`.
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.
Returns **PluggableMap** The OpenLayers Map instance that will be populated with the
contents described in the Mapbox Style object.
### getLayer
```js
import {getLayer} from 'ol-mapbox-style';
```
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`.
#### Parameters
* `map` **PluggableMap** OpenLayers Map.
* `layerId` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Mapbox Style layer id.
Returns **Layer** OpenLayers layer instance.
### getLayers
```js
import {getLayers} from 'ol-mapbox-style';
```
Get the OpenLayers layer instances for the provided Mapbox Style `source`.
#### Parameters
* `map` **PluggableMap** OpenLayers Map.
* `sourceId` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Mapbox Style source id.
Returns **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)\<Layer>** OpenLayers layer instances.
### getSource
```js
import {getSource} from 'ol-mapbox-style';
```
Get the OpenLayers source instance for the provided Mapbox Style `source`.
#### Parameters
* `map` **PluggableMap** OpenLayers Map.
* `sourceId` **[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)** Mapbox Style source id.
Returns **Source** OpenLayers source instance.
## Building the library

@@ -366,0 +81,0 @@

@@ -1,912 +0,16 @@

/*
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
*/
import GeoJSON from 'ol/format/GeoJSON.js';
import MVT from 'ol/format/MVT.js';
import Map from 'ol/Map.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 from 'ol/source/VectorTile.js';
import View from 'ol/View.js';
import applyStyleFunction, {
_colorWithOpacity,
getValue,
export {
stylefunction,
recordStyleLayer,
renderTransparent,
} from './stylefunction.js';
import googleFonts from 'webfont-matcher/lib/fonts/google.js';
import mb2css from 'mapbox-to-css-font';
import {Color} from '@mapbox/mapbox-gl-style-spec';
import {assign, defaultResolutions} from './util.js';
import {createXYZ} from 'ol/tilegrid.js';
import {fromLonLat} from 'ol/proj.js';
import {unByKey} from 'ol/Observable.js';
/**
* @typedef {import("ol/Map").default} PluggableMap
* @typedef {import("ol/layer/Layer").default} Layer
* @typedef {import("ol/source/Source").default} Source
* @private
*/
const tilejsonCache = {};
const fontFamilyRegEx = /font-family: ?([^;]*);/;
const stripQuotesRegEx = /("|')/g;
let loadedFontFamilies;
function hasFontFamily(family) {
if (!loadedFontFamilies) {
loadedFontFamilies = {};
const styleSheets = document.styleSheets;
for (let i = 0, ii = styleSheets.length; i < ii; ++i) {
const styleSheet = /** @type {CSSStyleSheet} */ (styleSheets[i]);
try {
const cssRules = styleSheet.rules || styleSheet.cssRules;
if (cssRules) {
for (let j = 0, jj = cssRules.length; j < jj; ++j) {
const cssRule = cssRules[j];
if (cssRule.type == 5) {
const match = cssRule.cssText.match(fontFamilyRegEx);
loadedFontFamilies[match[1].replace(stripQuotesRegEx, '')] = true;
}
}
}
} catch (e) {
// empty catch block
}
}
}
return family in loadedFontFamilies;
}
const processedFontFamilies = {};
const googleFamilies = googleFonts.getNames();
/**
* @private
* @param {Array} fonts Fonts.
* @return {Array} Processed fonts.
*/
function getFonts(fonts) {
const fontsKey = fonts.toString();
if (fontsKey in processedFontFamilies) {
return fonts;
}
const googleFontDescriptions = fonts.map(function (font) {
const parts = mb2css(font, 1).split(' ');
return [parts.slice(3).join(' ').replace(/"/g, ''), parts[1] + parts[0]];
});
for (let i = 0, ii = googleFontDescriptions.length; i < ii; ++i) {
const googleFontDescription = googleFontDescriptions[i];
const family = googleFontDescription[0];
if (!hasFontFamily(family) && googleFamilies.indexOf(family) !== -1) {
const fontUrl =
'https://fonts.googleapis.com/css?family=' +
family.replace(/ /g, '+') +
':' +
googleFontDescription[1];
if (!document.querySelector('link[href="' + fontUrl + '"]')) {
const markup = document.createElement('link');
markup.href = fontUrl;
markup.rel = 'stylesheet';
document.head.appendChild(markup);
}
}
}
processedFontFamilies[fontsKey] = true;
return fonts;
}
const spriteRegEx = /^(.*)(\?.*)$/;
function withPath(url, path) {
if (path && url.indexOf('.') === 0) {
url = path + url;
}
return url;
}
function toSpriteUrl(url, path, extension) {
url = withPath(url, path);
const parts = url.match(spriteRegEx);
return parts
? parts[1] + extension + (parts.length > 2 ? parts[2] : '')
: url + extension;
}
/**
* ```js
* import {applyStyle} from 'ol-mapbox-style';
* ```
*
* Applies a style function to an `ol.layer.VectorTile` or `ol.layer.Vector`
* with an `ol.source.VectorTile` or an `ol.source.Vector`. The style function
* will render all layers from the `glStyle` object that use 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.
* @param {string|Object} glStyle Mapbox Style object.
* @param {string|Array<string>} source `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 {string} [path=undefined] Path of the style file. Only required when
* a relative path is used with the `"sprite"` property of the style.
* @param {Array<number>} [resolutions=undefined] Resolutions for mapping resolution to zoom level.
* @return {Promise} Promise which will be resolved when the style can be used
* for rendering.
*/
export function applyStyle(layer, glStyle, source, path, resolutions) {
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
if (typeof glStyle != 'object') {
glStyle = JSON.parse(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')
);
}
let spriteScale, spriteData, spriteImageUrl, style;
function onChange() {
if (!style && (!glStyle.sprite || spriteData)) {
style = applyStyleFunction(
layer,
glStyle,
source,
resolutions,
spriteData,
spriteImageUrl,
getFonts
);
if (!layer.getStyle()) {
reject(new Error(`Nothing to show for source [${source}]`));
} else {
resolve();
}
} else if (style) {
layer.setStyle(style);
resolve();
} else {
reject(new Error('Something went wrong trying to apply style.'));
}
}
if (glStyle.sprite) {
spriteScale = window.devicePixelRatio >= 1.5 ? 0.5 : 1;
const sizeFactor = spriteScale == 0.5 ? '@2x' : '';
let spriteUrl = toSpriteUrl(glStyle.sprite, path, sizeFactor + '.json');
fetch(spriteUrl, {credentials: 'same-origin'})
.then(function (response) {
if (!response.ok && sizeFactor !== '') {
spriteUrl = toSpriteUrl(glStyle.sprite, path, '.json');
return fetch(spriteUrl, {credentials: 'same-origin'});
} else {
return response;
}
})
.then(function (response) {
if (response.ok) {
return response.json();
} else {
reject(
new Error(
`Problem fetching sprite from ${spriteUrl}: ${response.statusText}`
)
);
}
})
.then(function (spritesJson) {
if (spritesJson === undefined) {
return reject(new Error('No sprites found.'));
}
spriteData = spritesJson;
spriteImageUrl = toSpriteUrl(
glStyle.sprite,
path,
sizeFactor + '.png'
);
onChange();
})
.catch(function (err) {
reject(
new Error(`Sprites cannot be loaded: ${spriteUrl}: ${err.message}`)
);
});
} else {
onChange();
}
});
}
const emptyObj = {};
function setBackground(mapOrLayer, layer) {
const background = {
id: layer.id,
type: layer.type,
};
const functionCache = {};
function updateStyle(resolution) {
const layout = layer.layout || {};
const paint = layer.paint || {};
background['paint'] = paint;
const zoom =
typeof mapOrLayer.getSource === 'function'
? mapOrLayer.getSource().getTileGrid().getZForResolution(resolution)
: mapOrLayer.getView().getZoom();
const element =
typeof mapOrLayer.getTargetElement === 'function'
? mapOrLayer.getTargetElement()
: undefined;
let bg, opacity;
if (paint['background-color'] !== undefined) {
bg = getValue(
background,
'paint',
'background-color',
zoom,
emptyObj,
functionCache
);
if (element) {
element.style.background = Color.parse(bg).toString();
}
}
if (paint['background-opacity'] !== undefined) {
opacity = getValue(
background,
'paint',
'background-opacity',
zoom,
emptyObj,
functionCache
);
if (element) {
element.style.opacity = opacity;
}
}
if (layout.visibility == 'none') {
if (element) {
element.style.backgroundColor = '';
element.style.opacity = '';
}
return undefined;
}
return _colorWithOpacity(bg, opacity);
}
if (typeof mapOrLayer.getTargetElement === 'function') {
if (mapOrLayer.getTargetElement()) {
updateStyle();
}
mapOrLayer.on(['change:resolution', 'change:target'], updateStyle);
} else if (typeof mapOrLayer.setBackground === 'function') {
mapOrLayer.setBackground(updateStyle);
} else {
throw new Error('Unable to apply background.');
}
}
/**
* ```js
* import {applyBackground} from 'ol-mapbox-style';
* ```
* Applies properties of the Mapbox Style's first `background` layer to the
* provided map or VectorTile layer.
* @param {PluggableMap|VectorTileLayer} mapOrLayer OpenLayers Map or VectorTile layer.
* @param {Object} glStyle Mapbox Style object.
*/
export function applyBackground(mapOrLayer, glStyle) {
glStyle.layers.some(function (l) {
if (l.type == 'background') {
setBackground(mapOrLayer, l);
return true;
}
});
}
function getSourceIdByRef(layers, ref) {
let sourceId;
layers.some(function (layer) {
if (layer.id == ref) {
sourceId = layer.source;
return true;
}
});
return sourceId;
}
function extentFromTileJSON(tileJSON) {
const bounds = tileJSON.bounds;
if (bounds) {
const ll = fromLonLat([bounds[0], bounds[1]]);
const tr = fromLonLat([bounds[2], bounds[3]]);
return [ll[0], ll[1], tr[0], tr[1]];
}
}
/**
* Creates an OpenLayers VectorTile source for a gl source entry.
* @param {Object} glSource "source" entry from a Mapbox Style object.
* @param {string|undefined} url URL to use for the source. This is expected to be the complete http(s) url,
* with access key applied.When not provided, `glSource.tiles` has to be set.
* @return {Promise<import("ol/source/VectorTile").default>} Promise resolving to a VectorTile source.
* @private
*/
export function setupVectorSource(glSource, url) {
glSource = assign({}, glSource);
const cacheKey = [url, JSON.stringify(glSource)].toString();
let tilejson = tilejsonCache[cacheKey];
if (!tilejson) {
tilejson = new TileJSON({
url: glSource.tiles ? undefined : url,
tileJSON: glSource.tiles ? glSource : undefined,
});
tilejsonCache[cacheKey] = tilejson;
}
return new Promise((resolve) => {
const key = tilejson.on('change', function () {
const state = tilejson.getState();
if (state === 'ready') {
const tileJSONDoc = tilejson.getTileJSON();
const tiles = Array.isArray(tileJSONDoc.tiles)
? tileJSONDoc.tiles
: [tileJSONDoc.tiles];
if (url) {
for (let i = 0, ii = tiles.length; i < ii; ++i) {
tiles[i] = decodeURI(new URL(tiles[i], url).href);
}
}
const tileGrid = tilejson.getTileGrid();
const extent = extentFromTileJSON(tileJSONDoc);
const minZoom = tileJSONDoc.minzoom || 0;
const maxZoom = tileJSONDoc.maxzoom || 22;
let source = tilejson.get('ol-source');
if (source === undefined) {
source = new VectorTileSource({
attributions: tilejson.getAttributions(),
format: new MVT(),
tileGrid: new TileGrid({
origin: tileGrid.getOrigin(0),
extent: extent || tileGrid.getExtent(),
minZoom: minZoom,
resolutions: defaultResolutions.slice(0, maxZoom + 1),
tileSize: 512,
}),
urls: tiles,
});
tilejson.set('ol-source', source);
}
unByKey(key);
resolve(source);
} else if (state === 'error') {
tilejson.set('ol-source', null);
unByKey(key);
resolve(undefined);
}
});
if (tilejson.getState() === 'ready') {
tilejson.changed();
}
});
}
function setupVectorLayer(glSource, url) {
const layer = new VectorTileLayer({
declutter: true,
visible: false,
});
setupVectorSource(glSource, url).then((source) => {
layer.setSource(source);
});
return layer;
}
function setupRasterLayer(glSource, url) {
const layer = new TileLayer();
const source = new TileJSON({
transition: 0,
url: glSource.tiles ? undefined : url,
tileJSON: glSource.tiles ? glSource : undefined,
crossOrigin: 'anonymous',
});
const key = source.on('change', function () {
const state = source.getState();
if (state === 'ready') {
unByKey(key);
const tileJSONDoc = /** @type {Object} */ (source.getTileJSON());
const extent = extentFromTileJSON(tileJSONDoc);
const tileGrid = source.getTileGrid();
const tileSize = glSource.tileSize || tileJSONDoc.tileSize || 512;
const minZoom = tileJSONDoc.minzoom || 0;
const maxZoom = tileJSONDoc.maxzoom || 22;
// Only works when using ES modules
//@ts-ignore
source.tileGrid = new TileGrid({
origin: tileGrid.getOrigin(0),
extent: extent || tileGrid.getExtent(),
minZoom: minZoom,
resolutions: createXYZ({
maxZoom: maxZoom,
tileSize: tileSize,
}).getResolutions(),
tileSize: tileSize,
});
layer.setSource(source);
} else if (state === 'error') {
unByKey(key);
layer.setSource(undefined);
}
});
source.setTileLoadFunction(function (tile, src) {
if (src.indexOf('{bbox-epsg-3857}') != -1) {
const bbox = source.getTileGrid().getTileCoordExtent(tile.getTileCoord());
src = src.replace('{bbox-epsg-3857}', bbox.toString());
}
const img = /** @type {import("ol/ImageTile").default} */ (tile).getImage();
/** @type {HTMLImageElement} */ (img).src = src;
});
return layer;
}
const geoJsonFormat = new GeoJSON();
function setupGeoJSONLayer(glSource, path) {
const data = glSource.data;
let features, geoJsonUrl;
if (typeof data == 'string') {
geoJsonUrl = withPath(data, path);
} else {
features = geoJsonFormat.readFeatures(data, {
featureProjection: 'EPSG:3857',
});
}
return new VectorLayer({
declutter: true,
source: new VectorSource({
attributions: glSource.attribution,
features: features,
format: geoJsonFormat,
url: geoJsonUrl,
}),
visible: false,
});
}
function updateRasterLayerProperties(glLayer, layer, view, functionCache) {
const zoom = view.getZoom();
const opacity = getValue(
glLayer,
'paint',
'raster-opacity',
zoom,
emptyObj,
functionCache
);
layer.setOpacity(opacity);
}
function processStyle(glStyle, map, baseUrl, host, path, accessToken = '') {
const promises = [];
let view = map.getView();
if (!view.isDef() && !view.getRotation() && !view.getResolutions()) {
view = new View(
assign(view.getProperties(), {
maxResolution: defaultResolutions[0],
})
);
map.setView(view);
}
if ('center' in glStyle && !view.getCenter()) {
view.setCenter(fromLonLat(glStyle.center));
}
if ('zoom' in glStyle && view.getZoom() === undefined) {
view.setResolution(defaultResolutions[0] / Math.pow(2, glStyle.zoom));
}
if (!view.getCenter() || view.getZoom() === undefined) {
view.fit(view.getProjection().getExtent(), {
nearest: true,
size: map.getSize(),
});
}
if (glStyle.sprite) {
if (glStyle.sprite.indexOf('mapbox://') == 0) {
glStyle.sprite = baseUrl + '/sprite' + accessToken;
} else if (glStyle.sprite.indexOf('http') != 0) {
glStyle.sprite = (host ? host + path : '') + glStyle.sprite + accessToken;
}
}
const glLayers = glStyle.layers;
let layerIds = [];
let glLayer, glSource, glSourceId, id, layer, url;
for (let i = 0, ii = glLayers.length; i < ii; ++i) {
glLayer = glLayers[i];
const type = glLayer.type;
if (type == 'heatmap' || type == 'hillshade') {
//FIXME Unsupported layer type
} else if (type == 'background') {
setBackground(map, glLayer);
} else {
id = glLayer.source || getSourceIdByRef(glLayers, glLayer.ref);
// this technique assumes gl layers will be in a particular order
if (id != glSourceId) {
if (layerIds.length) {
promises.push(finalizeLayer(layer, layerIds, glStyle, path, map));
layerIds = [];
}
glSource = glStyle.sources[id];
url = glSource.url;
if (url) {
url = withPath(url, path);
if (url.indexOf('mapbox://') == 0) {
const mapid = url.replace('mapbox://', '');
glSource.tiles = ['a', 'b', 'c', 'd'].map(function (host) {
return (
'https://' +
host +
'.tiles.mapbox.com/v4/' +
mapid +
'/{z}/{x}/{y}.' +
(glSource.type == 'vector' ? 'vector.pbf' : 'png') +
accessToken
);
});
} else if (url.indexOf('/') === 0 && host.indexOf('http') === 0) {
url = host + url;
}
}
if (glSource.tiles) {
glSource.tiles = glSource.tiles.map((url) => withPath(url, path));
}
if (glSource.type == 'vector') {
layer = setupVectorLayer(glSource, url);
} else if (glSource.type == 'raster') {
layer = setupRasterLayer(glSource, url);
layer.setVisible(
glLayer.layout ? glLayer.layout.visibility !== 'none' : true
);
const functionCache = {};
view.on(
'change:resolution',
updateRasterLayerProperties.bind(
this,
glLayer,
layer,
view,
functionCache
)
);
updateRasterLayerProperties(glLayer, layer, view, functionCache);
} else if (glSource.type == 'geojson') {
layer = setupGeoJSONLayer(glSource, path);
}
glSourceId = id;
if (layer) {
layer.set('mapbox-source', glSourceId);
}
}
layerIds.push(glLayer.id);
}
}
promises.push(finalizeLayer(layer, layerIds, glStyle, path, map));
map.set('mapbox-style', glStyle);
return Promise.all(promises);
}
/**
* ```js
* import olms from 'ol-mapbox-style';
* ```
*
* Loads and applies a Mapbox Style object to an OpenLayers Map. This includes
* the map background, the layers, the center and the zoom.
*
* 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 instance, which holds the Mapbox Style object.
*
* @param {PluggableMap|HTMLElement|string} map 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.
* @param {string|Object} style JSON style object or style url pointing to a
* Mapbox Style object. When using Mapbox APIs, the url must contain an access
* token and look like
* `https://api.mapbox.com/styles/v1/mapbox/bright-v9?access_token=[your_access_token_here]`.
* 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.
* @return {Promise} A promise that resolves after all layers have been added to
* the OpenLayers Map instance, their sources set, and their styles applied. the
* `resolve` callback will be called with the OpenLayers Map instance as
* argument.
*/
export default function olms(map, style) {
let promise,
accessToken = '',
baseUrl = '',
host = '',
path = '';
if (typeof map === 'string' || map instanceof HTMLElement) {
map = new Map({
target: map,
});
}
if (typeof style === 'string') {
const parts = style.match(spriteRegEx);
if (parts) {
baseUrl = parts[1];
accessToken = parts.length > 2 ? parts[2] : '';
}
promise = new Promise(function (resolve, reject) {
fetch(style, {
credentials: 'same-origin',
})
.then(function (response) {
return response.json();
})
.then(function (glStyle) {
const a = /** @type {HTMLAnchorElement} */ (
document.createElement('A')
);
a.href = style;
const href = a.href;
path = a.pathname.split('/').slice(0, -1).join('/') + '/';
host = href.substr(0, href.indexOf(path));
processStyle(glStyle, map, baseUrl, host, path, accessToken)
.then(function () {
resolve(map);
})
.catch(reject);
})
.catch(function (err) {
reject(new Error(`Could not load ${style}: ${err.message}`));
});
});
} else {
promise = new Promise(function (resolve, reject) {
processStyle(style, map)
.then(function () {
resolve(map);
})
.catch(reject);
});
}
return promise;
}
/**
* ```js
* import {apply} from 'ol-mapbox-style';
* ```
* Like `olms`, but returns an `ol/Map` instance instead of a `Promise`.
*
* @param {PluggableMap|HTMLElement|string} map 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.
* @param {string|Object} style JSON style object or style url pointing to a
* Mapbox Style object. When using Mapbox APIs, the url must contain an access
* token and look like
* `https://api.mapbox.com/styles/v1/mapbox/bright-v9?access_token=[your_access_token_here]`.
* 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.
* @return {PluggableMap} The OpenLayers Map instance that will be populated with the
* contents described in the Mapbox Style object.
*/
export function apply(map, style) {
if (typeof map === 'string' || map instanceof HTMLElement) {
map = new Map({
target: map,
});
}
setTimeout(function () {
olms(map, style);
}, 0);
return map;
}
/**
* 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<string>} layerIds Array containing layer ids of already-processed layers.
* @param {Object} glStyle Style as a JSON object.
* @param {string|undefined} path The path part of the style URL. Only required
* when a relative path is used with the `"sprite"` property of the style.
* @param {PluggableMap} map OpenLayers Map.
* @return {Promise} Returns a promise that resolves after the source has
* been set on the specified layer, and the style has been applied.
* @private
*/
function finalizeLayer(layer, layerIds, glStyle, path, map) {
let minZoom = 24;
let maxZoom = 0;
const glLayers = glStyle.layers;
for (let i = 0, ii = glLayers.length; i < ii; ++i) {
const 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) {
const setStyle = function () {
const 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) {
const tileGrid =
/** @type {import("ol/source/Tile.js").default|import("ol/source/VectorTile.js").default} */ (
source
).getTileGrid();
if (tileGrid) {
const 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);
}
}
}
if (
source instanceof VectorSource ||
source instanceof VectorTileSource
) {
applyStyle(
/** @type {import("ol/layer/Vector").default|import("ol/layer/VectorTile").default} */ (
layer
),
glStyle,
layerIds,
path
).then(
function () {
layer.setVisible(true);
resolve();
},
function (e) {
reject(e);
}
);
} else {
resolve();
}
};
layer.set('mapbox-layers', layerIds);
if (map.getLayers().getArray().indexOf(layer) === -1) {
map.addLayer(layer);
}
if (layer.getSource()) {
setStyle();
} else {
layer.once('change:source', setStyle);
}
});
}
/**
* ```js
* import {getLayer} from 'ol-mapbox-style';
* ```
* 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 {PluggableMap} map OpenLayers Map.
* @param {string} layerId Mapbox Style layer id.
* @return {Layer} OpenLayers layer instance.
*/
export function getLayer(map, layerId) {
const layers = map.getLayers().getArray();
for (let i = 0, ii = layers.length; i < ii; ++i) {
const mapboxLayers = layers[i].get('mapbox-layers');
if (mapboxLayers && mapboxLayers.indexOf(layerId) !== -1) {
return /** @type {Layer} */ (layers[i]);
}
}
}
/**
* ```js
* import {getLayers} from 'ol-mapbox-style';
* ```
* Get the OpenLayers layer instances for the provided Mapbox Style `source`.
* @param {PluggableMap} map OpenLayers Map.
* @param {string} sourceId Mapbox Style source id.
* @return {Array<Layer>} OpenLayers layer instances.
*/
export function getLayers(map, sourceId) {
const result = [];
const layers = map.getLayers().getArray();
for (let i = 0, ii = layers.length; i < ii; ++i) {
if (layers[i].get('mapbox-source') === sourceId) {
result.push(/** @type {Layer} */ (layers[i]));
}
}
return result;
}
/**
* ```js
* import {getSource} from 'ol-mapbox-style';
* ```
* Get the OpenLayers source instance for the provided Mapbox Style `source`.
* @param {PluggableMap} map OpenLayers Map.
* @param {string} sourceId Mapbox Style source id.
* @return {Source} OpenLayers source instance.
*/
export function getSource(map, sourceId) {
const layers = map.getLayers().getArray();
for (let i = 0, ii = layers.length; i < ii; ++i) {
const source = /** @type {Layer} */ (layers[i]).getSource();
if (layers[i].get('mapbox-source') === sourceId) {
return source;
}
}
}
export {finalizeLayer as _finalizeLayer, getFonts as _getFonts};
export {
apply as default,
apply,
applyBackground,
applyStyle,
getFeatureState,
setFeatureState,
getLayer,
getLayers,
getSource,
} from './apply.js';

@@ -15,13 +15,10 @@ /*

import Color from '@mapbox/mapbox-gl-style-spec/util/color.js';
import convertFunction from '@mapbox/mapbox-gl-style-spec/function/convert.js';
import createFilter from '@mapbox/mapbox-gl-style-spec/feature_filter/index.js';
import derefLayers from '@mapbox/mapbox-gl-style-spec/deref.js';
import mb2css from 'mapbox-to-css-font';
import spec from '@mapbox/mapbox-gl-style-spec/reference/v8.json';
import {applyLetterSpacing, wrapText} from './text.js';
import {
Color,
featureFilter as createFilter,
derefLayers,
expression,
function as fn,
latest as spec,
} from '@mapbox/mapbox-gl-style-spec';
import {
applyLetterSpacing,
createCanvas,

@@ -31,4 +28,8 @@ defaultResolutions,

getZoomForResolution,
wrapText,
} from './util.js';
import {
createPropertyExpression,
isExpression,
} from '@mapbox/mapbox-gl-style-spec/expression/index.js';
import {isFunction} from '@mapbox/mapbox-gl-style-spec/function/index.js';

@@ -41,7 +42,2 @@ /**

const isFunction = fn.isFunction;
const convertFunction = fn.convertFunction;
const isExpression = expression.isExpression;
const createPropertyExpression = expression.createPropertyExpression;
const types = {

@@ -94,2 +90,3 @@ 'Point': 1,

* @param {Object} [functionCache] Function cache.
* @param {Object} [featureState] Feature state.
* @return {?} Value.

@@ -103,3 +100,4 @@ */

feature,
functionCache
functionCache,
featureState
) {

@@ -140,3 +138,3 @@ const layerId = layer.id;

zoomObj.zoom = zoom;
return functions[property](zoomObj, feature);
return functions[property](zoomObj, feature, featureState);
}

@@ -167,5 +165,2 @@

/**
* ```js
* import {renderTransparent} from 'ol-mapbox-style/dist/stylefunction';
* ```
* Configure whether features with a transparent style should be rendered. When

@@ -185,3 +180,3 @@ * set to `true`, it will be possible to hit detect content that is not visible,

* @param {?} color Color.
* @param {number} opacity Opacity.
* @param {number} [opacity] Opacity.
* @return {string} Color.

@@ -234,5 +229,2 @@ */

/**
* ```js
* import {recordStyleLayer} from 'ol-mapbox-style/dist/stylefunction';
* ```
* Turns recording of the Mapbox Style's `layer` on and off. When turned on,

@@ -248,5 +240,2 @@ * the layer that a rendered feature belongs to will be set as the feature's

/**
* ```js
* import stylefunction from 'ol-mapbox-style/dist/stylefunction';
* ```
* Creates a style function from the `glStyle` object for all layers that use

@@ -294,3 +283,3 @@ * the specified `source`, which needs to be a `"type": "vector"` or

* @param {string|Object} glStyle Mapbox Style object.
* @param {string|Array<string>} source `source` key or an array of layer `id`s
* @param {string|Array<string>} sourceOrLayers `source` key or an array of layer `id`s
* from the Mapbox Style object. When a `source` key is provided, all layers for

@@ -315,6 +304,6 @@ * the specified source will be included in the style function. When layer `id`s

*/
export default function (
export function stylefunction(
olLayer,
glStyle,
source,
sourceOrLayers,
resolutions = defaultResolutions,

@@ -378,4 +367,4 @@ spriteData,

if (
(typeof source == 'string' && layer.source == source) ||
source.indexOf(layerId) !== -1
(typeof sourceOrLayers == 'string' && layer.source == sourceOrLayers) ||
sourceOrLayers.indexOf(layerId) !== -1
) {

@@ -395,2 +384,6 @@ const sourceLayer = layer['source-layer'];

}
} else if (layer.source !== mapboxSource) {
throw new Error(
`Layer "${layerId}" does not use source "${mapboxSource}`
);
}

@@ -430,2 +423,3 @@ let layers = layersBySourceLayer[sourceLayer];

};
const featureState = olLayer.get('mapbox-featurestate')[feature.getId()];
let stylesLength = -1;

@@ -462,3 +456,4 @@ let featureBelongsToLayer;

f,
functionCache
functionCache,
featureState
);

@@ -472,3 +467,4 @@ if (layer.type + '-pattern' in paint) {

f,
functionCache
functionCache,
featureState
);

@@ -533,3 +529,4 @@ if (fillIcon) {

f,
functionCache
functionCache,
featureState
),

@@ -546,3 +543,4 @@ opacity

f,
functionCache
functionCache,
featureState
),

@@ -595,3 +593,4 @@ opacity

f,
functionCache
functionCache,
featureState
),

@@ -604,3 +603,4 @@ getValue(

f,
functionCache
functionCache,
featureState
)

@@ -615,3 +615,4 @@ )

f,
functionCache
functionCache,
featureState
);

@@ -634,6 +635,22 @@ if (color && width > 0) {

stroke.setLineCap(
getValue(layer, 'layout', 'line-cap', zoom, f, functionCache)
getValue(
layer,
'layout',
'line-cap',
zoom,
f,
functionCache,
featureState
)
);
stroke.setLineJoin(
getValue(layer, 'layout', 'line-join', zoom, f, functionCache)
getValue(
layer,
'layout',
'line-join',
zoom,
f,
functionCache,
featureState
)
);

@@ -647,3 +664,4 @@ stroke.setMiterLimit(

f,
functionCache
functionCache,
featureState
)

@@ -661,3 +679,4 @@ );

f,
functionCache
functionCache,
featureState
).map(function (x) {

@@ -683,3 +702,4 @@ return x * width;

f,
functionCache
functionCache,
featureState
);

@@ -699,3 +719,4 @@ if (iconImage) {

f,
functionCache
functionCache,
featureState
);

@@ -738,3 +759,4 @@ if (type == 2) {

f,
functionCache
functionCache,
featureState
);

@@ -781,3 +803,4 @@ if (

f,
functionCache
functionCache,
featureState
);

@@ -792,3 +815,4 @@ const iconColor =

f,
functionCache
functionCache,
featureState
)

@@ -828,3 +852,4 @@ : null;

f,
functionCache
functionCache,
featureState
).map((v) => -v * spriteImageData.pixelRatio)

@@ -858,3 +883,4 @@ : undefined,

f,
functionCache
functionCache,
featureState
)

@@ -870,3 +896,4 @@ )

f,
functionCache
functionCache,
featureState
)

@@ -882,3 +909,4 @@ );

f,
functionCache
functionCache,
featureState
)

@@ -921,3 +949,4 @@ ]

f,
functionCache
functionCache,
featureState
)

@@ -932,3 +961,4 @@ : 5;

f,
functionCache
functionCache,
featureState
),

@@ -941,8 +971,25 @@ getValue(

f,
functionCache
functionCache,
featureState
)
);
const circleColor = colorWithOpacity(
getValue(layer, 'paint', 'circle-color', zoom, f, functionCache),
getValue(layer, 'paint', 'circle-opacity', zoom, f, functionCache)
getValue(
layer,
'paint',
'circle-color',
zoom,
f,
functionCache,
featureState
),
getValue(
layer,
'paint',
'circle-opacity',
zoom,
f,
functionCache,
featureState
)
);

@@ -955,3 +1002,4 @@ const circleStrokeWidth = getValue(

f,
functionCache
functionCache,
featureState
);

@@ -996,3 +1044,11 @@ const cache_key =

textSize = Math.round(
getValue(layer, 'layout', 'text-size', zoom, f, functionCache)
getValue(
layer,
'layout',
'text-size',
zoom,
f,
functionCache,
featureState
)
);

@@ -1005,3 +1061,4 @@ const fontArray = getValue(

f,
functionCache
functionCache,
featureState
);

@@ -1014,3 +1071,4 @@ textLineHeight = getValue(

f,
functionCache
functionCache,
featureState
);

@@ -1028,3 +1086,4 @@ font = mb2css(

f,
functionCache
functionCache,
featureState
);

@@ -1037,3 +1096,4 @@ maxTextWidth = getValue(

f,
functionCache
functionCache,
featureState
);

@@ -1046,3 +1106,4 @@ const textField = getValue(

f,
functionCache
functionCache,
featureState
);

@@ -1095,3 +1156,4 @@ if (typeof textField === 'object' && textField.sections) {

f,
functionCache
functionCache,
featureState
);

@@ -1143,3 +1205,11 @@ }

deg2rad(
getValue(layer, 'layout', 'text-rotate', zoom, f, functionCache)
getValue(
layer,
'layout',
'text-rotate',
zoom,
f,
functionCache,
featureState
)
)

@@ -1153,3 +1223,4 @@ );

f,
functionCache
functionCache,
featureState
);

@@ -1165,3 +1236,4 @@ const placement =

f,
functionCache
functionCache,
featureState
);

@@ -1176,3 +1248,4 @@ text.setPlacement(placement);

f,
functionCache
functionCache,
featureState
);

@@ -1185,3 +1258,4 @@ const textOffset = getValue(

f,
functionCache
functionCache,
featureState
);

@@ -1194,3 +1268,4 @@ const textTranslate = getValue(

f,
functionCache
functionCache,
featureState
);

@@ -1216,3 +1291,4 @@ // Text offset has to take halo width and line height into account

f,
functionCache
functionCache,
featureState
);

@@ -1229,3 +1305,4 @@ text.setRotateWithView(textRotationAlignment == 'map');

f,
functionCache
functionCache,
featureState
)

@@ -1256,3 +1333,11 @@ ) *

colorWithOpacity(
getValue(layer, 'paint', 'text-color', zoom, f, functionCache),
getValue(
layer,
'paint',
'text-color',
zoom,
f,
functionCache,
featureState
),
opacity

@@ -1263,3 +1348,11 @@ )

const haloColor = colorWithOpacity(
getValue(layer, 'paint', 'text-halo-color', zoom, f, functionCache),
getValue(
layer,
'paint',
'text-halo-color',
zoom,
f,
functionCache,
featureState
),
opacity

@@ -1287,3 +1380,4 @@ );

f,
functionCache
functionCache,
featureState
);

@@ -1320,2 +1414,3 @@ const padding = text.getPadding();

olLayer.set('mapbox-layers', mapboxLayers);
olLayer.set('mapbox-featurestate', {});
return styleFunction;

@@ -1322,0 +1417,0 @@ }

@@ -1,36 +0,4 @@

import EventType from 'ol/events/EventType.js';
import {labelCache} from 'ol/render/canvas.js';
import {listen} from 'ol/events.js';
import {assign} from 'ol/obj.js';
import {normalizeSourceUrl, normalizeStyleUrl} from './mapbox.js';
/**
* Polyfill for Object.assign(). Assigns enumerable and own properties from
* one or more source objects to a target object.
* See https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign.
*
* @param {!Object} target The target object.
* @param {...Object} var_sources The source object(s).
* @return {!Object} The modified target object.
*/
export const assign =
typeof Object.assign === 'function'
? Object.assign
: function (target, var_sources) {
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
const output = Object(target);
for (let i = 1, ii = arguments.length; i < ii; ++i) {
const source = arguments[i];
if (source !== undefined && source !== null) {
for (const key in source) {
if (source.hasOwnProperty(key)) {
output[key] = source[key];
}
}
}
}
return output;
};
export function deg2rad(degrees) {

@@ -77,124 +45,128 @@ return (degrees * Math.PI) / 180;

const hairSpacePool = Array(256).join('\u200A');
export function applyLetterSpacing(text, letterSpacing) {
if (letterSpacing >= 0.05) {
let textWithLetterSpacing = '';
const lines = text.split('\n');
const joinSpaceString = hairSpacePool.slice(
0,
Math.round(letterSpacing / 0.1)
);
for (let l = 0, ll = lines.length; l < ll; ++l) {
if (l > 0) {
textWithLetterSpacing += '\n';
}
textWithLetterSpacing += lines[l].split('').join(joinSpaceString);
}
return textWithLetterSpacing;
const pendingRequests = {};
/**
* @param {ResourceType} resourceType Type of resource to load.
* @param {string} url Url of the resource.
* @param {Options} [options={}] Options.
* @return {Promise<Object|Response>} Promise that resolves with the loaded resource
* or rejects with the Response object.
* @private
*/
export function fetchResource(resourceType, url, options = {}) {
if (url in pendingRequests) {
return pendingRequests[url];
} else {
const request = options.transformRequest
? options.transformRequest(url, resourceType) || new Request(url)
: new Request(url);
const 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] = pendingRequest;
return pendingRequest;
}
return text;
}
let measureContext;
function getMeasureContext() {
if (!measureContext) {
measureContext = createCanvas(1, 1).getContext('2d');
export function getGlStyle(glStyleOrUrl, options) {
if (typeof glStyleOrUrl === 'string') {
if (glStyleOrUrl.trim().startsWith('{')) {
try {
const 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);
}
return measureContext;
}
function measureText(text, letterSpacing) {
return (
getMeasureContext().measureText(text).width +
(text.length - 1) * letterSpacing
);
}
let measureCache = {};
if (labelCache) {
// Only available when using ES modules
//@ts-ignore
listen(labelCache, EventType.CLEAR, function () {
measureCache = {};
});
}
export function wrapText(text, font, em, letterSpacing) {
if (text.indexOf('\n') !== -1) {
const hardLines = text.split('\n');
const lines = [];
for (let i = 0, ii = hardLines.length; i < ii; ++i) {
lines.push(wrapText(hardLines[i], font, em, letterSpacing));
}
return lines.join('\n');
}
const key = em + ',' + font + ',' + text + ',' + letterSpacing;
let wrappedText = measureCache[key];
if (!wrappedText) {
const words = text.split(' ');
if (words.length > 1) {
const ctx = getMeasureContext();
ctx.font = font;
const oneEm = ctx.measureText('M').width;
const maxWidth = oneEm * em;
let line = '';
const lines = [];
// Pass 1 - wrap lines to not exceed maxWidth
for (let i = 0, ii = words.length; i < ii; ++i) {
const word = words[i];
const testLine = line + (line ? ' ' : '') + word;
if (measureText(testLine, letterSpacing) <= maxWidth) {
line = testLine;
} else {
if (line) {
lines.push(line);
const tilejsonCache = {};
/**
* @param {Object} glSource glStyle source object.
* @param {string} styleUrl Style URL.
* @param {Options} options Options.
* @return {Object} TileJson
*/
export function getTileJson(glSource, styleUrl, options = {}) {
const cacheKey = [styleUrl, JSON.stringify(glSource)].toString();
let promise = tilejsonCache[cacheKey];
if (!promise || options.transformRequest) {
const url = glSource.url;
if (url) {
const normalizedUrl = normalizeSourceUrl(
url,
options.accessToken,
options.accessTokenParam || 'access_token',
styleUrl || location.href
);
if (url.startsWith('mapbox://')) {
promise = Promise.resolve(
assign({}, glSource, {
url: undefined,
tiles: normalizedUrl,
})
);
} else {
promise = fetchResource('Source', normalizedUrl, options).then(
function (tileJson) {
for (let i = 0, ii = tileJson.tiles.length; i < ii; ++i) {
const tileUrl = tileJson.tiles[i];
let normalizedTileUrl = normalizeSourceUrl(
tileUrl,
options.accessToken,
options.accessTokenParam || 'access_token',
normalizedUrl || location.href
);
if (options.transformRequest) {
const transformedRequest = options.transformRequest(
normalizedTileUrl,
'Tiles'
);
if (transformedRequest instanceof Request) {
normalizedTileUrl = decodeURI(transformedRequest.url);
}
}
tileJson.tiles[i] = normalizedTileUrl;
}
return Promise.resolve(tileJson);
}
line = word;
}
);
}
if (line) {
lines.push(line);
}
// Pass 2 - add lines with a width of less than 30% of maxWidth to the previous or next line
for (let i = 0, ii = lines.length; i < ii && ii > 1; ++i) {
const line = lines[i];
if (measureText(line, letterSpacing) < maxWidth * 0.35) {
const prevWidth =
i > 0 ? measureText(lines[i - 1], letterSpacing) : Infinity;
const nextWidth =
i < ii - 1 ? measureText(lines[i + 1], letterSpacing) : Infinity;
lines.splice(i, 1);
ii -= 1;
if (prevWidth < nextWidth) {
lines[i - 1] += ' ' + line;
i -= 1;
} else {
lines[i] = line + ' ' + lines[i];
}
}
}
// Pass 3 - try to fill 80% of maxWidth for each line
for (let i = 0, ii = lines.length - 1; i < ii; ++i) {
const line = lines[i];
const next = lines[i + 1];
if (
measureText(line, letterSpacing) > maxWidth * 0.7 &&
measureText(next, letterSpacing) < maxWidth * 0.6
) {
const lineWords = line.split(' ');
const lastWord = lineWords.pop();
if (measureText(lastWord, letterSpacing) < maxWidth * 0.2) {
lines[i] = lineWords.join(' ');
lines[i + 1] = lastWord + ' ' + next;
}
ii -= 1;
}
}
wrappedText = lines.join('\n');
} else {
wrappedText = text;
glSource = assign({}, glSource, {
tiles: glSource.tiles.map(function (tileUrl) {
return normalizeSourceUrl(
tileUrl,
options.accessToken,
options.accessTokenParam || 'access_token',
styleUrl || location.href
);
}),
});
promise = Promise.resolve(assign({}, glSource));
}
wrappedText = applyLetterSpacing(wrappedText, letterSpacing);
measureCache[key] = wrappedText;
if (!options.transformRequest) {
tilejsonCache[cacheKey] = promise;
}
}
return wrappedText;
return promise;
}
/**
* @typedef {import("./apply.js").Options} Options
* @typedef {import('./apply.js').ResourceType} ResourceType
* @private
*/

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc