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

ol-mapbox-style

Package Overview
Dependencies
Maintainers
4
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 9.2.1 to 9.7.0

dist/examples/esri-4326.css

41

CHANGELOG.md

@@ -5,2 +5,43 @@ # Changelog

## 9.7.0
* Improved icon halo - now looks the same as text halo
* New API for working with layer style objects and updating the rendered style
* Improved access token handling for the Mapbox example
## 9.6.0
* New `updateSource` option on `applyStyle()` for keeping pre-configured OpenLayers sources
* Fix `mapbox-layers` array for `raster` or `raster-dem` layers that share the same source
* Support for `paint` properties `icon-halo-color` and `icon-halo-width`
## 9.5.0
* Support for projections, using the new `projection` option
## 9.4.0
* Add support for labels with `symbol-spacing`
## 9.3.0
* Fix background bleeding issue when re-applying style
* Add support for `hillshade-highlight-color` and `hillshade-shadow-color`
* Fix geojson layers with `bbox` in combination with `transformRequest`
* Fix tilejson loading when using same source in different styles at the same time
## 9.2.4
* Update documentation for `getLayer()` and `getSource()` for `LayerGroup` support
* Update `getLayers()` to work with `LayerGroup`s
* Make `transformRequest` option work for raster sources with inlint TileJSON definition
## 9.2.3
* Fix a regression that prevented mapbox:// tiles from getting loaded
## 9.2.2
* Avoid excessive data downloads for geojson layers below minzoom
## 9.2.1

@@ -7,0 +48,0 @@

79

dist/apply.d.ts
/**
* Applies a style function to an `ol/layer/VectorTile` or `ol/layer/Vector`
* with an `ol/source/VectorTile` or an `ol/source/Vector`. If the layer does not have a source
* yet, it will be created and populated from the information in the `glStyle`.
* yet, it will be created and populated from the information in the `glStyle` (unless `updateSource` is
* set to `false`).
*

@@ -38,3 +39,3 @@ * **Example:**

* value, all layers using the first source specified in the glStyle will be rendered.
* @param {Options|string} [optionsOrPath] **Deprecated**. Options. Alternatively the path of the style file
* @param {Options&ApplyStyleOptions|string} [optionsOrPath] **Deprecated**. Options. Alternatively the path of the style file
* (only required when a relative path is used for the `"sprite"` property of the style).

@@ -47,3 +48,3 @@ * @param {Array<number>} [resolutions] **Deprecated**. Resolutions for mapping resolution to zoom level.

*/
export function applyStyle(layer: VectorTileLayer | VectorLayer<any>, glStyle: string | any, sourceOrLayersOrOptions?: string | string[] | (Options & ApplyStyleOptions) | undefined, optionsOrPath?: string | Options | undefined, resolutions?: number[] | undefined): Promise<any>;
export function applyStyle(layer: VectorTileLayer | VectorLayer<any>, glStyle: string | any, sourceOrLayersOrOptions?: string | string[] | (Options & ApplyStyleOptions) | undefined, optionsOrPath?: string | (Options & ApplyStyleOptions) | undefined, resolutions?: number[] | undefined): Promise<any>;
/**

@@ -107,5 +108,5 @@ * Applies properties of the Mapbox Style's first `background` layer to the

*
* @param {Map|HTMLElement|string|LayerGroup} mapOrGroup Either an existing OpenLayers Map
* instance, or a HTML element, or the id of a HTML element that will be the
* target of a new OpenLayers Map, or a layer group. If layer group, styles
* @param {Map|HTMLElement|string|LayerGroup} mapOrGroupOrElement Either an existing
* OpenLayers Map instance, or a HTML element, or the id of a HTML element that will be
* the target of a new OpenLayers Map, or a layer group. If layer group, styles
* releated to the map and view will be ignored.

@@ -127,3 +128,3 @@ * @param {string|Object} style JSON style object or style url pointing to a

*/
export function apply(mapOrGroup: Map | HTMLElement | string | LayerGroup, style: string | any, options?: Options): Promise<Map | LayerGroup>;
export function apply(mapOrGroupOrElement: Map | HTMLElement | string | LayerGroup, style: string | any, options?: Options): Promise<Map | LayerGroup>;
/**

@@ -133,21 +134,21 @@ * Get the OpenLayers layer instance that contains the provided Mapbox Style

* OpenLayers layer instance when they use the same Mapbox Style `source`.
* @param {Map} map OpenLayers Map.
* @param {Map|LayerGroup} map OpenLayers Map or LayerGroup.
* @param {string} layerId Mapbox Style layer id.
* @return {Layer} OpenLayers layer instance.
*/
export function getLayer(map: Map, layerId: string): Layer;
export function getLayer(map: Map | LayerGroup, layerId: string): Layer;
/**
* Get the OpenLayers layer instances for the provided Mapbox Style `source`.
* @param {Map} map OpenLayers Map.
* @param {Map|LayerGroup} map OpenLayers Map or LayerGroup.
* @param {string} sourceId Mapbox Style source id.
* @return {Array<Layer>} OpenLayers layer instances.
*/
export function getLayers(map: Map, sourceId: string): Array<Layer>;
export function getLayers(map: Map | LayerGroup, sourceId: string): Array<Layer>;
/**
* Get the OpenLayers source instance for the provided Mapbox Style `source`.
* @param {Map} map OpenLayers Map.
* @param {Map|LayerGroup} map OpenLayers Map or LayerGroup.
* @param {string} sourceId Mapbox Style source id.
* @return {Source} OpenLayers source instance.
*/
export function getSource(map: Map, sourceId: string): Source;
export function getSource(map: Map | LayerGroup, sourceId: string): Source;
/**

@@ -176,4 +177,23 @@ * Sets or removes a feature state. The feature state is taken into account for styling,

export function getFeatureState(mapOrLayer: Map | VectorLayer<any> | VectorTileLayer, feature: FeatureIdentifier): any | null;
/**
* Get the Mapbox Layer object for the provided `layerId`.
* @param {Map|LayerGroup} mapOrGroup Map or LayerGroup.
* @param {string} layerId Mapbox Layer id.
* @return {Object} Mapbox Layer object.
*/
export function getMapboxLayer(mapOrGroup: Map | LayerGroup, layerId: string): any;
/**
* Add a new Mapbox Layer object to the style.
* @param {Map|LayerGroup} mapOrGroup Map or LayerGroup.
* @param {Object} mapboxLayer Mapbox Layer object.
* @param {string} [beforeLayerId] Optional id of the Mapbox Layer before the new layer that will be added.
*/
export function addMapboxLayer(mapOrGroup: Map | LayerGroup, mapboxLayer: any, beforeLayerId?: string | undefined): void;
/**
* Update a Mapbox Layer object in the style. The map will be re-rendered with the new style.
* @param {Map|LayerGroup} mapOrGroup Map or LayerGroup.
* @param {Object} mapboxLayer Updated Mapbox Layer object.
*/
export function updateMapboxLayer(mapOrGroup: Map | LayerGroup, mapboxLayer: any): void;
export { finalizeLayer as _finalizeLayer };
export type LayerGroup = import("ol/layer/Group.js").default;
export type FeatureIdentifier = {

@@ -203,5 +223,14 @@ /**

/**
* Resolutions for mapping resolution to zoom level.
* Only needed when working with non-standard tile grids or projections.
* Only useful when working with non-standard projections.
* Code of a projection registered with OpenLayers. All sources of the style must be provided in this
* projection. The projection must also have a valid extent defined, which will be used to determine the
* origin and resolutions of the tile grid for all tiled sources of the style. When provided, the bbox
* placeholder in tile and geojson urls changes: the default is `{bbox-epsg-3857}`, when projection is e.g.
* set to `EPSG:4326`, the bbox placeholder will be `{bbox-epsg-4326}`.
*/
projection?: string | undefined;
/**
* Only useful when working with non-standard projections.
* Resolutions for mapping resolution to the `zoom` used in the Mapbox style.
*/
resolutions?: number[] | undefined;

@@ -214,6 +243,2 @@ /**

/**
* Access token param. For internal use.
*/
accessTokenParam?: string | undefined;
/**
* Function that returns an image for an icon name. If the result is an HTMLImageElement, it must already be

@@ -224,2 +249,6 @@ * loaded. The layer can be used to call layer.changed() when the loading and processing of the image has finished.

getImage?: ((arg0: VectorLayer<any> | VectorTileLayer, arg1: string) => HTMLImageElement | HTMLCanvasElement | string | undefined) | undefined;
/**
* Access token param. For internal use.
*/
accessTokenParam?: string | undefined;
};

@@ -237,9 +266,15 @@ export type ApplyStyleOptions = {

layers?: string[] | undefined;
/**
* Update or create vector (tile) layer source with parameters
* specified for the source in the mapbox style definition.
*/
updateSource?: boolean | undefined;
};
export type ResourceType = 'Style' | 'Source' | 'Sprite' | 'SpriteImage' | 'Tiles' | 'GeoJSON';
export type Layer = import("ol/layer/Layer").default;
export type Source = import("ol/source/Source").default;
import VectorTileLayer from "ol/layer/VectorTile.js";
import VectorLayer from "ol/layer/Vector.js";
import Map from "ol/Map.js";
import LayerGroup from "ol/layer/Group.js";
import Layer from "ol/layer/Layer.js";
import Source from "ol/source/Source.js";
/**

@@ -246,0 +281,0 @@ * If layerIds is not empty, applies the style specified in glStyle to the layer,

@@ -5,2 +5,8 @@ {

"layers": [{
"id": "background",
"type": "background",
"paint": {
"background-color": "#aaa"
}
}, {
"source": "points",

@@ -19,2 +25,6 @@ "type": "symbol",

}
},
"paint": {
"icon-halo-color": "#fff",
"icon-halo-width": 1
}

@@ -21,0 +31,0 @@ }],

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

"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[862],{9742:(e,o,s)=>{s(9789);var c=s(707),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=9742)}]);
"use strict";(self.webpackChunkol_mapbox_style=self.webpackChunkol_mapbox_style||[]).push([[862],{9742:(e,o,s)=>{s(9789);var c=s(707),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=9742)}]);
//# sourceMappingURL=mapbox.js.map
export { stylefunction, recordStyleLayer, renderTransparent } from "./stylefunction.js";
export { apply as default, apply, applyBackground, applyStyle, getFeatureState, setFeatureState, getLayer, getLayers, getSource } from "./apply.js";
export { apply as default, apply, applyBackground, applyStyle, getFeatureState, setFeatureState, getLayer, getLayers, getSource, getMapboxLayer, updateMapboxLayer, addMapboxLayer } from "./apply.js";

@@ -0,1 +1,11 @@

/**
* @param {Object} glStyle Mapboox style object.
* @return {Object} Function cache.
*/
export function getFunctionCache(glStyle: any): any;
/**
* @param {Object} glStyle Mapboox style object.
* @return {Object} Filter cache.
*/
export function getFilterCache(glStyle: any): any;
export function deg2rad(degrees: any): number;

@@ -13,2 +23,3 @@ /**

* @param {Options} [options={}] Options.
* @param {{request?: Request}} [metadata] Object to be filled with the request.
* @return {Promise<Object|Response>} Promise that resolves with the loaded resource

@@ -18,3 +29,5 @@ * or rejects with the Response object.

*/
export function fetchResource(resourceType: ResourceType, url: string, options?: import("./apply.js").Options | undefined): Promise<any | Response>;
export function fetchResource(resourceType: ResourceType, url: string, options?: import("./apply.js").Options | undefined, metadata?: {
request?: Request | undefined;
} | undefined): Promise<any | Response>;
export function getGlStyle(glStyleOrUrl: any, options: any): Promise<any>;

@@ -28,4 +41,23 @@ /**

export function getTileJson(glSource: any, styleUrl: string, options?: Options): any;
/**
* @param {HTMLImageElement} spriteImage Sprite image id.
* @param {{x: number, y: number, width: number, height: number, pixelRatio: number}} spriteImageData Sprite image data.
* @param {number} haloWidth Halo width.
* @param {{r: number, g: number, b: number, a: number}} haloColor Halo color.
* @return {HTMLCanvasElement} Canvas element with the halo.
*/
export function drawIconHalo(spriteImage: HTMLImageElement, spriteImageData: {
x: number;
y: number;
width: number;
height: number;
pixelRatio: number;
}, haloWidth: number, haloColor: {
r: number;
g: number;
b: number;
a: number;
}): HTMLCanvasElement;
export const defaultResolutions: number[];
export type Options = import("./apply.js").Options;
export type ResourceType = import('./apply.js').ResourceType;
{
"name": "ol-mapbox-style",
"version": "9.2.1",
"version": "9.7.0",
"description": "Create OpenLayers maps from Mapbox Style objects",

@@ -46,11 +46,11 @@ "type": "module",

"@mapbox/flow-remove-types": "^2.0.0",
"@rollup/plugin-buble": "^0.21.3",
"@rollup/plugin-commonjs": "^23.0.2",
"@rollup/plugin-buble": "^1.0.1",
"@rollup/plugin-commonjs": "^24.0.0",
"@rollup/plugin-node-resolve": "^15.0.1",
"@types/arcgis-rest-api": "^10.4.4",
"@types/mocha": "^9.1.0",
"@types/mocha": "^10.0.0",
"@types/offscreencanvas": "^2019.6.4",
"@types/topojson-specification": "^1.0.1",
"add-text-to-markdown": "^2.0.0",
"babel-loader": "^8.0.6",
"babel-loader": "^9.1.0",
"buble": "^0.20.0",

@@ -72,3 +72,3 @@ "buble-loader": "^0.5.1",

"karma-mocha": "^2.0.1",
"karma-sourcemap-loader": "^0.3.7",
"karma-sourcemap-loader": "^0.4.0",
"karma-webpack": "^5.0.0",

@@ -79,3 +79,3 @@ "mapbox-gl-styles": "^2.0.2",

"nanoassert": "^2.0.0",
"ol": "^7.1.1-dev.1668111618807",
"ol": "^7.2.3-dev.1672696068643",
"puppeteer": "^19.2.2",

@@ -87,3 +87,3 @@ "remove-flow-types-loader": "^1.1.0",

"should": "^13.2.3",
"sinon": "^14.0.0",
"sinon": "^15.0.1",
"style-loader": "^3.3.1",

@@ -95,5 +95,5 @@ "typedoc": "^0.23.10",

"webpack": "^5.62.1",
"webpack-cli": "^4.9.1",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.4.0"
}
}

@@ -111,2 +111,3 @@ # ol-mapbox-style

- [addMapboxLayer](#addMapboxLayer)
- [apply](#apply)

@@ -118,2 +119,3 @@ - [applyBackground](#applyBackground)

- [getLayers](#getLayers)
- [getMapboxLayer](#getMapboxLayer)
- [getSource](#getSource)

@@ -124,2 +126,3 @@ - [recordStyleLayer](#recordStyleLayer)

- [stylefunction](#stylefunction)
- [updateMapboxLayer](#updateMapboxLayer)

@@ -134,5 +137,25 @@ ### References

#### addMapboxLayer
▸ **addMapboxLayer**(`mapOrGroup`, `mapboxLayer`, `beforeLayerId?`): `void`
Add a new Mapbox Layer object to the style.
##### Parameters
| Name | Type | Description |
| :--------------- | :-------------------- | :----------------------------------------------------------------------- |
| `mapOrGroup` | `Map` \| `LayerGroup` | Map or LayerGroup. |
| `mapboxLayer` | `any` | Mapbox Layer object. |
| `beforeLayerId?` | `string` | Optional id of the Mapbox Layer before the new layer that will be added. |
##### Returns
`void`
* * *
#### apply
▸ **apply**(`mapOrGroup`, `style`, `options?`): `Promise`&lt;`LayerGroup` \| `Map`>
▸ **apply**(`mapOrGroupOrElement`, `style`, `options?`): `Promise`&lt;`Map` \| `LayerGroup`>

@@ -171,11 +194,11 @@ Loads and applies a Mapbox Style object into an OpenLayers Map or LayerGroup.

| Name | Type | Description |
| :----------- | :------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mapOrGroup` | `string` \| `HTMLElement` \| `LayerGroup` \| `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, or a layer group. If layer group, styles releated to the map and view will be ignored. |
| `style` | `any` | JSON style object or style url pointing to a Mapbox Style object. When using Mapbox APIs, the url is the `styleUrl` shown in Mapbox Studio's "share" panel. In addition, the `accessToken` option (see below) must be set. When passed as JSON style object, all OpenLayers layers created by `apply()` will be immediately available, but they may not have a source yet (i.e. when they are defined by a TileJSON url in the Mapbox Style document). When passed as style url, layers will be added to the map when the Mapbox Style document is loaded and parsed. |
| `options` | [`Options`](#interfacesinternal_optionsmd) | Options. |
| Name | Type | Description |
| :-------------------- | :------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `mapOrGroupOrElement` | `string` \| `HTMLElement` \| `Map` \| `LayerGroup` | Either an existing OpenLayers Map instance, or a HTML element, or the id of a HTML element that will be the target of a new OpenLayers Map, or a layer group. If layer group, styles releated to the map and view will be ignored. |
| `style` | `any` | JSON style object or style url pointing to a Mapbox Style object. When using Mapbox APIs, the url is the `styleUrl` shown in Mapbox Studio's "share" panel. In addition, the `accessToken` option (see below) must be set. When passed as JSON style object, all OpenLayers layers created by `apply()` will be immediately available, but they may not have a source yet (i.e. when they are defined by a TileJSON url in the Mapbox Style document). When passed as style url, layers will be added to the map when the Mapbox Style document is loaded and parsed. |
| `options` | [`Options`](#interfacesinternal_optionsmd) | Options. |
##### Returns
`Promise`&lt;`LayerGroup` \| `Map`>
`Promise`&lt;`Map` \| `LayerGroup`>

@@ -228,3 +251,4 @@ A promise that resolves after all layers have been added to

with an `ol/source/VectorTile` or an `ol/source/Vector`. If the layer does not have a source
yet, it will be created and populated from the information in the `glStyle`.
yet, it will be created and populated from the information in the `glStyle` (unless `updateSource` is
set to `false`).

@@ -261,3 +285,3 @@ **Example:**

| `sourceOrLayersOrOptions?` | `string` \| `string`\[] \| [`Options`](#interfacesinternal_optionsmd) & [`ApplyStyleOptions`](#interfacesinternal_applystyleoptionsmd) | `''` | Options or `source` key or an array of layer `id`s from the Mapbox Style object. When a `source` key is provided, all layers for the specified source will be included in the style function. When layer `id`s are provided, they must be from layers that use the same source. When not provided or a falsey value, all layers using the first source specified in the glStyle will be rendered. |
| `optionsOrPath?` | `string` \| [`Options`](#interfacesinternal_optionsmd) | `{}` | **Deprecated**. Options. Alternatively the path of the style file (only required when a relative path is used for the `"sprite"` property of the style). |
| `optionsOrPath?` | `string` \| [`Options`](#interfacesinternal_optionsmd) & [`ApplyStyleOptions`](#interfacesinternal_applystyleoptionsmd) | `{}` | **Deprecated**. Options. Alternatively the path of the style file (only required when a relative path is used for the `"sprite"` property of the style). |
| `resolutions?` | `number`\[] | `undefined` | **Deprecated**. Resolutions for mapping resolution to zoom level. Only needed when working with non-standard tile grids or projections, can also be supplied with options. |

@@ -308,6 +332,6 @@

| Name | Type | Description |
| :-------- | :------- | :--------------------- |
| `map` | `Map` | OpenLayers Map. |
| `layerId` | `string` | Mapbox Style layer id. |
| Name | Type | Description |
| :-------- | :-------------------- | :---------------------------- |
| `map` | `Map` \| `LayerGroup` | OpenLayers Map or LayerGroup. |
| `layerId` | `string` | Mapbox Style layer id. |

@@ -330,6 +354,6 @@ ##### Returns

| Name | Type | Description |
| :--------- | :------- | :---------------------- |
| `map` | `Map` | OpenLayers Map. |
| `sourceId` | `string` | Mapbox Style source id. |
| Name | Type | Description |
| :--------- | :-------------------- | :---------------------------- |
| `map` | `Map` \| `LayerGroup` | OpenLayers Map or LayerGroup. |
| `sourceId` | `string` | Mapbox Style source id. |

@@ -344,2 +368,23 @@ ##### Returns

#### getMapboxLayer
▸ **getMapboxLayer**(`mapOrGroup`, `layerId`): `any`
Get the Mapbox Layer object for the provided `layerId`.
##### Parameters
| Name | Type | Description |
| :----------- | :-------------------- | :----------------- |
| `mapOrGroup` | `Map` \| `LayerGroup` | Map or LayerGroup. |
| `layerId` | `string` | Mapbox Layer id. |
##### Returns
`any`
Mapbox Layer object.
* * *
#### getSource

@@ -353,6 +398,6 @@

| Name | Type | Description |
| :--------- | :------- | :---------------------- |
| `map` | `Map` | OpenLayers Map. |
| `sourceId` | `string` | Mapbox Style source id. |
| Name | Type | Description |
| :--------- | :-------------------- | :---------------------------- |
| `map` | `Map` \| `LayerGroup` | OpenLayers Map or LayerGroup. |
| `sourceId` | `string` | Mapbox Style source id. |

@@ -493,2 +538,21 @@ ##### Returns

* * *
#### updateMapboxLayer
▸ **updateMapboxLayer**(`mapOrGroup`, `mapboxLayer`): `void`
Update a Mapbox Layer object in the style. The map will be re-rendered with the new style.
##### Parameters
| Name | Type | Description |
| :------------ | :-------------------- | :--------------------------- |
| `mapOrGroup` | `Map` \| `LayerGroup` | Map or LayerGroup. |
| `mapboxLayer` | `any` | Updated Mapbox Layer object. |
##### Returns
`void`
<a name="interfacesinternal_applystyleoptionsmd"></a>

@@ -506,2 +570,3 @@

- [source](#source)
- [updateSource](#updateSource)

@@ -526,2 +591,11 @@ ### Properties

* * *
#### updateSource
• **updateSource**: `boolean`
Update or create vector (tile) layer source with parameters
specified for the source in the mapbox style definition.
<a name="interfacesinternal_featureidentifiermd"></a>

@@ -569,2 +643,3 @@

- [getImage](#getImage)
- [projection](#projection)
- [resolutions](#resolutions)

@@ -617,2 +692,15 @@ - [styleUrl](#styleUrl)

#### projection
• **projection**: `string`
Only useful when working with non-standard projections.
Code of a projection registered with OpenLayers. All sources of the style must be provided in this
projection. The projection must also have a valid extent defined, which will be used to determine the
origin and resolutions of the tile grid for all tiled sources of the style. When provided, the bbox
placeholder in tile and geojson urls changes: the default is `{bbox-epsg-3857}`, when projection is e.g.
set to `EPSG:4326`, the bbox placeholder will be `{bbox-epsg-4326}`.
* * *
#### resolutions

@@ -622,4 +710,4 @@

Resolutions for mapping resolution to zoom level.
Only needed when working with non-standard tile grids or projections.
Only useful when working with non-standard projections.
Resolutions for mapping resolution to the `zoom` used in the Mapbox style.

@@ -626,0 +714,0 @@ * * *

@@ -9,5 +9,8 @@ /*

import ImageLayer from 'ol/layer/Image.js';
import Layer from 'ol/layer/Layer.js';
import LayerGroup from 'ol/layer/Group.js';
import MVT from 'ol/format/MVT.js';
import Map from 'ol/Map.js';
import Raster from 'ol/source/Raster.js';
import Source from 'ol/source/Source.js';
import TileGrid from 'ol/tilegrid/TileGrid.js';

@@ -22,2 +25,9 @@ import TileJSON from 'ol/source/TileJSON.js';

import {
METERS_PER_UNIT,
equivalent,
fromLonLat,
get as getProjection,
getUserProjection,
} from 'ol/proj.js';
import {
_colorWithOpacity,

@@ -32,2 +42,4 @@ stylefunction as applyStyleFunction,

fetchResource,
getFilterCache,
getFunctionCache,
getGlStyle,

@@ -37,4 +49,4 @@ getTileJson,

} from './util.js';
import {equivalent, fromLonLat, getUserProjection} from 'ol/proj.js';
import {getFonts} from './text.js';
import {getTopLeft} from 'ol/extent.js';
import {hillshade} from './shaders.js';

@@ -47,4 +59,2 @@ import {

/** @typedef {import("ol/layer/Group.js").default} LayerGroup */
/**

@@ -65,7 +75,12 @@ * @typedef {Object} FeatureIdentifier

* the returned request will be respected.
* @property {Array<number>} [resolutions] Resolutions for mapping resolution to zoom level.
* Only needed when working with non-standard tile grids or projections.
* @property {string} [projection='EPSG:3857'] Only useful when working with non-standard projections.
* Code of a projection registered with OpenLayers. All sources of the style must be provided in this
* projection. The projection must also have a valid extent defined, which will be used to determine the
* origin and resolutions of the tile grid for all tiled sources of the style. When provided, the bbox
* placeholder in tile and geojson urls changes: the default is `{bbox-epsg-3857}`, when projection is e.g.
* set to `EPSG:4326`, the bbox placeholder will be `{bbox-epsg-4326}`.
* @property {Array<number>} [resolutions] Only useful when working with non-standard projections.
* Resolutions for mapping resolution to the `zoom` used in the Mapbox style.
* @property {string} [styleUrl] URL of the Mapbox GL style. Required for styles that were provided
* as object, when they contain a relative sprite url, or sources referencing data by relative url.
* @property {string} [accessTokenParam='access_token'] Access token param. For internal use.
* @property {function(VectorLayer|VectorTileLayer, string):HTMLImageElement|HTMLCanvasElement|string|undefined} [getImage=undefined]

@@ -75,2 +90,3 @@ * Function that returns an image for an icon name. If the result is an HTMLImageElement, it must already be

* This function be used for icons not in the sprite or to override sprite icons.
* @property {string} [accessTokenParam='access_token'] Access token param. For internal use.
*/

@@ -84,9 +100,24 @@

* provided ids will be used from the style's `layers` array. All layers need to use the same source.
* @property {boolean} [updateSource=true] Update or create vector (tile) layer source with parameters
* specified for the source in the mapbox style definition.
*/
/** @typedef {'Style'|'Source'|'Sprite'|'SpriteImage'|'Tiles'|'GeoJSON'} ResourceType */
/** @typedef {import("ol/layer/Layer").default} Layer */
/** @typedef {import("ol/source/Source").default} Source */
/**
* @param {import("ol/proj/Projection.js").default} projection Projection.
* @param {number} [tileSize=512] Tile size.
* @return {Array<number>} Resolutions.
*/
function getTileResolutions(projection, tileSize = 512) {
return projection.getExtent()
? createXYZ({
extent: projection.getExtent(),
tileSize: tileSize,
maxZoom: 22,
}).getResolutions()
: defaultResolutions;
}
/**
* @param {string} styleUrl Style URL.

@@ -112,3 +143,4 @@ * @param {Options} options Options.

* with an `ol/source/VectorTile` or an `ol/source/Vector`. If the layer does not have a source
* yet, it will be created and populated from the information in the `glStyle`.
* yet, it will be created and populated from the information in the `glStyle` (unless `updateSource` is
* set to `false`).
*

@@ -147,3 +179,3 @@ * **Example:**

* value, all layers using the first source specified in the glStyle will be rendered.
* @param {Options|string} [optionsOrPath] **Deprecated**. Options. Alternatively the path of the style file
* @param {Options&ApplyStyleOptions|string} [optionsOrPath] **Deprecated**. Options. Alternatively the path of the style file
* (only required when a relative path is used for the `"sprite"` property of the style).

@@ -167,2 +199,3 @@ * @param {Array<number>} [resolutions] **Deprecated**. Resolutions for mapping resolution to zoom level.

let sourceOrLayers;
let updateSource = true;
if (

@@ -185,2 +218,5 @@ typeof sourceOrLayersOrOptions !== 'string' &&

}
if (options.updateSource === false) {
updateSource = false;
}
if (!resolutions) {

@@ -238,2 +274,5 @@ resolutions = options.resolutions;

function assignSource() {
if (!updateSource) {
return Promise.resolve();
}
if (layer instanceof VectorTileLayer) {

@@ -311,2 +350,11 @@ return setupVectorSource(

if (!style && (!glStyle.sprite || spriteData)) {
if (options.projection && !resolutions) {
const projection = getProjection(options.projection);
const units = projection.getUnits();
if (units !== 'm') {
resolutions = defaultResolutions.map(
(resolution) => resolution / METERS_PER_UNIT[units]
);
}
}
style = applyStyleFunction(

@@ -402,97 +450,17 @@ layer,

function setBackground(mapOrLayer, layer, options) {
const background = {
id: layer.id,
type: layer.type,
};
const functionCache = {};
function getBackgroundColor(resolution) {
const layout = layer.layout || {};
const paint = layer.paint || {};
background['paint'] = paint;
const zoom = getZoomForResolution(
resolution,
options.resolutions || defaultResolutions
);
let bg, opacity;
if (paint['background-color'] !== undefined) {
bg = getValue(
background,
'paint',
'background-color',
zoom,
emptyObj,
functionCache
);
}
if (paint['background-opacity'] !== undefined) {
opacity = getValue(
background,
'paint',
'background-opacity',
zoom,
emptyObj,
functionCache
);
}
return layout.visibility == 'none'
? undefined
: _colorWithOpacity(bg, opacity);
}
let lastRenderTime = 0;
let backgroundRendered = false;
/**
* @param {import("ol/render/Event.js").default} e Render event
*/
function renderBackground(e) {
if (e.frameState.time !== lastRenderTime) {
lastRenderTime = e.frameState.time;
backgroundRendered = false;
}
if (backgroundRendered) {
return;
}
if (!(e.context instanceof CanvasRenderingContext2D)) {
throw new Error('Cannot apply background to WebGL context');
}
const resolution = e.frameState.viewState.resolution;
const color = getBackgroundColor(resolution);
if (color) {
const context = e.context;
const alpha = context.globalAlpha;
const gobalCompositeOperation = context.globalCompositeOperation;
context.globalAlpha = 1;
context.globalCompositeOperation = 'destination-over';
context.fillStyle = color;
context.fillRect(0, 0, e.context.canvas.width, e.context.canvas.height);
context.globalAlpha = alpha;
context.globalCompositeOperation = gobalCompositeOperation;
}
backgroundRendered = true;
}
if (typeof mapOrLayer.getLayers === 'function') {
// map or layer group
const layers = mapOrLayer.getLayers();
layers.forEach(function (layer) {
layer.on('postrender', renderBackground);
});
layers.on('add', function (e) {
e.element.on('postrender', renderBackground);
});
layers.on('remove', function (e) {
e.element.un('postrender', renderBackground);
});
} else {
mapOrLayer.on('postrender', renderBackground);
}
}
function setFirstBackground(mapOrLayer, glStyle, options) {
glStyle.layers.some(function (layer) {
if (layer.type === 'background') {
setBackground(mapOrLayer, layer, options);
return true;
if (mapOrLayer instanceof Layer) {
mapOrLayer.setBackground(function (resolution) {
return getBackgroundColor(layer, resolution, options, {});
});
return true;
} else if (
mapOrLayer instanceof Map ||
mapOrLayer instanceof LayerGroup
) {
mapOrLayer.getLayers().push(setupBackgroundLayer(layer, options, {}));
return true;
}
}

@@ -520,6 +488,2 @@ });

export function applyBackground(mapOrLayer, glStyle, options = {}) {
if (typeof glStyle === 'object') {
setFirstBackground(mapOrLayer, glStyle, options);
return Promise.resolve();
}
return getGlStyle(glStyle, options).then(function (glStyle) {

@@ -541,12 +505,115 @@ setFirstBackground(mapOrLayer, glStyle, options);

function extentFromTileJSON(tileJSON) {
function extentFromTileJSON(tileJSON, projection) {
const bounds = tileJSON.bounds;
if (bounds) {
const ll = fromLonLat([bounds[0], bounds[1]]);
const tr = fromLonLat([bounds[2], bounds[3]]);
const ll = fromLonLat([bounds[0], bounds[1]], projection);
const tr = fromLonLat([bounds[2], bounds[3]], projection);
return [ll[0], ll[1], tr[0], tr[1]];
}
return getProjection(projection).getExtent();
}
function sourceOptionsFromTileJSON(glSource, tileJSON, options) {
const tileJSONSource = new TileJSON({
tileJSON: tileJSON,
tileSize: glSource.tileSize || tileJSON.tileSize || 512,
});
const tileJSONDoc = tileJSONSource.getTileJSON();
const tileGrid = tileJSONSource.getTileGrid();
const projection = getProjection(options.projection || 'EPSG:3857');
const extent = extentFromTileJSON(tileJSONDoc, projection);
const projectionExtent = projection.getExtent();
const minZoom = tileJSONDoc.minzoom || 0;
const maxZoom = tileJSONDoc.maxzoom || 22;
/** @type {import("ol/source/VectorTile.js").Options} */
const sourceOptions = {
attributions: tileJSONSource.getAttributions(),
projection: projection,
tileGrid: new TileGrid({
origin: projectionExtent
? getTopLeft(projectionExtent)
: tileGrid.getOrigin(0),
extent: extent || tileGrid.getExtent(),
minZoom: minZoom,
resolutions: getTileResolutions(projection, tileJSON.tileSize).slice(
0,
maxZoom + 1
),
tileSize: tileGrid.getTileSize(0),
}),
};
if (Array.isArray(tileJSONDoc.tiles)) {
sourceOptions.urls = tileJSONDoc.tiles;
} else {
sourceOptions.url = tileJSONDoc.tiles;
}
return sourceOptions;
}
function getBackgroundColor(glLayer, resolution, options, functionCache) {
const background = {
id: glLayer.id,
type: glLayer.type,
};
const layout = glLayer.layout || {};
const paint = glLayer.paint || {};
background['paint'] = paint;
const zoom = getZoomForResolution(
resolution,
options.resolutions || defaultResolutions
);
let bg, opacity;
if (paint['background-color'] !== undefined) {
bg = getValue(
background,
'paint',
'background-color',
zoom,
emptyObj,
functionCache
);
}
if (paint['background-opacity'] !== undefined) {
opacity = getValue(
background,
'paint',
'background-opacity',
zoom,
emptyObj,
functionCache
);
}
return layout.visibility == 'none'
? undefined
: _colorWithOpacity(bg, opacity);
}
/**
* @param {Object} glLayer Mapbox Style layer object.
* @param {Options} options Options.
* @param {Object} functionCache Cache for functions.
* @return {Layer} OpenLayers layer.
*/
function setupBackgroundLayer(glLayer, options, functionCache) {
const div = document.createElement('div');
div.className = 'ol-mapbox-style-background';
div.style.position = 'absolute';
div.style.width = '100%';
div.style.height = '100%';
return new Layer({
source: new Source({}),
render(frameState) {
const color = getBackgroundColor(
glLayer,
frameState.viewState.resolution,
options,
functionCache
);
div.style.backgroundColor = color;
return div;
},
});
}
/**
* Creates an OpenLayers VectorTile source for a gl source entry.

@@ -564,27 +631,14 @@ * @param {Object} glSource "source" entry from a Mapbox Style object.

.then(function (tileJSON) {
const tileJSONSource = new TileJSON({tileJSON: tileJSON});
const tileJSONDoc = tileJSONSource.getTileJSON();
const tileGrid = tileJSONSource.getTileGrid();
const extent = extentFromTileJSON(tileJSONDoc);
const minZoom = tileJSONDoc.minzoom || 0;
const maxZoom = tileJSONDoc.maxzoom || 22;
const sourceOptions = {
attributions: tileJSONSource.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,
}),
};
if (Array.isArray(tileJSONDoc.tiles)) {
sourceOptions.urls = tileJSONDoc.tiles;
const sourceOptions = sourceOptionsFromTileJSON(
glSource,
tileJSON,
options
);
sourceOptions.format = new MVT();
if (Array.isArray(tileJSON.tiles)) {
sourceOptions.urls = tileJSON.tiles;
} else {
sourceOptions.url = tileJSONDoc.tiles;
sourceOptions.url = tileJSON.tiles;
}
if (tileJSON.olSourceOptions) {
Object.assign(sourceOptions, tileJSON.olSourceOptions);
}
resolve(new VectorTileSource(sourceOptions));

@@ -612,2 +666,7 @@ })

function getBboxTemplate(projection) {
const projCode = projection ? projection.getCode() : 'EPSG:3857';
return `{bbox-${projCode.toLowerCase().replace(/[^a-z0-9]/g, '-')}}`;
}
function setupRasterLayer(glSource, styleUrl, options) {

@@ -624,24 +683,18 @@ const layer = new TileLayer();

});
const extent = extentFromTileJSON(tileJson);
const tileGrid = source.getTileGrid();
const tileSize = glSource.tileSize || tileJson.tileSize || 512;
const minZoom = tileJson.minzoom || 0;
const maxZoom = tileJson.maxzoom || 22;
//@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,
});
source.tileGrid = sourceOptionsFromTileJSON(
glSource,
tileJson,
options
).tileGrid;
if (options.projection) {
//@ts-ignore
source.projection = getProjection(options.projection);
}
const getTileUrl = source.getTileUrlFunction();
source.setTileUrlFunction(function (tileCoord, pixelRatio, projection) {
const bboxTemplate = getBboxTemplate(projection);
let src = getTileUrl(tileCoord, pixelRatio, projection);
if (src.indexOf('{bbox-epsg-3857}') != -1) {
if (src.indexOf(bboxTemplate) != -1) {
const bbox = source.getTileGrid().getTileCoordExtent(tileCoord);
src = src.replace('{bbox-epsg-3857}', bbox.toString());
src = src.replace(bboxTemplate, bbox.toString());
}

@@ -699,10 +752,11 @@ return src;

if (transformed instanceof Request) {
geoJsonUrl = encodeURI(transformed.url);
geoJsonUrl = decodeURI(transformed.url);
}
}
if (geoJsonUrl.indexOf('{bbox-epsg-3857}') != -1) {
const extentUrl = (extent) => {
if (/\{bbox-[0-9a-z-]+\}/.test(geoJsonUrl)) {
const extentUrl = (extent, resolution, projection) => {
const bboxTemplate = getBboxTemplate(projection);
return geoJsonUrl.replace(
'{bbox-epsg-3857}',
`${extent.join(',')},EPSG:3857`
bboxTemplate,
`${extent.join(',')},${projection.getCode()}`
);

@@ -777,2 +831,9 @@ };

/**
* @param {*} glStyle Mapbox Style.
* @param {Map|LayerGroup} mapOrGroup Map or layer group.
* @param {string} styleUrl Style URL.
* @param {Options} options Options.
* @return {Promise} Promise that resolves when the style is loaded.
*/
function processStyle(glStyle, mapOrGroup, styleUrl, options) {

@@ -785,5 +846,10 @@ const promises = [];

if (!view.isDef() && !view.getRotation() && !view.getResolutions()) {
const projection = options.projection
? getProjection(options.projection)
: view.getProjection();
view = new View(
Object.assign(view.getProperties(), {
maxResolution: defaultResolutions[0],
maxResolution:
defaultResolutions[0] / METERS_PER_UNIT[projection.getUnits()],
projection: options.projection || view.getProjection(),
})

@@ -795,6 +861,10 @@ );

if ('center' in glStyle && !view.getCenter()) {
view.setCenter(fromLonLat(glStyle.center));
view.setCenter(fromLonLat(glStyle.center, view.getProjection()));
}
if ('zoom' in glStyle && view.getZoom() === undefined) {
view.setResolution(defaultResolutions[0] / Math.pow(2, glStyle.zoom));
view.setResolution(
defaultResolutions[0] /
METERS_PER_UNIT[view.getProjection().getUnits()] /
Math.pow(2, glStyle.zoom)
);
}

@@ -819,8 +889,6 @@ if (!view.getCenter() || view.getZoom() === undefined) {

throw new Error(`${type} layers are not supported`);
} else if (type == 'background') {
setBackground(mapOrGroup, glLayer, options);
} else {
id = glLayer.source || getSourceIdByRef(glLayers, glLayer.ref);
// this technique assumes gl layers will be in a particular order
if (id != glSourceId) {
if (!id || id != glSourceId) {
if (layerIds.length) {

@@ -839,7 +907,12 @@ promises.push(

}
const functionCache = getFunctionCache(glStyle);
glSource = glStyle.sources[id];
const functionCache = {};
if (glSource.type == 'vector') {
if (type == 'background') {
layer = setupBackgroundLayer(glLayer, options, functionCache);
} else if (glSource.type == 'vector') {
layer = setupVectorLayer(glSource, styleUrl, options);
} else if (glSource.type == 'raster') {
layerIds = [];
layer = setupRasterLayer(glSource, styleUrl, options);

@@ -859,2 +932,3 @@ layer.setVisible(

) {
layerIds = [];
const hillshadeLayer = setupHillshadeLayer(

@@ -892,3 +966,27 @@ glSource,

data.sunEl = 35;
data.opacity = 0.15;
data.opacity = 0.3;
data.highlightColor = getValue(
glLayer,
'paint',
'hillshade-highlight-color',
zoom,
emptyObj,
functionCache
);
data.shadowColor = getValue(
glLayer,
'paint',
'hillshade-shadow-color',
zoom,
emptyObj,
functionCache
);
data.accentColor = getValue(
glLayer,
'paint',
'hillshade-accent-color',
zoom,
emptyObj,
functionCache
);
});

@@ -944,5 +1042,5 @@ layer.setVisible(

*
* @param {Map|HTMLElement|string|LayerGroup} mapOrGroup Either an existing OpenLayers Map
* instance, or a HTML element, or the id of a HTML element that will be the
* target of a new OpenLayers Map, or a layer group. If layer group, styles
* @param {Map|HTMLElement|string|LayerGroup} mapOrGroupOrElement Either an existing
* OpenLayers Map instance, or a HTML element, or the id of a HTML element that will be
* the target of a new OpenLayers Map, or a layer group. If layer group, styles
* releated to the map and view will be ignored.

@@ -964,9 +1062,15 @@ * @param {string|Object} style JSON style object or style url pointing to a

*/
export function apply(mapOrGroup, style, options = {}) {
export function apply(mapOrGroupOrElement, style, options = {}) {
let promise;
if (typeof mapOrGroup === 'string' || mapOrGroup instanceof HTMLElement) {
/** @type {Map|LayerGroup} */
let mapOrGroup;
if (
typeof mapOrGroupOrElement === 'string' ||
mapOrGroupOrElement instanceof HTMLElement
) {
mapOrGroup = new Map({
target: mapOrGroup,
target: mapOrGroupOrElement,
});
} else {
mapOrGroup = mapOrGroupOrElement;
}

@@ -1079,2 +1183,6 @@

}
} else {
if (minZoom > 0) {
layer.setMaxResolution(defaultResolutions[minZoom] + 1e-9);
}
}

@@ -1121,3 +1229,3 @@ if (

* OpenLayers layer instance when they use the same Mapbox Style `source`.
* @param {Map} map OpenLayers Map.
* @param {Map|LayerGroup} map OpenLayers Map or LayerGroup.
* @param {string} layerId Mapbox Style layer id.

@@ -1138,3 +1246,3 @@ * @return {Layer} OpenLayers layer instance.

* Get the OpenLayers layer instances for the provided Mapbox Style `source`.
* @param {Map} map OpenLayers Map.
* @param {Map|LayerGroup} map OpenLayers Map or LayerGroup.
* @param {string} sourceId Mapbox Style source id.

@@ -1145,3 +1253,3 @@ * @return {Array<Layer>} OpenLayers layer instances.

const result = [];
const layers = map.getAllLayers();
const layers = map.getLayers().getArray();
for (let i = 0, ii = layers.length; i < ii; ++i) {

@@ -1157,3 +1265,3 @@ if (layers[i].get('mapbox-source') === sourceId) {

* Get the OpenLayers source instance for the provided Mapbox Style `source`.
* @param {Map} map OpenLayers Map.
* @param {Map|LayerGroup} map OpenLayers Map or LayerGroup.
* @param {string} sourceId Mapbox Style source id.

@@ -1227,2 +1335,72 @@ * @return {Source} OpenLayers source instance.

/**
* Get the Mapbox Layer object for the provided `layerId`.
* @param {Map|LayerGroup} mapOrGroup Map or LayerGroup.
* @param {string} layerId Mapbox Layer id.
* @return {Object} Mapbox Layer object.
*/
export function getMapboxLayer(mapOrGroup, layerId) {
const style = mapOrGroup.get('mapbox-style');
const layerStyle = style.layers.find(function (layer) {
return layer.id === layerId;
});
return layerStyle;
}
/**
* Add a new Mapbox Layer object to the style.
* @param {Map|LayerGroup} mapOrGroup Map or LayerGroup.
* @param {Object} mapboxLayer Mapbox Layer object.
* @param {string} [beforeLayerId] Optional id of the Mapbox Layer before the new layer that will be added.
*/
export function addMapboxLayer(mapOrGroup, mapboxLayer, beforeLayerId) {
const mapboxLayers = mapOrGroup.get('mapbox-style').layers;
let index;
if (beforeLayerId !== undefined) {
const beforeLayer = getMapboxLayer(mapOrGroup, beforeLayerId);
if (beforeLayer === undefined) {
throw new Error(`Layer with id "${beforeLayerId}" not found.`);
}
index = mapboxLayers.indexOf(beforeLayer);
} else {
index = mapboxLayers.length;
}
if (index === 0) {
throw new Error('Cannot add layer before first layer.');
}
if (mapboxLayers[index - 1].source !== mapboxLayer.source) {
throw new Error('Added layer and layer before must use the same source.');
}
if (mapboxLayers.some((layer) => layer.id === mapboxLayer.id)) {
throw new Error(`Layer with id "${mapboxLayer.id}" already exists.`);
}
mapboxLayers.splice(index, 0, mapboxLayer);
}
/**
* Update a Mapbox Layer object in the style. The map will be re-rendered with the new style.
* @param {Map|LayerGroup} mapOrGroup Map or LayerGroup.
* @param {Object} mapboxLayer Updated Mapbox Layer object.
*/
export function updateMapboxLayer(mapOrGroup, mapboxLayer) {
const glStyle = mapOrGroup.get('mapbox-style');
const mapboxLayers = glStyle.layers;
const index = mapboxLayers.findIndex(function (layer) {
return layer.id === mapboxLayer.id;
});
if (index === -1) {
throw new Error(`Layer with id "${mapboxLayer.id}" not found.`);
}
const oldLayer = mapboxLayers[index];
if (oldLayer.source !== mapboxLayer.source) {
throw new Error(
'Updated layer and previous version must use the same source.'
);
}
delete getFunctionCache(glStyle)[mapboxLayer.id];
delete getFilterCache(glStyle)[mapboxLayer.id];
mapboxLayers[index] = mapboxLayer;
getLayer(mapOrGroup, mapboxLayer.id).changed();
}
export {finalizeLayer as _finalizeLayer};

@@ -16,2 +16,5 @@ export {

getSource,
getMapboxLayer,
updateMapboxLayer,
addMapboxLayer,
} from './apply.js';

@@ -24,2 +24,6 @@ /**

const sinSunEl = Math.sin(sunEl);
const highlightColor = data.highlightColor;
const shadowColor = data.shadowColor;
const accentColor = data.accentColor;
let pixelX,

@@ -38,4 +42,12 @@ pixelY,

aspect,
cosIncidence,
scaled;
accent,
scaled,
shade,
scaledAccentColor,
compositeShadeColor,
clamp,
slopeScaleBase,
scaledSlope,
cosIncidence;
function calculateElevation(pixel) {

@@ -96,4 +108,2 @@ // The method used to extract elevations from the DEM.

slope = Math.atan(Math.sqrt(dzdx * dzdx + dzdy * dzdy));
aspect = Math.atan2(dzdy, -dzdx);

@@ -108,12 +118,61 @@ if (aspect < 0) {

// Bootstrap slope and corresponding incident values
slope = Math.atan(Math.sqrt(dzdx * dzdx + dzdy * dzdy));
cosIncidence =
sinSunEl * Math.cos(slope) +
cosSunEl * Math.sin(slope) * Math.cos(sunAz - aspect);
accent = Math.cos(slope);
// 255 for Hex colors
scaled = 255 * cosIncidence;
/*
* The following is heavily inspired
* by [Maplibre's equivalent WebGL shader](https://github.com/maplibre/maplibre-gl-js/blob/main/src/shaders/hillshade.fragment.glsl)
*/
// Forces given value to stay between two given extremes
clamp = Math.min(Math.max(2 * data.sunEl, 0), 1);
// Intensity basis for hillshade opacity
slopeScaleBase = 1.875 - data.opacity * 1.75;
// Intensity interpolation so that higher intensity values create more opaque hillshading
scaledSlope =
data.opacity !== 0.5
? halfPi *
((Math.pow(slopeScaleBase, slope) - 1) /
(Math.pow(slopeScaleBase, halfPi) - 1))
: slope;
// Accent hillshade color with given accentColor to emphasize rougher terrain
scaledAccentColor = {
r: (1 - accent) * accentColor.r * clamp * 255,
g: (1 - accent) * accentColor.g * clamp * 255,
b: (1 - accent) * accentColor.b * clamp * 255,
a: (1 - accent) * accentColor.a * clamp * 255,
};
// Allows highlight vs shadow discrimination
shade = Math.abs((((aspect + sunAz) / Math.PI + 0.5) % 2) - 1);
// Creates a composite color mix between highlight & shadow colors to emphasize slopes
compositeShadeColor = {
r: (highlightColor.r * (1 - shade) + shadowColor.r * shade) * scaled,
g: (highlightColor.g * (1 - shade) + shadowColor.g * shade) * scaled,
b: (highlightColor.b * (1 - shade) + shadowColor.b * shade) * scaled,
a: (highlightColor.a * (1 - shade) + shadowColor.a * shade) * scaled,
};
// Fill in result color value
offset = (pixelY * width + pixelX) * 4;
scaled = 255 * cosIncidence;
shadeData[offset] = scaled;
shadeData[offset + 1] = scaled;
shadeData[offset + 2] = scaled;
shadeData[offset + 3] = elevationData[offset + 3] * data.opacity;
shadeData[offset] =
scaledAccentColor.r * (1 - shade) + compositeShadeColor.r;
shadeData[offset + 1] =
scaledAccentColor.g * (1 - shade) + compositeShadeColor.g;
shadeData[offset + 2] =
scaledAccentColor.b * (1 - shade) + compositeShadeColor.b;
// Key opacity on the scaledSlope to improve legibility by increasing higher elevation rates' contrast
shadeData[offset + 3] =
elevationData[offset + 3] *
data.opacity *
clamp *
Math.sin(scaledSlope);
}

@@ -120,0 +179,0 @@ }

@@ -26,2 +26,5 @@ /*

deg2rad,
drawIconHalo,
getFilterCache,
getFunctionCache,
getZoomForResolution,

@@ -381,4 +384,4 @@ } from './util.js';

const patternCache = {};
const functionCache = {};
const filterCache = {};
const functionCache = getFunctionCache(glStyle);
const filterCache = getFilterCache(glStyle);

@@ -830,7 +833,25 @@ let mapboxSource;

if (!iconColor || iconColor.a !== 0) {
let icon_cache_key = icon + '.' + iconSize;
const haloColor = getValue(
layer,
'paint',
'icon-halo-color',
zoom,
f,
functionCache,
featureState
);
const haloWidth = getValue(
layer,
'paint',
'icon-halo-width',
zoom,
f,
functionCache,
featureState
);
let iconCacheKey = `${icon}.${iconSize}.${haloWidth}.${haloColor}`;
if (iconColor !== null) {
icon_cache_key += '.' + iconColor;
iconCacheKey += `.${iconColor}`;
}
iconImg = iconImageCache[icon_cache_key];
iconImg = iconImageCache[iconCacheKey];
if (!iconImg) {

@@ -865,30 +886,42 @@ const declutterMode = getIconDeclutterMode(

if (imageElement) {
const iconOptions = {
color: color,
rotateWithView: iconRotationAlignment === 'map',
displacement: displacement,
declutterMode: declutterMode,
};
if (typeof imageElement === 'string') {
// it is a src URL
iconImg = new Icon({
color: color,
src: imageElement,
rotateWithView: iconRotationAlignment === 'map',
displacement: displacement,
declutterMode: declutterMode,
});
iconOptions.src = imageElement;
} else {
iconImg = new Icon({
color: color,
img: imageElement,
imgSize: [imageElement.width, imageElement.height],
rotateWithView: iconRotationAlignment === 'map',
displacement: displacement,
declutterMode: declutterMode,
});
iconOptions.img = imageElement;
iconOptions.imgSize = [
imageElement.width,
imageElement.height,
];
}
iconImg = new Icon(iconOptions);
} else {
const spriteImageData = spriteData[icon];
let img, imgSize, size, offset;
if (haloWidth) {
img = drawIconHalo(
spriteImage,
spriteImageData,
haloWidth,
haloColor
);
imgSize = [img.width, img.height];
} else {
img = spriteImage;
imgSize = spriteImageSize;
size = [spriteImageData.width, spriteImageData.height];
offset = [spriteImageData.x, spriteImageData.y];
}
iconImg = new Icon({
color: color,
img: spriteImage,
imgSize: spriteImageSize,
size: [spriteImageData.width, spriteImageData.height],
offset: [spriteImageData.x, spriteImageData.y],
img: img,
imgSize: imgSize,
size: size,
offset: offset,
rotateWithView: iconRotationAlignment === 'map',

@@ -900,3 +933,3 @@ scale: iconSize / spriteImageData.pixelRatio,

}
iconImageCache[icon_cache_key] = iconImg;
iconImageCache[iconCacheKey] = iconImg;
}

@@ -1271,2 +1304,14 @@ }

text.setPlacement(placement);
if (typeof text.setRepeat === 'function') {
const symbolSpacing = getValue(
layer,
'layout',
'symbol-spacing',
zoom,
f,
functionCache,
featureState
);
text.setRepeat(symbolSpacing * 2);
}
text.setOverflow(placement === 'point');

@@ -1273,0 +1318,0 @@ let textHaloWidth = getValue(

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

import {expandUrl} from 'ol/tileurlfunction.js';
import {normalizeSourceUrl, normalizeStyleUrl} from './mapbox.js';
let styleId = 0;
const functionCacheByStyleId = {};
const filterCacheByStyleId = {};
/**
* @param {Object} glStyle Mapboox style object.
* @return {Object} Function cache.
*/
export function getFunctionCache(glStyle) {
if (!glStyle.id) {
glStyle.id = styleId++;
}
const functionCache = {};
functionCacheByStyleId[glStyle.id] = functionCache;
return functionCache;
}
/**
* @param {Object} glStyle Mapboox style object.
* @return {Object} Filter cache.
*/
export function getFilterCache(glStyle) {
if (!glStyle.id) {
glStyle.id = styleId++;
}
const filterCache = {};
filterCacheByStyleId[glStyle.id] = filterCache;
return filterCache;
}
export function deg2rad(degrees) {

@@ -48,2 +79,3 @@ return (degrees * Math.PI) / 180;

* @param {Options} [options={}] Options.
* @param {{request?: Request}} [metadata] Object to be filled with the request.
* @return {Promise<Object|Response>} Promise that resolves with the loaded resource

@@ -53,5 +85,8 @@ * or rejects with the Response object.

*/
export function fetchResource(resourceType, url, options = {}) {
export function fetchResource(resourceType, url, options = {}, metadata) {
if (url in pendingRequests) {
return pendingRequests[url];
if (metadata) {
metadata.request = pendingRequests[url][0];
}
return pendingRequests[url][1];
}

@@ -64,2 +99,5 @@ const request = options.transformRequest

}
if (metadata) {
metadata.request = request;
}
const pendingRequest = fetch(request)

@@ -76,3 +114,3 @@ .then(function (response) {

});
pendingRequests[url] = pendingRequest;
pendingRequests[url] = [request, pendingRequest];
return pendingRequest;

@@ -99,2 +137,12 @@ }

function getTransformedTilesUrl(tilesUrl, options) {
if (options.transformRequest) {
const transformedRequest = options.transformRequest(tilesUrl, 'Tiles');
if (transformedRequest instanceof Request) {
return decodeURI(transformedRequest.url);
}
}
return tilesUrl;
}
const tilejsonCache = {};

@@ -113,3 +161,3 @@ /**

if (url && !glSource.tiles) {
let normalizedSourceUrl = normalizeSourceUrl(
const normalizedSourceUrl = normalizeSourceUrl(
url,

@@ -124,39 +172,26 @@ options.accessToken,

url: undefined,
tiles: [normalizedSourceUrl],
tiles: expandUrl(normalizedSourceUrl),
})
);
} else {
promise = fetchResource('Source', normalizedSourceUrl, options).then(
function (tileJson) {
for (let i = 0, ii = tileJson.tiles.length; i < ii; ++i) {
const tileUrl = tileJson.tiles[i];
if (options.transformRequest) {
const request = options.transformRequest(
normalizedSourceUrl,
'Source'
);
if (request) {
normalizedSourceUrl = request.url;
}
}
let normalizedTileUrl = normalizeSourceUrl(
const metadata = {};
promise = fetchResource(
'Source',
normalizedSourceUrl,
options,
metadata
).then(function (tileJson) {
tileJson.tiles = tileJson.tiles.map(function (tileUrl) {
return getTransformedTilesUrl(
normalizeSourceUrl(
tileUrl,
options.accessToken,
options.accessTokenParam || 'access_token',
normalizedSourceUrl
);
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);
}
);
metadata.request.url
),
options
);
});
return Promise.resolve(tileJson);
});
}

@@ -166,7 +201,10 @@ } else {

tiles: glSource.tiles.map(function (tileUrl) {
return normalizeSourceUrl(
tileUrl,
options.accessToken,
options.accessTokenParam || 'access_token',
styleUrl || location.href
return getTransformedTilesUrl(
normalizeSourceUrl(
tileUrl,
options.accessToken,
options.accessTokenParam || 'access_token',
styleUrl || location.href
),
options
);

@@ -183,2 +221,59 @@ }),

/**
* @param {HTMLImageElement} spriteImage Sprite image id.
* @param {{x: number, y: number, width: number, height: number, pixelRatio: number}} spriteImageData Sprite image data.
* @param {number} haloWidth Halo width.
* @param {{r: number, g: number, b: number, a: number}} haloColor Halo color.
* @return {HTMLCanvasElement} Canvas element with the halo.
*/
export function drawIconHalo(
spriteImage,
spriteImageData,
haloWidth,
haloColor
) {
const imageCanvas = document.createElement('canvas');
const imgSize = [
2 * haloWidth * spriteImageData.pixelRatio + spriteImageData.width,
2 * haloWidth * spriteImageData.pixelRatio + spriteImageData.height,
];
imageCanvas.width = imgSize[0];
imageCanvas.height = imgSize[1];
const imageContext = imageCanvas.getContext('2d');
imageContext.drawImage(
spriteImage,
spriteImageData.x,
spriteImageData.y,
spriteImageData.width,
spriteImageData.height,
haloWidth * spriteImageData.pixelRatio,
haloWidth * spriteImageData.pixelRatio,
spriteImageData.width,
spriteImageData.height
);
const imageData = imageContext.getImageData(0, 0, imgSize[0], imgSize[1]);
imageContext.globalCompositeOperation = 'destination-over';
imageContext.fillStyle = `rgba(${haloColor.r * 255},${haloColor.g * 255},${
haloColor.b * 255
},${haloColor.a})`;
const data = imageData.data;
for (let i = 0, ii = imageData.width; i < ii; ++i) {
for (let j = 0, jj = imageData.height; j < jj; ++j) {
const index = (j * ii + i) * 4;
const alpha = data[index + 3];
if (alpha > 0) {
imageContext.arc(
i,
j,
haloWidth * spriteImageData.pixelRatio,
0,
2 * Math.PI
);
}
}
}
imageContext.fill();
return imageCanvas;
}
/**
* @typedef {import("./apply.js").Options} Options

@@ -185,0 +280,0 @@ * @typedef {import('./apply.js').ResourceType} ResourceType

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 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