├── .npmignore
├── .gitignore
├── debug
├── src
│ ├── main.ts
│ └── App.vue
├── tsconfig.json
├── vite.config.ts
├── .gitignore
├── index.html
├── README.md
├── tsconfig.app.json
├── package.json
└── tsconfig.node.json
├── CHANGES.md
├── src
├── index.d.ts
└── index.js
├── package.json
├── LICENSE
└── README.md
/.npmignore:
--------------------------------------------------------------------------------
1 | debug/
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | debug/node_modules
3 | debug/.vscode
4 | package-lock.json
5 | pnpm-lock.yaml
6 |
--------------------------------------------------------------------------------
/debug/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 |
4 | createApp(App).mount('#app')
5 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | ## 0.0.1
2 | - Initial release
3 |
4 | ## 0.0.3
5 | - Add improved sprite support
6 | - add v12 mapbox style support
7 |
--------------------------------------------------------------------------------
/debug/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": [],
3 | "references": [
4 | { "path": "./tsconfig.app.json" },
5 | { "path": "./tsconfig.node.json" }
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/debug/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 |
4 | // https://vite.dev/config/
5 | export default defineConfig({
6 | plugins: [vue()],
7 | })
8 |
--------------------------------------------------------------------------------
/debug/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/debug/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + Vue + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/index.d.ts:
--------------------------------------------------------------------------------
1 | import { ResourceType } from 'maplibre-gl';
2 | import { StyleSpecification, RequestParameters } from 'maplibre-gl'
3 |
4 | export function isMapboxURL(url: string): boolean;
5 |
6 | export function transformMapboxUrl(url: string, resourceType?: ResourceType, accessToken?: string): RequestParameters
7 |
8 | export function transformMapboxStyle(_previousStyle: StyleSpecification, nextStyle: StyleSpecification): StyleSpecification
9 |
--------------------------------------------------------------------------------
/debug/README.md:
--------------------------------------------------------------------------------
1 | # Vue 3 + TypeScript + Vite
2 |
3 | This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `
41 |
42 |
48 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export function isMapboxURL(url) {
2 | return url.indexOf('mapbox:') === 0;
3 | }
4 |
5 | export function transformMapboxStyle (_previousStyle, nextStyle) {
6 | if (nextStyle.projection && nextStyle.projection.name) {
7 | delete nextStyle.projection.name;
8 | }
9 | return nextStyle;
10 | }
11 |
12 | export function transformMapboxUrl (url, resourceType, accessToken) {
13 | if (url.indexOf('/styles/') > -1 && url.indexOf('/sprite') === -1) return {url: normalizeStyleURL(url, accessToken)}
14 | if (url.indexOf('/sprites/') > -1) return {url: normalizeSpriteURL(url, '', '.json', accessToken)}
15 | if (url.indexOf('/fonts/') > -1) return {url: normalizeGlyphsURL(url, accessToken)}
16 | if (url.indexOf('/v4/') > -1) return {url: normalizeSourceURL(url, accessToken)}
17 | if (resourceType && resourceType === 'Source') return {url: normalizeSourceURL(url, accessToken)}
18 | }
19 |
20 | function parseUrl(url) {
21 | const urlRe = /^(\w+):\/\/([^/?]*)(\/[^?]+)?\??(.+)?/;
22 | const parts = url.match(urlRe);
23 | if (!parts) {
24 | throw new Error('Unable to parse URL object');
25 | }
26 | return {
27 | protocol: parts[1],
28 | authority: parts[2],
29 | path: parts[3] || '/',
30 | params: parts[4] ? parts[4].split('&') : []
31 | };
32 | }
33 |
34 | function formatUrl(urlObject, accessToken) {
35 | const apiUrlObject = parseUrl("https://api.mapbox.com");
36 | urlObject.protocol = apiUrlObject.protocol;
37 | urlObject.authority = apiUrlObject.authority;
38 | urlObject.params.push(`access_token=${accessToken}`);
39 | const params = urlObject.params.length ? `?${urlObject.params.join('&')}` : '';
40 | return `${urlObject.protocol}://${urlObject.authority}${urlObject.path}${params}`;
41 | }
42 |
43 | function normalizeStyleURL(url, accessToken) {
44 | const urlObject = parseUrl(url);
45 | urlObject.path = `/styles/v1${urlObject.path}`;
46 | return formatUrl(urlObject, accessToken);
47 | }
48 |
49 | function normalizeGlyphsURL(url, accessToken) {
50 | const urlObject = parseUrl(url);
51 | urlObject.path = `/fonts/v1${urlObject.path}`;
52 | return formatUrl(urlObject, accessToken);
53 | }
54 |
55 | function normalizeSourceURL(url, accessToken) {
56 | const urlObject = parseUrl(url);
57 | urlObject.path = `/v4/${urlObject.authority}.json`;
58 | urlObject.params.push('secure');
59 | return formatUrl(urlObject, accessToken);
60 | }
61 |
62 | /**
63 | * Normalizes a sprite URL.
64 | *
65 | * @param {string} url - The original sprite URL.
66 | * @param {string} _format - The format (not used in the function).
67 | * @param {string} _extension - The extension (not used in the function).
68 | * @param {string} accessToken - The access token.
69 | *
70 | * @returns {string} - The normalized URL.
71 | *
72 | * @throws {Error} Throws an error if the URL cannot be normalized.
73 | */
74 | function normalizeSpriteURL(url, _format, _extension, accessToken) {
75 | const urlObject = parseUrl(url);
76 | let path = urlObject.path.split('.');
77 | let properPath = path[0]
78 | const extension = path[1] || 'json'; // <- this only line is changed
79 | let format = ''
80 |
81 | if (properPath.indexOf('@2x')) {
82 | properPath = properPath.split('@2x')[0];
83 | format = '@2x'
84 | }
85 | urlObject.path = `/styles/v1${properPath}/sprite${format}.${extension}`;
86 | return formatUrl(urlObject, accessToken);
87 | }
88 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This library provides a request transforming function enabling the consumption of MapboxGL Styles in MapLibreGL.
2 |
3 | By default Mapbox styles are referenced by, and include others to mapbox URLs such as `mapbox://styles/mapbox/satellite-streets-v11`, however MapLibreGL, since version 2, does not know how to handle these references. This library parsers the mapbox URL and converts into a valid http urls usable by MapLibreGL.
4 |
5 | Also compatible with react-map-gl.
6 |
7 | ## Install
8 | ````
9 | npm install maplibregl-mapbox-request-transformer --save
10 | ````
11 |
12 | ## Usage
13 | ### For v12 mapbox styles
14 | For v12 styles you can either use the built in style transformer
15 | ````
16 | import {
17 | isMapboxURL,
18 | transformMapboxUrl,
19 | transformMapboxStyle
20 | } from 'maplibregl-mapbox-request-transformer'
21 |
22 | const mapboxKey = 'pk.123'
23 |
24 | const transformRequest = (url: string, resourceType: string) => {
25 | if (isMapboxURL(url)) {
26 | return transformMapboxUrl(url, resourceType, mapboxKey)
27 | }
28 | return {url}
29 | }
30 |
31 | var map = new maplibregl.Map({
32 | container: 'map',
33 | center: [-122.420679, 37.772537],
34 | zoom: 13,
35 | transformRequest
36 | });
37 |
38 | // For V12 Styles you'll also need to add
39 | map.setStyle('mapbox://styles/mapbox/streets-v12', {
40 | transformStyle: transformMapboxStyle
41 | })
42 | ````
43 | Or pass you can pass in `validateStyle: false` to the map options
44 | ````
45 | import {
46 | isMapboxURL,
47 | transformMapboxUrl
48 | } from 'maplibregl-mapbox-request-transformer'
49 |
50 | const mapboxKey = 'pk.123'
51 |
52 | const transformRequest = (url: string, resourceType: string) => {
53 | if (isMapboxURL(url)) {
54 | return transformMapboxUrl(url, resourceType, mapboxKey)
55 | }
56 | return {url}
57 | }
58 |
59 | var map = new maplibregl.Map({
60 | container: 'map',
61 | center: [-122.420679, 37.772537],
62 | zoom: 13,
63 | style: 'mapbox://styles/mapbox/streets-v12'
64 | transformRequest,
65 | validateStyle: false,
66 | });
67 |
68 | ````
69 |
70 | ### For < v12 mapbox styles
71 | ````
72 | import { isMapboxURL, transformMapboxUrl } from 'maplibregl-mapbox-request-transformer'
73 |
74 | const mapboxKey = 'pk.123'
75 |
76 | const transformRequest = (url: string, resourceType: string) => {
77 | if (isMapboxURL(url)) {
78 | return transformMapboxUrl(url, resourceType, mapboxKey)
79 | }
80 | return {url}
81 | }
82 |
83 | var map = new maplibregl.Map({
84 | container: 'map',
85 | center: [-122.420679, 37.772537],
86 | zoom: 13,
87 | style: 'mapbox://styles/mapbox/streets-v11'
88 | transformRequest
89 | });
90 |
91 | ````
92 |
93 | ## Notes on Mapbox Pricing
94 | When upgrading from MapLibre v1 to >= v2 or react-map-gl, and using this transformer, be advised that Mapbox bills tile requests using their Vector Tiles API requests. A standard Mapbox GL JS application is billed using the Map Loads API, which includes unlimited Vector Tiles API requests ([see pricing docs](https://docs.mapbox.com/mapbox-gl-js/guides/pricing/)). This billing difference could make hosting an often-visited map more expensive. As of Feb 2023 Mapbox offers 200,000 monthly tile requests on their free tier (see their [pricing page](https://www.mapbox.com/pricing#vector-tiles-api) for current details).
95 |
96 | ## Acknowledgements
97 | This code was mostly taken and adpted from [here](https://github.com/maplibre/maplibre-gl-js/blob/04ff47d53ec16e17b92475fe9028c1477f6df02f/src/util/mapbox.ts).
98 |
--------------------------------------------------------------------------------