Mapbox GL JS and GeoJSON as an external file - mapbox

I have code to set markers with Mapbox map
$(function() {
mapboxgl.accessToken = 'pk.###';
var map = new mapboxgl.Map({
container: 'map-global',
style: '..'
});
var geojson = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"title": "POI Title"
},
"geometry": {
"type": "Point",
"coordinates": [0, 0]
}
}
]
};
geojson.features.forEach(function(marker) {
// create a HTML element for each feature
var el = document.createElement('div');
el.className = 'marker';
new mapboxgl.Marker(el)
.setLngLat(marker.geometry.coordinates)
.setPopup(new mapboxgl.Popup()
.setHTML(marker.properties.title))
.addTo(map);
});
});
And it works fine. But I want to use GeoJSON as an external file:
var geojson = 'file.geojson';
And here I have a problem — it doesn't work:
TypeError: undefined is not an object (evaluating '"map.geojson".features.forEach')".
Is there any way to use external GeoJSON file with custom HTML
markers?

You can load external geojson files with plain mapbox addSource().
map.on('load', function() {
var url = 'http://your_geojson_file.com/some_file.geojson';
map.addSource('source_id', { type: 'geojson', data: url});
});
See this example:
https://www.mapbox.com/mapbox-gl-js/example/live-geojson/

Since you are using Jquery, you could use getJSON to load your file:
Load JSON-encoded data from the server using a GET HTTP request.
Reference: http://api.jquery.com/jquery.getjson/
Example:
$.getJSON('file.geojson', function (geojson) {
geojson.features.forEach(function (marker) {
// etc
});
});

Related

Mapbox popup displays "unknown" instead of properties

After clicking on a street (which is supposed to display a popup with properties), the popup displays "unknown". What should be done to make the popup show the properties? If anyone knows what to change or what could be the cause of the popups not working, I would be really grateful!
<div class="container" style="background-color:#F6F3F3">
<div id='map' style='width: 100%; height: 900px;'></div>
<script>
mapboxgl.accessToken =
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/bisqpski/cjssto8kw77g11gk4rwur575q'
});
map.on('load', function() {
// Add a layer showing the state polygons.
map.addLayer({
'id': 'kazimierz-tileset',
'type': 'fill',
'source': {
"type": "Feature",
"properties": {
"Street": "Świętego Wawrzyńca",
"Probability": "13%"
},
"geometry": {
"coordinates": [
[19.944511, 50.049316],
[19.94617, 50.049681],
[19.946307, 50.049719],
[19.947699, 50.050025],
[19.948851, 50.050282],
[19.949689, 50.050456],
[19.951076, 50.05076],
[19.951401, 50.050831]
],
"type": "LineString"
}
}
});
// When a click event occurs on a feature in the states layer, open a popup
at the
// location of the click, with description HTML from its properties.
map.on('click', 'kazimierz-tileset', function(e) {
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML(e.features[0].properties.name)
.addTo(map);
});
// Change the cursor to a pointer when the mouse is over the states layer.
map.on('mouseenter', 'kazimierz-tileset', function() {
map.getCanvas().style.cursor = 'pointer';
});
// Change it back to a pointer when it leaves.
map.on('mouseleave', 'kazimierz-tileset', function() {
map.getCanvas().style.cursor = '';
});
});
</script>
</div>
You don't have name as a property for your features. Only street and probability. So you're calling a property that doesn't exist. Use street or define the property name with whatever you want.
"properties": {
"Street": "Świętego Wawrzyńca",
"Probability": "13%"
"Name": "Your Name Here"
},
Or just use the street property.
.setHTML(e.features[0].properties.Street)
Snippet:
<div class="container" style="background-color:#F6F3F3">
<div id='map' style='width: 100%; height: 900px;'></div>
<script>
mapboxgl.accessToken =
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/bisqpski/cjssto8kw77g11gk4rwur575q'
});
map.on('load', function() {
// Add a layer showing the state polygons.
map.addLayer({
'id': 'kazimierz-tileset',
'type': 'fill',
'source': {
"type": "Feature",
"properties": {
"Street": "Świętego Wawrzyńca",
"Probability": "13%"
},
"geometry": {
"coordinates": [
[19.944511, 50.049316],
[19.94617, 50.049681],
[19.946307, 50.049719],
[19.947699, 50.050025],
[19.948851, 50.050282],
[19.949689, 50.050456],
[19.951076, 50.05076],
[19.951401, 50.050831]
],
"type": "LineString"
}
}
});
// When a click event occurs on a feature in the states layer, open a popup
at the
// location of the click, with description HTML from its properties.
map.on('click', 'kazimierz-tileset', function(e) {
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML(e.features[0].properties.Street)
.addTo(map);
});
// Change the cursor to a pointer when the mouse is over the states layer.
map.on('mouseenter', 'kazimierz-tileset', function() {
map.getCanvas().style.cursor = 'pointer';
});
// Change it back to a pointer when it leaves.
map.on('mouseleave', 'kazimierz-tileset', function() {
map.getCanvas().style.cursor = '';
});
});
</script>
</div>
Lastly, in your example you're adding a layer. But you already have that layer added with the same name in the style you created. You don't need to add it again or you'll get a Error: Layer with id "kazimierz-tileset" already exists on this map since it will naturally pull directly from the style. Make sure to rename the layer or remove the addLayer.

Access geojson property of a layer in a featuregroup in Mapbox

I have a GEOJSON which I added to the featuregroup in my Mapbox map like this:
var featureCollection = {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"id": 1
},
"geometry": {
"type": "Point",
"coordinates": [0, 0]
}
},{
"type": "Feature",
"properties": {
"id": 2
},
"geometry": {
"type": "Point",
"coordinates": [30, 30]
}
},{
"type": "Feature",
"properties": {
"id": 3
},
"geometry": {
"type": "Point",
"coordinates": [-30, -30]
}
}]
};
var geojson = L.geoJson(featureCollection);
var featureGroup = L.featureGroup().addTo(map);
featureGroup.addLayer(geojson);
Now, I wish to access the id property of each layer while looping through the featuregroup, so that I can pass it as an argument to another function. In the case of a featurelayer, I can easily access it using something like this:
var featureLayer = L.mapbox.featureLayer(featureCollection).addTo(map);
featureLayer.eachLayer(function (layer) {
layer.on('click', function (e) {
console.log('Clicked feature ID: ' + e.target.feature.properties.id);
});
});
But I want to be able to access it while looping inside a featuregroup, and also I want to be able to do it without a 'click' or any such event. For example, ideally I would use something like this:
featureGroup.eachLayer(function (layer) {
var id = layer.feature.properties.id;
testfunction(id);
});
I haven't been able to figure out how to do that. I've tried searching online, but because I'm new to this, I probably haven't been using the right keywords in my search.
geojson is nested within featureGroup, so when your eachLayer function runs, it is not operating on the individual features within geojson, but instead on geojson itself. To extract each feature's id property, you will need to go one level deeper and iterate over the features within geojson.
Fortunately, the L.GeoJson class also supports the eachLayer method (because it is an extension of L.FeatureGroup, which is itself an extension of L.LayerGroup). To print the id of each feature, you could just use the eachLayer method directly on geojson:
geojson.eachLayer(function (layer) {
var id = layer.feature.properties.id;
testfunction(id);
});
Or, if you have a bunch of L.GeoJson objects nested within featureGroup, you can use:
featureGroup.eachLayer(function (layer) {
layer.eachLayer(function (layer) {
var id = layer.feature.properties.id;
testfunction(id);
});
});

What is the proper way to select and style markers on Mapbox GL JS?

I am working with a Mapbox map that has points. I would like to know the correct procedure for adding a marker-symbol. Here is my GeoJSON:
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-89.12312324,
13.686886
]
},
"properties": {
"title": "Random Location",
"description": "Individual"
}
}
]
Here is an example from the Mapbox docs:
map.addLayer({
"id": "airport",
"source": "airports",
"source-layer": "ne_10m_airports",
"type": "symbol",
"layout": {
"icon-image": "airport-15",
"icon-padding": 0
},
"filter": ["in", "abbrev", ""]
});
When I use this
"layout": {
"icon-image": "marker-11",
"icon-allow-overlap": true,
}
I get little brown dots instead of the classic marker.
I am using
<script src='https://api.mapbox.com/mapbox-gl-js/v0.18.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v0.18.0/mapbox-gl.css' rel='stylesheet' />
and I am using the
style: 'mapbox://styles/mapbox/outdoors-v9', //stylesheet location
My entire script looks like this:
mapboxgl.accessToken = 'pk.mylongAkey';
var map = new mapboxgl.Map({
container: 'map', // container id
style: 'mapbox://styles/mapbox/outdoors-v9', //stylesheet location
center: [-88.866245, 13.770391], // starting position
zoom: 6 // starting zoom
});
var url = '/maps/index.json';
var source = new mapboxgl.GeoJSONSource({
data: url
});
map.on('load', function () {
map.addSource('location', source);
map.addLayer({
"id": "map",
"type": "symbol",
"source": "location",
"source-layer": 'location',
"layout": {
"icon-image": "marker-11",
"icon-allow-overlap": true,
}
});
});
map.on('click', function (e) {
var features = map.queryRenderedFeatures(e.point, { layers: ['map'] });
if (!features.length) {
return;
}
var feature = features[0];
// Populate the popup and set its coordinates
// based on the feature found.
var popup = new mapboxgl.Popup()
.setLngLat(feature.geometry.coordinates)
.setHTML(feature.properties.title)
.addTo(map);
});
// Use the same approach as above to indicate that the symbols are clickable
// by changing the cursor style to 'pointer'.
map.on('mousemove', function (e) {
var features = map.queryRenderedFeatures(e.point, { layers: ['map'] });
map.getCanvas().style.cursor = (features.length) ? 'pointer' : '';
});
Am I missing something? Also, the popups don't popup above the points, they popup over top of the icon. You can't tell with this little brown dot, but with the rocket for example the popup is in the middle of the rocket. Thanks!
Here is a screenshot
I am working with a Mapbox map that has points. I would like to know the correct procedure for adding a marker-symbol. Is it better to do it in the GeoJSON like:
...
Or is better to use layout like this:
...
Embedding style information in the GeoJSON (the former) is a specification called simplestyle, which is not supported in GL JS. Using layout (the latter) is the only way to style features in GL JS.
I get little brown dots instead of the classic marker.
Could you please provide a screenshot of this?
In the Mapbox Studio Editor, you need to make sure that you actually have an icon called "marker-11" in your icon library. If not, it doesn't know what you are referencing and will default to a dot.
Otherwise, everything else looks fine.

Mapbox GL setData to update layer with multiple markers

I have a Mapbox GL map with a single layer and multiple markers on that layer, I am trying to update a specific marker, so I am using setData in order to update only one marker but setData will reset the whole layer markers to add only that I am trying to update as the single marker on the whole layer, thus removing all old markers.
By trying to add multiple markers in GEOJson format as an array of GEOJson objects as shown below I get an error:
Uncaught Error: Input data is not a valid GeoJSON object.
code:
map.getSource('cafespots').setData([{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [31.331849098205566, 30.095422632059062]
},
"properties": {
"marker-symbol": "cafe"
}
},{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [31.39, 30.10]
},
"properties": {
"marker-symbol": "cafe"
}
}]);
Will appreciate it so much if someone can please help by telling me what I am doing wrong / missing here, thanks
setData expects a complete GeoJSON object (not just it's features) or a url pointing to a GeoJSON object.
You'll need to manage the state of the GeoJSON in your code and update the entire object via setData when a change is made.
var geojson = {
"type": "FeatureCollection",
"features": []
};
map.on('load', function() {
map.addSource('custom', {
"type": "geojson",
"data": geojson
});
// Add a marker feature to your geojson object
var marker {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [0, 0]
}
};
geojson.features.push(marker);
map.getSource('custom').setData(geojson);
});
https://www.mapbox.com/mapbox-gl-js/example/measure/ is a good example that demonstrates this behaviour.

can't implement L.mapbox.simplestyle with geoJson

I'm trying to implement simplestyle's options for marker size and color , but can't get them to render. In this simple test case, I'm trying to follow Mapbox's own example quite closely:
var myData = [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [4.509373,51.932994]
},
"properties": {
"marker-size": "large",
"marker-color": "#ffcc00"
}
}
];
var map = L.mapbox.map('map', 'examples.map-20v6611k')
.setView([51.932994,4.509373], 8);
L.geoJson(myData, { style: L.mapbox.simplestyle.style }).addTo(map);
fiddle
But the marker renders in default style. What am I missing?
OK, I've got it working using this extended function from this page of Mapbox's documentation:
L.geoJson(myData, {
pointToLayer: L.mapbox.marker.style,
style: function(feature) { return feature.properties; }
}).addTo(map);
The other Mapbox example didn't make it look like the pointToLayer argument was required, but whatever works:
fiddle
Another alternative would be to create a featureLayer based on your myData:
var featureLayer = L.mapbox.featureLayer(myData).addTo(map);
Your data will have to be an object, however, and not an array:
var myData = {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [4.509373,51.932994]
},
"properties": {
"marker-size": "large",
"marker-color": "#ffcc00"
}
};