Updates and example improvements for ol-mapbox-style v8
This commit is contained in:
@@ -5,9 +5,9 @@ import TileQueue, {
|
|||||||
import VectorTileLayer from '../src/ol/layer/VectorTile.js';
|
import VectorTileLayer from '../src/ol/layer/VectorTile.js';
|
||||||
import VectorTileSource from '../src/ol/source/VectorTile.js';
|
import VectorTileSource from '../src/ol/source/VectorTile.js';
|
||||||
import stringify from 'json-stringify-safe';
|
import stringify from 'json-stringify-safe';
|
||||||
import styleFunction from 'ol-mapbox-style/dist/stylefunction.js';
|
|
||||||
import {get} from '../src/ol/proj.js';
|
import {get} from '../src/ol/proj.js';
|
||||||
import {inView} from '../src/ol/layer/Layer.js';
|
import {inView} from '../src/ol/layer/Layer.js';
|
||||||
|
import {stylefunction} from 'ol-mapbox-style';
|
||||||
|
|
||||||
/** @type {any} */
|
/** @type {any} */
|
||||||
const worker = self;
|
const worker = self;
|
||||||
@@ -95,7 +95,7 @@ function loadStyles() {
|
|||||||
};
|
};
|
||||||
rendererTransform = transform;
|
rendererTransform = transform;
|
||||||
};
|
};
|
||||||
styleFunction(
|
stylefunction(
|
||||||
layer,
|
layer,
|
||||||
styleJson,
|
styleJson,
|
||||||
bucket.layers,
|
bucket.layers,
|
||||||
|
|||||||
@@ -1,55 +1,36 @@
|
|||||||
import MVT from '../src/ol/format/MVT.js';
|
import VectorTileLayer from '../src/ol/layer/VectorTile.js';
|
||||||
import TileGrid from '../src/ol/tilegrid/TileGrid.js';
|
|
||||||
import VectorTileSource from '../src/ol/source/VectorTile.js';
|
import VectorTileSource from '../src/ol/source/VectorTile.js';
|
||||||
import View from '../src/ol/View.js';
|
import {Map, View} from '../src/ol/index.js';
|
||||||
|
import {applyBackground, applyStyle} from 'ol-mapbox-style';
|
||||||
import olms from 'ol-mapbox-style';
|
import {createXYZ} from '../src/ol/tilegrid.js';
|
||||||
import {defaultResolutions} from 'ol-mapbox-style/dist/util.js';
|
|
||||||
|
|
||||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||||
|
const url = 'https://api.maptiler.com/maps/basic-4326/style.json?key=' + key;
|
||||||
|
|
||||||
// Match the server resolutions
|
// Match the server resolutions
|
||||||
const maxResolution = 360 / 512;
|
const tileGrid = createXYZ({
|
||||||
defaultResolutions.length = 14;
|
extent: [-180, -90, 180, 90],
|
||||||
for (let i = 0; i < 14; ++i) {
|
tileSize: 512,
|
||||||
defaultResolutions[i] = maxResolution / Math.pow(2, i + 1);
|
maxResolution: 180 / 512,
|
||||||
}
|
maxZoom: 13,
|
||||||
|
});
|
||||||
olms(
|
|
||||||
'map',
|
const layer = new VectorTileLayer({
|
||||||
'https://api.maptiler.com/maps/basic-4326/style.json?key=' + key
|
declutter: true,
|
||||||
).then(function (map) {
|
source: new VectorTileSource({
|
||||||
// Custom tile grid for the EPSG:4326 projection
|
projection: 'EPSG:4326',
|
||||||
const tileGrid = new TileGrid({
|
tileGrid: tileGrid,
|
||||||
extent: [-180, -90, 180, 90],
|
}),
|
||||||
tileSize: 512,
|
});
|
||||||
resolutions: defaultResolutions,
|
applyStyle(layer, url, '', {resolutions: tileGrid.getResolutions()});
|
||||||
});
|
applyBackground(layer, url);
|
||||||
|
|
||||||
const mapboxStyle = map.get('mapbox-style');
|
const map = new Map({
|
||||||
|
target: 'map',
|
||||||
// Replace the source with a EPSG:4326 projection source for each vector tile layer
|
layers: [layer],
|
||||||
map.getLayers().forEach(function (layer) {
|
view: new View({
|
||||||
const mapboxSource = layer.get('mapbox-source');
|
projection: 'EPSG:4326',
|
||||||
if (mapboxSource && mapboxStyle.sources[mapboxSource].type === 'vector') {
|
zoom: 0,
|
||||||
const source = layer.getSource();
|
center: [0, 30],
|
||||||
layer.setSource(
|
}),
|
||||||
new VectorTileSource({
|
|
||||||
format: new MVT(),
|
|
||||||
projection: 'EPSG:4326',
|
|
||||||
urls: source.getUrls(),
|
|
||||||
tileGrid: tileGrid,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Configure the map with a view with EPSG:4326 projection
|
|
||||||
map.setView(
|
|
||||||
new View({
|
|
||||||
projection: 'EPSG:4326',
|
|
||||||
zoom: mapboxStyle.zoom,
|
|
||||||
center: mapboxStyle.center,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|||||||
38
package-lock.json
generated
38
package-lock.json
generated
@@ -10,7 +10,7 @@
|
|||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"geotiff": "^2.0.2",
|
"geotiff": "^2.0.2",
|
||||||
"ol-mapbox-style": "^7.1.1",
|
"ol-mapbox-style": "^8.0.4",
|
||||||
"pbf": "3.2.1",
|
"pbf": "3.2.1",
|
||||||
"rbush": "^3.0.1"
|
"rbush": "^3.0.1"
|
||||||
},
|
},
|
||||||
@@ -1785,9 +1785,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mapbox/mapbox-gl-style-spec": {
|
"node_modules/@mapbox/mapbox-gl-style-spec": {
|
||||||
"version": "13.20.1",
|
"version": "13.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.24.0.tgz",
|
||||||
"integrity": "sha512-xVCJ3IbKoPwcPrxxtGAxUqHEVxXi1hnJtLIFqgkuZfnzj0KeRbk3dZlDr/KNo1/doJjIoFgPFUO/HMOT+wXGPA==",
|
"integrity": "sha512-9yhRSqnKX+59MrG647x2pACfR2Ewk8Ii5X75Ag8oToEKZU+PSY0+r10EirIVCTDwuHPzp/VuuN3j6n+Hv/gGpQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
||||||
"@mapbox/point-geometry": "^0.1.0",
|
"@mapbox/point-geometry": "^0.1.0",
|
||||||
@@ -1799,10 +1799,10 @@
|
|||||||
"sort-object": "^0.3.2"
|
"sort-object": "^0.3.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"gl-style-composite": "bin/gl-style-composite",
|
"gl-style-composite": "bin/gl-style-composite.js",
|
||||||
"gl-style-format": "bin/gl-style-format",
|
"gl-style-format": "bin/gl-style-format.js",
|
||||||
"gl-style-migrate": "bin/gl-style-migrate",
|
"gl-style-migrate": "bin/gl-style-migrate.js",
|
||||||
"gl-style-validate": "bin/gl-style-validate"
|
"gl-style-validate": "bin/gl-style-validate.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mapbox/point-geometry": {
|
"node_modules/@mapbox/point-geometry": {
|
||||||
@@ -7451,11 +7451,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/ol-mapbox-style": {
|
"node_modules/ol-mapbox-style": {
|
||||||
"version": "7.1.1",
|
"version": "8.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-8.0.4.tgz",
|
||||||
"integrity": "sha512-GLTEYiH/Ec9Zn1eS4S/zXyR2sierVrUc+OLVP8Ra0FRyqRhoYbXdko0b7OIeSHWdtJfHssWYefDOGxfTRUUZ/A==",
|
"integrity": "sha512-Tvjy3reugxZ1CO+PzngdbCwBgEBfHJI7gBTk0RUhj6o01OZKbjr+9obqPav22TLhQB4f/8w+RPUF/M8+bnqtiQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mapbox/mapbox-gl-style-spec": "^13.20.1",
|
"@mapbox/mapbox-gl-style-spec": "^13.23.1",
|
||||||
"mapbox-to-css-font": "^2.4.1",
|
"mapbox-to-css-font": "^2.4.1",
|
||||||
"webfont-matcher": "^1.1.0"
|
"webfont-matcher": "^1.1.0"
|
||||||
}
|
}
|
||||||
@@ -11802,9 +11802,9 @@
|
|||||||
"integrity": "sha1-zlblOfg1UrWNENZy6k1vya3HsjQ="
|
"integrity": "sha1-zlblOfg1UrWNENZy6k1vya3HsjQ="
|
||||||
},
|
},
|
||||||
"@mapbox/mapbox-gl-style-spec": {
|
"@mapbox/mapbox-gl-style-spec": {
|
||||||
"version": "13.20.1",
|
"version": "13.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.24.0.tgz",
|
||||||
"integrity": "sha512-xVCJ3IbKoPwcPrxxtGAxUqHEVxXi1hnJtLIFqgkuZfnzj0KeRbk3dZlDr/KNo1/doJjIoFgPFUO/HMOT+wXGPA==",
|
"integrity": "sha512-9yhRSqnKX+59MrG647x2pACfR2Ewk8Ii5X75Ag8oToEKZU+PSY0+r10EirIVCTDwuHPzp/VuuN3j6n+Hv/gGpQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
|
||||||
"@mapbox/point-geometry": "^0.1.0",
|
"@mapbox/point-geometry": "^0.1.0",
|
||||||
@@ -16194,11 +16194,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ol-mapbox-style": {
|
"ol-mapbox-style": {
|
||||||
"version": "7.1.1",
|
"version": "8.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-7.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-8.0.4.tgz",
|
||||||
"integrity": "sha512-GLTEYiH/Ec9Zn1eS4S/zXyR2sierVrUc+OLVP8Ra0FRyqRhoYbXdko0b7OIeSHWdtJfHssWYefDOGxfTRUUZ/A==",
|
"integrity": "sha512-Tvjy3reugxZ1CO+PzngdbCwBgEBfHJI7gBTk0RUhj6o01OZKbjr+9obqPav22TLhQB4f/8w+RPUF/M8+bnqtiQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@mapbox/mapbox-gl-style-spec": "^13.20.1",
|
"@mapbox/mapbox-gl-style-spec": "^13.23.1",
|
||||||
"mapbox-to-css-font": "^2.4.1",
|
"mapbox-to-css-font": "^2.4.1",
|
||||||
"webfont-matcher": "^1.1.0"
|
"webfont-matcher": "^1.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"geotiff": "^2.0.2",
|
"geotiff": "^2.0.2",
|
||||||
"ol-mapbox-style": "^7.1.1",
|
"ol-mapbox-style": "^8.0.4",
|
||||||
"pbf": "3.2.1",
|
"pbf": "3.2.1",
|
||||||
"rbush": "^3.0.1"
|
"rbush": "^3.0.1"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,110 +7,7 @@ import MVT from '../format/MVT.js';
|
|||||||
import SourceState from '../source/State.js';
|
import SourceState from '../source/State.js';
|
||||||
import VectorTileLayer from '../layer/VectorTile.js';
|
import VectorTileLayer from '../layer/VectorTile.js';
|
||||||
import VectorTileSource from '../source/VectorTile.js';
|
import VectorTileSource from '../source/VectorTile.js';
|
||||||
import {applyBackground, applyStyle, setupVectorSource} from 'ol-mapbox-style';
|
import {applyBackground, applyStyle} from 'ol-mapbox-style';
|
||||||
|
|
||||||
const mapboxBaseUrl = 'https://api.mapbox.com';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the path from a mapbox:// URL.
|
|
||||||
* @param {string} url The Mapbox URL.
|
|
||||||
* @return {string} The path.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
export function getMapboxPath(url) {
|
|
||||||
const startsWith = 'mapbox://';
|
|
||||||
if (url.indexOf(startsWith) !== 0) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
return url.slice(startsWith.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns mapbox:// sprite URLs into resolvable URLs.
|
|
||||||
* @param {string} url The sprite URL.
|
|
||||||
* @param {string} token The access token.
|
|
||||||
* @param {string} styleUrl The style URL.
|
|
||||||
* @return {string} A resolvable URL.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
export function normalizeSpriteUrl(url, token, styleUrl) {
|
|
||||||
const mapboxPath = getMapboxPath(url);
|
|
||||||
if (!mapboxPath) {
|
|
||||||
return decodeURI(new URL(url, styleUrl).href);
|
|
||||||
}
|
|
||||||
const startsWith = 'sprites/';
|
|
||||||
if (mapboxPath.indexOf(startsWith) !== 0) {
|
|
||||||
throw new Error(`unexpected sprites url: ${url}`);
|
|
||||||
}
|
|
||||||
const sprite = mapboxPath.slice(startsWith.length);
|
|
||||||
|
|
||||||
return `${mapboxBaseUrl}/styles/v1/${sprite}/sprite?access_token=${token}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns mapbox:// glyphs URLs into resolvable URLs.
|
|
||||||
* @param {string} url The glyphs URL.
|
|
||||||
* @param {string} token The access token.
|
|
||||||
* @param {string} styleUrl The style URL.
|
|
||||||
* @return {string} A resolvable URL.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
export function normalizeGlyphsUrl(url, token, styleUrl) {
|
|
||||||
const mapboxPath = getMapboxPath(url);
|
|
||||||
if (!mapboxPath) {
|
|
||||||
return decodeURI(new URL(url, styleUrl).href);
|
|
||||||
}
|
|
||||||
const startsWith = 'fonts/';
|
|
||||||
if (mapboxPath.indexOf(startsWith) !== 0) {
|
|
||||||
throw new Error(`unexpected fonts url: ${url}`);
|
|
||||||
}
|
|
||||||
const font = mapboxPath.slice(startsWith.length);
|
|
||||||
|
|
||||||
return `${mapboxBaseUrl}/fonts/v1/${font}/0-255.pbf?access_token=${token}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns mapbox:// style URLs into resolvable URLs.
|
|
||||||
* @param {string} url The style URL.
|
|
||||||
* @param {string} token The access token.
|
|
||||||
* @return {string} A resolvable URL.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
export function normalizeStyleUrl(url, token) {
|
|
||||||
const mapboxPath = getMapboxPath(url);
|
|
||||||
if (!mapboxPath) {
|
|
||||||
return decodeURI(new URL(url, location.href).href);
|
|
||||||
}
|
|
||||||
const startsWith = 'styles/';
|
|
||||||
if (mapboxPath.indexOf(startsWith) !== 0) {
|
|
||||||
throw new Error(`unexpected style url: ${url}`);
|
|
||||||
}
|
|
||||||
const style = mapboxPath.slice(startsWith.length);
|
|
||||||
|
|
||||||
return `${mapboxBaseUrl}/styles/v1/${style}?&access_token=${token}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turns mapbox:// source URLs into vector tile URL templates.
|
|
||||||
* @param {string} url The source URL.
|
|
||||||
* @param {string} token The access token.
|
|
||||||
* @param {string} tokenParam The access token key.
|
|
||||||
* @param {string} styleUrl The style URL.
|
|
||||||
* @return {string} A vector tile template.
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
export function normalizeSourceUrl(url, token, tokenParam, styleUrl) {
|
|
||||||
const urlObject = new URL(url, styleUrl);
|
|
||||||
const mapboxPath = getMapboxPath(url);
|
|
||||||
if (!mapboxPath) {
|
|
||||||
if (!token) {
|
|
||||||
return decodeURI(urlObject.href);
|
|
||||||
}
|
|
||||||
urlObject.searchParams.set(tokenParam, token);
|
|
||||||
return decodeURI(urlObject.href);
|
|
||||||
}
|
|
||||||
return `https://{a-d}.tiles.mapbox.com/v4/${mapboxPath}/{z}/{x}/{y}.vector.pbf?access_token=${token}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @classdesc
|
* @classdesc
|
||||||
@@ -130,38 +27,6 @@ class ErrorEvent extends BaseEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} StyleObject
|
|
||||||
* @property {Object<string, SourceObject>} sources The style sources.
|
|
||||||
* @property {string} sprite The sprite URL.
|
|
||||||
* @property {string} glyphs The glyphs URL.
|
|
||||||
* @property {Array<LayerObject>} layers The style layers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} SourceObject
|
|
||||||
* @property {string} url The source URL.
|
|
||||||
* @property {SourceType} type The source type.
|
|
||||||
* @property {Array<string>} [tiles] TileJSON tiles.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Mapbox source type.
|
|
||||||
* @enum {string}
|
|
||||||
*/
|
|
||||||
const SourceType = {
|
|
||||||
VECTOR: 'vector',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {Object} LayerObject
|
|
||||||
* @property {string} id The layer id.
|
|
||||||
* @property {string} type The layer type.
|
|
||||||
* @property {string} source The source id.
|
|
||||||
* @property {Object} layout The layout.
|
|
||||||
* @property {Object} paint The paint.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
* @property {string} styleUrl The URL of the Mapbox style object to use for this layer. For a
|
* @property {string} styleUrl The URL of the Mapbox style object to use for this layer. For a
|
||||||
@@ -306,211 +171,26 @@ class MapboxVectorLayer extends VectorTileLayer {
|
|||||||
properties: options.properties,
|
properties: options.properties,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.setMaxResolutionFromTileGrid_ =
|
|
||||||
options.maxResolution === undefined && options.minZoom === undefined;
|
|
||||||
|
|
||||||
this.sourceId = options.source;
|
|
||||||
this.layers = options.layers;
|
|
||||||
|
|
||||||
if (options.accessToken) {
|
if (options.accessToken) {
|
||||||
this.accessToken = options.accessToken;
|
this.accessToken = options.accessToken;
|
||||||
} else {
|
|
||||||
const url = new URL(options.styleUrl, location.href);
|
|
||||||
// The last search parameter is the access token
|
|
||||||
url.searchParams.forEach((value, key) => {
|
|
||||||
this.accessToken = value;
|
|
||||||
this.accessTokenParam_ = key;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
this.fetchStyle(options.styleUrl);
|
const url = options.styleUrl;
|
||||||
}
|
applyStyle(this, url, options.layers || options.source, {
|
||||||
|
accessToken: this.accessToken,
|
||||||
/**
|
})
|
||||||
* Fetch the style object.
|
.then(() => {
|
||||||
* @param {string} styleUrl The URL of the style to load.
|
source.setState(SourceState.READY);
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
fetchStyle(styleUrl) {
|
|
||||||
const url = normalizeStyleUrl(styleUrl, this.accessToken);
|
|
||||||
fetch(url)
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(
|
|
||||||
`unexpected response when fetching style: ${response.status}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then((style) => {
|
|
||||||
this.onStyleLoad(style, url.startsWith('data:') ? location.href : url);
|
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.handleError(error);
|
this.dispatchEvent(new ErrorEvent(error));
|
||||||
|
const source = this.getSource();
|
||||||
|
source.setState(SourceState.ERROR);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle the loaded style object.
|
|
||||||
* @param {StyleObject} style The loaded style.
|
|
||||||
* @param {string} styleUrl The URL of the style.
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
onStyleLoad(style, styleUrl) {
|
|
||||||
let sourceId;
|
|
||||||
let sourceIdOrLayersList;
|
|
||||||
if (this.layers) {
|
|
||||||
// confirm all layers share the same source
|
|
||||||
const lookup = {};
|
|
||||||
for (let i = 0; i < style.layers.length; ++i) {
|
|
||||||
const layer = style.layers[i];
|
|
||||||
if (layer.source) {
|
|
||||||
lookup[layer.id] = layer.source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let firstSource;
|
|
||||||
for (let i = 0; i < this.layers.length; ++i) {
|
|
||||||
const candidate = lookup[this.layers[i]];
|
|
||||||
if (!candidate) {
|
|
||||||
this.handleError(
|
|
||||||
new Error(`could not find source for ${this.layers[i]}`)
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!firstSource) {
|
|
||||||
firstSource = candidate;
|
|
||||||
} else if (firstSource !== candidate) {
|
|
||||||
this.handleError(
|
|
||||||
new Error(
|
|
||||||
`layers can only use a single source, found ${firstSource} and ${candidate}`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sourceId = firstSource;
|
|
||||||
sourceIdOrLayersList = this.layers;
|
|
||||||
} else {
|
|
||||||
sourceId = this.sourceId;
|
|
||||||
sourceIdOrLayersList = sourceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sourceIdOrLayersList) {
|
|
||||||
// default to the first source in the style
|
|
||||||
sourceId = Object.keys(style.sources)[0];
|
|
||||||
sourceIdOrLayersList = sourceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.sprite) {
|
|
||||||
style.sprite = normalizeSpriteUrl(
|
|
||||||
style.sprite,
|
|
||||||
this.accessToken,
|
|
||||||
styleUrl
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (style.glyphs) {
|
|
||||||
style.glyphs = normalizeGlyphsUrl(
|
|
||||||
style.glyphs,
|
|
||||||
this.accessToken,
|
|
||||||
styleUrl
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const styleSource = style.sources[sourceId];
|
|
||||||
if (styleSource.type !== SourceType.VECTOR) {
|
|
||||||
this.handleError(
|
|
||||||
new Error(`only works for vector sources, found ${styleSource.type}`)
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const source = this.getSource();
|
|
||||||
if (styleSource.url && styleSource.url.indexOf('mapbox://') === 0) {
|
|
||||||
// Tile source url, handle it directly
|
|
||||||
source.setUrl(
|
|
||||||
normalizeSourceUrl(
|
|
||||||
styleSource.url,
|
|
||||||
this.accessToken,
|
|
||||||
this.accessTokenParam_,
|
|
||||||
styleUrl
|
|
||||||
)
|
|
||||||
);
|
|
||||||
applyStyle(this, style, sourceIdOrLayersList)
|
|
||||||
.then(() => {
|
|
||||||
this.configureSource(source, style);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.handleError(error);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// TileJSON url, let ol-mapbox-style handle it
|
|
||||||
if (styleSource.tiles) {
|
|
||||||
styleSource.tiles = styleSource.tiles.map((url) =>
|
|
||||||
normalizeSourceUrl(
|
|
||||||
url,
|
|
||||||
this.accessToken,
|
|
||||||
this.accessTokenParam_,
|
|
||||||
styleUrl
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
setupVectorSource(
|
|
||||||
styleSource,
|
|
||||||
styleSource.url
|
|
||||||
? normalizeSourceUrl(
|
|
||||||
styleSource.url,
|
|
||||||
this.accessToken,
|
|
||||||
this.accessTokenParam_,
|
|
||||||
styleUrl
|
|
||||||
)
|
|
||||||
: undefined
|
|
||||||
).then((source) => {
|
|
||||||
applyStyle(this, style, sourceIdOrLayersList)
|
|
||||||
.then(() => {
|
|
||||||
this.configureSource(source, style);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.configureSource(source, style);
|
|
||||||
this.handleError(error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Applies configuration from the provided source to this layer's source,
|
|
||||||
* and reconfigures the loader to add a feature that renders the background,
|
|
||||||
* if the style is configured with a background.
|
|
||||||
* @param {import("../source/VectorTile.js").default} source The source to configure from.
|
|
||||||
* @param {StyleObject} style The style to configure the background from.
|
|
||||||
*/
|
|
||||||
configureSource(source, style) {
|
|
||||||
const targetSource = this.getSource();
|
|
||||||
if (source !== targetSource) {
|
|
||||||
targetSource.setAttributions(source.getAttributions());
|
|
||||||
targetSource.setTileUrlFunction(source.getTileUrlFunction());
|
|
||||||
targetSource.setTileLoadFunction(source.getTileLoadFunction());
|
|
||||||
targetSource.tileGrid = source.tileGrid;
|
|
||||||
}
|
|
||||||
if (this.getBackground() === undefined) {
|
if (this.getBackground() === undefined) {
|
||||||
applyBackground(this, style);
|
applyBackground(this, options.styleUrl, {
|
||||||
|
accessToken: this.accessToken,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (this.setMaxResolutionFromTileGrid_) {
|
|
||||||
const tileGrid = targetSource.getTileGrid();
|
|
||||||
this.setMaxResolution(tileGrid.getResolution(tileGrid.getMinZoom()));
|
|
||||||
}
|
|
||||||
targetSource.setState(SourceState.READY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle configuration or loading error.
|
|
||||||
* @param {Error} error The error.
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
handleError(error) {
|
|
||||||
this.dispatchEvent(new ErrorEvent(error));
|
|
||||||
const source = this.getSource();
|
|
||||||
source.setState(SourceState.ERROR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,123 +1,9 @@
|
|||||||
import MapboxVectorLayer, {
|
import MapboxVectorLayer from '../../../../../src/ol/layer/MapboxVector.js';
|
||||||
getMapboxPath,
|
|
||||||
normalizeSourceUrl,
|
|
||||||
normalizeSpriteUrl,
|
|
||||||
normalizeStyleUrl,
|
|
||||||
} from '../../../../../src/ol/layer/MapboxVector.js';
|
|
||||||
import {asString} from '../../../../../src/ol/color.js';
|
import {asString} from '../../../../../src/ol/color.js';
|
||||||
|
import {strokeInstruction} from '../../../../../src/ol/render/canvas/Instruction.js';
|
||||||
import {unByKey} from '../../../../../src/ol/Observable.js';
|
import {unByKey} from '../../../../../src/ol/Observable.js';
|
||||||
|
|
||||||
describe('ol/layer/MapboxVector', () => {
|
describe('ol/layer/MapboxVector', () => {
|
||||||
describe('getMapboxPath()', () => {
|
|
||||||
const cases = [
|
|
||||||
{
|
|
||||||
url: 'mapbox://path/to/resource',
|
|
||||||
expected: 'path/to/resource',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'mapbox://path/to/resource?query',
|
|
||||||
expected: 'path/to/resource?query',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'https://example.com/resource',
|
|
||||||
expected: '',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const c of cases) {
|
|
||||||
it(`works for ${c.url}`, () => {
|
|
||||||
expect(getMapboxPath(c.url)).to.be(c.expected);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('normalizeStyleUrl()', () => {
|
|
||||||
const cases = [
|
|
||||||
{
|
|
||||||
url: 'mapbox://styles/mapbox/bright-v9',
|
|
||||||
expected:
|
|
||||||
'https://api.mapbox.com/styles/v1/mapbox/bright-v9?&access_token=test-token',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'https://example.com/style',
|
|
||||||
expected: 'https://example.com/style',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const token = 'test-token';
|
|
||||||
for (const c of cases) {
|
|
||||||
it(`works for ${c.url}`, () => {
|
|
||||||
expect(normalizeStyleUrl(c.url, token)).to.be(c.expected);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('normalizeSpriteUrl()', () => {
|
|
||||||
const cases = [
|
|
||||||
{
|
|
||||||
url: 'mapbox://sprites/mapbox/bright-v9',
|
|
||||||
expected:
|
|
||||||
'https://api.mapbox.com/styles/v1/mapbox/bright-v9/sprite?access_token=test-token',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'https://example.com/sprite',
|
|
||||||
expected: 'https://example.com/sprite',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: '../sprite',
|
|
||||||
expected: 'https://example.com:8000/sprite',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: '/sprite',
|
|
||||||
expected: 'https://example.com:8000/sprite',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: './sprite',
|
|
||||||
expected: 'https://example.com:8000/mystyle/sprite',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const token = 'test-token';
|
|
||||||
for (const c of cases) {
|
|
||||||
it(`works for ${c.url}`, () => {
|
|
||||||
expect(
|
|
||||||
normalizeSpriteUrl(
|
|
||||||
c.url,
|
|
||||||
token,
|
|
||||||
'https://example.com:8000/mystyle/style.json'
|
|
||||||
)
|
|
||||||
).to.be(c.expected);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('normalizeSourceUrl()', () => {
|
|
||||||
const cases = [
|
|
||||||
{
|
|
||||||
url: 'mapbox://mapbox.mapbox-streets-v7',
|
|
||||||
expected:
|
|
||||||
'https://{a-d}.tiles.mapbox.com/v4/mapbox.mapbox-streets-v7/{z}/{x}/{y}.vector.pbf?access_token=test-token',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'https://example.com/source/{z}/{x}/{y}.pbf',
|
|
||||||
expected: 'https://example.com/source/{z}/{x}/{y}.pbf?token=test-token',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'https://example.com/source/{z}/{x}/{y}.pbf?foo=bar',
|
|
||||||
expected:
|
|
||||||
'https://example.com/source/{z}/{x}/{y}.pbf?foo=bar&token=test-token',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const token = 'test-token';
|
|
||||||
const tokenParam = 'token';
|
|
||||||
for (const c of cases) {
|
|
||||||
it(`works for ${c.url}`, () => {
|
|
||||||
expect(normalizeSourceUrl(c.url, token, tokenParam)).to.be(c.expected);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('TileJSON', function () {
|
describe('TileJSON', function () {
|
||||||
it('lets ol-mapbox-style handle TileJSON URLs', function (done) {
|
it('lets ol-mapbox-style handle TileJSON URLs', function (done) {
|
||||||
const layer = new MapboxVectorLayer({
|
const layer = new MapboxVectorLayer({
|
||||||
@@ -136,6 +22,9 @@ describe('ol/layer/MapboxVector', () => {
|
|||||||
})
|
})
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
layer.on('error', function (e) {
|
||||||
|
done(e.error);
|
||||||
|
});
|
||||||
const source = layer.getSource();
|
const source = layer.getSource();
|
||||||
const key = source.on('change', function () {
|
const key = source.on('change', function () {
|
||||||
if (source.getState() === 'ready') {
|
if (source.getState() === 'ready') {
|
||||||
@@ -185,6 +74,9 @@ describe('ol/layer/MapboxVector', () => {
|
|||||||
const layer = new MapboxVectorLayer({
|
const layer = new MapboxVectorLayer({
|
||||||
styleUrl: styleUrl,
|
styleUrl: styleUrl,
|
||||||
});
|
});
|
||||||
|
layer.on('error', function (e) {
|
||||||
|
done(e.error);
|
||||||
|
});
|
||||||
const source = layer.getSource();
|
const source = layer.getSource();
|
||||||
source.on('change', function onchange() {
|
source.on('change', function onchange() {
|
||||||
if (source.getState() === 'ready') {
|
if (source.getState() === 'ready') {
|
||||||
@@ -312,20 +204,31 @@ describe('ol/layer/MapboxVector', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('Access token', function () {
|
describe('Access token', function () {
|
||||||
it('applies correct access token from access_token', function () {
|
let originalFetch, fetchUrl;
|
||||||
const layer = new MapboxVectorLayer({
|
beforeEach(function () {
|
||||||
|
originalFetch = fetch;
|
||||||
|
window.fetch = function (url) {
|
||||||
|
fetchUrl = url;
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterEach(function () {
|
||||||
|
window.fetch = originalFetch;
|
||||||
|
});
|
||||||
|
it('applies correct access token', function () {
|
||||||
|
new MapboxVectorLayer({
|
||||||
styleUrl: 'mapbox://styles/mapbox/streets-v7',
|
styleUrl: 'mapbox://styles/mapbox/streets-v7',
|
||||||
accessToken: '123',
|
accessToken: '123',
|
||||||
});
|
});
|
||||||
expect(layer.accessToken).to.be('123');
|
expect(fetchUrl.url).to.be(
|
||||||
expect(layer.accessTokenParam_).to.be(undefined);
|
'https://api.mapbox.com/styles/v1/mapbox/streets-v7?&access_token=123'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
it('applies correct access token from url', function () {
|
it('applies correct access token from url', function () {
|
||||||
const layer = new MapboxVectorLayer({
|
new MapboxVectorLayer({
|
||||||
styleUrl: 'foo?key=123',
|
styleUrl: 'foo?key=123',
|
||||||
});
|
});
|
||||||
expect(layer.accessToken).to.be('123');
|
expect(fetchUrl.url).to.be(`${location.origin}/foo?key=123`);
|
||||||
expect(layer.accessTokenParam_).to.be('key');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user