geojson ignored when using mapbox - mapbox

why does mapbox ignore my geoJson marker-symbol, marker-color, and marker-size? if for whatever reason it ignores, how do you set either?
sample geoJson:
"properties": {
"id": 578202,
"name": "University of North Carolina at Charlotte",
"marker-symbol": "marker",
"marker-color": "#ff8888",
"marker-size": "small",
"description": 1
}
script:
$.getJSON(url, function(data) {
var geojson = L.geoJson(data, {
onEachFeature: function(feature, layer) {
var popupContent = feature.properties.name +'project(s)';
layer.bindPopup(popupContent, {
closeButton: true,
minWidth: 225
});
}
});
var map = L.mapbox.map('map', '', {
attributionControl: false
});
geojson.addTo(map);
});

That's happening because L.GeoJSON doesn't automaticly know that you want to set the marker options, so if it encounters a Point feature, it simply adds a default marker. If you want to do something special with point features, you can use the pointToLayer function of L.GeoJSON, check the following example:
var geoJsonLayer = L.geoJson(geoJson, {
pointToLayer: function (feature, latLng) {
return L.marker(latLng, {
icon: L.mapbox.marker.icon(feature.properties)
});
}
}).addTo(map);
The only problem with this is that it also adds all the other properties as options of the markericon. Personally i would write some logic so that only the relevant properties get added to the icon options.
Here's a working example on Plunker: http://plnkr.co/edit/3OJPXxOYdzX8mSnjEb90?p=preview
As tmcw pointed out in the comments (see below): you could use L.mapbox.featureLayer, it does exactly what you're trying to accomplish with L.GeoJSON without having to resort to the pointToLayer method i described above and it only uses the appropriate properties. It can even load your data for you so you can do away with jQuery's $.getJSON. Win/win situation if you ask me. You can simply do the following and you're set:
L.mapbox.featureLayer(url).addTo(map);
Here's the working example of this on Plunker: http://plnkr.co/edit/Og6tuYDIkTX7ftedoR3C?p=preview

Related

Update style of individual feature from single geoJSON source on Mapbox map, when clicked

I'm working with Mapbox GL JS to plot geoJSON data on a map using their external geoJSON example as a starting point. The geoJSON file contains lots of features which are plotted as individual markers on the same layer. I would like to highlight the clicked marker by changing its colour from red to blue. I have adapted the example to show a pop-up with the point id when clicked (just as a proof of concept that the markers can fire events when clicked), however, I'm struggling to find a way to change the styling of the individual clicked marker.
The code is currently as follows:
mapboxgl.accessToken = 'pk.eyJ1IjoiZGFuYnJhbWFsbCIsImEiOiJjbDB3ODFveHYxOG5rM2pubWpwZ2R1Y2xuIn0.yatzJHqBTjQ6F3DHASlriw';
const map = new mapboxgl.Map({
container: 'map', // container ID
style: 'mapbox://styles/mapbox/satellite-v9', // style URL
zoom: 7, // starting zoom
center: [138.043, 35.201] // starting center
});
map.on('load', () => {
map.addSource('earthquakes', {
type: 'geojson',
data: 'https://docs.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson'
});
map.addLayer({
'id': 'earthquakes-layer',
'type': 'circle',
'source': 'earthquakes',
'paint': {
'circle-radius': 8,
'circle-stroke-width': 2,
'circle-color': 'red',
'circle-stroke-color': 'white'
}
});
});
map.on('click', 'earthquakes-layer', (e) => {
new mapboxgl.Popup()
.setLngLat(e.lngLat)
.setHTML('Id: ' + e.features[0].properties.id)
.addTo(map);
});
Here is a codepen: https://codepen.io/danb1/pen/BaYjOyx
Is it the case that it's actually not possible to use this approach, and instead each feature from the geoJSON file needs to be plotted as a separate layer? I'm struggling to find any examples of this and am not able to modify the geoJSON source — it has to come from one single file (rather than loading multiple geoJSON files separately on separate layers).
This is possible using feature-state. The first thing to do is to ensure the layer data contains ids for each feature (in the example the source data doesn't so we need to add generateId: true to the map.addSource method).
We then need to add mousemove and mouseleave events to the map to store the moused-over feature id (if there is one, i.e. if the mouse is hovering over a feature):
let hoveredEarthquakeId = null;
map.on('mousemove', 'earthquakes-layer', (e) => {
map.getCanvas().style.cursor = 'pointer';
if (e.features.length > 0) {
map.setFeatureState(
{ source: 'earthquakes', id: e.features[0].id },
{ hover: true }
);
hoveredEarthquakeId = e.features[0].id;
}
});
map.on('mouseleave', 'earthquakes-layer', () => {
map.getCanvas().style.cursor = '';
if (hoveredEarthquakeId !== null) {
map.setFeatureState(
{ source: 'earthquakes', id: hoveredEarthquakeId },
{ hover: false }
);
}
hoveredEarthquakeId = null;
});
Finally, in the layer properties, the colour setting of the circle needs to be updated to reflect the hover value stored against the feature:
'circle-color': [
'case',
['boolean', ['feature-state', 'hover'], false],
'#00f',
'#f00'
],
The final thing can be seen in the modified pen. There is also a MapBox tutorial covering this kind of thing in a slightly more complicated way, which I hadn't come across until now: https://docs.mapbox.com/help/tutorials/create-interactive-hover-effects-with-mapbox-gl-js/.

Leaflet: how to change map center and zoom level clicking on circleMarker?

I'm working on a map with a few circleMarkers. When a user is clickin on one of this circleMarker, I would like to center the map on this circleMarker and to zoom in. It works when I try this on multipolygon layers, but I didn't succeed on circleMarkers. Does anyone can help me?
Here is the code for my circleMarkers:
<script>
var map = L.map('map', {
center: [41.8, 12.5],
zoom: 5,
zoomControl:true, maxZoom:15, minZoom:4,
});
var feature_group = new L.featureGroup([]);
var raster_group = new L.LayerGroup([]);
var basemap = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Shaded_Relief/MapServer/tile/{z}/{y}/{x}', {
attribution: 'Tiles © Esri — Source: Esri',
});
basemap.addTo(map);
function style1(feature) {
return {
weight: 2,
radius: 10,
opacity: 1,
color: 'black',
weight: 1,
fillOpacity: 1,
fillColor: 'red'
};
}
L.geoJson(villes, {
style: style1,
pointToLayer: function (feature, latlng)
{
return L.circleMarker(latlng).bindLabel( feature.properties.Name, {className: "ville", noHide: true });
}
}
)
.addTo(map)
.showLabel;
</script>.
Here is a link to the complete map.
Thank you.
This can be achieved really simply.
Let's assume marker points to your leaflet marker and map to your leaflet map.
Quick way (recommended)
marker.on("click", function(event) {
map.setView(marker.getLatLng(), 16);
}, marker);
Here, I don't even compute the needed zoom level, because I assume leaflet will have to zoom to its max level anyway.
I could also have added my marker to a L.LayerGroup, even if the main point of a LayerGroup is to group multiple markers.
Anyhow, the more precise way
marker.on("click", function(event) {
map.setView(marker.getLatLng(), map.getBoundsZoom(layerGroup.getBounds());
}, marker);
Note that the quick way will do it nicely too. The second solution might seem more precise but it also slower, and implies a use of LayerGroup which is not the way it has been designed to work (create a new layergroup for each marker).
Don't forget to take yout time reading the docs, it's well-designed and pretty easy to understand.
I find the solution:
function onClick(e) {map.setView(this.getLatLng(),15);}
L.geoJson(villes, {
style: style1,
pointToLayer: function (feature, latlng)
{
return L.circleMarker(latlng).bindLabel( feature.properties.Name, {className: "ville", noHide: true }).on('click', onClick);
}
}
)
.addTo(zoom1)
.showLabel;
Thanks Stranded Kid for your help.

Leaflet elevation profiles with multiple GeoJSON features

I have a map which loads a GeoJSON containing two features (lines). I would like to use Leaflet Elevation plugin to display an elevation profile for each of those lines. The problem with my code is that when I click a feature, there is no data added to the elevation profile.
var map = L.map('map').setView([44.635, 22.653], 11);
var osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
function addData(e) {
var el = L.control.elevation();
el.addData(e);
map.addControl(el);
}
function onEachFeature(feature, layer) {
layer.on({
click: addData
});
}
var trails = new L.GeoJSON.AJAX('https://googledrive.com/host/0B55_4P6vMjhITEU4Ym9iVG8yZUU/map.geojson', {
onEachFeature: onEachFeature
}).addTo(map);
Here's a JSFiddle of my work: http://jsfiddle.net/pufanalexandru/eaok0Lnz/3/
To anyone who might be interested, I think I found a way to achieve this:
var trails = new L.GeoJSON.AJAX('https://googledrive.com/host/0B55_4P6vMjhITEU4Ym9iVG8yZUU/map.geojson', {
onEachFeature: function onEachFeature(feature, layer) {
layer.on({
click: function () {
el.clear();
el.addData(feature);
}
});
}
}).addTo(map);

Load geoJson in MapBox for editing with Leaflet.Draw

I try to load geoJson data in Mapbox and edit it with the plugin Leaflet.Draw
Here is an example : fiddle
var featureGroup = L.featureGroup().addTo(map);
var geojson = {
"type": "FeatureCollection",
"features": [ ........... ]
}
L.geoJson(geojson).addTo(featureGroup);
When i click to the edit button, i have an error :
Uncaught TypeError: Cannot read property 'enable' of undefined
Object seems to be editable but i can't modify it.
What is the correct way to add geojson object in mapbox draw layer ?
I have found the solution :
L.geoJson(geojson, {
onEachFeature: function (feature, layer) {
featureGroup.addLayer(layer);
}
});
Here is working example using CoffeeScript:
drawnItems = new L.FeatureGroup()
map.addLayer drawnItems
layers = L.geoJson geojson
layers.eachLayer (layer) => drawnItems.addLayer layer
I had to do the following to get mine to work (in addition to the above answers):
L.geoJson(geojson, {
onEachFeature: function (feature, layer) {
if (layer.getLayers) {
layer.getLayers().forEach(function (l) {
featureGroup.addLayer(l);
})
} else {
featureGroup.addLayer(layer);
}
}
});
This was for a geojson that was a "Feature" type.

How to display Leaflet Static Labels for objects in a LayerGroup?

I'm trying to add a static label to a few CircleMarkers I've created. These markers are added to a LayerGroup and then added to the map. I've read that I need to call .showLabel() after I've added it to the object to the map. But since I am building the LayerGroup first, then adding it to the map I'm unsure of how to do this.
I thought about using L.LayerGroup.eachLayer but I'm unsure which object I would actually call the .showLayers() on. My code is below, any help is appreciated, thanks!
var jsonLayers = new L.LayerGroup();
jsonLayers.addLayer(L.geoJson(mapFeature.features[i], {
style: function (feature) {
return feature.properties && feature.properties.style;
},
onEachFeature: onEachFeature,
pointToLayer: function (feature, latlng) {
var newCircle = L.circleMarker(latlng, {
radius: 5,
fillColor: fColor,
color: "#000",
weight: 1,
opacity: 1,
fillOpacity: 0.8
});
newCircle.bindLabel(feature.properties.name, { noHide: true });
return newCircle;
}
}));
map.addLayer(jsonLayers);
It turns out that static labels are not supported on CircleMarkers. To solve this, I added code to Leaflet.label to allow this. I've also issued a pull request in case someone else would like to do the same thing I am doing.