Mapbox Matching API switched coordinates - leaflet

Edit: I reformatted the question as it was pointed out to me that the problem is not in the Mapbox API.
As of a few days ago an application using mapbox matching API coupled with leaflet.js started drawing polylines on the other side of the planet.
While the path it self looks as it should be, leaflet drew it on another continent.
The Mapbox Matching API returns the response following GEOJson standard as:
{
"code": "Ok",
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": "e`s`YmyazuAg`#y]uo#ej#eQcOkFkEyCeCaYmUuFoMkWgOo[_ReGqDoGyDmVaPaU|RoDlDsa#z`#sTdSXJf#j#??Jr#Mp#ML[Z}#ZiAHgAK]MaJzJsUbWkSxRyHpHuLhLuFzFqDrDq[`\\oPrPyK|KmU|TuLzKyClCr#ZZf#Fj#Ij#e#b#zn#fZ}Zf]gCdKmHxQErC[jV",
"properties": {
"confidence": 0.45413768894813844,
"distance": 1366.4,
"duration": 243.3,
"matchedPoints": [
[13.658131, 45.532583],
[13.659851, 45.534127],
[13.661445, 45.535438],
[13.662397, 45.535398],
[13.663582, 45.534237],
[13.666378, 45.531441],
[13.666457, 45.529215]
],
"indices": [0, 1, 2, 3, 4, 5, 6]
}
}]
}
Using the code below to draw the layer with leaflet.js results in a polyline drawn on a wrong position.
L.mapbox.mapmatching(geojson, options, function (error, layer) {
layer.addTo(map);
layer.setStyle({
color: '#3c8dbc',
weight: 4,
opacity: 0.8
});
//fit bounds to added layer
map.fitBounds(layer.getBounds());
The result being:
While the polyline it self is as it should be, the position is not.
I speculate the problem is that leaflet expect the coordinates to be in format [latitude, longitude] while the Mapbox matching API returns GEOJson format namely [longitude, latitude].
Should I manually switch the coordinates of the response before drawing it or am I just doing it wrong?
Thanks.
Edit 2 : It appears the problem is in fact in different formats. More about it can be found in this post
Changing the order of the coordinates in the returned object is very tedious hence an elegant solution to this would be greatly appropriated.

Related

Tile out of range error when using wmts on Geoserver with Mapbox

I'd like to render a layer from geoserver with using WMTS.
I'm using mapbox-gl to render a map and layers.
The website I'm referring to is https://docs.geoserver.org/stable/en/user/styling/mbstyle/source.html.
This shows how to create a layer on geoserver and render it on a mapbox map.
However, I'm getting an error TileOutOfRange when I request tiles.
For example, when I request tiles with this url,
http://<my_server>:8080/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=myspace:japan&STYLE=&TILEMATRIX=EPSG:4326:8&TILEMATRIXSET=EPSG:4326&FORMAT=application/vnd.mapbox-vector-tile&TILECOL=221&TILEROW=102.
I get this error message.
Column 221 is out of range, min: 440 max:462.
Here below is my code to fetch a layer that I created on geoserver.
map.on("load", () => {
map.addSource("test", {
type: "vector",
tiles: ["http://<my_server>:8080/geoserver/gwc/service/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&LAYER=myspace:japan&STYLE=&TILEMATRIX=EPSG:4326:{z}&TILEMATRIXSET=EPSG:4326&FORMAT=application/vnd.mapbox-vector-tile&TILECOL={x}&TILEROW={y}"],
generateId: true,
minZoom: 0,
maxZoom: 14,
});
map.addLayer({
"id": "test",
"type": "fill",
"source": "test",
"source-layer": "japan",
"layout": { "visibility": "visible" },
"paint": {}
});
});
It would be much appreciated if anyone gave me a way to solve this.
Thank you.
I made sure that I checked this box application/vnd.mapbox-vector-tile in the tile caching settings.
I left out 900913 from the default gridset settings, since my data is EPSG:4326.
When creating a layer, I made sure that I clicked Compute from data and Compute from native bounds to set bounding boxes.

querySourceFeature returns empty array

I am using mapbox to try and query all features of the mapbox tileset and return them as geojson. From what I understand, to query features that are no visible on the screen, you must use querysourcefeatures. My tileset only shows up at zoom 14 so I am having trouble querying all the features in the dataset at once and then applying a filter. Is this possible? It stills like querySourceFeatures returns an empty array.
function addLayers() {
map.addSource('plutonew-c03oxi', {
'type': 'vector',
'url': 'mapbox://samtpr.4ehwzn0r'
});
map.addLayer({
"id": "parcels_fill",
"type": "fill",
"source": "plutonew-c03oxi",
"source-layer": "plutonew-c03oxi",
'layout': {
'visibility': 'visible'
},
paint: {
'fill-color': 'blue',
'fill-outline-color': 'gray',
"fill-opacity": ["case",
["boolean", ["feature-state", "hover"], false],
0.5,
0
]
}
});
var features = map.querySourceFeatures('plutonew-c03oxi', {filter: ["==", ['get','ZIPCODE'], zipcode_val]});
From what I understand, to query features that are no visible on the screen, you must use querysourcefeatures
You may have misunderstood. querySourceFeatures allows you to query features that are present within the vector tiles currently loaded and displayable within the current viewport and zoom level. Unlike queryRenderedFeatures they don't have to actually be rendered through a visible layer, however.
In this case it sounds like you're hoping to gain access to features that are not available at the current zoom level, which is not possible.

Constant heat map with mapbox

The new mapbox heatmap api looks awesome.
I want to achieve a constant heat map while zooming someone posted on github: https://cloud.githubusercontent.com/assets/186834/26474453/068dbd00-4166-11e7-996d-ec1756eb7355.gif
Looking at the official api example (https://www.mapbox.com/mapbox-gl-js/example/heatmap-layer/), how can I achieve this?
I believe the gif you posted is from a development prototype. This "constant heat map" effect is not the intended/default behavior of heat maps in GL.
That said, this behavior can be simulated using expressions! You'll need to use an expression that double heatmap-radius at each zoom level with a base of 2.
{
"id": "heatmap",
"type": "heatmap",
"source": "heatmap-source",
"paint": {
"heatmap-radius": {
"base": 2,
"stops": [
[
10,
2
],
[
19,
512
]
]
}
}
}

Adding custom markers to the mapbox gl

I would like to add a custom marker to my map. I am using a mapbox gl script.
The only documentation that I found related to this topic is this one https://www.mapbox.com/mapbox-gl-js/example/geojson-markers/.
I tried to customize given example and I managed to add a marker and modify it a little changing the size, but since I don't understand all the parameters, I don't know how to add my own marker. Is there any documentation that is more detailed?
Here is my code:
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoiYWl3YXRrbyIsImEiOiJjaXBncnI5ejgwMDE0dmJucTA5aDRrb2wzIn0.B2zm8WB9M_qiS1tNESWslg';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/aiwatko/cipo0wkip002ddfm1tp395va4', //stylesheet location
center: [7.449932,46.948856], // starting position
zoom: 14.3, // starting zoom
interactive: true
});
map.on('load', function () {
map.addSource("markers", {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [7.4368330, 46.9516040]
},
"properties": {
"title": "Duotones",
"marker-symbol": "marker",
}
}]
}
});
map.addLayer({
"id": "markers",
"type": "symbol",
"source": "markers",
"layout": {
"icon-image": "{marker-symbol}-15",
"icon-size": 3
}
});
});
</script>
Thanks in advance!
Oktawia
There are two ways to customize markers in Mapbox.
Raster Markers in Mapbox
See this link on Mapbox.com for Custom marker icons. That example shows how to use a .png as a marker.
SVG Markers in Mapbox
You are pretty close to modifying the icons, but take some time to familiarize yourself with the parameters.
The icon-image may be the harder one to understand. It takes the property "marker-symbol": "marker" from the GeoJson, and "icon-image": "{marker-symbol}-15", to create the final result of marker-15.
This brings up a further question: where/how are the markers defined?!?
The markers also come from Mapbox and are called Maki Icons. You can change the "marker-symbol" to aquarium or cafe to see the results.
From the Mapbox GL Style Reference
icon-size — Scale factor for icon. 1 is original size, 3 triples the size.
icon-image — A string with {tokens} replaced, referencing the data property to pull from.

Difference between leaflet Marker and mapbox featureLayer

I understood that I can use the general Leaflet layer, and the more advanced map-box featureLayer, that provides useful functions as the filter.
However, I don't understand the difference between
marker = L.Marker (new L.LatLng(lat, lng),
{
icon: L.mapbox.marker.icon(
{'marker-color': 'fc4353'
'marker-size': 'large'
}),
title: name,
});
map.addLayer(marker);
and
var poijson = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [lng, lat]
},
"properties": {
"title": poi.name,
"marker-color": "#fc4353",
"marker-size": "large"
}
};
map.featureLayer.setGeoJSON(geojson);
Is it just the same?
[UPDATE]
Moreover, if I had many markers, should I add a new layer for each marker? It seems not a good thing for performance..
For instance, If I do:
var pois; //loaded with pois info
var geojson=[]; //will contain geojson data
for (p=0; p< pois.length; p++)
{
var poi = pois[p];
var poijson =
{
"type": "Feature",
"geometry":
{
"type": "Point",
"coordinates": [poi.lng, poi.lat]
}
};
geojson.push(poijson);
}
map.featureLayer.setGeoJSON(geojson);
Does it will create many layers for each poi, or just one layer with all the markers?
thank you
When you add a marker to a Leaflet map via map.addLayer(marker);, the marker is added to the 'leaflet-maker-pane'. The markers are plain images/icons.
You can use a geoJSON layer to draw GIS features: points, lines, polygons, etc.
See here: http://leafletjs.com/examples/geojson.html
Mapbox's featureLayers is just an extension to Leaflet's geoJSONLayer
To add multiple markers, call addMarker multiple times. Leaflet will create a new layer for each of the markers. Each marker will be added as an image element to the leaflet-marker-pane div:
http://bl.ocks.org/d3noob/9150014
Updated response:
If you add a GeoJSON layer with multiple features, Leaflet will create separate layer for each of the features. You can inspect the layers of the map by calling map._layers after adding the GeoJSON Layer.
marker.addTo(map) and map.addLayer(marker) are doing the same thing.
Here's the addTo function taken from the source
addTo: function (map) {
map.addLayer(this);
return this;
},