I am trying to create a very simple popup that brings info from a (point) geoJson attribute - popup

I am using the following code and it just doesn't work!!! Working with a point geoJson.
This same type of code DOES work for a polygon geoJson a few steps after.
js:
var points2 = L.geoJson(points2,{onEachFeature: function(feature, layer) {
layer.bindPopup(feature.properties.popup);}}).addTo(map);
the relevant geojson:
var points2 = {"type": "FeatureCollection", "features":
[
{"type":"Feature","geometry":{"type":"Point","coordinates":[-73.997208,40.743771]},"properties":{"cartodb_id":2,"description":"Private home","popup":"Casa Señora Arnao (Bernardo's 1st abode in NYC)","address":"228 West 22nd Street"}},
{"type":"Feature","geometry":{"type":"Point","coordinates":[-73.926637,40.858235]},"properties":{"cartodb_id":5,"description":"Urban scene","popup":"Couples kissing openly - \"I quickly realized that our presence didn’t matter to them….what a difference between our customs back home and the behavior of Puerto Rican men and women in New York!”","address":"Park at 191st Street and St-Nicholas Avenue"}},
{"type":"Feature","geometry":{"type":"Point","coordinates":[-73.95678,40.805015]},"properties":{"cartodb_id":4,"description":"Private home","popup":"Casa Familia León","address":"116th Street and Manhattan Avenue"}},
{"type":"Feature","geometry":{"type":"Point","coordinates":[-73.949677,40.797255]},"properties":{"cartodb_id":7,"description":"Political/Cultural meeting place","popup":"Park Palace","address":"3-5 West 110th Street"}},
{"type":"Feature","geometry":{"type":"Point","coordinates":[-73.9467,40.790554]},"properties":{"cartodb_id":8,"description":"Political/Cultural meeting place","popup":"Harlem Terrace","address":"210 East 104th Street"}},
{"type":"Feature","geometry":{"type":"Point","coordinates":[-73.948755,40.793271]},"properties":{"cartodb_id":9,"description":"Political/Cultural meeting place","popup":"Harlem Educational Center","address":"106th Street (between Park and Madison Aves)"}}
]}
What could be possible cause of the error and How can I fix it?
Thanks.

Related

MapBox Reserved Country Code Elements (ISO 3166)

I'm curious if anybody knows how to colour a specific country that no longer exists (i.e., Soviet Union) using MapBox's built-in function?
map.on('load', function () {
// Add source for country polygons using the Mapbox Countries tileset
// The polygons contain an ISO 3166 alpha-3 code which can be used to for joining the data
// https://docs.mapbox.com/vector-tiles/reference/mapbox-countries-v1
map.addSource('countries', {
type: 'vector',
url: 'mapbox://mapbox.country-boundaries-v1'
});
// Add filled county polygons for highlighted display.
map.addLayer(
{
'id': 'countries-highlighted',
'type': 'fill',
'source': 'countries',
'source-layer': 'country_boundaries',
'paint': {
'fill-outline-color': '#484896',
'fill-color': '#6e599f',
'fill-opacity': 0.75
},
// Display a single country
'filter': ['in', 'iso_3166_1', 'SU']
},
'admin-1-boundary-bg'
);
This works fine for a country like USA (ISO 3166-1: 'US'). However, nothing is displayed for former countries like the Soviet Union (ISO 3166-1: 'SU')
I would appreciate if anyone has accomplished this before or can recommend the optimal procedure.
For example, group all of the current countries that made up the former U.S.S.R. (although the border boundaries may not match perfectly)
Or, if there is a downloadable tileset that includes all former countries.
SU
Removed from ISO 3166-1 in 1992 when former USSR was divided into:
Armenia (AM, ARM, 051), Azerbaijan (AZ, AZE, 031), Estonia (EE, EST,
233), Georgia (GE, GEO, 268), Kazakstan (KZ, KAZ, 398), Kyrgyzstan
(KG, KGZ, 417), Latvia (LV, LVA, 428), Lithuania (LT, LTU, 440),
Republic of Moldova (MD, MDA, 498), Russian Federation (RU, RUS, 643),
Tajikistan (TJ, TJK, 762), Turkmenistan (TM, TKM, 795), Uzbekistan
(UZ, UZB, 860). NOTE: Belarus (BY, BLR, 112) and Ukraine (UA, UKR,
804) are not listed because they were separately coded in ISO 3166
already before the USSR was split.

Mapbox GL JS: zoom to filtered polygon?

I am using Mapbox GL JS to display a polygon layer. I would to allow the user to choose a name from a dropdown, and then highlight and zoom to the matching polygon.
I already know how to highlight the matching polygon using map.setFilter, but I don't know how to zoom to the bounds of the matching polygon. This is my current code:
map.addLayer({
'id': 'polygon_hover',
'source': 'mysource',
'source-layer': 'mylayer',
'type': 'fill',
'paint': {
'fill-color': 'red',
"fill-opacity": 0.6
},
"filter": ["==", 'CUSTNAME', ""]
});
// Get details from dropdown
custname.on("change", function(e) {
// get details of name from select event
map.setFilter('polygon_hover', ["==", 'CUSTNAME', name]);
// Get bounds of filtered polygon somehow?
// var bounds = ??;
// map.fitBounds(bounds);
});
I have examined the Mapbox example of zooming to bounds, but it assumes that you already know what the bounds are.
Is there any way it's possible to get the bounds of the polygon matching a map filter in Mapbox?
I've the following code to fitBounds to Polygon center coords:
var coordinates = f.geometry.coordinates[0];
var bounds = coordinates.reduce(function (bounds, coord) {
return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(coordinates[0], coordinates[0]));
map.fitBounds(bounds, {
padding: 20
});
Where f is one Feature.
I found a solution to your problem. Leaflet has a polygon Class which takes an Array of polygon coordinates and has a function called getBounds() that returns south west and north east bounds. However, Leaflet doesn't follow the convention of LngLat, its format is LatLng. Therefore, you have to switch it. I took an example out from Mapbox Show drawn polygon area, and added exactly what you're looking for.
var polygon = data.features[0].geometry.coordinates;
var fit = new L.Polygon(polygon).getBounds();
var southWest = new mapboxgl.LngLat(fit['_southWest']['lat'], fit['_southWest']['lng']);
var northEast = new mapboxgl.LngLat(fit['_northEast']['lat'], fit['_northEast']['lng']);
var center = new mapboxgl.LngLatBounds(southWest, northEast).getCenter();
// map.flyTo({center: center, zoom: 10});
map.fitBounds(new mapboxgl.LngLatBounds(southWest, northEast));
I see that the question is still relevant - I solved it making a separate request to the database containing all points of a given polygon and building bounds [[minLng, minLat], [maxLng, maxLat]].
All attempts to address geometry of already rendered or source features didn't work for me - most probably because Mapbox doesn't keep initial geoJSON in the tiles.

Mapbox GL JS Bearing

Is it possible in Mapbox GL JS to get the users bearing?
I would like to show the direction in which the user is facing, to assist them in navigating to nearby POI.
I understand that it is possible to set the bearing of the map and also get the current bearing of it, but i need the actual real life bearing of the user.
Kind of the same thing as on Google Maps:
The service is intended to run as an Ionic app on iOS and Android, and the assistance in bearing is a key feature in helping them locate nearby POI on a well populated map.
You can get the user's bearing (if their device has such a sensor) by obtaining a Coordinates object from Gelocation#getCurrentPosition() and reading Coordinates#heading.
Mapbox GL JS has no built-in user interface for displaying a user's heading. Building your own user interface is easy. See this example which uses the symbol-rotation property.
So, after some time spend on this, i thought I'd show how i ended up doing this, in case someone else needs it or have a better solution.
It seems cordova has a built in "heading" property in the position object.
https://github.com/apache/cordova-plugin-geolocation
var heading = $rootScope.position.heading;
First, i make sure that the marker is always pointing in the heading direction, even when the user turns the map, by subtracting the mapBearing(degrees the map has turned from North), from the user heading.
map.on('rotate', function(){
map.setLayoutProperty('drone', 'icon-rotate', heading - map.getBearing())
});
I create an icon, at the users position, add the source and add the layer with the source.
map.on('load', function () {
var point = {"type": "Point", "coordinates": [$rootScope.position.long, $rootScope.position.lat]};
map.addSource('drone', {type: 'geojson', data: point });
map.addLayer({
"id": "drone",
"type": "symbol",
"source": "drone"
}
});
Next i check that heading is actually available, since it only appears to return a value, when the user is moving(only tested on Android so far), and if it is, update the heading of the point.
if($rootScope.position.heading){
var heading = $rootScope.position.heading;
map.setLayoutProperty('drone', 'icon-rotate', $rootScope.position.heading);
};
Finally i update the position of the point, in a "$watch" position.
map.getSource('drone').setData(point);
This way, i can watch the users heading, and the point keeps on track, even when the user rotates the map.
For the users coming here after 2020 (what an year lol), mapbox gl js now supports geolocation which not only provides user's heading but also a bunch of other helpful data:
const geolocate = map.addControl(
new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
trackUserLocation: true
})
)
then listen for geolocate event:
geolocate.on('geolocate', (e) => {
console.log(e);
});
this will give you following object:
{
coords: {
accuracy: number;
altitude: number;
altitudeAccuracy: number;
heading: number;
latitude: number;
longitude: number;
speed: number;
};
timestamp: number;
heading will give you direction of the user. As the geolocate control keeps triggering automatically so can get the user's direction as well as speed and altitude etc in real time and use that to display data driven symbols on map.

Mapbox Matching API switched coordinates

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.

Openlayers 3 coordinate conversions

Newb alert: I'm completely new to OpenLayers 3 and mapping in general. My background is in SQL Server, and back end systems design. I have no experience in HTML, JavaScript, web development etc. I'm sure this is a very simple issue but I can't seem to figure out the details.
I've modified one of the samples for OpenLayers.org and it doesn't behave as expected. It uses a GeoJSON object and draws points on the map, but they don't end up where expected. Apparently there is some conversion or something that happens.
The sample I used is here: GeoJSON example
My test map is here: Test Map
The GeoJSON object is defined as
var geojsonObject = {
'type': 'FeatureCollection',
'crs': {
'type': 'name',
'properties': {
'name': 'EPSG:3857'
}
},
'features': [
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [0, 0]
}
},
{
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [-8.575653e6, 4.70681e6]
//White House, Washington DC Lon -77.03648269999997 Lat 38.89767579999999
}
}
]
};
Through a little trial and error, I was able to get my point to display on the White House Lawn (NSA has no doubt flagged this conversation) and there is no resemblance to the latitude and longitude I pulled from a different source. I understand that the order of coordinates is [lon, lat] but I can see no rhyme or reason that -77.036 = -8.575e6. The other point [0,0] displays right where I would expect it.
I have tried to figure this out myself and searched quite a few places, but I can't seem to find the answer.
Also, if you could direct me to any good tutorials, it would be most appreciated. Thanks!
Your GeoJSON data is in EPSG:3857, a different coordinate system than latitude/longitude. The coordinates are not equal, but represent the same geographical location.
See http://spatialreference.org/ref/sr-org/6864/ for information about EPSG:3857. The map there clearly shows the difference between a given points coordinates in the coordinate reference systems.
Openlayers actually allows you to convert these using the ol.proj functions.
For instance, to convert from lat/lon (EPSG:4326) to Spherical mercator ( EPSG:3857 - the one most online web maps use, in metres) you could do:-
var newCoordinates = ol.proj.transform(latLonCoordinate, "EPSG:4326", "EPSG:3857");
newCoordinates would then contain the converted values in a coordinates array. Same can be done for 'extents' (the box coordinates for top left/bottom right of a map view) using ol.proj.transformExtent(extent, fromProj, toProj).