Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MapTiler SDK #199

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## Unreleased

- add support for MapTiler SDK

## 0.16.0

- Add multi-level dropdowns
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,22 @@ Here, you can customize the following options:

- `mapboxGlAccessToken`: Your Mapbox GL token to allow style reads
- `mapboxBaseApiUrl`: (optional) Support for a Mapbox flavored style that is served from a different server other than `api.mapbox.com`, e.g., Mapbox Atlas.
- `maptilerApiKey`: Your MapTiler API key to use with `maptiler-sdk`
- `googleMapsAPIKey`: Your Google Maps API key to enable API usage
- `stylePresets`: A list of styles with urls to show in the dropdowns. Styles must have the following keys:
- `id`: a unique id
- `name`: a display name
- `type`: the type of map or referencing a sublist of presets (`mapbox-gl`, `maplibre-gl`, `google`, `leaflet`, `sublist`)
- `url`: (currently applies to `mapbox-gl`, `maplibre-gl`, and `leaflet` maps only) the style's url
- `type`: the type of map or referencing a sublist of presets (`mapbox-gl`, `maplibre-gl`, `maptiler-sdk`, `google`, `leaflet`, `sublist`)
- `url`: (currently applies to `mapbox-gl`, `maplibre-gl`, `maptiler-sdk` and `leaflet` maps only) the style's url
- `mapId`: (currently `google` only) the style's id
- [`presets`]: used only with `type: sublist`, this allows one level of nesting to add an additional nested list of style presets following this format
- `branchPatterns`: An array of objects that specify how to build a URL to fetch a style living on a branch with the following keys:
- `pattern`: a tokenized url pattern using `{branch}` and `{style}` tokens
- `styles`: an array specifying specific styles you can view on the specified branch
- `type`: the type of map (`mapbox-gl`, `maplibre-gl`, `google`, `leaflet`)
- `stylePresetUrls`: An array of URLs pointing to additional presets. URLs must point to JSON arrays containing objects of the same shape as those in `stylePresets`.
- `viewMode`: The starting view configuration, one of `swipe` (the default), `mirror`, `phone`, or `responsive`.
- `mapState`: An object containing options for the Mapbox or MapLibre `Map` (see [MapOptions](https://maplibre.org/maplibre-gl-js/docs/API/type-aliases/MapOptions/) in the MapLibre documentation).
- `gazetteer`: An object that specifies the options available in the interface for navigating directly to specific geographic locations or changing other view options such as the pitch and zoom of the map. The object is a map of **option group names** to arrays of options. Each **option** is an object of names to map options to update.

See `defaultGazetteer` in `src/make-config.js` for the default gazetteer, but as an example you might use:
Expand Down
168 changes: 168 additions & 0 deletions dist/bundle.css

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions dist/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/bundle.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@beyonk/svelte-mapbox": "^8.1.4",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@googlemaps/js-api-loader": "^1.13.10",
"@maptiler/sdk": "^2.3.0",
"autoprefixer": "^10.4.14",
"deep-equal": "^2.0.5",
"hat": "^0.0.3",
Expand Down
18 changes: 17 additions & 1 deletion public/config/local.example.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Replace with your Mapbox GL token, if any
const mapboxGlAccessToken = 'pk.eyAAAABBBCCC';

// Replace with your MapTiler API key
const maptilerApiKey = '';

// Example of setting up a gazetteer object. This is described in the `README`
// but these are the options that populate the dropdown in the UI that take you
// to specific locations or map views. You can add as many as you like here and
Expand Down Expand Up @@ -54,6 +57,19 @@ const stylePresets = [
attribution:
'&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
},
{
id: 'maplibre-demo-tiles',
name: 'Maplibre Demo Tiles',
type: 'maplibre-gl',
url: 'https://demotiles.maplibre.org/style.json',
},
// In order for this to work you need to set the maptilerApiKey
// {
// id: 'maptiler-streets',
// name: 'MapTiler Streets',
// type: 'maptiler-sdk',
// url: 'https://api.maptiler.com/maps/streets-v2/style.json',
// },
];

// Commented out example for branchpattern
Expand All @@ -73,4 +89,4 @@ const stylePresets = [
// Example of stylePresetUrls
// const stylePresetUrls = ['./presets/example.json'];

export { gazetteer, mapboxGlAccessToken, stylePresets };
export { gazetteer, mapboxGlAccessToken, stylePresets, maptilerApiKey };
1 change: 1 addition & 0 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export default {
resolve({
browser: true,
dedupe: ['svelte'],
preferBuiltins: false,
}),
commonjs(),

Expand Down
8 changes: 6 additions & 2 deletions src/components/GlMap.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script>
import deepEqual from 'deep-equal';
import throttle from 'lodash.throttle';
import { createEventDispatcher, onMount, onDestroy } from 'svelte';
import { createEventDispatcher, onDestroy, onMount } from 'svelte';
import { config as configStore } from '../stores';

export let id;
Expand All @@ -23,6 +23,10 @@
if (mapRenderer === 'maplibre-gl') {
await import('maplibre-gl/dist/maplibre-gl.css');
renderer = await import('maplibre-gl');
} else if (mapRenderer === 'maptiler-sdk') {
await import('@maptiler/sdk/dist/maptiler-sdk.css');
renderer = await import('@maptiler/sdk');
renderer.config.apiKey = $configStore.maptilerApiKey;
} else {
await import('mapbox-gl/dist/mapbox-gl.css');
renderer = await import('mapbox-gl');
Expand Down Expand Up @@ -195,7 +199,7 @@
// Resize the map when adding more maps and changing container size
$: if (map && numberOfMaps) {
// As of `v3.0.0` maplibre no longer needs this resizing: https://github.com/maplibre/maplibre-gl-js/blob/main/CHANGELOG.md#potentially-breaking-changes
if (mapRenderer !== 'maplibre-gl') {
if (mapRenderer !== 'maplibre-gl' || mapRenderer !== 'maptiler-sdk') {
map.once('render', () => {
const container = document.getElementById(id);
if (container) {
Expand Down
3 changes: 0 additions & 3 deletions src/components/Map.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,6 @@
MapComponent = TangramMap;
break;
case 'maplibre-gl':
MapComponent = GlMap;
props.mapRenderer = mapRenderer;
break;
case 'mapbox-gl':
default:
MapComponent = GlMap;
Expand Down
16 changes: 12 additions & 4 deletions src/fetch-url.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { config as configStore } from './stores';
import { isMapboxUrl, normalizeMapboxUrl } from './mapbox-urls';

let mapboxGlAccessToken;
configStore.subscribe(value => ({ mapboxGlAccessToken } = value));
let mapboxGlAccessToken, maptilerApiKey;
configStore.subscribe(
value => ({ mapboxGlAccessToken, maptilerApiKey } = value)
);

const fetchUrl = async url => {
const urlIsMapbox = isMapboxUrl(url);
let nextUrl = url;
let nextUrl = new URL(url);
if (urlIsMapbox) {
nextUrl = normalizeMapboxUrl(url, mapboxGlAccessToken);
nextUrl = normalizeMapboxUrl(nextUrl.toString(), mapboxGlAccessToken);
} else if (
maptilerApiKey &&
nextUrl.host === 'api.maptiler.com' &&
!nextUrl.searchParams.has('key')
) {
nextUrl.searchParams.append('key', maptilerApiKey);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm seeing Maptiler URLs fail in other renderers (Mapbox and Maplibre).

I think it's because here you're following the same pattern we use for a mapbox URL and as I think on this, I wonder if we need a change in this PR for Maptiler and a followup for Mapbox URLs.

Basically we haven't run into this with Mapbox URLs (with the mapbox protocol mapbox://) because we've considered them only valid via the Mapbox renderer despite us normalizing the URL here. This is because they typically also reference additional Mapbox protocol URLs for sprites and glyphs so we didn't consider this a bug (You'll see Mapbox styles using the protocol fail in Maplibre for example).

Maptiler (correct me if I'm wrong) is different in that it does not use a custom protocol inside the style and instead creates a valid url with the key present when requesting the style url with that key:

"glyphs": "[https://api.maptiler.com/fonts/{fontstack}/{range}.pbf?key=fBwWvQI476rYQ6q9LrJf](https://api.maptiler.com/fonts/%7Bfontstack%7D/%7Brange%7D.pbf?key=fBwWvQI476rYQ6q9LrJf)"

So basically, we should be able to request the style with the new maptilerApiKey param while rendering with Maplibre, but we fail here because it looks at the URL (without accounting for the API key) before the style requested from the normalized the URL.

tl;dr

  • I think this line should privilege style over url (I don't think there's a side effect of this?) like this:
    map.setStyle(style || url);
    
  • As a followup, we should consider normalizing the URLs using the Mapbox protocol within a stylesheet to allow it to be rendered outside of the Mapbox renderer.

Let me know if this does not sound accurate!

}
let response;
try {
Expand Down
2 changes: 2 additions & 0 deletions src/renderers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const mapboxGlOption = { name: 'Mapbox GL JS', value: 'mapbox-gl' };
const glVectorRenderers = [
mapboxGlOption,
{ name: 'Maplibre GL JS', value: 'maplibre-gl' },
{ name: 'MapTiler SDK', value: 'maptiler-sdk' },
];

const typeToRenderers = {
Expand All @@ -14,6 +15,7 @@ const typeToRenderers = {
'vector-gl': glVectorRenderers,
'mapbox-gl': glVectorRenderers,
'maplibre-gl': glVectorRenderers,
'maptiler-sdk': glVectorRenderers,
};

export const getRenderers = (map, sources) => {
Expand Down
Loading