How to use a remote wmts and generate its tiles in mapbox - mapbox-gl-js

according to How to implement a tile source to mapbox-gl i have an issue on a raster tile source in mapbox gl JS, which probably seems to fit to your declaration that mapbox only supports x/y/z and not lat/lon tile coordinates. I've trouble on this with the following tile source (WMTS): https://www.wmts.nrw.de/geobasis/wmts_nw_dop20/1.0.0/WMTSCapabilities.xml.
I want to include this wmts as source and add as layer like this:
map.on("load", function() {
map.addSource("wmts-layer", {
"type": "raster",
"tiles":['https://www.wmts.nrw.de/geobasis/wmts_nw_dop20/tiles/nw_dop20/EPSG_3857_16/{z}/{x}/{y}.jpeg'],
"tileSize": 256
});
map.addLayer({
"id": "wmts-layer",
"source": "wmts-layer",
"type": "raster",
"visibility": "visible",
"source-layer": "nw_dop20",
});
});
it does not work at all, Tiles get loaded but are empty images!
Can anyone point out whats the problem here?
cheers phil

You seem to be using Mapbox-GL-JS correctly (although you don't need source-layer). For whatever reason, that service is returinng blank tiles for example.

Thank you for investigation Steve,
this is really weird and for some reason the service seems to be unusable in mapbox gl as it serves different coordinates on each zoomlevel than it is specified in the tilescheme of mapbox (tms or xyz)!
see:
https://github.com/mapbox/mapbox-gl-js/issues/6089

Related

How to use Ordance Survey vector tiles with React-Leaflet?

I'm unsure of the correct syntax to add Ordnance Survey vector tiles to a React-Leaflet application.
The example code at https://labs.os.uk/public/os-data-hub-examples/os-vector-tile-api/vts-3857-basic-map loads some vector tile libraries from Mapbox:
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.13.1/mapbox-gl.js"></script>
<script src="https://unpkg.com/mapbox-gl-leaflet/leaflet-mapbox-gl.js"></script>
then uses this JavaScript syntax to load the OS vector tiles:
// Load and display vector tile layer on the map.
var gl = L.mapboxGL({
style: 'https://api.os.uk/maps/vector/v1/vts/resources/styles?key=' + apiKey,
transformRequest: url => {
return {
url: url += '&srs=3857'
}
}
});
(I've verified that my OS api key works in the stand-alone demo.)
How can accomplish the equivalent using React and Leaflet?
I'm using React-Leaflet to add Leaflet functionality to my React app, and I've tried adding react-leaflet-vector-tile-layer - I've verified that this works for vector tile layers supplied by Mapbox Studio:
<VectorTileLayer
styleUrl="mapbox://styles/my-org/my-style"
accessToken="my-key"
/>
I'm trying to use this approach for the Ordnance Survey vector tile layer too but it's not working as I probably have the syntax wrong:
<VectorTileLayer
styleUrl="https://api.os.uk/maps/vector/v1/vts/resources/styles?key=my-key"
/>
No error message is shown but the OS vector tile layer does not appear on the map. In the developer console I can see a PBF file has been downloaded but it doesn't draw on the map. Could this be because I'm missing the transformRequest function in their example? Assuming it's required, how can I add this transformation request when using react-leaflet-vector-tile-layer?
The answer came from Ted Piotrowski, the developer of the react-leaflet-vector-tile-layer library. I needed to add the transformRequest parameter using this syntax:
<VectorTileLayer
styleUrl="https://api.os.uk/maps/vector/v1/vts/resources/styles?key=my-key"
transformRequest={url => { return { url: url += '&srs=3857' }}}
/>

What I need to put "url" in mapbox addSource

This is my first time using mapbox and I can't figure out how to addSource when map load.
Below is the sample code.
I uploaded 'KML' file for tilesets and I want to use this tileset for source, but I don't know how to write 'url' part.
I also want to know what is 'source-layer'. What should I write in the 'source-layer?
I am sorry I know this is very basic question, but I really need to know.
Please help me.
Thanks.
map.on('load', function() {
// Add the source to query. In this example we're using
// county polygons uploaded as vector tiles
map.addSource('counties', {
"type": "vector",
"url": "mapbox://mapbox.82pkq93d" <<---here
});
map.addLayer({
"id": "counties",
"type": "fill",
"source": "counties",
"source-layer": "original", <<---source layer
"paint": {
"fill-outline-color": "rgba(0,0,0,0.1)",
"fill-color": "rgba(0,0,0,0.1)"
}
}, 'place-city-sm'); // Place polygon under these labels.
});
EDIT:
Your tile url should also be fine like this:
mapbox://{}
It is a bit tricky to find in the documentation: When uploading KML you are creating tileset for which you should get a map ID. With the map ID you can either request separate tiles using a tile url like this:
/v4/{map_id}/{zoom}/{x}/{y}{#2x}.{format}
You can use the tile url when adding a source
map.addSource({
type: 'vector',
tiles: ['https://api.mapbox.com/v4/{map_id}/{zoom}/{x}/{y}.mvt']
});
Or you can request a TileJSON metadata object and use this to add the source:
map.addSource({
type: 'vector',
url: 'https://api.mapbox.com/v4/{map_id}.json' // <-- tileJSON url
});
For your source layer question: Vector tiles include multiple "layers" of data/geometry, when adding a map layer you need to define which source-layer the map layer refers to. E.g. you can have a single vector tile set consisting of line strings and points (two different source-layers), but your map layer should only render on of them. You can either check to tile JSON to see what source-layers are included in your tile set or create a map style in mapbox studio, using your uploaded tile set as a source.

Mapbox GL JS unclustered point icon-image

I'm trying to display a clustered map with Mapbox GL JS.
Using this example from the documentation: https://www.mapbox.com/mapbox-gl-js/example/cluster/, I'd like to show a marker icon instead of a circle for unclustered points.
I modified the last addLayer call like this :
map.addLayer({
id: "unclustered-point",
type: "symbol",
source: "companies",
filter: ["!has", "point_count"],
layout: {
"icon-image": "marker-15", // THIS SHOULD BE A MARKER
"icon-size": 5 // ZOOMED FOR DEMO
},
});
Here is the result I got :
Why can't I get access to Maki Icons like it is suggested here : Mapbox GL js available icons
Without a link to your (non) working example, it's hard to diagnose fully, but one possibility is that that icon is not included in your style.
You could try starting from a style that definitely includes them, like these: https://github.com/mapbox/mapbox-gl-styles

Using a custom Mapbox Style's internal GeoJSON data as a source

I'm currently trying to render a map, with data coming from shapefiles (transformed into GeoJSON), upon uploading to Mapbox's servers.
My demo output can be viewed at:
https://ciatph.github.io/amia-lowres-hover.html
I would like to inquire if I have rendered the map efficiently, as used in the demo page. So far, I have:
Uploaded a GeoJSON Dataset
Exported the Dataset into a Tileset
Added the Tileset into a Style
Used the Style to load an initial base map
Used the uploaded Dataset as a data source for another Layer (on top of the initial map). This Layer listens and responds to mouse hover and click events
Used the uploaded Dataset as a data source for another Layer with Filters to color the hovered region differently for the created Layer in step #5.
Screenshot of relevant Mapbox script
My questions for this approach are:
Is there a way to use the Style's internal (GeoJSON) Dataset for the map.addSource() part, such that it doesn't need to be re-loaded or redefined again for creating interactive Layers? I'm concerned of network activity if its being re-downloaded again at this point. I'm also interested to know if this is possible, because we have large GeoJSON data that are almost 100MB in size. This gets automatically converted into Tileset upon moving from Amazon S3 temporary servers to mapbox, and there are no Dataset created to play with the map.addSource() part
I can use Mapbox's default styles for basemap, (i.e., mapbox://styles/mapbox/streets-v9), and omit step #4. If I go for this approach, will the Dataset loading (for step #5) be efficient and fast enough for large data, as opposed if its used or loaded via Style?
I hope you can help me with my queries and enlighten me of more salable and efficient approaches. Thank you.
Let's start by clarifying your current situation:
Your style contains a vector tileset with id ciatph.cj64in9zo1ksx32mr7ke3g7vb-93srz, referred to in your style as amia-lowres-tileset within the composite vector tile source.
It is also accessible as a dataset through the ID ciatph/cj64in9zo1ksx32mr7ke3g7vb, since you uploaded it as a dataset.
Your script is loading the dataset at runtime.
I don't see any reason you need to refer to the dataset instead of the tileset. So, remove the code that adds the dataset, and update the two styles to refer to the tileset (source: "composite") instead.
// Only used for coloring hover effect. Data informatiion be retrieved from styles alone
/*
map.addSource("dataSource", {
"type": "geojson",
'data': 'https://api.mapbox.com/datasets/v1/ciatph/cj64in9zo1ksx32mr7ke3g7vb/features?access_token=pk.eyJ1IjoiY2lhdHBoIiwiYSI6ImNqNXcyeTNhcTA5MzEycHFpdG90enFxMG8ifQ.gwZ6uo6pvx4-RZ1lHODcBQ'
});
*/
// add layer to color the raw source data
map.addLayer({
'id': 'municipalities',
"type": "fill",
"source": "composite",
"source-layer": "amia-lowres-tileset",
"layout": {},
"paint": {
"fill-color": "#627BC1",
"fill-opacity": 0.5
}
});
// add a conditional layer to play over the source data on hover event
map.addLayer({
"id": "state-fills-hover",
"type": "fill",
"source": "composite",
"source-layer": "amia-lowres-tileset",
"layout": {},
"paint": {
"fill-color": "#ff4",
"fill-opacity": 1
},
"filter": ["==", "MUNI_CITY", ""]
});
https://codepen.io/stevebennett/pen/OjvMWO

Mapbox gl directions API

So I am writing an app which allows an admin user to create a journey around a specific location with different stopping points.
For displaying a map, adding markers, flyTo location and etc I am using Mapbox GL.
I was using cURL implementation of Mapbox API to get driving directions and then draw a line on a map
So as an example of a cURL call I recieve a list of coordinates which represent my directions.
The Problem comes when I try to connect these points on a map.
As an example of HTML with some JS
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<title></title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.18.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.18.0/mapbox-gl.css' rel='stylesheet' />
<style>
body { margin:0; padding:0; }
#map { position:absolute; top:0; bottom:0; width:100%; }
</style>
</head>
<body>
<div id='map'></div>
<script>
mapboxgl.accessToken = '<ACCESS TOKEN>';
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v8',
center: [-122.486052, 37.830348],
zoom: 15
});
map.on('load', function () {
map.addSource("route", {
"type": "geojson",
"data": {
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [
[-155.088899,19.722942],[-155.08565,19.72472],[-155.084661,19.723701],[-155.083569,19.723139],[-155.079557,19.722262],[-155.074227,19.721938],[-155.069939,19.722545],[-155.070061,19.721225],[-155.07007,19.711726]
]
}
}
});
map.addLayer({
"id": "route",
"type": "line",
"source": "route",
"layout": {
"line-join": "round",
"line-cap": "round"
},
"paint": {
"line-color": "#888",
"line-width": 8
}
});
});
</script>
</body>
</html>
You can see a set of coordinates that will be connected to draw a line. I was wondering if there is a way to connect these points so that the line will follow only the road (for driving)?
To explain it better, this is a close zoom of the output
I know it's quite generic explanation of my problem, but I hope it's understandable.
I have been trying to do some magic with Mapbox Gl Directions API but no luck, as I have to add a contoller which I dont want to. I only need to draw a route and not allow a public user to be able to modify it.
Any advices?
Not sure if I understood correctly, but when you send you request to get directions include in the url 'overview=full'. This will return a more detailed path, so you have no need to use Matching API after.
Example:
`https://api.mapbox.com/directions/v5/mapbox/driving/-74.50,40;-80,50?overview=full&geometries=geojson&access_token=
I've been trying to do this today and succeded to get directions into a map and remove the start and end control by pulling down the mapbox-gl-directions project from git hub and making a minor mod to src/directions.js
I commented out lines 48 to 52
// Add controllers to the page
//new Inputs(inputEl, store, this.actions, this.map);
//new Instructions(directionsEl, store, {
// hoverMarker: this.actions.hoverMarker,
// setRouteIndex: this.actions.setRouteIndex
//}, this.map);
This was relatively easy to test with the setup in npm and my own test files by running the npm setup as per https://github.com/mapbox/mapbox-gl-directions/blob/master/CONTRIBUTING.md
npm install & npm start & open http://localhost:9966/example/
I also added the line:
localStorage.setItem('MapboxAccessToken', '<TOKEN HERE>');
below the require('../); in example/index.js. While you have the example running in npm you can access a new bundled version of the plugin from http://localhost:9966/example/bundle.js
I was then able to change the line
<script src='https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-directions/v2.0.0/mapbox-gl-directions.js'></script>
to
<script src='http://localhost:9966/example/bundle.js'></script>
There's a whole bunch of magic going in on in the example runner in npm which I don't know anything about but it all just worked on my machine. Hope this helps. The directions line works with animations and pitch, zoom and bearing animations. See a screen grab below:
UPDATE: Adding reply to here so I can show a screen grab. #Andrejus, as this hack relies on the mapbox gl directions plugin behaviour rather than drawing the paths from scratch you get road following built in and you have access to the directions API to add waypoints to do your A->B->C->D as so:
map.on('load', function() {
directions.setOrigin(start);
directions.addWaypoint(0, [-0.07571203, 51.51424049]);
directions.addWaypoint(1, [-0.12416858, 51.50779757]);
directions.setDestination(end);
});
The documentation says you can have up to 25 way points.
The mapbox-gl-directions plugin doesn't have an option to turn off the on-screen controls, they are added in the onAdd(map) method of the Directions class which is called when the directions are added to the map. I wanted to see if I could remove them earlier and was experimenting, thus the hack. To make a flexible solution, it might be possible to add an option passed in to the constructor of the Directions class. There are other options passed in there although these seem to be bound to parameters for the call to the Directions API:
var directions = new mapboxgl.Directions({
unit: 'metric',
profile: 'cycling'
});
So there might be a better solution than that. I've been using Mapbox for <1 day and don't know much about how its written or structured.
Note also that the code alterations are in a plugin, not the core of mapbox gl, so relatively isolated. BTW this plugin is a wrapper for the cURL API you were calling which returned the array of points. Presumably the source on GitHub will include code which does the road following where it renders the line, if that's definitely what you want to do.
Actually it was easier that I thought, All I had to do is to get a response from directions API, and pass a returned array to Mapbox Map Matching, that way it returns a perfect route. All documented in Mapbox API